From f3386cfc50cddf5cdae635d04b04124b6af35863 Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Wed, 11 Oct 2017 23:41:15 +0200 Subject: nrf/boards/microbit: Rename display/image files from .cpp to .c ext. Also rename modmicrobit.h to microbitconstimage.h. --- ports/nrf/boards/microbit/modules/MicroBitFont.cpp | 99 --- .../boards/microbit/modules/microbitconstimage.c | 562 ++++++++++++ .../boards/microbit/modules/microbitconstimage.cpp | 562 ------------ .../boards/microbit/modules/microbitconstimage.h | 234 +++++ .../nrf/boards/microbit/modules/microbitdisplay.c | 579 ++++++++++++ .../boards/microbit/modules/microbitdisplay.cpp | 579 ------------ ports/nrf/boards/microbit/modules/microbitfont.h | 99 +++ ports/nrf/boards/microbit/modules/microbitimage.c | 973 +++++++++++++++++++++ .../nrf/boards/microbit/modules/microbitimage.cpp | 973 --------------------- ports/nrf/boards/microbit/modules/modmicrobit.c | 158 ++++ ports/nrf/boards/microbit/modules/modmicrobit.cpp | 158 ---- ports/nrf/boards/microbit/modules/modmicrobit.h | 234 ----- 12 files changed, 2605 insertions(+), 2605 deletions(-) delete mode 100644 ports/nrf/boards/microbit/modules/MicroBitFont.cpp create mode 100644 ports/nrf/boards/microbit/modules/microbitconstimage.c delete mode 100644 ports/nrf/boards/microbit/modules/microbitconstimage.cpp create mode 100644 ports/nrf/boards/microbit/modules/microbitconstimage.h create mode 100644 ports/nrf/boards/microbit/modules/microbitdisplay.c delete mode 100644 ports/nrf/boards/microbit/modules/microbitdisplay.cpp create mode 100644 ports/nrf/boards/microbit/modules/microbitfont.h create mode 100644 ports/nrf/boards/microbit/modules/microbitimage.c delete mode 100644 ports/nrf/boards/microbit/modules/microbitimage.cpp create mode 100644 ports/nrf/boards/microbit/modules/modmicrobit.c delete mode 100644 ports/nrf/boards/microbit/modules/modmicrobit.cpp delete mode 100644 ports/nrf/boards/microbit/modules/modmicrobit.h diff --git a/ports/nrf/boards/microbit/modules/MicroBitFont.cpp b/ports/nrf/boards/microbit/modules/MicroBitFont.cpp deleted file mode 100644 index 040316bd1..000000000 --- a/ports/nrf/boards/microbit/modules/MicroBitFont.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2016 British Broadcasting Corporation. -This software is provided by Lancaster University by arrangement with the BBC. - -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. -*/ - -/** - * Class definition for a MicrobitFont - * This class represents a font that can be used by the display to render text. - * - * A MicroBitFont is 5x5. - * Each Row is represented by a byte in the array. - * - * Row Format: - * ================================================================ - * | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | - * ================================================================ - * | N/A | N/A | N/A | Col 1 | Col 2 | Col 3 | Col 4 | Col 5 | - * | 0x80 | 0x40 | 0x20 | 0x10 | 0x08 | 0x04 | 0x02 | 0x01 | - * - * Example: { 0x08, 0x08, 0x08, 0x0, 0x08 } - * - * The above will produce an exclaimation mark on the second column in form the left. - * - * We could compress further, but the complexity of decode would likely outweigh the gains. - */ - -#include "MicroBitConfig.h" -#include "MicroBitFont.h" - -const unsigned char pendolino3[475] = { -0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x0, 0x8, 0xa, 0x4a, 0x40, 0x0, 0x0, 0xa, 0x5f, 0xea, 0x5f, 0xea, 0xe, 0xd9, 0x2e, 0xd3, 0x6e, 0x19, 0x32, 0x44, 0x89, 0x33, 0xc, 0x92, 0x4c, 0x92, 0x4d, 0x8, 0x8, 0x0, 0x0, 0x0, 0x4, 0x88, 0x8, 0x8, 0x4, 0x8, 0x4, 0x84, 0x84, 0x88, 0x0, 0xa, 0x44, 0x8a, 0x40, 0x0, 0x4, 0x8e, 0xc4, 0x80, 0x0, 0x0, 0x0, 0x4, 0x88, 0x0, 0x0, 0xe, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x1, 0x22, 0x44, 0x88, 0x10, 0xc, 0x92, 0x52, 0x52, 0x4c, 0x4, 0x8c, 0x84, 0x84, 0x8e, 0x1c, 0x82, 0x4c, 0x90, 0x1e, 0x1e, 0xc2, 0x44, 0x92, 0x4c, 0x6, 0xca, 0x52, 0x5f, 0xe2, 0x1f, 0xf0, 0x1e, 0xc1, 0x3e, 0x2, 0x44, 0x8e, 0xd1, 0x2e, 0x1f, 0xe2, 0x44, 0x88, 0x10, 0xe, 0xd1, 0x2e, 0xd1, 0x2e, 0xe, 0xd1, 0x2e, 0xc4, 0x88, 0x0, 0x8, 0x0, 0x8, 0x0, 0x0, 0x4, 0x80, 0x4, 0x88, 0x2, 0x44, 0x88, 0x4, 0x82, 0x0, 0xe, 0xc0, 0xe, 0xc0, 0x8, 0x4, 0x82, 0x44, 0x88, 0xe, 0xd1, 0x26, 0xc0, 0x4, 0xe, 0xd1, 0x35, 0xb3, 0x6c, 0xc, 0x92, 0x5e, 0xd2, 0x52, 0x1c, 0x92, 0x5c, 0x92, 0x5c, 0xe, 0xd0, 0x10, 0x10, 0xe, 0x1c, 0x92, 0x52, 0x52, 0x5c, 0x1e, 0xd0, 0x1c, 0x90, 0x1e, 0x1e, 0xd0, 0x1c, 0x90, 0x10, 0xe, 0xd0, 0x13, 0x71, 0x2e, 0x12, 0x52, 0x5e, 0xd2, 0x52, 0x1c, 0x88, 0x8, 0x8, 0x1c, 0x1f, 0xe2, 0x42, 0x52, 0x4c, 0x12, 0x54, 0x98, 0x14, 0x92, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x11, 0x3b, 0x75, 0xb1, 0x31, 0x11, 0x39, 0x35, 0xb3, 0x71, 0xc, 0x92, 0x52, 0x52, 0x4c, 0x1c, 0x92, 0x5c, 0x90, 0x10, 0xc, 0x92, 0x52, 0x4c, 0x86, 0x1c, 0x92, 0x5c, 0x92, 0x51, 0xe, 0xd0, 0xc, 0x82, 0x5c, 0x1f, 0xe4, 0x84, 0x84, 0x84, 0x12, 0x52, 0x52, 0x52, 0x4c, 0x11, 0x31, 0x31, 0x2a, 0x44, 0x11, 0x31, 0x35, 0xbb, 0x71, 0x12, 0x52, 0x4c, 0x92, 0x52, 0x11, 0x2a, 0x44, 0x84, 0x84, 0x1e, 0xc4, 0x88, 0x10, 0x1e, 0xe, 0xc8, 0x8, 0x8, 0xe, 0x10, 0x8, 0x4, 0x82, 0x41, 0xe, 0xc2, 0x42, 0x42, 0x4e, 0x4, 0x8a, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x8, 0x4, 0x80, 0x0, 0x0, 0x0, 0xe, 0xd2, 0x52, 0x4f, 0x10, 0x10, 0x1c, 0x92, 0x5c, 0x0, 0xe, 0xd0, 0x10, 0xe, 0x2, 0x42, 0x4e, 0xd2, 0x4e, 0xc, 0x92, 0x5c, 0x90, 0xe, 0x6, 0xc8, 0x1c, 0x88, 0x8, 0xe, 0xd2, 0x4e, 0xc2, 0x4c, 0x10, 0x10, 0x1c, 0x92, 0x52, 0x8, 0x0, 0x8, 0x8, 0x8, 0x2, 0x40, 0x2, 0x42, 0x4c, 0x10, 0x14, 0x98, 0x14, 0x92, 0x8, 0x8, 0x8, 0x8, 0x6, 0x0, 0x1b, 0x75, 0xb1, 0x31, 0x0, 0x1c, 0x92, 0x52, 0x52, 0x0, 0xc, 0x92, 0x52, 0x4c, 0x0, 0x1c, 0x92, 0x5c, 0x90, 0x0, 0xe, 0xd2, 0x4e, 0xc2, 0x0, 0xe, 0xd0, 0x10, 0x10, 0x0, 0x6, 0xc8, 0x4, 0x98, 0x8, 0x8, 0xe, 0xc8, 0x7, 0x0, 0x12, 0x52, 0x52, 0x4f, 0x0, 0x11, 0x31, 0x2a, 0x44, 0x0, 0x11, 0x31, 0x35, 0xbb, 0x0, 0x12, 0x4c, 0x8c, 0x92, 0x0, 0x11, 0x2a, 0x44, 0x98, 0x0, 0x1e, 0xc4, 0x88, 0x1e, 0x6, 0xc4, 0x8c, 0x84, 0x86, 0x8, 0x8, 0x8, 0x8, 0x8, 0x18, 0x8, 0xc, 0x88, 0x18, 0x0, 0x0, 0xc, 0x83, 0x60}; - - -const unsigned char* MicroBitFont::defaultFont = pendolino3; -MicroBitFont MicroBitFont::systemFont = MicroBitFont(defaultFont, MICROBIT_FONT_ASCII_END); - -/** - * Constructor. - * - * Sets the font represented by this font object. - * - * @param font A pointer to the beginning of the new font. - * - * @param asciiEnd the char value at which this font finishes. - */ -MicroBitFont::MicroBitFont(const unsigned char* characters, int asciiEnd) -{ - this->characters = characters; - this->asciiEnd = asciiEnd; -} - -/** - * Default Constructor. - * - * Configures the default font for the display to use. - */ -MicroBitFont::MicroBitFont() -{ - this->characters = defaultFont; - this->asciiEnd = MICROBIT_FONT_ASCII_END; -} - -/** - * Modifies the current system font to the given instance of MicroBitFont. - * - * @param font the new font that will be used to render characters on the display. - */ -void MicroBitFont::setSystemFont(MicroBitFont font) -{ - MicroBitFont::systemFont = font; -} - -/** - * Retreives the font object used for rendering characters on the display. - */ -MicroBitFont MicroBitFont::getSystemFont() -{ - return MicroBitFont::systemFont; -} diff --git a/ports/nrf/boards/microbit/modules/microbitconstimage.c b/ports/nrf/boards/microbit/modules/microbitconstimage.c new file mode 100644 index 000000000..c6c38d0c3 --- /dev/null +++ b/ports/nrf/boards/microbit/modules/microbitconstimage.c @@ -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/microbitconstimage.cpp b/ports/nrf/boards/microbit/modules/microbitconstimage.cpp deleted file mode 100644 index c6c38d0c3..000000000 --- a/ports/nrf/boards/microbit/modules/microbitconstimage.cpp +++ /dev/null @@ -1,562 +0,0 @@ -/* - * 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/microbitconstimage.h b/ports/nrf/boards/microbit/modules/microbitconstimage.h new file mode 100644 index 000000000..722bf1c1a --- /dev/null +++ b/ports/nrf/boards/microbit/modules/microbitconstimage.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__ diff --git a/ports/nrf/boards/microbit/modules/microbitdisplay.c b/ports/nrf/boards/microbit/modules/microbitdisplay.c new file mode 100644 index 000000000..92bf58d82 --- /dev/null +++ b/ports/nrf/boards/microbit/modules/microbitdisplay.c @@ -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 +#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) == µbit_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 = µbit_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(µbit_display_obj, BLANK_IMAGE); + async_clear = false; + } else { + async_stop(); + } + } else if (mp_obj_get_type(obj) == µbit_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(µbit_display_obj, BLANK_IMAGE); + async_stop(); + break; + } +} + +#define GREYSCALE_MASK ((1<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(µbit_p3_obj); + microbit_obj_pin_free(µbit_p4_obj); + microbit_obj_pin_free(µbit_p6_obj); + microbit_obj_pin_free(µbit_p7_obj); + microbit_obj_pin_free(µbit_p9_obj); + microbit_obj_pin_free(µbit_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)µbit_display_get_pixel_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_pixel), (mp_obj_t)µbit_display_set_pixel_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_show), (mp_obj_t)µbit_display_show_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_scroll), (mp_obj_t)µbit_display_scroll_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_clear), (mp_obj_t)µbit_display_clear_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_on), (mp_obj_t)µbit_display_on_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_off), (mp_obj_t)µbit_display_off_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_is_on), (mp_obj_t)µbit_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*)µbit_display_locals_dict, +}; + +microbit_display_obj_t microbit_display_obj = { + {µbit_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.cpp b/ports/nrf/boards/microbit/modules/microbitdisplay.cpp deleted file mode 100644 index 92bf58d82..000000000 --- a/ports/nrf/boards/microbit/modules/microbitdisplay.cpp +++ /dev/null @@ -1,579 +0,0 @@ -/* - * 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 -#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) == µbit_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 = µbit_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(µbit_display_obj, BLANK_IMAGE); - async_clear = false; - } else { - async_stop(); - } - } else if (mp_obj_get_type(obj) == µbit_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(µbit_display_obj, BLANK_IMAGE); - async_stop(); - break; - } -} - -#define GREYSCALE_MASK ((1<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(µbit_p3_obj); - microbit_obj_pin_free(µbit_p4_obj); - microbit_obj_pin_free(µbit_p6_obj); - microbit_obj_pin_free(µbit_p7_obj); - microbit_obj_pin_free(µbit_p9_obj); - microbit_obj_pin_free(µbit_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)µbit_display_get_pixel_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_set_pixel), (mp_obj_t)µbit_display_set_pixel_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_show), (mp_obj_t)µbit_display_show_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_scroll), (mp_obj_t)µbit_display_scroll_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_clear), (mp_obj_t)µbit_display_clear_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_on), (mp_obj_t)µbit_display_on_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_off), (mp_obj_t)µbit_display_off_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_is_on), (mp_obj_t)µbit_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*)µbit_display_locals_dict, -}; - -microbit_display_obj_t microbit_display_obj = { - {µbit_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/microbitfont.h b/ports/nrf/boards/microbit/modules/microbitfont.h new file mode 100644 index 000000000..040316bd1 --- /dev/null +++ b/ports/nrf/boards/microbit/modules/microbitfont.h @@ -0,0 +1,99 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 British Broadcasting Corporation. +This software is provided by Lancaster University by arrangement with the BBC. + +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. +*/ + +/** + * Class definition for a MicrobitFont + * This class represents a font that can be used by the display to render text. + * + * A MicroBitFont is 5x5. + * Each Row is represented by a byte in the array. + * + * Row Format: + * ================================================================ + * | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | + * ================================================================ + * | N/A | N/A | N/A | Col 1 | Col 2 | Col 3 | Col 4 | Col 5 | + * | 0x80 | 0x40 | 0x20 | 0x10 | 0x08 | 0x04 | 0x02 | 0x01 | + * + * Example: { 0x08, 0x08, 0x08, 0x0, 0x08 } + * + * The above will produce an exclaimation mark on the second column in form the left. + * + * We could compress further, but the complexity of decode would likely outweigh the gains. + */ + +#include "MicroBitConfig.h" +#include "MicroBitFont.h" + +const unsigned char pendolino3[475] = { +0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x0, 0x8, 0xa, 0x4a, 0x40, 0x0, 0x0, 0xa, 0x5f, 0xea, 0x5f, 0xea, 0xe, 0xd9, 0x2e, 0xd3, 0x6e, 0x19, 0x32, 0x44, 0x89, 0x33, 0xc, 0x92, 0x4c, 0x92, 0x4d, 0x8, 0x8, 0x0, 0x0, 0x0, 0x4, 0x88, 0x8, 0x8, 0x4, 0x8, 0x4, 0x84, 0x84, 0x88, 0x0, 0xa, 0x44, 0x8a, 0x40, 0x0, 0x4, 0x8e, 0xc4, 0x80, 0x0, 0x0, 0x0, 0x4, 0x88, 0x0, 0x0, 0xe, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x1, 0x22, 0x44, 0x88, 0x10, 0xc, 0x92, 0x52, 0x52, 0x4c, 0x4, 0x8c, 0x84, 0x84, 0x8e, 0x1c, 0x82, 0x4c, 0x90, 0x1e, 0x1e, 0xc2, 0x44, 0x92, 0x4c, 0x6, 0xca, 0x52, 0x5f, 0xe2, 0x1f, 0xf0, 0x1e, 0xc1, 0x3e, 0x2, 0x44, 0x8e, 0xd1, 0x2e, 0x1f, 0xe2, 0x44, 0x88, 0x10, 0xe, 0xd1, 0x2e, 0xd1, 0x2e, 0xe, 0xd1, 0x2e, 0xc4, 0x88, 0x0, 0x8, 0x0, 0x8, 0x0, 0x0, 0x4, 0x80, 0x4, 0x88, 0x2, 0x44, 0x88, 0x4, 0x82, 0x0, 0xe, 0xc0, 0xe, 0xc0, 0x8, 0x4, 0x82, 0x44, 0x88, 0xe, 0xd1, 0x26, 0xc0, 0x4, 0xe, 0xd1, 0x35, 0xb3, 0x6c, 0xc, 0x92, 0x5e, 0xd2, 0x52, 0x1c, 0x92, 0x5c, 0x92, 0x5c, 0xe, 0xd0, 0x10, 0x10, 0xe, 0x1c, 0x92, 0x52, 0x52, 0x5c, 0x1e, 0xd0, 0x1c, 0x90, 0x1e, 0x1e, 0xd0, 0x1c, 0x90, 0x10, 0xe, 0xd0, 0x13, 0x71, 0x2e, 0x12, 0x52, 0x5e, 0xd2, 0x52, 0x1c, 0x88, 0x8, 0x8, 0x1c, 0x1f, 0xe2, 0x42, 0x52, 0x4c, 0x12, 0x54, 0x98, 0x14, 0x92, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x11, 0x3b, 0x75, 0xb1, 0x31, 0x11, 0x39, 0x35, 0xb3, 0x71, 0xc, 0x92, 0x52, 0x52, 0x4c, 0x1c, 0x92, 0x5c, 0x90, 0x10, 0xc, 0x92, 0x52, 0x4c, 0x86, 0x1c, 0x92, 0x5c, 0x92, 0x51, 0xe, 0xd0, 0xc, 0x82, 0x5c, 0x1f, 0xe4, 0x84, 0x84, 0x84, 0x12, 0x52, 0x52, 0x52, 0x4c, 0x11, 0x31, 0x31, 0x2a, 0x44, 0x11, 0x31, 0x35, 0xbb, 0x71, 0x12, 0x52, 0x4c, 0x92, 0x52, 0x11, 0x2a, 0x44, 0x84, 0x84, 0x1e, 0xc4, 0x88, 0x10, 0x1e, 0xe, 0xc8, 0x8, 0x8, 0xe, 0x10, 0x8, 0x4, 0x82, 0x41, 0xe, 0xc2, 0x42, 0x42, 0x4e, 0x4, 0x8a, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x8, 0x4, 0x80, 0x0, 0x0, 0x0, 0xe, 0xd2, 0x52, 0x4f, 0x10, 0x10, 0x1c, 0x92, 0x5c, 0x0, 0xe, 0xd0, 0x10, 0xe, 0x2, 0x42, 0x4e, 0xd2, 0x4e, 0xc, 0x92, 0x5c, 0x90, 0xe, 0x6, 0xc8, 0x1c, 0x88, 0x8, 0xe, 0xd2, 0x4e, 0xc2, 0x4c, 0x10, 0x10, 0x1c, 0x92, 0x52, 0x8, 0x0, 0x8, 0x8, 0x8, 0x2, 0x40, 0x2, 0x42, 0x4c, 0x10, 0x14, 0x98, 0x14, 0x92, 0x8, 0x8, 0x8, 0x8, 0x6, 0x0, 0x1b, 0x75, 0xb1, 0x31, 0x0, 0x1c, 0x92, 0x52, 0x52, 0x0, 0xc, 0x92, 0x52, 0x4c, 0x0, 0x1c, 0x92, 0x5c, 0x90, 0x0, 0xe, 0xd2, 0x4e, 0xc2, 0x0, 0xe, 0xd0, 0x10, 0x10, 0x0, 0x6, 0xc8, 0x4, 0x98, 0x8, 0x8, 0xe, 0xc8, 0x7, 0x0, 0x12, 0x52, 0x52, 0x4f, 0x0, 0x11, 0x31, 0x2a, 0x44, 0x0, 0x11, 0x31, 0x35, 0xbb, 0x0, 0x12, 0x4c, 0x8c, 0x92, 0x0, 0x11, 0x2a, 0x44, 0x98, 0x0, 0x1e, 0xc4, 0x88, 0x1e, 0x6, 0xc4, 0x8c, 0x84, 0x86, 0x8, 0x8, 0x8, 0x8, 0x8, 0x18, 0x8, 0xc, 0x88, 0x18, 0x0, 0x0, 0xc, 0x83, 0x60}; + + +const unsigned char* MicroBitFont::defaultFont = pendolino3; +MicroBitFont MicroBitFont::systemFont = MicroBitFont(defaultFont, MICROBIT_FONT_ASCII_END); + +/** + * Constructor. + * + * Sets the font represented by this font object. + * + * @param font A pointer to the beginning of the new font. + * + * @param asciiEnd the char value at which this font finishes. + */ +MicroBitFont::MicroBitFont(const unsigned char* characters, int asciiEnd) +{ + this->characters = characters; + this->asciiEnd = asciiEnd; +} + +/** + * Default Constructor. + * + * Configures the default font for the display to use. + */ +MicroBitFont::MicroBitFont() +{ + this->characters = defaultFont; + this->asciiEnd = MICROBIT_FONT_ASCII_END; +} + +/** + * Modifies the current system font to the given instance of MicroBitFont. + * + * @param font the new font that will be used to render characters on the display. + */ +void MicroBitFont::setSystemFont(MicroBitFont font) +{ + MicroBitFont::systemFont = font; +} + +/** + * Retreives the font object used for rendering characters on the display. + */ +MicroBitFont MicroBitFont::getSystemFont() +{ + return MicroBitFont::systemFont; +} diff --git a/ports/nrf/boards/microbit/modules/microbitimage.c b/ports/nrf/boards/microbit/modules/microbitimage.c new file mode 100644 index 000000000..60f5526dc --- /dev/null +++ b/ports/nrf/boards/microbit/modules/microbitimage.c @@ -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 +#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 = { + { µbit_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 = µbit_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) != µbit_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)µbit_image_width_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_height), (mp_obj_t)µbit_image_height_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_get_pixel), (mp_obj_t)µbit_image_get_pixel_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_pixel), (mp_obj_t)µbit_image_set_pixel_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_shift_left), (mp_obj_t)µbit_image_shift_left_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_shift_right), (mp_obj_t)µbit_image_shift_right_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_shift_up), (mp_obj_t)µbit_image_shift_up_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_shift_down), (mp_obj_t)µbit_image_shift_down_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_copy), (mp_obj_t)µbit_image_copy_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_crop), (mp_obj_t)µbit_image_crop_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_invert), (mp_obj_t)µbit_image_invert_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_fill), (mp_obj_t)µbit_image_fill_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_blit), (mp_obj_t)µbit_image_blit_obj }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_HEART), (mp_obj_t)µbit_const_image_heart_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_HEART_SMALL), (mp_obj_t)µbit_const_image_heart_small_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_HAPPY), (mp_obj_t)µbit_const_image_happy_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SMILE), (mp_obj_t)µbit_const_image_smile_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SAD), (mp_obj_t)µbit_const_image_sad_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CONFUSED), (mp_obj_t)µbit_const_image_confused_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ANGRY), (mp_obj_t)µbit_const_image_angry_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ASLEEP), (mp_obj_t)µbit_const_image_asleep_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SURPRISED), (mp_obj_t)µbit_const_image_surprised_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SILLY), (mp_obj_t)µbit_const_image_silly_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_FABULOUS), (mp_obj_t)µbit_const_image_fabulous_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MEH), (mp_obj_t)µbit_const_image_meh_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_YES), (mp_obj_t)µbit_const_image_yes_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_NO), (mp_obj_t)µbit_const_image_no_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK12), (mp_obj_t)µbit_const_image_clock12_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK1), (mp_obj_t)µbit_const_image_clock1_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK2), (mp_obj_t)µbit_const_image_clock2_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK3), (mp_obj_t)µbit_const_image_clock3_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK4), (mp_obj_t)µbit_const_image_clock4_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK5), (mp_obj_t)µbit_const_image_clock5_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK6), (mp_obj_t)µbit_const_image_clock6_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK7), (mp_obj_t)µbit_const_image_clock7_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK8), (mp_obj_t)µbit_const_image_clock8_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK9), (mp_obj_t)µbit_const_image_clock9_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK10), (mp_obj_t)µbit_const_image_clock10_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK11), (mp_obj_t)µbit_const_image_clock11_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_N), (mp_obj_t)µbit_const_image_arrow_n_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_NE), (mp_obj_t)µbit_const_image_arrow_ne_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_E), (mp_obj_t)µbit_const_image_arrow_e_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_SE), (mp_obj_t)µbit_const_image_arrow_se_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_S), (mp_obj_t)µbit_const_image_arrow_s_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_SW), (mp_obj_t)µbit_const_image_arrow_sw_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_W), (mp_obj_t)µbit_const_image_arrow_w_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_NW), (mp_obj_t)µbit_const_image_arrow_nw_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TRIANGLE), (mp_obj_t)µbit_const_image_triangle_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TRIANGLE_LEFT), (mp_obj_t)µbit_const_image_triangle_left_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CHESSBOARD), (mp_obj_t)µbit_const_image_chessboard_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_DIAMOND), (mp_obj_t)µbit_const_image_diamond_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_DIAMOND_SMALL), (mp_obj_t)µbit_const_image_diamond_small_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SQUARE), (mp_obj_t)µbit_const_image_square_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SQUARE_SMALL), (mp_obj_t)µbit_const_image_square_small_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_RABBIT), (mp_obj_t)µbit_const_image_rabbit }, + { MP_OBJ_NEW_QSTR(MP_QSTR_COW), (mp_obj_t)µbit_const_image_cow }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MUSIC_CROTCHET), (mp_obj_t)µbit_const_image_music_crotchet_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MUSIC_QUAVER), (mp_obj_t)µbit_const_image_music_quaver_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MUSIC_QUAVERS), (mp_obj_t)µbit_const_image_music_quavers_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_PITCHFORK), (mp_obj_t)µbit_const_image_pitchfork_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_XMAS), (mp_obj_t)µbit_const_image_xmas_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_PACMAN), (mp_obj_t)µbit_const_image_pacman_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TARGET), (mp_obj_t)µbit_const_image_target_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ALL_CLOCKS), (mp_obj_t)µbit_const_image_all_clocks_tuple_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ALL_ARROWS), (mp_obj_t)µbit_const_image_all_arrows_tuple_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TSHIRT), (mp_obj_t)µbit_const_image_tshirt_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ROLLERSKATE), (mp_obj_t)µbit_const_image_rollerskate_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_DUCK), (mp_obj_t)µbit_const_image_duck_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_HOUSE), (mp_obj_t)µbit_const_image_house_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TORTOISE), (mp_obj_t)µbit_const_image_tortoise_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_BUTTERFLY), (mp_obj_t)µbit_const_image_butterfly_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_STICKFIGURE), (mp_obj_t)µbit_const_image_stickfigure_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GHOST), (mp_obj_t)µbit_const_image_ghost_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SWORD), (mp_obj_t)µbit_const_image_sword_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GIRAFFE), (mp_obj_t)µbit_const_image_giraffe_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SKULL), (mp_obj_t)µbit_const_image_skull_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_UMBRELLA), (mp_obj_t)µbit_const_image_umbrella_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SNAKE), (mp_obj_t)µbit_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) != µbit_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) != µbit_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*)µbit_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 = µbit_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 = µbit_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 = µbit_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.cpp b/ports/nrf/boards/microbit/modules/microbitimage.cpp deleted file mode 100644 index 60f5526dc..000000000 --- a/ports/nrf/boards/microbit/modules/microbitimage.cpp +++ /dev/null @@ -1,973 +0,0 @@ -/* - * 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 -#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 = { - { µbit_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 = µbit_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) != µbit_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)µbit_image_width_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_height), (mp_obj_t)µbit_image_height_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_get_pixel), (mp_obj_t)µbit_image_get_pixel_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_set_pixel), (mp_obj_t)µbit_image_set_pixel_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_shift_left), (mp_obj_t)µbit_image_shift_left_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_shift_right), (mp_obj_t)µbit_image_shift_right_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_shift_up), (mp_obj_t)µbit_image_shift_up_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_shift_down), (mp_obj_t)µbit_image_shift_down_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_copy), (mp_obj_t)µbit_image_copy_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_crop), (mp_obj_t)µbit_image_crop_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_invert), (mp_obj_t)µbit_image_invert_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_fill), (mp_obj_t)µbit_image_fill_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_blit), (mp_obj_t)µbit_image_blit_obj }, - - { MP_OBJ_NEW_QSTR(MP_QSTR_HEART), (mp_obj_t)µbit_const_image_heart_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_HEART_SMALL), (mp_obj_t)µbit_const_image_heart_small_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_HAPPY), (mp_obj_t)µbit_const_image_happy_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SMILE), (mp_obj_t)µbit_const_image_smile_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SAD), (mp_obj_t)µbit_const_image_sad_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CONFUSED), (mp_obj_t)µbit_const_image_confused_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ANGRY), (mp_obj_t)µbit_const_image_angry_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ASLEEP), (mp_obj_t)µbit_const_image_asleep_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SURPRISED), (mp_obj_t)µbit_const_image_surprised_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SILLY), (mp_obj_t)µbit_const_image_silly_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_FABULOUS), (mp_obj_t)µbit_const_image_fabulous_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_MEH), (mp_obj_t)µbit_const_image_meh_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_YES), (mp_obj_t)µbit_const_image_yes_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_NO), (mp_obj_t)µbit_const_image_no_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK12), (mp_obj_t)µbit_const_image_clock12_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK1), (mp_obj_t)µbit_const_image_clock1_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK2), (mp_obj_t)µbit_const_image_clock2_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK3), (mp_obj_t)µbit_const_image_clock3_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK4), (mp_obj_t)µbit_const_image_clock4_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK5), (mp_obj_t)µbit_const_image_clock5_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK6), (mp_obj_t)µbit_const_image_clock6_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK7), (mp_obj_t)µbit_const_image_clock7_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK8), (mp_obj_t)µbit_const_image_clock8_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK9), (mp_obj_t)µbit_const_image_clock9_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK10), (mp_obj_t)µbit_const_image_clock10_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK11), (mp_obj_t)µbit_const_image_clock11_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_N), (mp_obj_t)µbit_const_image_arrow_n_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_NE), (mp_obj_t)µbit_const_image_arrow_ne_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_E), (mp_obj_t)µbit_const_image_arrow_e_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_SE), (mp_obj_t)µbit_const_image_arrow_se_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_S), (mp_obj_t)µbit_const_image_arrow_s_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_SW), (mp_obj_t)µbit_const_image_arrow_sw_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_W), (mp_obj_t)µbit_const_image_arrow_w_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_NW), (mp_obj_t)µbit_const_image_arrow_nw_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_TRIANGLE), (mp_obj_t)µbit_const_image_triangle_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_TRIANGLE_LEFT), (mp_obj_t)µbit_const_image_triangle_left_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CHESSBOARD), (mp_obj_t)µbit_const_image_chessboard_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_DIAMOND), (mp_obj_t)µbit_const_image_diamond_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_DIAMOND_SMALL), (mp_obj_t)µbit_const_image_diamond_small_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SQUARE), (mp_obj_t)µbit_const_image_square_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SQUARE_SMALL), (mp_obj_t)µbit_const_image_square_small_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_RABBIT), (mp_obj_t)µbit_const_image_rabbit }, - { MP_OBJ_NEW_QSTR(MP_QSTR_COW), (mp_obj_t)µbit_const_image_cow }, - { MP_OBJ_NEW_QSTR(MP_QSTR_MUSIC_CROTCHET), (mp_obj_t)µbit_const_image_music_crotchet_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_MUSIC_QUAVER), (mp_obj_t)µbit_const_image_music_quaver_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_MUSIC_QUAVERS), (mp_obj_t)µbit_const_image_music_quavers_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_PITCHFORK), (mp_obj_t)µbit_const_image_pitchfork_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_XMAS), (mp_obj_t)µbit_const_image_xmas_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_PACMAN), (mp_obj_t)µbit_const_image_pacman_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_TARGET), (mp_obj_t)µbit_const_image_target_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ALL_CLOCKS), (mp_obj_t)µbit_const_image_all_clocks_tuple_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ALL_ARROWS), (mp_obj_t)µbit_const_image_all_arrows_tuple_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_TSHIRT), (mp_obj_t)µbit_const_image_tshirt_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ROLLERSKATE), (mp_obj_t)µbit_const_image_rollerskate_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_DUCK), (mp_obj_t)µbit_const_image_duck_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_HOUSE), (mp_obj_t)µbit_const_image_house_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_TORTOISE), (mp_obj_t)µbit_const_image_tortoise_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_BUTTERFLY), (mp_obj_t)µbit_const_image_butterfly_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_STICKFIGURE), (mp_obj_t)µbit_const_image_stickfigure_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_GHOST), (mp_obj_t)µbit_const_image_ghost_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SWORD), (mp_obj_t)µbit_const_image_sword_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_GIRAFFE), (mp_obj_t)µbit_const_image_giraffe_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SKULL), (mp_obj_t)µbit_const_image_skull_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_UMBRELLA), (mp_obj_t)µbit_const_image_umbrella_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SNAKE), (mp_obj_t)µbit_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) != µbit_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) != µbit_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*)µbit_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 = µbit_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 = µbit_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 = µbit_facade_iterator_type; - result->string = iterable->string; - result->image = iterable->image; - result->index = 0; - return result; -} - -} diff --git a/ports/nrf/boards/microbit/modules/modmicrobit.c b/ports/nrf/boards/microbit/modules/modmicrobit.c new file mode 100644 index 000000000..7201790cf --- /dev/null +++ b/ports/nrf/boards/microbit/modules/modmicrobit.c @@ -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(µbit_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(µbit_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)µbit_image_type }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_display), (mp_obj_t)µbit_display_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_button_a), (mp_obj_t)µbit_button_a_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_button_b), (mp_obj_t)µbit_button_b_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_accelerometer), (mp_obj_t)µbit_accelerometer_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_compass), (mp_obj_t)µbit_compass_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_i2c), (mp_obj_t)µbit_i2c_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_uart), (mp_obj_t)µbit_uart_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_spi), (mp_obj_t)µbit_spi_obj }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)µbit_reset_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)µbit_sleep_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_running_time), (mp_obj_t)µbit_running_time_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_panic), (mp_obj_t)µbit_panic_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_temperature), (mp_obj_t)µbit_temperature_obj }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_pin0), (mp_obj_t)µbit_p0_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin1), (mp_obj_t)µbit_p1_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin2), (mp_obj_t)µbit_p2_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin3), (mp_obj_t)µbit_p3_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin4), (mp_obj_t)µbit_p4_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin5), (mp_obj_t)µbit_p5_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin6), (mp_obj_t)µbit_p6_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin7), (mp_obj_t)µbit_p7_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin8), (mp_obj_t)µbit_p8_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin9), (mp_obj_t)µbit_p9_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin10), (mp_obj_t)µbit_p10_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin11), (mp_obj_t)µbit_p11_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin12), (mp_obj_t)µbit_p12_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin13), (mp_obj_t)µbit_p13_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin14), (mp_obj_t)µbit_p14_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin15), (mp_obj_t)µbit_p15_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin16), (mp_obj_t)µbit_p16_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin19), (mp_obj_t)µbit_p19_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin20), (mp_obj_t)µbit_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*)µbit_module_globals, +}; + +} diff --git a/ports/nrf/boards/microbit/modules/modmicrobit.cpp b/ports/nrf/boards/microbit/modules/modmicrobit.cpp deleted file mode 100644 index 7201790cf..000000000 --- a/ports/nrf/boards/microbit/modules/modmicrobit.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* - * 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(µbit_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(µbit_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)µbit_image_type }, - - { MP_OBJ_NEW_QSTR(MP_QSTR_display), (mp_obj_t)µbit_display_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_button_a), (mp_obj_t)µbit_button_a_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_button_b), (mp_obj_t)µbit_button_b_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_accelerometer), (mp_obj_t)µbit_accelerometer_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_compass), (mp_obj_t)µbit_compass_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_i2c), (mp_obj_t)µbit_i2c_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_uart), (mp_obj_t)µbit_uart_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_spi), (mp_obj_t)µbit_spi_obj }, - - { MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)µbit_reset_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)µbit_sleep_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_running_time), (mp_obj_t)µbit_running_time_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_panic), (mp_obj_t)µbit_panic_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_temperature), (mp_obj_t)µbit_temperature_obj }, - - { MP_OBJ_NEW_QSTR(MP_QSTR_pin0), (mp_obj_t)µbit_p0_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_pin1), (mp_obj_t)µbit_p1_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_pin2), (mp_obj_t)µbit_p2_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_pin3), (mp_obj_t)µbit_p3_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_pin4), (mp_obj_t)µbit_p4_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_pin5), (mp_obj_t)µbit_p5_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_pin6), (mp_obj_t)µbit_p6_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_pin7), (mp_obj_t)µbit_p7_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_pin8), (mp_obj_t)µbit_p8_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_pin9), (mp_obj_t)µbit_p9_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_pin10), (mp_obj_t)µbit_p10_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_pin11), (mp_obj_t)µbit_p11_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_pin12), (mp_obj_t)µbit_p12_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_pin13), (mp_obj_t)µbit_p13_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_pin14), (mp_obj_t)µbit_p14_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_pin15), (mp_obj_t)µbit_p15_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_pin16), (mp_obj_t)µbit_p16_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_pin19), (mp_obj_t)µbit_p19_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_pin20), (mp_obj_t)µbit_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*)µbit_module_globals, -}; - -} diff --git a/ports/nrf/boards/microbit/modules/modmicrobit.h b/ports/nrf/boards/microbit/modules/modmicrobit.h deleted file mode 100644 index 722bf1c1a..000000000 --- a/ports/nrf/boards/microbit/modules/modmicrobit.h +++ /dev/null @@ -1,234 +0,0 @@ -/* - * 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__ -- cgit v1.2.3