aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn Ruben Bakke2017-10-11 23:31:34 +0200
committerDamien George2018-07-18 17:12:25 +1000
commit7a2e136049188f550d80a8a76cb4efbad6301c43 (patch)
treeaa6950dd3f9fb5a35c7efd14f8902e352d1d4af2
parenta248db6916dd534f82b6faad7d6aa430ad0d5056 (diff)
nrf/boards/microbit: Add copy of microbit display and image files.
From micro:bit port repository, https://github.com/bbcmicrobit/micropython
-rw-r--r--ports/nrf/boards/microbit/modules/AUTHORS9
-rw-r--r--ports/nrf/boards/microbit/modules/LICENSE22
-rw-r--r--ports/nrf/boards/microbit/modules/iters.c70
-rw-r--r--ports/nrf/boards/microbit/modules/iters.h4
-rw-r--r--ports/nrf/boards/microbit/modules/microbitconstimage.cpp562
-rw-r--r--ports/nrf/boards/microbit/modules/microbitconstimagetuples.c60
-rw-r--r--ports/nrf/boards/microbit/modules/microbitdisplay.cpp579
-rw-r--r--ports/nrf/boards/microbit/modules/microbitdisplay.h54
-rw-r--r--ports/nrf/boards/microbit/modules/microbitimage.cpp973
-rw-r--r--ports/nrf/boards/microbit/modules/microbitimage.h92
-rw-r--r--ports/nrf/boards/microbit/modules/modmicrobit.cpp158
-rw-r--r--ports/nrf/boards/microbit/modules/modmicrobit.h234
12 files changed, 2817 insertions, 0 deletions
diff --git a/ports/nrf/boards/microbit/modules/AUTHORS b/ports/nrf/boards/microbit/modules/AUTHORS
new file mode 100644
index 000000000..60ed2e52e
--- /dev/null
+++ b/ports/nrf/boards/microbit/modules/AUTHORS
@@ -0,0 +1,9 @@
+Damien P. George (@dpgeorge)
+Nicholas H. Tollervey (@ntoll)
+Matthew Else (@matthewelse)
+Alan M. Jackson (@alanmjackson)
+Mark Shannon (@markshannon)
+Larry Hastings (@larryhastings)
+Mariia Koroliuk (@marichkakorolyuk)
+Andrew Mulholland (@gbaman)
+Joe Glancy (@JoeGlancy)
diff --git a/ports/nrf/boards/microbit/modules/LICENSE b/ports/nrf/boards/microbit/modules/LICENSE
new file mode 100644
index 000000000..621229028
--- /dev/null
+++ b/ports/nrf/boards/microbit/modules/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2013-2016 The MicroPython-on-micro:bit Developers, as listed
+in the accompanying AUTHORS file
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/ports/nrf/boards/microbit/modules/iters.c b/ports/nrf/boards/microbit/modules/iters.c
new file mode 100644
index 000000000..a024793ed
--- /dev/null
+++ b/ports/nrf/boards/microbit/modules/iters.c
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015/6 Mark Shannon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "lib/iters.h"
+
+
+typedef struct _repeat_iterator_t {
+ mp_obj_base_t base;
+ mp_obj_t iterable;
+ mp_int_t index;
+} repeat_iterator_t;
+
+static mp_obj_t microbit_repeat_iter_next(mp_obj_t iter_in) {
+ repeat_iterator_t *iter = (repeat_iterator_t *)iter_in;
+ iter->index++;
+ if (iter->index >= mp_obj_get_int(mp_obj_len(iter->iterable))) {
+ iter->index = 0;
+ }
+ return mp_obj_subscr(iter->iterable, MP_OBJ_NEW_SMALL_INT(iter->index), MP_OBJ_SENTINEL);
+}
+
+const mp_obj_type_t microbit_repeat_iterator_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_iterator,
+ .print = NULL,
+ .make_new = NULL,
+ .call = NULL,
+ .unary_op = NULL,
+ .binary_op = NULL,
+ .attr = NULL,
+ .subscr = NULL,
+ .getiter = mp_identity,
+ .iternext = microbit_repeat_iter_next,
+ .buffer_p = {NULL},
+ .stream_p = NULL,
+ .bases_tuple = MP_OBJ_NULL,
+ MP_OBJ_NULL
+};
+
+mp_obj_t microbit_repeat_iterator(mp_obj_t iterable) {
+ repeat_iterator_t *result = m_new_obj(repeat_iterator_t);
+ result->base.type = &microbit_repeat_iterator_type;
+ result->iterable = iterable;
+ result->index = -1;
+ return result;
+}
diff --git a/ports/nrf/boards/microbit/modules/iters.h b/ports/nrf/boards/microbit/modules/iters.h
new file mode 100644
index 000000000..f7f716c8b
--- /dev/null
+++ b/ports/nrf/boards/microbit/modules/iters.h
@@ -0,0 +1,4 @@
+
+#include "py/runtime.h"
+
+mp_obj_t microbit_repeat_iterator(mp_obj_t iterable);
diff --git a/ports/nrf/boards/microbit/modules/microbitconstimage.cpp b/ports/nrf/boards/microbit/modules/microbitconstimage.cpp
new file mode 100644
index 000000000..c6c38d0c3
--- /dev/null
+++ b/ports/nrf/boards/microbit/modules/microbitconstimage.cpp
@@ -0,0 +1,562 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "microbitobj.h"
+
+extern "C" {
+
+#include "py/runtime.h"
+#include "modmicrobit.h"
+#include "microbitimage.h"
+
+
+#define IMAGE_T const monochrome_5by5_t
+
+IMAGE_T microbit_const_image_heart_obj = SMALL_IMAGE(
+ 0,1,0,1,0,
+ 1,1,1,1,1,
+ 1,1,1,1,1,
+ 0,1,1,1,0,
+ 0,0,1,0,0
+);
+
+IMAGE_T microbit_const_image_heart_small_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 0,1,0,1,0,
+ 0,1,1,1,0,
+ 0,0,1,0,0,
+ 0,0,0,0,0
+);
+
+// smilies
+
+IMAGE_T microbit_const_image_happy_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 0,1,0,1,0,
+ 0,0,0,0,0,
+ 1,0,0,0,1,
+ 0,1,1,1,0
+);
+
+IMAGE_T microbit_const_image_smile_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 0,0,0,0,0,
+ 0,0,0,0,0,
+ 1,0,0,0,1,
+ 0,1,1,1,0
+);
+
+IMAGE_T microbit_const_image_sad_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 0,1,0,1,0,
+ 0,0,0,0,0,
+ 0,1,1,1,0,
+ 1,0,0,0,1
+);
+
+IMAGE_T microbit_const_image_confused_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 0,1,0,1,0,
+ 0,0,0,0,0,
+ 0,1,0,1,0,
+ 1,0,1,0,1
+);
+
+IMAGE_T microbit_const_image_angry_obj = SMALL_IMAGE(
+ 1,0,0,0,1,
+ 0,1,0,1,0,
+ 0,0,0,0,0,
+ 1,1,1,1,1,
+ 1,0,1,0,1
+);
+
+IMAGE_T microbit_const_image_asleep_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 1,1,0,1,1,
+ 0,0,0,0,0,
+ 0,1,1,1,0,
+ 0,0,0,0,0
+);
+
+IMAGE_T microbit_const_image_surprised_obj = SMALL_IMAGE(
+ 0,1,0,1,0,
+ 0,0,0,0,0,
+ 0,0,1,0,0,
+ 0,1,0,1,0,
+ 0,0,1,0,0
+);
+
+IMAGE_T microbit_const_image_silly_obj = SMALL_IMAGE(
+ 1,0,0,0,1,
+ 0,0,0,0,0,
+ 1,1,1,1,1,
+ 0,0,1,0,1,
+ 0,0,1,1,1
+);
+
+IMAGE_T microbit_const_image_fabulous_obj = SMALL_IMAGE(
+ 1,1,1,1,1,
+ 1,1,0,1,1,
+ 0,0,0,0,0,
+ 0,1,0,1,0,
+ 0,1,1,1,0
+);
+
+IMAGE_T microbit_const_image_meh_obj = SMALL_IMAGE(
+ 0,1,0,1,0,
+ 0,0,0,0,0,
+ 0,0,0,1,0,
+ 0,0,1,0,0,
+ 0,1,0,0,0
+);
+
+// yes/no
+
+IMAGE_T microbit_const_image_yes_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 0,0,0,0,1,
+ 0,0,0,1,0,
+ 1,0,1,0,0,
+ 0,1,0,0,0
+);
+
+IMAGE_T microbit_const_image_no_obj = SMALL_IMAGE(
+ 1,0,0,0,1,
+ 0,1,0,1,0,
+ 0,0,1,0,0,
+ 0,1,0,1,0,
+ 1,0,0,0,1
+);
+
+// clock hands
+
+IMAGE_T microbit_const_image_clock12_obj = SMALL_IMAGE(
+ 0,0,1,0,0,
+ 0,0,1,0,0,
+ 0,0,1,0,0,
+ 0,0,0,0,0,
+ 0,0,0,0,0
+);
+
+IMAGE_T microbit_const_image_clock1_obj = SMALL_IMAGE(
+ 0,0,0,1,0,
+ 0,0,0,1,0,
+ 0,0,1,0,0,
+ 0,0,0,0,0,
+ 0,0,0,0,0
+);
+
+IMAGE_T microbit_const_image_clock2_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 0,0,0,1,1,
+ 0,0,1,0,0,
+ 0,0,0,0,0,
+ 0,0,0,0,0
+);
+
+IMAGE_T microbit_const_image_clock3_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 0,0,0,0,0,
+ 0,0,1,1,1,
+ 0,0,0,0,0,
+ 0,0,0,0,0
+);
+
+IMAGE_T microbit_const_image_clock4_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 0,0,0,0,0,
+ 0,0,1,0,0,
+ 0,0,0,1,1,
+ 0,0,0,0,0
+);
+
+IMAGE_T microbit_const_image_clock5_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 0,0,0,0,0,
+ 0,0,1,0,0,
+ 0,0,0,1,0,
+ 0,0,0,1,0
+);
+
+IMAGE_T microbit_const_image_clock6_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 0,0,0,0,0,
+ 0,0,1,0,0,
+ 0,0,1,0,0,
+ 0,0,1,0,0
+);
+
+IMAGE_T microbit_const_image_clock7_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 0,0,0,0,0,
+ 0,0,1,0,0,
+ 0,1,0,0,0,
+ 0,1,0,0,0
+);
+
+IMAGE_T microbit_const_image_clock8_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 0,0,0,0,0,
+ 0,0,1,0,0,
+ 1,1,0,0,0,
+ 0,0,0,0,0
+);
+
+IMAGE_T microbit_const_image_clock9_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 0,0,0,0,0,
+ 1,1,1,0,0,
+ 0,0,0,0,0,
+ 0,0,0,0,0
+);
+
+IMAGE_T microbit_const_image_clock10_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 1,1,0,0,0,
+ 0,0,1,0,0,
+ 0,0,0,0,0,
+ 0,0,0,0,0
+);
+
+IMAGE_T microbit_const_image_clock11_obj = SMALL_IMAGE(
+ 0,1,0,0,0,
+ 0,1,0,0,0,
+ 0,0,1,0,0,
+ 0,0,0,0,0,
+ 0,0,0,0,0
+);
+
+// arrows
+
+IMAGE_T microbit_const_image_arrow_n_obj = SMALL_IMAGE(
+ 0,0,1,0,0,
+ 0,1,1,1,0,
+ 1,0,1,0,1,
+ 0,0,1,0,0,
+ 0,0,1,0,0
+);
+
+IMAGE_T microbit_const_image_arrow_ne_obj = SMALL_IMAGE(
+ 0,0,1,1,1,
+ 0,0,0,1,1,
+ 0,0,1,0,1,
+ 0,1,0,0,0,
+ 1,0,0,0,0
+);
+
+IMAGE_T microbit_const_image_arrow_e_obj = SMALL_IMAGE(
+ 0,0,1,0,0,
+ 0,0,0,1,0,
+ 1,1,1,1,1,
+ 0,0,0,1,0,
+ 0,0,1,0,0
+);
+
+IMAGE_T microbit_const_image_arrow_se_obj = SMALL_IMAGE(
+ 1,0,0,0,0,
+ 0,1,0,0,0,
+ 0,0,1,0,1,
+ 0,0,0,1,1,
+ 0,0,1,1,1
+);
+
+IMAGE_T microbit_const_image_arrow_s_obj = SMALL_IMAGE(
+ 0,0,1,0,0,
+ 0,0,1,0,0,
+ 1,0,1,0,1,
+ 0,1,1,1,0,
+ 0,0,1,0,0
+);
+
+IMAGE_T microbit_const_image_arrow_sw_obj = SMALL_IMAGE(
+ 0,0,0,0,1,
+ 0,0,0,1,0,
+ 1,0,1,0,0,
+ 1,1,0,0,0,
+ 1,1,1,0,0
+);
+
+IMAGE_T microbit_const_image_arrow_w_obj = SMALL_IMAGE(
+ 0,0,1,0,0,
+ 0,1,0,0,0,
+ 1,1,1,1,1,
+ 0,1,0,0,0,
+ 0,0,1,0,0
+);
+
+IMAGE_T microbit_const_image_arrow_nw_obj = SMALL_IMAGE(
+ 1,1,1,0,0,
+ 1,1,0,0,0,
+ 1,0,1,0,0,
+ 0,0,0,1,0,
+ 0,0,0,0,1
+);
+
+// geometry
+
+IMAGE_T microbit_const_image_triangle_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 0,0,1,0,0,
+ 0,1,0,1,0,
+ 1,1,1,1,1,
+ 0,0,0,0,0
+);
+
+IMAGE_T microbit_const_image_triangle_left_obj = SMALL_IMAGE(
+ 1,0,0,0,0,
+ 1,1,0,0,0,
+ 1,0,1,0,0,
+ 1,0,0,1,0,
+ 1,1,1,1,1
+);
+
+IMAGE_T microbit_const_image_chessboard_obj = SMALL_IMAGE(
+ 0,1,0,1,0,
+ 1,0,1,0,1,
+ 0,1,0,1,0,
+ 1,0,1,0,1,
+ 0,1,0,1,0
+);
+
+IMAGE_T microbit_const_image_diamond_obj = SMALL_IMAGE(
+ 0,0,1,0,0,
+ 0,1,0,1,0,
+ 1,0,0,0,1,
+ 0,1,0,1,0,
+ 0,0,1,0,0
+);
+
+IMAGE_T microbit_const_image_diamond_small_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 0,0,1,0,0,
+ 0,1,0,1,0,
+ 0,0,1,0,0,
+ 0,0,0,0,0
+);
+
+IMAGE_T microbit_const_image_square_obj = SMALL_IMAGE(
+ 1,1,1,1,1,
+ 1,0,0,0,1,
+ 1,0,0,0,1,
+ 1,0,0,0,1,
+ 1,1,1,1,1
+);
+
+IMAGE_T microbit_const_image_square_small_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 0,1,1,1,0,
+ 0,1,0,1,0,
+ 0,1,1,1,0,
+ 0,0,0,0,0
+);
+
+// animals
+
+IMAGE_T microbit_const_image_rabbit = SMALL_IMAGE(
+ 1,0,1,0,0,
+ 1,0,1,0,0,
+ 1,1,1,1,0,
+ 1,1,0,1,0,
+ 1,1,1,1,0
+);
+
+IMAGE_T microbit_const_image_cow = SMALL_IMAGE(
+ 1,0,0,0,1,
+ 1,0,0,0,1,
+ 1,1,1,1,1,
+ 0,1,1,1,0,
+ 0,0,1,0,0
+);
+
+// musical notes
+
+IMAGE_T microbit_const_image_music_crotchet_obj = SMALL_IMAGE(
+ 0,0,1,0,0,
+ 0,0,1,0,0,
+ 0,0,1,0,0,
+ 1,1,1,0,0,
+ 1,1,1,0,0
+);
+
+IMAGE_T microbit_const_image_music_quaver_obj = SMALL_IMAGE(
+ 0,0,1,0,0,
+ 0,0,1,1,0,
+ 0,0,1,0,1,
+ 1,1,1,0,0,
+ 1,1,1,0,0
+);
+
+IMAGE_T microbit_const_image_music_quavers_obj = SMALL_IMAGE(
+ 0,1,1,1,1,
+ 0,1,0,0,1,
+ 0,1,0,0,1,
+ 1,1,0,1,1,
+ 1,1,0,1,1
+);
+
+// other icons
+
+IMAGE_T microbit_const_image_pitchfork_obj = SMALL_IMAGE(
+ 1,0,1,0,1,
+ 1,0,1,0,1,
+ 1,1,1,1,1,
+ 0,0,1,0,0,
+ 0,0,1,0,0
+);
+
+IMAGE_T microbit_const_image_xmas_obj = SMALL_IMAGE(
+ 0,0,1,0,0,
+ 0,1,1,1,0,
+ 0,0,1,0,0,
+ 0,1,1,1,0,
+ 1,1,1,1,1
+);
+
+IMAGE_T microbit_const_image_pacman_obj = SMALL_IMAGE(
+ 0,1,1,1,1,
+ 1,1,0,1,0,
+ 1,1,1,0,0,
+ 1,1,1,1,0,
+ 0,1,1,1,1
+);
+
+IMAGE_T microbit_const_image_target_obj = SMALL_IMAGE(
+ 0,0,1,0,0,
+ 0,1,1,1,0,
+ 1,1,0,1,1,
+ 0,1,1,1,0,
+ 0,0,1,0,0
+);
+
+/*
+The following images were designed by Abbie Brooks.
+*/
+
+IMAGE_T microbit_const_image_tshirt_obj = SMALL_IMAGE(
+ 1,1,0,1,1,
+ 1,1,1,1,1,
+ 0,1,1,1,0,
+ 0,1,1,1,0,
+ 0,1,1,1,0
+);
+
+IMAGE_T microbit_const_image_rollerskate_obj = SMALL_IMAGE(
+ 0,0,0,1,1,
+ 0,0,0,1,1,
+ 1,1,1,1,1,
+ 1,1,1,1,1,
+ 0,1,0,1,0
+);
+
+IMAGE_T microbit_const_image_duck_obj = SMALL_IMAGE(
+ 0,1,1,0,0,
+ 1,1,1,0,0,
+ 0,1,1,1,1,
+ 0,1,1,1,0,
+ 0,0,0,0,0
+);
+
+IMAGE_T microbit_const_image_house_obj = SMALL_IMAGE(
+ 0,0,1,0,0,
+ 0,1,1,1,0,
+ 1,1,1,1,1,
+ 0,1,1,1,0,
+ 0,1,0,1,0
+);
+
+IMAGE_T microbit_const_image_tortoise_obj = SMALL_IMAGE(
+ 0,0,0,0,0,
+ 0,1,1,1,0,
+ 1,1,1,1,1,
+ 0,1,0,1,0,
+ 0,0,0,0,0
+);
+
+IMAGE_T microbit_const_image_butterfly_obj = SMALL_IMAGE(
+ 1,1,0,1,1,
+ 1,1,1,1,1,
+ 0,0,1,0,0,
+ 1,1,1,1,1,
+ 1,1,0,1,1
+);
+
+IMAGE_T microbit_const_image_stickfigure_obj = SMALL_IMAGE(
+ 0,0,1,0,0,
+ 1,1,1,1,1,
+ 0,0,1,0,0,
+ 0,1,0,1,0,
+ 1,0,0,0,1
+);
+
+IMAGE_T microbit_const_image_ghost_obj = SMALL_IMAGE(
+ 1,1,1,1,1,
+ 1,0,1,0,1,
+ 1,1,1,1,1,
+ 1,1,1,1,1,
+ 1,0,1,0,1
+);
+
+IMAGE_T microbit_const_image_sword_obj = SMALL_IMAGE(
+ 0,0,1,0,0,
+ 0,0,1,0,0,
+ 0,0,1,0,0,
+ 0,1,1,1,0,
+ 0,0,1,0,0
+);
+
+IMAGE_T microbit_const_image_giraffe_obj = SMALL_IMAGE(
+ 1,1,0,0,0,
+ 0,1,0,0,0,
+ 0,1,0,0,0,
+ 0,1,1,1,0,
+ 0,1,0,1,0
+);
+
+IMAGE_T microbit_const_image_skull_obj = SMALL_IMAGE(
+ 0,1,1,1,0,
+ 1,0,1,0,1,
+ 1,1,1,1,1,
+ 0,1,1,1,0,
+ 0,1,1,1,0
+);
+
+IMAGE_T microbit_const_image_umbrella_obj = SMALL_IMAGE(
+ 0,1,1,1,0,
+ 1,1,1,1,1,
+ 0,0,1,0,0,
+ 1,0,1,0,0,
+ 0,1,1,0,0
+);
+
+IMAGE_T microbit_const_image_snake_obj = SMALL_IMAGE(
+ 1,1,0,0,0,
+ 1,1,0,1,1,
+ 0,1,0,1,0,
+ 0,1,1,1,0,
+ 0,0,0,0,0
+);
+
+}
diff --git a/ports/nrf/boards/microbit/modules/microbitconstimagetuples.c b/ports/nrf/boards/microbit/modules/microbitconstimagetuples.c
new file mode 100644
index 000000000..0779d1651
--- /dev/null
+++ b/ports/nrf/boards/microbit/modules/microbitconstimagetuples.c
@@ -0,0 +1,60 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Mark Shannon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "modmicrobit.h"
+
+const mp_obj_tuple_t microbit_const_image_all_clocks_tuple_obj = {
+ {&mp_type_tuple},
+ .len = 12,
+ .items = {
+ (mp_obj_t)&microbit_const_image_clock12_obj,
+ (mp_obj_t)&microbit_const_image_clock1_obj,
+ (mp_obj_t)&microbit_const_image_clock2_obj,
+ (mp_obj_t)&microbit_const_image_clock3_obj,
+ (mp_obj_t)&microbit_const_image_clock4_obj,
+ (mp_obj_t)&microbit_const_image_clock5_obj,
+ (mp_obj_t)&microbit_const_image_clock6_obj,
+ (mp_obj_t)&microbit_const_image_clock7_obj,
+ (mp_obj_t)&microbit_const_image_clock8_obj,
+ (mp_obj_t)&microbit_const_image_clock9_obj,
+ (mp_obj_t)&microbit_const_image_clock10_obj,
+ (mp_obj_t)&microbit_const_image_clock11_obj
+ }
+};
+
+const mp_obj_tuple_t microbit_const_image_all_arrows_tuple_obj = {
+ {&mp_type_tuple},
+ .len = 8,
+ .items = {
+ (mp_obj_t)&microbit_const_image_arrow_n_obj,
+ (mp_obj_t)&microbit_const_image_arrow_ne_obj,
+ (mp_obj_t)&microbit_const_image_arrow_e_obj,
+ (mp_obj_t)&microbit_const_image_arrow_se_obj,
+ (mp_obj_t)&microbit_const_image_arrow_s_obj,
+ (mp_obj_t)&microbit_const_image_arrow_sw_obj,
+ (mp_obj_t)&microbit_const_image_arrow_w_obj,
+ (mp_obj_t)&microbit_const_image_arrow_nw_obj
+ }
+};
diff --git a/ports/nrf/boards/microbit/modules/microbitdisplay.cpp b/ports/nrf/boards/microbit/modules/microbitdisplay.cpp
new file mode 100644
index 000000000..92bf58d82
--- /dev/null
+++ b/ports/nrf/boards/microbit/modules/microbitdisplay.cpp
@@ -0,0 +1,579 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+#include "microbitobj.h"
+#include "nrf_gpio.h"
+
+extern "C" {
+#include "py/runtime.h"
+#include "py/gc.h"
+#include "modmicrobit.h"
+#include "microbitimage.h"
+#include "microbitdisplay.h"
+#include "microbitpin.h"
+#include "lib/iters.h"
+#include "lib/ticker.h"
+
+#define min(a,b) (((a)<(b))?(a):(b))
+
+void microbit_display_show(microbit_display_obj_t *display, microbit_image_obj_t *image) {
+ mp_int_t w = min(image->width(), 5);
+ mp_int_t h = min(image->height(), 5);
+ mp_int_t x = 0;
+ mp_int_t brightnesses = 0;
+ for (; x < w; ++x) {
+ mp_int_t y = 0;
+ for (; y < h; ++y) {
+ uint8_t pix = image->getPixelValue(x, y);
+ display->image_buffer[x][y] = pix;
+ brightnesses |= (1 << pix);
+ }
+ for (; y < 5; ++y) {
+ display->image_buffer[x][y] = 0;
+ }
+ }
+ for (; x < 5; ++x) {
+ for (mp_int_t y = 0; y < 5; ++y) {
+ display->image_buffer[x][y] = 0;
+ }
+ }
+ display->brightnesses = brightnesses;
+}
+
+#define DEFAULT_PRINT_SPEED 400
+
+
+mp_obj_t microbit_display_show_func(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+
+ // Cancel any animations.
+ MP_STATE_PORT(async_data)[0] = NULL;
+ MP_STATE_PORT(async_data)[1] = NULL;
+
+ static const mp_arg_t show_allowed_args[] = {
+ { MP_QSTR_image, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_delay, MP_ARG_INT, {.u_int = DEFAULT_PRINT_SPEED} },
+ { MP_QSTR_clear, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_wait, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
+ { MP_QSTR_loop, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ };
+
+ // Parse the args.
+ microbit_display_obj_t *self = (microbit_display_obj_t*)pos_args[0];
+ mp_arg_val_t args[MP_ARRAY_SIZE(show_allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(show_allowed_args), show_allowed_args, args);
+
+ mp_obj_t image = args[0].u_obj;
+ mp_int_t delay = args[1].u_int;
+ bool clear = args[2].u_bool;
+ bool wait = args[3].u_bool;
+ bool loop = args[4].u_bool;
+
+ if (MP_OBJ_IS_STR(image)) {
+ // arg is a string object
+ mp_uint_t len;
+ const char *str = mp_obj_str_get_data(image, &len);
+ if (len == 0) {
+ // There are no chars; do nothing.
+ return mp_const_none;
+ } else if (len == 1) {
+ if (!clear && !loop) {
+ // A single char; convert to an image and print that.
+ image = microbit_image_for_char(str[0]);
+ goto single_image_immediate;
+ }
+ }
+ image = microbit_string_facade(image);
+ } else if (mp_obj_get_type(image) == &microbit_image_type) {
+ if (!clear && !loop) {
+ goto single_image_immediate;
+ }
+ image = mp_obj_new_tuple(1, &image);
+ }
+ // iterable:
+ if (args[4].u_bool) { /*loop*/
+ image = microbit_repeat_iterator(image);
+ }
+ microbit_display_animate(self, image, delay, clear, wait);
+ return mp_const_none;
+
+single_image_immediate:
+ microbit_display_show(self, (microbit_image_obj_t *)image);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(microbit_display_show_obj, 1, microbit_display_show_func);
+
+static uint8_t async_mode;
+static mp_obj_t async_iterator = NULL;
+// Record if an error occurs in async animation. Unfortunately there is no way to report this.
+static volatile bool wakeup_event = false;
+static mp_uint_t async_delay = 1000;
+static mp_uint_t async_tick = 0;
+static bool async_clear = false;
+
+
+bool microbit_display_active_animation(void) {
+ return async_mode == ASYNC_MODE_ANIMATION;
+}
+
+STATIC void async_stop(void) {
+ async_iterator = NULL;
+ async_mode = ASYNC_MODE_STOPPED;
+ async_tick = 0;
+ async_delay = 1000;
+ async_clear = false;
+ MP_STATE_PORT(async_data)[0] = NULL;
+ MP_STATE_PORT(async_data)[1] = NULL;
+ wakeup_event = true;
+}
+
+STATIC void wait_for_event() {
+ while (!wakeup_event) {
+ // allow CTRL-C to stop the animation
+ if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {
+ async_stop();
+ return;
+ }
+ __WFI();
+ }
+ wakeup_event = false;
+}
+
+struct DisplayPoint {
+ uint8_t x;
+ uint8_t y;
+};
+
+#define NO_CONN 0
+
+#define ROW_COUNT 3
+#define COLUMN_COUNT 9
+
+static const DisplayPoint display_map[COLUMN_COUNT][ROW_COUNT] = {
+ {{0,0}, {4,2}, {2,4}},
+ {{2,0}, {0,2}, {4,4}},
+ {{4,0}, {2,2}, {0,4}},
+ {{4,3}, {1,0}, {0,1}},
+ {{3,3}, {3,0}, {1,1}},
+ {{2,3}, {3,4}, {2,1}},
+ {{1,3}, {1,4}, {3,1}},
+ {{0,3}, {NO_CONN,NO_CONN}, {4,1}},
+ {{1,2}, {NO_CONN,NO_CONN}, {3,2}}
+};
+
+#define MIN_COLUMN_PIN 4
+#define COLUMN_PINS_MASK 0x1ff0
+#define MIN_ROW_PIN 13
+#define MAX_ROW_PIN 15
+#define ROW_PINS_MASK 0xe000
+
+inline void microbit_display_obj_t::setPinsForRow(uint8_t brightness) {
+ if (brightness == 0) {
+ nrf_gpio_pins_clear(COLUMN_PINS_MASK & ~this->pins_for_brightness[brightness]);
+ } else {
+ nrf_gpio_pins_set(this->pins_for_brightness[brightness]);
+ }
+}
+
+/* This is the primary PWM driver/display driver. It will operate on one row
+ * (9 pins) per invocation. It will turn on LEDs with maximum brightness,
+ * then let the "callback" callback turn off the LEDs as appropriate for the
+ * required brightness level.
+ *
+ * For each row
+ * Turn off all the LEDs in the previous row
+ * Set the column bits high (off)
+ * Set the row strobe low (off)
+ * Turn on all the LEDs in the current row that have maximum brightness
+ * Set the row strobe high (on)
+ * Set some/all column bits low (on)
+ * Register the PWM callback
+ * For each callback start with brightness 0
+ * If brightness 0
+ * Turn off the LEDs specified at this level
+ * Else
+ * Turn on the LEDs specified at this level
+ * If brightness max
+ * Disable the PWM callback
+ * Else
+ * Re-queue the PWM callback after the appropriate delay
+ */
+void microbit_display_obj_t::advanceRow() {
+ /* Clear all of the column bits */
+ nrf_gpio_pins_set(COLUMN_PINS_MASK);
+ /* Clear the strobe bit for this row */
+ nrf_gpio_pin_clear(strobe_row+MIN_ROW_PIN);
+
+ /* Move to the next row. Before this, "this row" refers to the row
+ * manipulated by the previous invocation of this function. After this,
+ * "this row" refers to the row manipulated by the current invocation of
+ * this function. */
+ strobe_row++;
+
+ // Reset the row counts and bit mask when we have hit the max.
+ if (strobe_row == ROW_COUNT) {
+ strobe_row = 0;
+ }
+
+ // Set pin for this row.
+ // Prepare row for rendering.
+ for (int i = 0; i <= MAX_BRIGHTNESS; i++) {
+ pins_for_brightness[i] = 0;
+ }
+ for (int i = 0; i < COLUMN_COUNT; i++) {
+ int x = display_map[i][strobe_row].x;
+ int y = display_map[i][strobe_row].y;
+ uint8_t brightness = microbit_display_obj.image_buffer[x][y];
+ pins_for_brightness[brightness] |= (1<<(i+MIN_COLUMN_PIN));
+ }
+ /* Enable the strobe bit for this row */
+ nrf_gpio_pin_set(strobe_row+MIN_ROW_PIN);
+ /* Enable the column bits for all pins that need to be on. */
+ nrf_gpio_pins_clear(pins_for_brightness[MAX_BRIGHTNESS]);
+}
+
+static const uint16_t render_timings[] =
+// The scale is (approximately) exponential,
+// each step is approx x1.9 greater than the previous.
+{ 0, // Bright, Ticks Duration, Relative power
+ 2, // 1, 2, 32µs, inf
+ 2, // 2, 4, 64µs, 200%
+ 4, // 3, 8, 128µs, 200%
+ 7, // 4, 15, 240µs, 187%
+ 13, // 5, 28, 448µs, 187%
+ 25, // 6, 53, 848µs, 189%
+ 49, // 7, 102, 1632µs, 192%
+ 97, // 8, 199, 3184µs, 195%
+// Always on 9, 375, 6000µs, 188%
+};
+
+#define DISPLAY_TICKER_SLOT 1
+
+/* This is the PWM callback. It is registered by the animation callback and
+ * will unregister itself when all of the brightness steps are complete. */
+static int32_t callback(void) {
+ microbit_display_obj_t *display = &microbit_display_obj;
+ mp_uint_t brightness = display->previous_brightness;
+ display->setPinsForRow(brightness);
+ brightness += 1;
+ if (brightness == MAX_BRIGHTNESS) {
+ clear_ticker_callback(DISPLAY_TICKER_SLOT);
+ return -1;
+ }
+ display->previous_brightness = brightness;
+ // Return interval (in 16µs ticks) until next callback
+ return render_timings[brightness];
+}
+
+static void draw_object(mp_obj_t obj) {
+ microbit_display_obj_t *display = (microbit_display_obj_t*)MP_STATE_PORT(async_data)[0];
+ if (obj == MP_OBJ_STOP_ITERATION) {
+ if (async_clear) {
+ microbit_display_show(&microbit_display_obj, BLANK_IMAGE);
+ async_clear = false;
+ } else {
+ async_stop();
+ }
+ } else if (mp_obj_get_type(obj) == &microbit_image_type) {
+ microbit_display_show(display, (microbit_image_obj_t *)obj);
+ } else if (MP_OBJ_IS_STR(obj)) {
+ mp_uint_t len;
+ const char *str = mp_obj_str_get_data(obj, &len);
+ if (len == 1) {
+ microbit_display_show(display, microbit_image_for_char(str[0]));
+ } else {
+ async_stop();
+ }
+ } else {
+ MP_STATE_VM(mp_pending_exception) = mp_obj_new_exception_msg(&mp_type_TypeError, "not an image.");
+ async_stop();
+ }
+}
+
+static void microbit_display_update(void) {
+ async_tick += MILLISECONDS_PER_MACRO_TICK;
+ if (async_tick < async_delay) {
+ return;
+ }
+ async_tick = 0;
+ switch (async_mode) {
+ case ASYNC_MODE_ANIMATION:
+ {
+ if (MP_STATE_PORT(async_data)[0] == NULL || MP_STATE_PORT(async_data)[1] == NULL) {
+ async_stop();
+ break;
+ }
+ /* WARNING: We are executing in an interrupt handler.
+ * If an exception is raised here then we must hand it to the VM. */
+ mp_obj_t obj;
+ nlr_buf_t nlr;
+ gc_lock();
+ if (nlr_push(&nlr) == 0) {
+ obj = mp_iternext_allow_raise(async_iterator);
+ nlr_pop();
+ gc_unlock();
+ } else {
+ gc_unlock();
+ if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type),
+ MP_OBJ_FROM_PTR(&mp_type_StopIteration))) {
+ // An exception other than StopIteration, so set it for the VM to raise later
+ // If memory error, write an appropriate message.
+ if (mp_obj_get_type(nlr.ret_val) == &mp_type_MemoryError) {
+ mp_printf(&mp_plat_print, "Allocation in interrupt handler");
+ }
+ MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(nlr.ret_val);
+ }
+ obj = MP_OBJ_STOP_ITERATION;
+ }
+ draw_object(obj);
+ break;
+ }
+ case ASYNC_MODE_CLEAR:
+ microbit_display_show(&microbit_display_obj, BLANK_IMAGE);
+ async_stop();
+ break;
+ }
+}
+
+#define GREYSCALE_MASK ((1<<MAX_BRIGHTNESS)-2)
+
+/* This is the top-level animation/display callback. It is not a registered
+ * callback. */
+void microbit_display_tick(void) {
+ /* Do nothing if the display is not active. */
+ if (!microbit_display_obj.active) {
+ return;
+ }
+
+ microbit_display_obj.advanceRow();
+
+ microbit_display_update();
+ microbit_display_obj.previous_brightness = 0;
+ if (microbit_display_obj.brightnesses & GREYSCALE_MASK) {
+ set_ticker_callback(DISPLAY_TICKER_SLOT, callback, 1800);
+ }
+}
+
+
+void microbit_display_animate(microbit_display_obj_t *self, mp_obj_t iterable, mp_int_t delay, bool clear, bool wait) {
+ // Reset the repeat state.
+ MP_STATE_PORT(async_data)[0] = NULL;
+ MP_STATE_PORT(async_data)[1] = NULL;
+ async_iterator = mp_getiter(iterable);
+ async_delay = delay;
+ async_clear = clear;
+ MP_STATE_PORT(async_data)[0] = self; // so it doesn't get GC'd
+ MP_STATE_PORT(async_data)[1] = async_iterator;
+ wakeup_event = false;
+ mp_obj_t obj = mp_iternext_allow_raise(async_iterator);
+ draw_object(obj);
+ async_tick = 0;
+ async_mode = ASYNC_MODE_ANIMATION;
+ if (wait) {
+ wait_for_event();
+ }
+}
+
+
+// Delay in ms in between moving display one column to the left.
+#define DEFAULT_SCROLL_SPEED 150
+
+void microbit_display_scroll(microbit_display_obj_t *self, const char* str, bool wait) {
+ mp_obj_t iterable = scrolling_string_image_iterable(str, strlen(str), NULL, false, false);
+ microbit_display_animate(self, iterable, DEFAULT_SCROLL_SPEED, false, wait);
+}
+
+
+mp_obj_t microbit_display_scroll_func(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ static const mp_arg_t scroll_allowed_args[] = {
+ { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_delay, MP_ARG_INT, {.u_int = DEFAULT_SCROLL_SPEED} },
+ { MP_QSTR_wait, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
+ { MP_QSTR_monospace, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_loop, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ };
+ // Parse the args.
+ microbit_display_obj_t *self = (microbit_display_obj_t*)pos_args[0];
+ mp_arg_val_t args[MP_ARRAY_SIZE(scroll_allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(scroll_allowed_args), scroll_allowed_args, args);
+ mp_uint_t len;
+ const char* str = mp_obj_str_get_data(args[0].u_obj, &len);
+ mp_obj_t iterable = scrolling_string_image_iterable(str, len, args[0].u_obj, args[3].u_bool /*monospace?*/, args[4].u_bool /*loop*/);
+ microbit_display_animate(self, iterable, args[1].u_int /*delay*/, false/*clear*/, args[2].u_bool/*wait?*/);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(microbit_display_scroll_obj, 1, microbit_display_scroll_func);
+
+mp_obj_t microbit_display_on_func(mp_obj_t obj) {
+ microbit_display_obj_t *self = (microbit_display_obj_t*)obj;
+ /* Try to reclaim the pins we need */
+ microbit_obj_pin_fail_if_cant_acquire(&microbit_p3_obj);
+ microbit_obj_pin_fail_if_cant_acquire(&microbit_p4_obj);
+ microbit_obj_pin_fail_if_cant_acquire(&microbit_p6_obj);
+ microbit_obj_pin_fail_if_cant_acquire(&microbit_p7_obj);
+ microbit_obj_pin_fail_if_cant_acquire(&microbit_p9_obj);
+ microbit_obj_pin_fail_if_cant_acquire(&microbit_p10_obj);
+ microbit_obj_pin_acquire(&microbit_p3_obj, microbit_pin_mode_display);
+ microbit_obj_pin_acquire(&microbit_p4_obj, microbit_pin_mode_display);
+ microbit_obj_pin_acquire(&microbit_p6_obj, microbit_pin_mode_display);
+ microbit_obj_pin_acquire(&microbit_p7_obj, microbit_pin_mode_display);
+ microbit_obj_pin_acquire(&microbit_p9_obj, microbit_pin_mode_display);
+ microbit_obj_pin_acquire(&microbit_p10_obj, microbit_pin_mode_display);
+ /* Make sure all pins are in the correct state */
+ microbit_display_init();
+ /* Re-enable the display loop. This will resume any animations in
+ * progress and display any static image. */
+ self->active = true;
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(microbit_display_on_obj, microbit_display_on_func);
+
+mp_obj_t microbit_display_off_func(mp_obj_t obj) {
+ microbit_display_obj_t *self = (microbit_display_obj_t*)obj;
+ /* Disable the display loop. This will pause any animations in progress.
+ * It will not prevent a user from attempting to modify the state, but
+ * modifications will not appear to have any effect until the display loop
+ * is re-enabled. */
+ self->active = false;
+ /* Disable the row strobes, allowing the columns to be used freely for
+ * GPIO. */
+ nrf_gpio_pins_clear(ROW_PINS_MASK);
+ /* Free pins for other uses */
+ microbit_obj_pin_free(&microbit_p3_obj);
+ microbit_obj_pin_free(&microbit_p4_obj);
+ microbit_obj_pin_free(&microbit_p6_obj);
+ microbit_obj_pin_free(&microbit_p7_obj);
+ microbit_obj_pin_free(&microbit_p9_obj);
+ microbit_obj_pin_free(&microbit_p10_obj);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(microbit_display_off_obj, microbit_display_off_func);
+
+mp_obj_t microbit_display_is_on_func(mp_obj_t obj) {
+ microbit_display_obj_t *self = (microbit_display_obj_t*)obj;
+ if (self->active) {
+ return mp_const_true;
+ }
+ else {
+ return mp_const_false;
+ }
+}
+MP_DEFINE_CONST_FUN_OBJ_1(microbit_display_is_on_obj, microbit_display_is_on_func);
+
+void microbit_display_clear(void) {
+ // Reset repeat state, cancel animation and clear screen.
+ wakeup_event = false;
+ async_mode = ASYNC_MODE_CLEAR;
+ async_tick = async_delay - MILLISECONDS_PER_MACRO_TICK;
+ wait_for_event();
+}
+
+mp_obj_t microbit_display_clear_func(void) {
+ microbit_display_clear();
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(microbit_display_clear_obj, microbit_display_clear_func);
+
+void microbit_display_set_pixel(microbit_display_obj_t *display, mp_int_t x, mp_int_t y, mp_int_t bright) {
+ if (x < 0 || y < 0 || x > 4 || y > 4) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "index out of bounds."));
+ }
+ if (bright < 0 || bright > MAX_BRIGHTNESS) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "brightness out of bounds."));
+ }
+ display->image_buffer[x][y] = bright;
+ display->brightnesses |= (1 << bright);
+}
+
+STATIC mp_obj_t microbit_display_set_pixel_func(mp_uint_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ microbit_display_obj_t *self = (microbit_display_obj_t*)args[0];
+ microbit_display_set_pixel(self, mp_obj_get_int(args[1]), mp_obj_get_int(args[2]), mp_obj_get_int(args[3]));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_display_set_pixel_obj, 4, 4, microbit_display_set_pixel_func);
+
+mp_int_t microbit_display_get_pixel(microbit_display_obj_t *display, mp_int_t x, mp_int_t y) {
+ if (x < 0 || y < 0 || x > 4 || y > 4) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "index out of bounds."));
+ }
+ return display->image_buffer[x][y];
+}
+
+STATIC mp_obj_t microbit_display_get_pixel_func(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) {
+ microbit_display_obj_t *self = (microbit_display_obj_t*)self_in;
+ return MP_OBJ_NEW_SMALL_INT(microbit_display_get_pixel(self, mp_obj_get_int(x_in), mp_obj_get_int(y_in)));
+}
+MP_DEFINE_CONST_FUN_OBJ_3(microbit_display_get_pixel_obj, microbit_display_get_pixel_func);
+
+STATIC const mp_map_elem_t microbit_display_locals_dict_table[] = {
+
+ { MP_OBJ_NEW_QSTR(MP_QSTR_get_pixel), (mp_obj_t)&microbit_display_get_pixel_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_set_pixel), (mp_obj_t)&microbit_display_set_pixel_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_show), (mp_obj_t)&microbit_display_show_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_scroll), (mp_obj_t)&microbit_display_scroll_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_clear), (mp_obj_t)&microbit_display_clear_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_on), (mp_obj_t)&microbit_display_on_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_off), (mp_obj_t)&microbit_display_off_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_is_on), (mp_obj_t)&microbit_display_is_on_obj },
+};
+
+STATIC MP_DEFINE_CONST_DICT(microbit_display_locals_dict, microbit_display_locals_dict_table);
+
+STATIC const mp_obj_type_t microbit_display_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_MicroBitDisplay,
+ .print = NULL,
+ .make_new = NULL,
+ .call = NULL,
+ .unary_op = NULL,
+ .binary_op = NULL,
+ .attr = NULL,
+ .subscr = NULL,
+ .getiter = NULL,
+ .iternext = NULL,
+ .buffer_p = {NULL},
+ .stream_p = NULL,
+ .bases_tuple = NULL,
+ .locals_dict = (mp_obj_dict_t*)&microbit_display_locals_dict,
+};
+
+microbit_display_obj_t microbit_display_obj = {
+ {&microbit_display_type},
+ { 0 },
+ .previous_brightness = 0,
+ .active = 1,
+ .strobe_row = 0,
+ .brightnesses = 0,
+ .pins_for_brightness = { 0 },
+};
+
+void microbit_display_init(void) {
+ // Set pins as output.
+ nrf_gpio_range_cfg_output(MIN_COLUMN_PIN, MIN_COLUMN_PIN + COLUMN_COUNT + ROW_COUNT);
+}
+
+}
diff --git a/ports/nrf/boards/microbit/modules/microbitdisplay.h b/ports/nrf/boards/microbit/modules/microbitdisplay.h
new file mode 100644
index 000000000..24d948af4
--- /dev/null
+++ b/ports/nrf/boards/microbit/modules/microbitdisplay.h
@@ -0,0 +1,54 @@
+
+#ifndef __MICROPY_INCLUDED_MICROBIT_DISPLAY_H__
+#define __MICROPY_INCLUDED_MICROBIT_DISPLAY_H__
+
+#include "py/runtime.h"
+#include "microbitimage.h"
+
+typedef struct _microbit_display_obj_t {
+ mp_obj_base_t base;
+ uint8_t image_buffer[5][5];
+ uint8_t previous_brightness;
+ bool active;
+ /* Current row for strobing */
+ uint8_t strobe_row;
+ /* boolean histogram of brightness in buffer */
+ uint16_t brightnesses;
+ uint16_t pins_for_brightness[MAX_BRIGHTNESS+1];
+
+ void advanceRow();
+ inline void setPinsForRow(uint8_t brightness);
+
+
+} microbit_display_obj_t;
+
+#define ASYNC_MODE_STOPPED 0
+#define ASYNC_MODE_ANIMATION 1
+#define ASYNC_MODE_CLEAR 2
+
+extern microbit_display_obj_t microbit_display_obj;
+
+
+extern "C" {
+
+void microbit_display_show(microbit_display_obj_t *display, microbit_image_obj_t *image);
+
+void microbit_display_animate(microbit_display_obj_t *display, mp_obj_t iterable, mp_int_t delay, bool clear, bool wait);
+
+void microbit_display_scroll(microbit_display_obj_t *display, const char* str, bool wait);
+
+mp_int_t microbit_display_get_pixel(microbit_display_obj_t *display, mp_int_t x, mp_int_t y);
+
+void microbit_display_set_pixel(microbit_display_obj_t *display, mp_int_t x, mp_int_t y, mp_int_t val);
+
+void microbit_display_clear(void);
+
+void microbit_display_init(void);
+
+void microbit_display_tick(void);
+
+bool microbit_display_active_animation(void);
+
+}
+
+#endif // __MICROPY_INCLUDED_MICROBIT_DISPLAY_H__
diff --git a/ports/nrf/boards/microbit/modules/microbitimage.cpp b/ports/nrf/boards/microbit/modules/microbitimage.cpp
new file mode 100644
index 000000000..60f5526dc
--- /dev/null
+++ b/ports/nrf/boards/microbit/modules/microbitimage.cpp
@@ -0,0 +1,973 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Damien George, Mark Shannon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+#include "microbitobj.h"
+#include "MicroBitFont.h"
+
+extern "C" {
+
+#include "py/runtime.h"
+#include "modmicrobit.h"
+#include "microbitimage.h"
+#include "py/runtime0.h"
+
+#define min(a,b) (((a)<(b))?(a):(b))
+#define max(a,b) (((a)>(b))?(a):(b))
+
+const monochrome_5by5_t microbit_blank_image = {
+ { &microbit_image_type },
+ 1, 0, 0, 0,
+ { 0, 0, 0 }
+};
+
+STATIC void microbit_image_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ microbit_image_obj_t *self = (microbit_image_obj_t*)self_in;
+ mp_printf(print, "Image(");
+ if (kind == PRINT_STR)
+ mp_printf(print, "\n ");
+ mp_printf(print, "'");
+ for (int y = 0; y < self->height(); ++y) {
+ for (int x = 0; x < self->width(); ++x) {
+ mp_printf(print, "%c", "0123456789"[self->getPixelValue(x, y)]);
+ }
+ mp_printf(print, ":");
+ if (kind == PRINT_STR && y < self->height()-1)
+ mp_printf(print, "'\n '");
+ }
+ mp_printf(print, "'");
+ if (kind == PRINT_STR)
+ mp_printf(print, "\n");
+ mp_printf(print, ")");
+}
+
+uint8_t monochrome_5by5_t::getPixelValue(mp_int_t x, mp_int_t y) {
+ unsigned int index = y*5+x;
+ if (index == 24)
+ return this->pixel44;
+ return (this->bits24[index>>3] >> (index&7))&1;
+}
+
+uint8_t greyscale_t::getPixelValue(mp_int_t x, mp_int_t y) {
+ unsigned int index = y*this->width+x;
+ unsigned int shift = ((index<<2)&4);
+ return (this->byte_data[index>>1] >> shift)&15;
+}
+
+void greyscale_t::setPixelValue(mp_int_t x, mp_int_t y, mp_int_t val) {
+ unsigned int index = y*this->width+x;
+ unsigned int shift = ((index<<2)&4);
+ uint8_t mask = 240 >> shift;
+ this->byte_data[index>>1] = (this->byte_data[index>>1] & mask) | (val << shift);
+}
+
+void greyscale_t::fill(mp_int_t val) {
+ mp_int_t byte = (val<<4) | val;
+ for (int i = 0; i < ((this->width*this->height+1)>>1); i++) {
+ this->byte_data[i] = byte;
+ }
+}
+
+void greyscale_t::clear() {
+ memset(&this->byte_data, 0, (this->width*this->height+1)>>1);
+}
+
+uint8_t microbit_image_obj_t::getPixelValue(mp_int_t x, mp_int_t y) {
+ if (this->base.five)
+ return this->monochrome_5by5.getPixelValue(x, y)*MAX_BRIGHTNESS;
+ else
+ return this->greyscale.getPixelValue(x, y);
+}
+
+mp_int_t microbit_image_obj_t::width() {
+ if (this->base.five)
+ return 5;
+ else
+ return this->greyscale.width;
+}
+
+mp_int_t microbit_image_obj_t::height() {
+ if (this->base.five)
+ return 5;
+ else
+ return this->greyscale.height;
+}
+
+STATIC greyscale_t *greyscale_new(mp_int_t w, mp_int_t h) {
+ greyscale_t *result = m_new_obj_var(greyscale_t, uint8_t, (w*h+1)>>1);
+ result->base.type = &microbit_image_type;
+ result->five = 0;
+ result->width = w;
+ result->height = h;
+ return result;
+}
+
+greyscale_t *microbit_image_obj_t::copy() {
+ mp_int_t w = this->width();
+ mp_int_t h = this->height();
+ greyscale_t *result = greyscale_new(w, h);
+ for (mp_int_t y = 0; y < h; y++) {
+ for (mp_int_t x = 0; x < w; ++x) {
+ result->setPixelValue(x,y, this->getPixelValue(x,y));
+ }
+ }
+ return result;
+}
+
+greyscale_t *microbit_image_obj_t::invert() {
+ mp_int_t w = this->width();
+ mp_int_t h = this->height();
+ greyscale_t *result = greyscale_new(w, h);
+ for (mp_int_t y = 0; y < h; y++) {
+ for (mp_int_t x = 0; x < w; ++x) {
+ result->setPixelValue(x,y, MAX_BRIGHTNESS - this->getPixelValue(x,y));
+ }
+ }
+ return result;
+}
+
+STATIC microbit_image_obj_t *image_from_parsed_str(const char *s, mp_int_t len) {
+ mp_int_t w = 0;
+ mp_int_t h = 0;
+ mp_int_t line_len = 0;
+ greyscale_t *result;
+ /*First pass -- Establish metadata */
+ for (int i = 0; i < len; i++) {
+ char c = s[i];
+ if (c == '\n' || c == ':') {
+ w = max(line_len, w);
+ line_len = 0;
+ ++h;
+ } else if (c == ' ') {
+ ++line_len;
+ } else if ('c' >= '0' && c <= '9') {
+ ++line_len;
+ } else {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
+ "Unexpected character in Image definition."));
+ }
+ }
+ if (line_len) {
+ // Omitted trailing terminator
+ ++h;
+ w = max(line_len, w);
+ }
+ result = greyscale_new(w, h);
+ mp_int_t x = 0;
+ mp_int_t y = 0;
+ /* Second pass -- Fill in data */
+ for (int i = 0; i < len; i++) {
+ char c = s[i];
+ if (c == '\n' || c == ':') {
+ while (x < w) {
+ result->setPixelValue(x, y, 0);
+ x++;
+ }
+ ++y;
+ x = 0;
+ } else if (c == ' ') {
+ /* Treat spaces as 0 */
+ result->setPixelValue(x, y, 0);
+ ++x;
+ } else if ('c' >= '0' && c <= '9') {
+ result->setPixelValue(x, y, c - '0');
+ ++x;
+ }
+ }
+ if (y < h) {
+ while (x < w) {
+ result->setPixelValue(x, y, 0);
+ x++;
+ }
+ }
+ return (microbit_image_obj_t *)result;
+}
+
+
+STATIC mp_obj_t microbit_image_make_new(const mp_obj_type_t *type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
+ (void)type_in;
+ mp_arg_check_num(n_args, n_kw, 0, 3, false);
+
+ switch (n_args) {
+ case 0: {
+ greyscale_t *image = greyscale_new(5, 5);
+ image->clear();
+ return image;
+ }
+
+ case 1: {
+ if (MP_OBJ_IS_STR(args[0])) {
+ // arg is a string object
+ mp_uint_t len;
+ const char *str = mp_obj_str_get_data(args[0], &len);
+ // make image from string
+ if (len == 1) {
+ /* For a single charater, return the font glyph */
+ return microbit_image_for_char(str[0]);
+ } else {
+ /* Otherwise parse the image description string */
+ return image_from_parsed_str(str, len);
+ }
+ } else {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
+ "Image(s) takes a string."));
+ }
+ }
+
+ case 2:
+ case 3: {
+ mp_int_t w = mp_obj_get_int(args[0]);
+ mp_int_t h = mp_obj_get_int(args[1]);
+ greyscale_t *image = greyscale_new(w, h);
+ if (n_args == 2) {
+ image->clear();
+ } else {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
+
+ if (w < 0 || h < 0 || (size_t)(w * h) != bufinfo.len) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
+ "image data is incorrect size"));
+ }
+ mp_int_t i = 0;
+ for (mp_int_t y = 0; y < h; y++) {
+ for (mp_int_t x = 0; x < w; ++x) {
+ uint8_t val = min(((const uint8_t*)bufinfo.buf)[i], MAX_BRIGHTNESS);
+ image->setPixelValue(x, y, val);
+ ++i;
+ }
+ }
+ }
+ return image;
+ }
+
+ default: {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
+ "Image() takes 0 to 3 arguments"));
+ }
+ }
+}
+
+static void clear_rect(greyscale_t *img, mp_int_t x0, mp_int_t y0,mp_int_t x1, mp_int_t y1) {
+ for (int i = x0; i < x1; ++i) {
+ for (int j = y0; j < y1; ++j) {
+ img->setPixelValue(i, j, 0);
+ }
+ }
+}
+
+STATIC void image_blit(microbit_image_obj_t *src, greyscale_t *dest, mp_int_t x, mp_int_t y, mp_int_t w, mp_int_t h, mp_int_t xdest, mp_int_t ydest) {
+ if (w < 0)
+ w = 0;
+ if (h < 0)
+ h = 0;
+ mp_int_t intersect_x0 = max(max(0, x), -xdest);
+ mp_int_t intersect_y0 = max(max(0, y), -ydest);
+ mp_int_t intersect_x1 = min(min(dest->width+x-xdest, src->width()), x+w);
+ mp_int_t intersect_y1 = min(min(dest->height+y-ydest, src->height()), y+h);
+ mp_int_t xstart, xend, ystart, yend, xdel, ydel;
+ mp_int_t clear_x0 = max(0, xdest);
+ mp_int_t clear_y0 = max(0, ydest);
+ mp_int_t clear_x1 = min(dest->width, xdest+w);
+ mp_int_t clear_y1 = min(dest->height, ydest+h);
+ if (intersect_x0 >= intersect_x1 || intersect_y0 >= intersect_y1) {
+ // Nothing to copy
+ clear_rect(dest, clear_x0, clear_y0, clear_x1, clear_y1);
+ return;
+ }
+ if (x > xdest) {
+ xstart = intersect_x0; xend = intersect_x1; xdel = 1;
+ } else {
+ xstart = intersect_x1-1; xend = intersect_x0-1; xdel = -1;
+ }
+ if (y > ydest) {
+ ystart = intersect_y0; yend = intersect_y1; ydel = 1;
+ } else {
+ ystart = intersect_y1-1; yend = intersect_y0-1; ydel = -1;
+ }
+ for (int i = xstart; i != xend; i += xdel) {
+ for (int j = ystart; j != yend; j += ydel) {
+ int val = src->getPixelValue(i, j);
+ dest->setPixelValue(i+xdest-x, j+ydest-y, val);
+ }
+ }
+ // Adjust intersection rectange to dest
+ intersect_x0 += xdest-x;
+ intersect_y0 += ydest-y;
+ intersect_x1 += xdest-x;
+ intersect_y1 += ydest-y;
+ // Clear four rectangles in the cleared area surrounding the copied area.
+ clear_rect(dest, clear_x0, clear_y0, intersect_x0, intersect_y1);
+ clear_rect(dest, clear_x0, intersect_y1, intersect_x1, clear_y1);
+ clear_rect(dest, intersect_x1, intersect_y0, clear_x1, clear_y1);
+ clear_rect(dest, intersect_x0, clear_y0, clear_x1, intersect_y0);
+}
+
+greyscale_t *image_shift(microbit_image_obj_t *self, mp_int_t x, mp_int_t y) {
+ greyscale_t *result = greyscale_new(self->width(), self->width());
+ image_blit(self, result, x, y, self->width(), self->width(), 0, 0);
+ return result;
+}
+
+STATIC microbit_image_obj_t *image_crop(microbit_image_obj_t *img, mp_int_t x, mp_int_t y, mp_int_t w, mp_int_t h) {
+ if (w < 0)
+ w = 0;
+ if (h < 0)
+ h = 0;
+ greyscale_t *result = greyscale_new(w, h);
+ image_blit(img, result, x, y, w, h, 0, 0);
+ return (microbit_image_obj_t *)result;
+}
+
+mp_obj_t microbit_image_width(mp_obj_t self_in) {
+ microbit_image_obj_t *self = (microbit_image_obj_t*)self_in;
+ return MP_OBJ_NEW_SMALL_INT(self->width());
+}
+MP_DEFINE_CONST_FUN_OBJ_1(microbit_image_width_obj, microbit_image_width);
+
+mp_obj_t microbit_image_height(mp_obj_t self_in) {
+ microbit_image_obj_t *self = (microbit_image_obj_t*)self_in;
+ return MP_OBJ_NEW_SMALL_INT(self->height());
+}
+MP_DEFINE_CONST_FUN_OBJ_1(microbit_image_height_obj, microbit_image_height);
+
+mp_obj_t microbit_image_get_pixel(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) {
+ microbit_image_obj_t *self = (microbit_image_obj_t*)self_in;
+ mp_int_t x = mp_obj_get_int(x_in);
+ mp_int_t y = mp_obj_get_int(y_in);
+ if (x < 0 || y < 0) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
+ "index cannot be negative"));
+ }
+ if (x < self->width() && y < self->height()) {
+ return MP_OBJ_NEW_SMALL_INT(self->getPixelValue(x, y));
+ }
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "index too large"));
+}
+MP_DEFINE_CONST_FUN_OBJ_3(microbit_image_get_pixel_obj, microbit_image_get_pixel);
+
+/* Raise an exception if not mutable */
+static void check_mutability(microbit_image_obj_t *self) {
+ if (self->base.five) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "image cannot be modified (try copying first)"));
+ }
+}
+
+
+mp_obj_t microbit_image_set_pixel(mp_uint_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ microbit_image_obj_t *self = (microbit_image_obj_t*)args[0];
+ check_mutability(self);
+ mp_int_t x = mp_obj_get_int(args[1]);
+ mp_int_t y = mp_obj_get_int(args[2]);
+ if (x < 0 || y < 0) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
+ "index cannot be negative"));
+ }
+ mp_int_t bright = mp_obj_get_int(args[3]);
+ if (bright < 0 || bright > MAX_BRIGHTNESS)
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "brightness out of bounds."));
+ if (x < self->width() && y < self->height()) {
+ self->greyscale.setPixelValue(x, y, bright);
+ return mp_const_none;
+ }
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "index too large"));
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_image_set_pixel_obj, 4, 4, microbit_image_set_pixel);
+
+mp_obj_t microbit_image_fill(mp_obj_t self_in, mp_obj_t n_in) {
+ microbit_image_obj_t *self = (microbit_image_obj_t*)self_in;
+ check_mutability(self);
+ mp_int_t n = mp_obj_get_int(n_in);
+ if (n < 0 || n > MAX_BRIGHTNESS) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "brightness out of bounds."));
+ }
+ self->greyscale.fill(n);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(microbit_image_fill_obj, microbit_image_fill);
+
+mp_obj_t microbit_image_blit(mp_uint_t n_args, const mp_obj_t *args) {
+ microbit_image_obj_t *self = (microbit_image_obj_t*)args[0];
+ check_mutability(self);
+
+ mp_obj_t src = args[1];
+ if (mp_obj_get_type(src) != &microbit_image_type) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "expecting an image"));
+ }
+ if (n_args == 7) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
+ "must specify both offsets"));
+ }
+ mp_int_t x = mp_obj_get_int(args[2]);
+ mp_int_t y = mp_obj_get_int(args[3]);
+ mp_int_t w = mp_obj_get_int(args[4]);
+ mp_int_t h = mp_obj_get_int(args[5]);
+ if (w < 0 || h < 0) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
+ "size cannot be negative"));
+ }
+ mp_int_t xdest;
+ mp_int_t ydest;
+ if (n_args == 6) {
+ xdest = 0;
+ ydest = 0;
+ } else {
+ xdest = mp_obj_get_int(args[6]);
+ ydest = mp_obj_get_int(args[7]);
+ }
+ image_blit((microbit_image_obj_t *)src, &(self->greyscale), x, y, w, h, xdest, ydest);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_image_blit_obj, 6, 8, microbit_image_blit);
+
+mp_obj_t microbit_image_crop(mp_uint_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ microbit_image_obj_t *self = (microbit_image_obj_t*)args[0];
+ mp_int_t x0 = mp_obj_get_int(args[1]);
+ mp_int_t y0 = mp_obj_get_int(args[2]);
+ mp_int_t x1 = mp_obj_get_int(args[3]);
+ mp_int_t y1 = mp_obj_get_int(args[4]);
+ return image_crop(self, x0, y0, x1, y1);
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_image_crop_obj, 5, 5, microbit_image_crop);
+
+mp_obj_t microbit_image_shift_left(mp_obj_t self_in, mp_obj_t n_in) {
+ microbit_image_obj_t *self = (microbit_image_obj_t*)self_in;
+ mp_int_t n = mp_obj_get_int(n_in);
+ return image_shift(self, n, 0);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(microbit_image_shift_left_obj, microbit_image_shift_left);
+
+mp_obj_t microbit_image_shift_right(mp_obj_t self_in, mp_obj_t n_in) {
+ microbit_image_obj_t *self = (microbit_image_obj_t*)self_in;
+ mp_int_t n = mp_obj_get_int(n_in);
+ return image_shift(self, -n, 0);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(microbit_image_shift_right_obj, microbit_image_shift_right);
+
+mp_obj_t microbit_image_shift_up(mp_obj_t self_in, mp_obj_t n_in) {
+ microbit_image_obj_t *self = (microbit_image_obj_t*)self_in;
+ mp_int_t n = mp_obj_get_int(n_in);
+ return image_shift(self, 0, n);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(microbit_image_shift_up_obj, microbit_image_shift_up);
+
+mp_obj_t microbit_image_shift_down(mp_obj_t self_in, mp_obj_t n_in) {
+ microbit_image_obj_t *self = (microbit_image_obj_t*)self_in;
+ mp_int_t n = mp_obj_get_int(n_in);
+ return image_shift(self, 0, -n);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(microbit_image_shift_down_obj, microbit_image_shift_down);
+
+mp_obj_t microbit_image_copy(mp_obj_t self_in) {
+ microbit_image_obj_t *self = (microbit_image_obj_t*)self_in;
+ return self->copy();
+}
+MP_DEFINE_CONST_FUN_OBJ_1(microbit_image_copy_obj, microbit_image_copy);
+
+mp_obj_t microbit_image_invert(mp_obj_t self_in) {
+ microbit_image_obj_t *self = (microbit_image_obj_t*)self_in;
+ return self->invert();
+}
+MP_DEFINE_CONST_FUN_OBJ_1(microbit_image_invert_obj, microbit_image_invert);
+
+
+STATIC const mp_map_elem_t microbit_image_locals_dict_table[] = {
+ { MP_OBJ_NEW_QSTR(MP_QSTR_width), (mp_obj_t)&microbit_image_width_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_height), (mp_obj_t)&microbit_image_height_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_get_pixel), (mp_obj_t)&microbit_image_get_pixel_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_set_pixel), (mp_obj_t)&microbit_image_set_pixel_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_shift_left), (mp_obj_t)&microbit_image_shift_left_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_shift_right), (mp_obj_t)&microbit_image_shift_right_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_shift_up), (mp_obj_t)&microbit_image_shift_up_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_shift_down), (mp_obj_t)&microbit_image_shift_down_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_copy), (mp_obj_t)&microbit_image_copy_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_crop), (mp_obj_t)&microbit_image_crop_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_invert), (mp_obj_t)&microbit_image_invert_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_fill), (mp_obj_t)&microbit_image_fill_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_blit), (mp_obj_t)&microbit_image_blit_obj },
+
+ { MP_OBJ_NEW_QSTR(MP_QSTR_HEART), (mp_obj_t)&microbit_const_image_heart_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_HEART_SMALL), (mp_obj_t)&microbit_const_image_heart_small_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_HAPPY), (mp_obj_t)&microbit_const_image_happy_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_SMILE), (mp_obj_t)&microbit_const_image_smile_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_SAD), (mp_obj_t)&microbit_const_image_sad_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_CONFUSED), (mp_obj_t)&microbit_const_image_confused_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ANGRY), (mp_obj_t)&microbit_const_image_angry_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ASLEEP), (mp_obj_t)&microbit_const_image_asleep_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_SURPRISED), (mp_obj_t)&microbit_const_image_surprised_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_SILLY), (mp_obj_t)&microbit_const_image_silly_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_FABULOUS), (mp_obj_t)&microbit_const_image_fabulous_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_MEH), (mp_obj_t)&microbit_const_image_meh_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_YES), (mp_obj_t)&microbit_const_image_yes_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_NO), (mp_obj_t)&microbit_const_image_no_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK12), (mp_obj_t)&microbit_const_image_clock12_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK1), (mp_obj_t)&microbit_const_image_clock1_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK2), (mp_obj_t)&microbit_const_image_clock2_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK3), (mp_obj_t)&microbit_const_image_clock3_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK4), (mp_obj_t)&microbit_const_image_clock4_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK5), (mp_obj_t)&microbit_const_image_clock5_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK6), (mp_obj_t)&microbit_const_image_clock6_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK7), (mp_obj_t)&microbit_const_image_clock7_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK8), (mp_obj_t)&microbit_const_image_clock8_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK9), (mp_obj_t)&microbit_const_image_clock9_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK10), (mp_obj_t)&microbit_const_image_clock10_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK11), (mp_obj_t)&microbit_const_image_clock11_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_N), (mp_obj_t)&microbit_const_image_arrow_n_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_NE), (mp_obj_t)&microbit_const_image_arrow_ne_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_E), (mp_obj_t)&microbit_const_image_arrow_e_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_SE), (mp_obj_t)&microbit_const_image_arrow_se_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_S), (mp_obj_t)&microbit_const_image_arrow_s_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_SW), (mp_obj_t)&microbit_const_image_arrow_sw_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_W), (mp_obj_t)&microbit_const_image_arrow_w_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_NW), (mp_obj_t)&microbit_const_image_arrow_nw_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_TRIANGLE), (mp_obj_t)&microbit_const_image_triangle_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_TRIANGLE_LEFT), (mp_obj_t)&microbit_const_image_triangle_left_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_CHESSBOARD), (mp_obj_t)&microbit_const_image_chessboard_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_DIAMOND), (mp_obj_t)&microbit_const_image_diamond_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_DIAMOND_SMALL), (mp_obj_t)&microbit_const_image_diamond_small_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_SQUARE), (mp_obj_t)&microbit_const_image_square_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_SQUARE_SMALL), (mp_obj_t)&microbit_const_image_square_small_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_RABBIT), (mp_obj_t)&microbit_const_image_rabbit },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_COW), (mp_obj_t)&microbit_const_image_cow },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_MUSIC_CROTCHET), (mp_obj_t)&microbit_const_image_music_crotchet_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_MUSIC_QUAVER), (mp_obj_t)&microbit_const_image_music_quaver_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_MUSIC_QUAVERS), (mp_obj_t)&microbit_const_image_music_quavers_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_PITCHFORK), (mp_obj_t)&microbit_const_image_pitchfork_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_XMAS), (mp_obj_t)&microbit_const_image_xmas_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_PACMAN), (mp_obj_t)&microbit_const_image_pacman_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_TARGET), (mp_obj_t)&microbit_const_image_target_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ALL_CLOCKS), (mp_obj_t)&microbit_const_image_all_clocks_tuple_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ALL_ARROWS), (mp_obj_t)&microbit_const_image_all_arrows_tuple_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_TSHIRT), (mp_obj_t)&microbit_const_image_tshirt_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ROLLERSKATE), (mp_obj_t)&microbit_const_image_rollerskate_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_DUCK), (mp_obj_t)&microbit_const_image_duck_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_HOUSE), (mp_obj_t)&microbit_const_image_house_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_TORTOISE), (mp_obj_t)&microbit_const_image_tortoise_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_BUTTERFLY), (mp_obj_t)&microbit_const_image_butterfly_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_STICKFIGURE), (mp_obj_t)&microbit_const_image_stickfigure_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_GHOST), (mp_obj_t)&microbit_const_image_ghost_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_SWORD), (mp_obj_t)&microbit_const_image_sword_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_GIRAFFE), (mp_obj_t)&microbit_const_image_giraffe_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_SKULL), (mp_obj_t)&microbit_const_image_skull_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_UMBRELLA), (mp_obj_t)&microbit_const_image_umbrella_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_SNAKE), (mp_obj_t)&microbit_const_image_snake_obj },
+};
+
+STATIC MP_DEFINE_CONST_DICT(microbit_image_locals_dict, microbit_image_locals_dict_table);
+
+#define THE_FONT MicroBitFont::defaultFont
+
+#define ASCII_START 32
+#define ASCII_END 126
+
+STATIC const unsigned char *get_font_data_from_char(char c) {
+ if (c < ASCII_START || c > ASCII_END) {
+ c = '?';
+ }
+ int offset = (c-ASCII_START) * 5;
+ return THE_FONT + offset;
+}
+
+STATIC mp_int_t get_pixel_from_font_data(const unsigned char *data, int x, int y) {
+ /* The following logic belongs in MicroBitFont */
+ return ((data[y]>>(4-x))&1);
+}
+
+void microbit_image_set_from_char(greyscale_t *img, char c) {
+ const unsigned char *data = get_font_data_from_char(c);
+ for (int x = 0; x < 5; ++x) {
+ for (int y = 0; y < 5; ++y) {
+ img->setPixelValue(x, y, get_pixel_from_font_data(data, x, y)*MAX_BRIGHTNESS);
+ }
+ }
+}
+
+
+microbit_image_obj_t *microbit_image_for_char(char c) {
+ greyscale_t *result = greyscale_new(5,5);
+ microbit_image_set_from_char(result, c);
+ return (microbit_image_obj_t *)result;
+}
+
+microbit_image_obj_t *microbit_image_dim(microbit_image_obj_t *lhs, mp_float_t fval) {
+ if (fval < 0)
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Brightness multiplier must not be negative."));
+ greyscale_t *result = greyscale_new(lhs->width(), lhs->height());
+ for (int x = 0; x < lhs->width(); ++x) {
+ for (int y = 0; y < lhs->width(); ++y) {
+ int val = min((int)lhs->getPixelValue(x,y)*fval+0.5, MAX_BRIGHTNESS);
+ result->setPixelValue(x, y, val);
+ }
+ }
+ return (microbit_image_obj_t *)result;
+}
+
+microbit_image_obj_t *microbit_image_sum(microbit_image_obj_t *lhs, microbit_image_obj_t *rhs, bool add) {
+ mp_int_t h = lhs->height();
+ mp_int_t w = lhs->width();
+ if (rhs->height() != h || lhs->width() != w) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Images must be the same size."));
+ }
+ greyscale_t *result = greyscale_new(w, h);
+ for (int x = 0; x < w; ++x) {
+ for (int y = 0; y < h; ++y) {
+ int val;
+ int lval = lhs->getPixelValue(x,y);
+ int rval = rhs->getPixelValue(x,y);
+ if (add)
+ val = min(lval + rval, MAX_BRIGHTNESS);
+ else
+ val = max(0, lval - rval);
+ result->setPixelValue(x, y, val);
+ }
+ }
+ return (microbit_image_obj_t *)result;
+}
+
+STATIC mp_obj_t image_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
+ if (mp_obj_get_type(lhs_in) != &microbit_image_type) {
+ return MP_OBJ_NULL; // op not supported
+ }
+ microbit_image_obj_t *lhs = (microbit_image_obj_t *)lhs_in;
+ switch(op) {
+ case MP_BINARY_OP_ADD:
+ case MP_BINARY_OP_SUBTRACT:
+ break;
+ case MP_BINARY_OP_MULTIPLY:
+ return microbit_image_dim(lhs, mp_obj_get_float(rhs_in));
+ case MP_BINARY_OP_TRUE_DIVIDE:
+ return microbit_image_dim(lhs, 1.0/mp_obj_get_float(rhs_in));
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+ if (mp_obj_get_type(rhs_in) != &microbit_image_type) {
+ return MP_OBJ_NULL; // op not supported
+ }
+ return microbit_image_sum(lhs, (microbit_image_obj_t *)rhs_in, op == MP_BINARY_OP_ADD);
+}
+
+
+const mp_obj_type_t microbit_image_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_MicroBitImage,
+ .print = microbit_image_print,
+ .make_new = microbit_image_make_new,
+ .call = NULL,
+ .unary_op = NULL,
+ .binary_op = image_binary_op,
+ .attr = NULL,
+ .subscr = NULL,
+ .getiter = NULL,
+ .iternext = NULL,
+ .buffer_p = {NULL},
+ .stream_p = NULL,
+ .bases_tuple = NULL,
+ .locals_dict = (mp_obj_dict_t*)&microbit_image_locals_dict,
+};
+
+typedef struct _scrolling_string_t {
+ mp_obj_base_t base;
+ char const *str;
+ mp_uint_t len;
+ mp_obj_t ref;
+ bool monospace;
+ bool repeat;
+} scrolling_string_t;
+
+typedef struct _scrolling_string_iterator_t {
+ mp_obj_base_t base;
+ mp_obj_t ref;
+ greyscale_t *img;
+ char const *next_char;
+ char const *start;
+ char const *end;
+ uint8_t offset;
+ uint8_t offset_limit;
+ bool monospace;
+ bool repeat;
+ char right;
+} scrolling_string_iterator_t;
+
+extern const mp_obj_type_t microbit_scrolling_string_type;
+extern const mp_obj_type_t microbit_scrolling_string_iterator_type;
+
+mp_obj_t scrolling_string_image_iterable(const char* str, mp_uint_t len, mp_obj_t ref, bool monospace, bool repeat) {
+ scrolling_string_t *result = m_new_obj(scrolling_string_t);
+ result->base.type = &microbit_scrolling_string_type;
+ result->str = str;
+ result->len = len;
+ result->ref = ref;
+ result->monospace = monospace;
+ result->repeat = repeat;
+ return result;
+}
+
+STATIC int font_column_non_blank(const unsigned char *font_data, unsigned int col) {
+ for (int y = 0; y < 5; ++y) {
+ if (get_pixel_from_font_data(font_data, col, y)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Not strictly the rightmost non-blank column, but the rightmost in columns 2,3 or 4. */
+STATIC unsigned int rightmost_non_blank_column(const unsigned char *font_data) {
+ if (font_column_non_blank(font_data, 4)) {
+ return 4;
+ }
+ if (font_column_non_blank(font_data, 3)) {
+ return 3;
+ }
+ return 2;
+}
+
+static void restart(scrolling_string_iterator_t *iter) {
+ iter->next_char = iter->start;
+ iter->offset = 0;
+ if (iter->start < iter->end) {
+ iter->right = *iter->next_char;
+ if (iter->monospace) {
+ iter->offset_limit = 5;
+ } else {
+ iter->offset_limit = rightmost_non_blank_column(get_font_data_from_char(iter->right)) + 1;
+ }
+ } else {
+ iter->right = ' ';
+ iter->offset_limit = 5;
+ }
+}
+
+STATIC mp_obj_t get_microbit_scrolling_string_iter(mp_obj_t o_in) {
+ scrolling_string_t *str = (scrolling_string_t *)o_in;
+ scrolling_string_iterator_t *result = m_new_obj(scrolling_string_iterator_t);
+ result->base.type = &microbit_scrolling_string_iterator_type;
+ result->img = greyscale_new(5,5);
+ result->start = str->str;
+ result->ref = str->ref;
+ result->monospace = str->monospace;
+ result->end = result->start + str->len;
+ result->repeat = str->repeat;
+ restart(result);
+ return result;
+}
+
+STATIC mp_obj_t microbit_scrolling_string_iter_next(mp_obj_t o_in) {
+ scrolling_string_iterator_t *iter = (scrolling_string_iterator_t *)o_in;
+ if (iter->next_char == iter->end && iter->offset == 5) {
+ if (iter->repeat) {
+ restart(iter);
+ iter->img->clear();
+ } else {
+ return MP_OBJ_STOP_ITERATION;
+ }
+ }
+ for (int x = 0; x < 4; x++) {
+ for (int y = 0; y < 5; y++) {
+ iter->img->setPixelValue(x, y, iter->img->getPixelValue(x+1, y));
+ }
+ }
+ for (int y = 0; y < 5; y++) {
+ iter->img->setPixelValue(4, y, 0);
+ }
+ const unsigned char *font_data;
+ if (iter->offset < iter->offset_limit) {
+ font_data = get_font_data_from_char(iter->right);
+ for (int y = 0; y < 5; ++y) {
+ int pix = get_pixel_from_font_data(font_data, iter->offset, y)*MAX_BRIGHTNESS;
+ iter->img->setPixelValue(4, y, pix);
+ }
+ } else if (iter->offset == iter->offset_limit) {
+ ++iter->next_char;
+ if (iter->next_char == iter->end) {
+ iter->right = ' ';
+ iter->offset_limit = 5;
+ iter->offset = 0;
+ } else {
+ iter->right = *iter->next_char;
+ font_data = get_font_data_from_char(iter->right);
+ if (iter->monospace) {
+ iter->offset = -1;
+ iter->offset_limit = 5;
+ } else {
+ iter->offset = -font_column_non_blank(font_data, 0);
+ iter->offset_limit = rightmost_non_blank_column(font_data)+1;
+ }
+ }
+ }
+ ++iter->offset;
+ return iter->img;
+}
+
+const mp_obj_type_t microbit_scrolling_string_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ScrollingString,
+ .print = NULL,
+ .make_new = NULL,
+ .call = NULL,
+ .unary_op = NULL,
+ .binary_op = NULL,
+ .attr = NULL,
+ .subscr = NULL,
+ .getiter = get_microbit_scrolling_string_iter,
+ .iternext = NULL,
+ .buffer_p = {NULL},
+ .stream_p = NULL,
+ .bases_tuple = NULL,
+ .locals_dict = NULL,
+};
+
+const mp_obj_type_t microbit_scrolling_string_iterator_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_iterator,
+ .print = NULL,
+ .make_new = NULL,
+ .call = NULL,
+ .unary_op = NULL,
+ .binary_op = NULL,
+ .attr = NULL,
+ .subscr = NULL,
+ .getiter = mp_identity,
+ .iternext = microbit_scrolling_string_iter_next,
+ .buffer_p = {NULL},
+ .stream_p = NULL,
+ .bases_tuple = NULL,
+ .locals_dict = NULL,
+};
+
+/** Facade types to present a string as a sequence of images.
+ * These are necessary to avoid allocation during iteration,
+ * which may happen in interrupt handlers.
+ */
+
+typedef struct _string_image_facade_t {
+ mp_obj_base_t base;
+ mp_obj_t string;
+ greyscale_t *image;
+} string_image_facade_t;
+
+static mp_obj_t string_image_facade_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
+ if (value == MP_OBJ_SENTINEL) {
+ // Fill in image
+ string_image_facade_t *self = (string_image_facade_t *)self_in;
+ mp_uint_t len;
+ const char *text = mp_obj_str_get_data(self->string, &len);
+ mp_uint_t index = mp_get_index(self->base.type, len, index_in, false);
+ microbit_image_set_from_char(self->image, text[index]);
+ return self->image;
+ } else {
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+static mp_obj_t facade_unary_op(mp_uint_t op, mp_obj_t self_in) {
+ string_image_facade_t *self = (string_image_facade_t *)self_in;
+ switch (op) {
+ case MP_UNARY_OP_LEN:
+ return mp_obj_len(self->string);
+ default: return MP_OBJ_NULL; // op not supported
+ }
+}
+
+static mp_obj_t microbit_facade_iterator(mp_obj_t iterable);
+
+const mp_obj_type_t string_image_facade_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Facade,
+ .print = NULL,
+ .make_new = NULL,
+ .call = NULL,
+ .unary_op = facade_unary_op,
+ .binary_op = NULL,
+ .attr = NULL,
+ .subscr = string_image_facade_subscr,
+ .getiter = microbit_facade_iterator,
+ .iternext = NULL,
+ .buffer_p = {NULL},
+ .stream_p = NULL,
+ .bases_tuple = NULL,
+ NULL
+};
+
+
+typedef struct _facade_iterator_t {
+ mp_obj_base_t base;
+ mp_obj_t string;
+ mp_uint_t index;
+ greyscale_t *image;
+} facade_iterator_t;
+
+mp_obj_t microbit_string_facade(mp_obj_t string) {
+ string_image_facade_t *result = m_new_obj(string_image_facade_t);
+ result->base.type = &string_image_facade_type;
+ result->string = string;
+ result->image = greyscale_new(5,5);
+ return result;
+}
+
+static mp_obj_t microbit_facade_iter_next(mp_obj_t iter_in) {
+ facade_iterator_t *iter = (facade_iterator_t *)iter_in;
+ mp_uint_t len;
+ const char *text = mp_obj_str_get_data(iter->string, &len);
+ if (iter->index >= len) {
+ return MP_OBJ_STOP_ITERATION;
+ }
+ microbit_image_set_from_char(iter->image, text[iter->index]);
+ iter->index++;
+ return iter->image;
+}
+
+const mp_obj_type_t microbit_facade_iterator_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_iterator,
+ .print = NULL,
+ .make_new = NULL,
+ .call = NULL,
+ .unary_op = NULL,
+ .binary_op = NULL,
+ .attr = NULL,
+ .subscr = NULL,
+ .getiter = mp_identity,
+ .iternext = microbit_facade_iter_next,
+ .buffer_p = {NULL},
+ .stream_p = NULL,
+ .bases_tuple = NULL,
+ NULL
+};
+
+mp_obj_t microbit_facade_iterator(mp_obj_t iterable_in) {
+ facade_iterator_t *result = m_new_obj(facade_iterator_t);
+ string_image_facade_t *iterable = (string_image_facade_t *)iterable_in;
+ result->base.type = &microbit_facade_iterator_type;
+ result->string = iterable->string;
+ result->image = iterable->image;
+ result->index = 0;
+ return result;
+}
+
+}
diff --git a/ports/nrf/boards/microbit/modules/microbitimage.h b/ports/nrf/boards/microbit/modules/microbitimage.h
new file mode 100644
index 000000000..94d167dae
--- /dev/null
+++ b/ports/nrf/boards/microbit/modules/microbitimage.h
@@ -0,0 +1,92 @@
+#ifndef __MICROPY_INCLUDED_MICROBIT_IMAGE_H__
+#define __MICROPY_INCLUDED_MICROBIT_IMAGE_H__
+
+#include "py/runtime.h"
+
+#define MAX_BRIGHTNESS 9
+
+/** Monochrome images are immutable, which means that
+ * we only need one bit per pixel which saves quite a lot
+ * of memory */
+
+/* we reserve a couple of bits, so we won't need to modify the
+ * layout if we need to add more functionality or subtypes. */
+#define TYPE_AND_FLAGS \
+ mp_obj_base_t base; \
+ uint8_t five:1; \
+ uint8_t reserved1:1; \
+ uint8_t reserved2:1
+
+typedef struct _image_base_t {
+ TYPE_AND_FLAGS;
+} image_base_t;
+
+typedef struct _monochrome_5by5_t {
+ TYPE_AND_FLAGS;
+ uint8_t pixel44: 1;
+ uint8_t bits24[3];
+
+ /* This is an internal method it is up to the caller to validate the inputs */
+ uint8_t getPixelValue(mp_int_t x, mp_int_t y);
+
+} monochrome_5by5_t;
+
+typedef struct _greyscale_t {
+ TYPE_AND_FLAGS;
+ uint8_t height;
+ uint8_t width;
+ uint8_t byte_data[]; /* Static initializer for this will have to be C, not C++ */
+ void clear();
+
+ /* Thiese are internal methods and it is up to the caller to validate the inputs */
+ uint8_t getPixelValue(mp_int_t x, mp_int_t y);
+ void setPixelValue(mp_int_t x, mp_int_t y, mp_int_t val);
+ void fill(mp_int_t val);
+} greyscale_t;
+
+typedef union _microbit_image_obj_t {
+ image_base_t base;
+ monochrome_5by5_t monochrome_5by5;
+ greyscale_t greyscale;
+
+ mp_int_t height();
+ mp_int_t width();
+ greyscale_t *copy();
+ greyscale_t *invert();
+
+ /* This is an internal method it is up to the caller to validate the inputs */
+ uint8_t getPixelValue(mp_int_t x, mp_int_t y);
+
+} microbit_image_obj_t;
+
+/** Return a facade object that presents the string as a sequence of images */
+mp_obj_t microbit_string_facade(mp_obj_t string);
+
+void microbit_image_set_from_char(greyscale_t *img, char c);
+microbit_image_obj_t *microbit_image_for_char(char c);
+mp_obj_t microbit_image_slice(microbit_image_obj_t *img, mp_int_t start, mp_int_t width, mp_int_t stride);
+/* ref exists so that we can pull a string out of an object and not have it GC'ed while oterating over it */
+mp_obj_t scrolling_string_image_iterable(const char* str, mp_uint_t len, mp_obj_t ref, bool monospace, bool repeat);
+
+#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) \
+{ \
+ { &microbit_image_type }, \
+ 1, 0, 0, (p44), \
+ { \
+ (p0)|((p1)<<1)|((p2)<<2)|((p3)<<3)|((p4)<<4)|((p5)<<5)|((p6)<<6)|((p7)<<7), \
+ (p8)|((p9)<<1)|((p10)<<2)|((p11)<<3)|((p12)<<4)|((p13)<<5)|((p14)<<6)|((p15)<<7), \
+ (p16)|((p17)<<1)|((p18)<<2)|((p19)<<3)|((p20)<<4)|((p21)<<5)|((p22)<<6)|((p23)<<7) \
+ } \
+}
+
+extern const monochrome_5by5_t microbit_blank_image;
+extern const monochrome_5by5_t microbit_const_image_heart_obj;
+
+#define BLANK_IMAGE (microbit_image_obj_t *)(&microbit_blank_image)
+#define HEART_IMAGE (microbit_image_obj_t *)(&microbit_const_image_heart_obj)
+#define HAPPY_IMAGE (microbit_image_obj_t *)(&microbit_const_image_happy_obj)
+
+microbit_image_obj_t *microbit_image_dim(microbit_image_obj_t *lhs, mp_float_t fval);
+microbit_image_obj_t *microbit_image_sum(microbit_image_obj_t *lhs, microbit_image_obj_t *rhs, bool add);
+
+#endif // __MICROPY_INCLUDED_MICROBIT_IMAGE_H__
diff --git a/ports/nrf/boards/microbit/modules/modmicrobit.cpp b/ports/nrf/boards/microbit/modules/modmicrobit.cpp
new file mode 100644
index 000000000..7201790cf
--- /dev/null
+++ b/ports/nrf/boards/microbit/modules/modmicrobit.cpp
@@ -0,0 +1,158 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "mbed.h"
+
+extern "C" {
+
+#include "py/nlr.h"
+#include "py/obj.h"
+#include "py/mphal.h"
+#include "modmicrobit.h"
+#include "microbitdisplay.h"
+#include "microbitimage.h"
+
+extern uint32_t ticks;
+
+STATIC mp_obj_t microbit_reset_(void) {
+ NVIC_SystemReset();
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(microbit_reset_obj, microbit_reset_);
+
+STATIC mp_obj_t microbit_sleep(mp_obj_t ms_in) {
+ mp_int_t ms;
+ if (mp_obj_is_integer(ms_in)) {
+ ms = mp_obj_get_int(ms_in);
+ } else {
+ ms = (mp_int_t)mp_obj_get_float(ms_in);
+ }
+ if (ms > 0) {
+ mp_hal_delay_ms(ms);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(microbit_sleep_obj, microbit_sleep);
+
+STATIC mp_obj_t microbit_running_time(void) {
+ return MP_OBJ_NEW_SMALL_INT(ticks);
+}
+MP_DEFINE_CONST_FUN_OBJ_0(microbit_running_time_obj, microbit_running_time);
+
+static const monochrome_5by5_t panic = SMALL_IMAGE(
+ 1,1,0,1,1,
+ 1,1,0,1,1,
+ 0,0,0,0,0,
+ 0,1,1,1,0,
+ 1,0,0,0,1
+);
+
+STATIC mp_obj_t microbit_panic(mp_uint_t n_args, const mp_obj_t *args) {
+ while(true) {
+ microbit_display_show(&microbit_display_obj, (microbit_image_obj_t*)&panic);
+ mp_hal_delay_ms(1000);
+ char num[4];
+ int code;
+ if (n_args) {
+ code = mp_obj_get_int(args[0]);
+ } else {
+ code = 0;
+ }
+ num[2] = code%10 + '0';
+ code /= 10;
+ num[1] = code%10 + '0';
+ code /= 10;
+ num[0] = code%10 + '0';
+ for (int i = 0; i < 3; i++) {
+ microbit_display_show(&microbit_display_obj, microbit_image_for_char(num[i]));
+ mp_hal_delay_ms(1000);
+ }
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_panic_obj, 0, 1, microbit_panic);
+
+STATIC mp_obj_t microbit_temperature(void) {
+ int temp;
+ NRF_TEMP->TASKS_START = 1;
+ while (NRF_TEMP->EVENTS_DATARDY == 0);
+ NRF_TEMP->EVENTS_DATARDY = 0;
+ temp = NRF_TEMP->TEMP;
+ NRF_TEMP->TASKS_STOP = 1;
+ return mp_obj_new_float(temp/4.0);
+}
+MP_DEFINE_CONST_FUN_OBJ_0(microbit_temperature_obj, microbit_temperature);
+
+STATIC const mp_map_elem_t microbit_module_globals_table[] = {
+ { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_microbit) },
+
+ { MP_OBJ_NEW_QSTR(MP_QSTR_Image), (mp_obj_t)&microbit_image_type },
+
+ { MP_OBJ_NEW_QSTR(MP_QSTR_display), (mp_obj_t)&microbit_display_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_button_a), (mp_obj_t)&microbit_button_a_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_button_b), (mp_obj_t)&microbit_button_b_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_accelerometer), (mp_obj_t)&microbit_accelerometer_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_compass), (mp_obj_t)&microbit_compass_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_i2c), (mp_obj_t)&microbit_i2c_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_uart), (mp_obj_t)&microbit_uart_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_spi), (mp_obj_t)&microbit_spi_obj },
+
+ { MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)&microbit_reset_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&microbit_sleep_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_running_time), (mp_obj_t)&microbit_running_time_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_panic), (mp_obj_t)&microbit_panic_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_temperature), (mp_obj_t)&microbit_temperature_obj },
+
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin0), (mp_obj_t)&microbit_p0_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin1), (mp_obj_t)&microbit_p1_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin2), (mp_obj_t)&microbit_p2_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin3), (mp_obj_t)&microbit_p3_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin4), (mp_obj_t)&microbit_p4_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin5), (mp_obj_t)&microbit_p5_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin6), (mp_obj_t)&microbit_p6_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin7), (mp_obj_t)&microbit_p7_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin8), (mp_obj_t)&microbit_p8_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin9), (mp_obj_t)&microbit_p9_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin10), (mp_obj_t)&microbit_p10_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin11), (mp_obj_t)&microbit_p11_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin12), (mp_obj_t)&microbit_p12_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin13), (mp_obj_t)&microbit_p13_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin14), (mp_obj_t)&microbit_p14_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin15), (mp_obj_t)&microbit_p15_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin16), (mp_obj_t)&microbit_p16_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin19), (mp_obj_t)&microbit_p19_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pin20), (mp_obj_t)&microbit_p20_obj },
+};
+
+STATIC MP_DEFINE_CONST_DICT(microbit_module_globals, microbit_module_globals_table);
+
+const mp_obj_module_t microbit_module = {
+ .base = { &mp_type_module },
+ .name = MP_QSTR_microbit,
+ .globals = (mp_obj_dict_t*)&microbit_module_globals,
+};
+
+}
diff --git a/ports/nrf/boards/microbit/modules/modmicrobit.h b/ports/nrf/boards/microbit/modules/modmicrobit.h
new file mode 100644
index 000000000..722bf1c1a
--- /dev/null
+++ b/ports/nrf/boards/microbit/modules/modmicrobit.h
@@ -0,0 +1,234 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef __MICROPY_INCLUDED_MICROBIT_MODMICROBIT_H__
+#define __MICROPY_INCLUDED_MICROBIT_MODMICROBIT_H__
+
+#include "py/objtuple.h"
+
+extern const mp_obj_type_t microbit_ad_pin_type;
+extern const mp_obj_type_t microbit_dig_pin_type;
+extern const mp_obj_type_t microbit_touch_pin_type;
+
+extern const struct _microbit_pin_obj_t microbit_p0_obj;
+extern const struct _microbit_pin_obj_t microbit_p1_obj;
+extern const struct _microbit_pin_obj_t microbit_p2_obj;
+extern const struct _microbit_pin_obj_t microbit_p3_obj;
+extern const struct _microbit_pin_obj_t microbit_p4_obj;
+extern const struct _microbit_pin_obj_t microbit_p5_obj;
+extern const struct _microbit_pin_obj_t microbit_p6_obj;
+extern const struct _microbit_pin_obj_t microbit_p7_obj;
+extern const struct _microbit_pin_obj_t microbit_p8_obj;
+extern const struct _microbit_pin_obj_t microbit_p9_obj;
+extern const struct _microbit_pin_obj_t microbit_p10_obj;
+extern const struct _microbit_pin_obj_t microbit_p11_obj;
+extern const struct _microbit_pin_obj_t microbit_p12_obj;
+extern const struct _microbit_pin_obj_t microbit_p13_obj;
+extern const struct _microbit_pin_obj_t microbit_p14_obj;
+extern const struct _microbit_pin_obj_t microbit_p15_obj;
+extern const struct _microbit_pin_obj_t microbit_p16_obj;
+extern const struct _microbit_pin_obj_t microbit_p19_obj;
+extern const struct _microbit_pin_obj_t microbit_p20_obj;
+
+extern const mp_obj_type_t microbit_const_image_type;
+extern const struct _monochrome_5by5_t microbit_const_image_heart_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_heart_small_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_happy_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_smile_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_sad_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_confused_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_angry_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_asleep_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_surprised_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_silly_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_fabulous_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_meh_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_yes_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_no_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_clock12_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_clock1_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_clock2_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_clock3_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_clock4_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_clock5_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_clock6_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_clock7_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_clock8_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_clock9_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_clock10_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_clock11_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_arrow_n_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_arrow_ne_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_arrow_e_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_arrow_se_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_arrow_s_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_arrow_sw_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_arrow_w_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_arrow_nw_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_triangle_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_triangle_left_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_chessboard_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_diamond_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_diamond_small_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_square_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_square_small_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_rabbit;
+extern const struct _monochrome_5by5_t microbit_const_image_cow;
+extern const struct _monochrome_5by5_t microbit_const_image_music_crotchet_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_music_quaver_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_music_quavers_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_pitchfork_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_xmas_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_pacman_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_target_obj;
+extern const struct _mp_obj_tuple_t microbit_const_image_all_clocks_tuple_obj;
+extern const struct _mp_obj_tuple_t microbit_const_image_all_arrows_tuple_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_tshirt_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_rollerskate_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_duck_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_house_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_tortoise_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_butterfly_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_stickfigure_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_ghost_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_sword_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_giraffe_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_skull_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_umbrella_obj;
+extern const struct _monochrome_5by5_t microbit_const_image_snake_obj;
+
+extern const struct _mp_obj_tuple_t microbit_music_tune_dadadadum_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_entertainer_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_prelude_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_ode_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_nyan_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_ringtone_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_funk_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_blues_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_birthday_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_wedding_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_funeral_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_punchline_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_python_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_baddy_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_chase_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_ba_ding_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_wawawawaa_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_jump_up_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_jump_down_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_power_up_obj;
+extern const struct _mp_obj_tuple_t microbit_music_tune_power_down_obj;
+
+extern const mp_obj_type_t microbit_image_type;
+
+extern const mp_obj_type_t microbit_accelerometer_type;
+extern const struct _microbit_accelerometer_obj_t microbit_accelerometer_obj;
+
+extern struct _microbit_display_obj_t microbit_display_obj;
+extern const struct _microbit_button_obj_t microbit_button_a_obj;
+extern const struct _microbit_button_obj_t microbit_button_b_obj;
+extern const struct _microbit_compass_obj_t microbit_compass_obj;
+extern const struct _microbit_i2c_obj_t microbit_i2c_obj;
+extern struct _microbit_uart_obj_t microbit_uart_obj;
+extern struct _microbit_spi_obj_t microbit_spi_obj;
+
+MP_DECLARE_CONST_FUN_OBJ(microbit_reset_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_sleep_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_random_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_running_time_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_temperature_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_panic_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_accelerometer_get_x_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_accelerometer_get_y_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_accelerometer_get_z_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_button_is_pressed_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_button_was_pressed_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_button_get_presses_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_compass_is_calibrated_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_compass_heading_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_compass_calibrate_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_compass_is_calibrating_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_compass_clear_calibration_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_compass_get_x_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_compass_get_y_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_compass_get_z_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_compass_get_field_strength_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_display_show_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_display_scroll_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_display_clear_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_display_get_pixel_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_display_set_pixel_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_display_on_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_display_off_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_display_is_on_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_pin_read_digital_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_pin_write_digital_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_pin_read_analog_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_pin_write_analog_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_pin_is_touched_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_pin_set_analog_period_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_pin_set_analog_period_microseconds_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_i2c_init_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_i2c_read_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_i2c_write_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_image_width_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_image_height_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_image_get_pixel_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_image_set_pixel_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_image_shift_left_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_image_shift_right_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_image_shift_up_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_image_shift_down_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_image_copy_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_image_crop_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_image_invert_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_image_slice_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_uart_init_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_uart_any_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_stream_read_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_stream_readall_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_stream_unbuffered_readline_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_stream_readinto_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_stream_write_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_spi_init_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_spi_write_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_spi_read_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_spi_write_readinto_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_music_set_tempo_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_music_pitch_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_music_play_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_music_get_tempo_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_music_stop_obj);
+MP_DECLARE_CONST_FUN_OBJ(microbit_music_reset_obj);
+MP_DECLARE_CONST_FUN_OBJ(love_badaboom_obj);
+MP_DECLARE_CONST_FUN_OBJ(this_authors_obj);
+
+extern const mp_obj_module_t microbit_module;
+extern const mp_obj_module_t music_module;
+extern const mp_obj_module_t love_module;
+extern const mp_obj_module_t antigravity_module;
+extern const mp_obj_module_t this_module;
+
+#endif // __MICROPY_INCLUDED_MICROBIT_MODMICROBIT_H__