diff --git a/libraries/pico_unicorn/pico_unicorn.cpp b/libraries/pico_unicorn/pico_unicorn.cpp index ac078d60..efe04cf5 100644 --- a/libraries/pico_unicorn/pico_unicorn.cpp +++ b/libraries/pico_unicorn/pico_unicorn.cpp @@ -143,7 +143,7 @@ namespace pimoroni { } // initialise the bcd timing values and row selects in the bitstream - for(uint8_t row = 0; row < 7; row++) { + for(uint8_t row = 0; row < HEIGHT; row++) { for(uint8_t frame = 0; frame < BCD_FRAMES; frame++) { // determine offset in the buffer for this row/frame uint16_t offset = (row * ROW_BYTES * BCD_FRAMES) + (ROW_BYTES * frame); @@ -198,18 +198,18 @@ namespace pimoroni { } void PicoUnicorn::clear() { - for(uint8_t y = 0; y < 7; y++) { - for(uint8_t x = 0; x < 16; x++) { + for(uint8_t y = 0; y < HEIGHT; y++) { + for(uint8_t x = 0; x < WIDTH; x++) { set_pixel(x, y, 0); } } } void PicoUnicorn::set_pixel(uint8_t x, uint8_t y, uint8_t r, uint8_t g, uint8_t b) { - if(x < 0 || x > 15 || y < 0 || y > 6) return; + if(x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT) return; // make those coordinates sane - x = 15 - x; + x = (WIDTH - 1) - x; // work out the byte offset of this pixel uint8_t byte_offset = x / 2; diff --git a/libraries/pico_unicorn/pico_unicorn.hpp b/libraries/pico_unicorn/pico_unicorn.hpp index 49f5b089..eac5b880 100644 --- a/libraries/pico_unicorn/pico_unicorn.hpp +++ b/libraries/pico_unicorn/pico_unicorn.hpp @@ -5,7 +5,15 @@ namespace pimoroni { class PicoUnicorn { - uint32_t __fb[16 * 7]; + public: + static const int WIDTH = 16; + static const int HEIGHT = 7; + static const uint8_t A = 12; + static const uint8_t B = 13; + static const uint8_t X = 14; + static const uint8_t Y = 15; + private: + uint32_t __fb[WIDTH * HEIGHT]; PIO bitstream_pio = pio0; uint bitstream_sm = 0; @@ -17,11 +25,6 @@ namespace pimoroni { void set_pixel(uint8_t x, uint8_t y, uint8_t v); bool is_pressed(uint8_t button); - - static const uint8_t A = 12; - static const uint8_t B = 13; - static const uint8_t X = 14; - static const uint8_t Y = 15; }; } \ No newline at end of file diff --git a/micropython/modules/pico_unicorn/micropython.mk b/micropython/modules/pico_unicorn/micropython.mk new file mode 100755 index 00000000..9ebaf20e --- /dev/null +++ b/micropython/modules/pico_unicorn/micropython.mk @@ -0,0 +1,12 @@ +PICOUNICORN_MOD_DIR := $(USERMOD_DIR) + +# Add our source files to the respective variables. +SRC_USERMOD += $(PICOUNICORN_MOD_DIR)/pico_unicorn.c +SRC_USERMOD_CXX += $(PICOUNICORN_MOD_DIR)/pico_unicorn.cpp + +# Add our module directory to the include path. +CFLAGS_USERMOD += -I$(PICOUNICORN_MOD_DIR) +CXXFLAGS_USERMOD += -I$(PICOUNICORN_MOD_DIR) + +# We use C++ features so have to link against the standard library. +LDFLAGS_USERMOD += -lstdc++ \ No newline at end of file diff --git a/micropython/modules/pico_unicorn/pico_unicorn.c b/micropython/modules/pico_unicorn/pico_unicorn.c new file mode 100755 index 00000000..b3cad262 --- /dev/null +++ b/micropython/modules/pico_unicorn/pico_unicorn.c @@ -0,0 +1,55 @@ +#include "pico_unicorn.h" + +/***** Constants *****/ + +enum buttons +{ + BUTTON_A = 0, + BUTTON_B, + BUTTON_X, + BUTTON_Y, +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// picounicorn Module +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/***** Module Functions *****/ +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picounicorn_init_obj, picounicorn_init); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picounicorn_get_width_obj, picounicorn_get_width); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picounicorn_get_height_obj, picounicorn_get_height); +//STATIC MP_DEFINE_CONST_FUN_OBJ_0(picounicorn_update_obj, picounicorn_update); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picounicorn_set_pixel_obj, 5, 5, picounicorn_set_pixel); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(picounicorn_set_pixel_value_obj, picounicorn_set_pixel_value); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picounicorn_clear_obj, picounicorn_init); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picounicorn_is_pressed_obj, picounicorn_is_pressed); + +/***** Globals Table *****/ +STATIC const mp_rom_map_elem_t picounicorn_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picounicorn) }, + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&picounicorn_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&picounicorn_get_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&picounicorn_get_height_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&picounicorn_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_pixel), MP_ROM_PTR(&picounicorn_set_pixel_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_pixel_value), MP_ROM_PTR(&picounicorn_set_pixel_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&picounicorn_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_pressed), MP_ROM_PTR(&picounicorn_is_pressed_obj) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_INT(BUTTON_A) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_INT(BUTTON_B) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_X), MP_ROM_INT(BUTTON_X) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_Y), MP_ROM_INT(BUTTON_Y) }, +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_picounicorn_globals, picounicorn_globals_table); + +/***** Module Definition *****/ +const mp_obj_module_t picounicorn_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&mp_module_picounicorn_globals, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +MP_REGISTER_MODULE(MP_QSTR_picounicorn, picounicorn_user_cmodule, MODULE_PICOUNICORN_ENABLED); +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/pico_unicorn/pico_unicorn.cpp b/micropython/modules/pico_unicorn/pico_unicorn.cpp new file mode 100644 index 00000000..e87b3ffd --- /dev/null +++ b/micropython/modules/pico_unicorn/pico_unicorn.cpp @@ -0,0 +1,111 @@ +#include "hardware/spi.h" +#include "hardware/sync.h" +#include "pico/binary_info.h" + +#include "../../../pimoroni-pico/libraries/pico_unicorn/pico_unicorn.hpp" + +using namespace pimoroni; + +PicoUnicorn unicorn; + + +extern "C" { +#include "pico_unicorn.h" + +mp_obj_t picounicorn_init() { + unicorn.init(); + return mp_const_none; +} + +mp_obj_t picounicorn_get_width() { + return mp_obj_new_int(PicoUnicorn::WIDTH); +} + +mp_obj_t picounicorn_get_height() { + return mp_obj_new_int(PicoUnicorn::HEIGHT); +} + +// mp_obj_t picounicorn_update() { +// unicorn.update(); +// return mp_const_none; +// } + +mp_obj_t picounicorn_set_pixel(mp_uint_t n_args, const mp_obj_t *args) { + (void)n_args; //Unused input parameter, we know it's 5 + + int x = mp_obj_get_int(args[0]); + int y = mp_obj_get_int(args[1]); + int r = mp_obj_get_int(args[2]); + int g = mp_obj_get_int(args[3]); + int b = mp_obj_get_int(args[4]); + + if(x < 0 || x >= PicoUnicorn::WIDTH || y < 0 || y >= PicoUnicorn::HEIGHT) + mp_raise_ValueError("x or y out of range."); + else + { + if(r < 0 || r > 255) + mp_raise_ValueError("r out of range. Expected 0 to 255"); + else if(g < 0 || g > 255) + mp_raise_ValueError("g out of range. Expected 0 to 255"); + else if(b < 0 || b > 255) + mp_raise_ValueError("b out of range. Expected 0 to 255"); + else + unicorn.set_pixel(x, y, r, g, b); + } + + return mp_const_none; +} + +mp_obj_t picounicorn_set_pixel_value(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t v_obj) { + int x = mp_obj_get_int(x_obj); + int y = mp_obj_get_int(y_obj); + int val = mp_obj_get_int(v_obj); + + if(x < 0 || x >= PicoUnicorn::WIDTH || y < 0 || y >= PicoUnicorn::HEIGHT) + mp_raise_ValueError("x or y out of range."); + else + { + if(val < 0 || val > 255) + mp_raise_ValueError("val out of range. Expected 0 to 255"); + else + unicorn.set_pixel(x, y, val); + } + + return mp_const_none; +} + +mp_obj_t picounicorn_clear() { + unicorn.clear(); + return mp_const_none; +} + +mp_obj_t picounicorn_is_pressed(mp_obj_t button_obj) { + int buttonID = mp_obj_get_int(button_obj); + + bool buttonPressed = false; + switch(buttonID) + { + case 0: + buttonPressed = unicorn.is_pressed(PicoUnicorn::A); + break; + + case 1: + buttonPressed = unicorn.is_pressed(PicoUnicorn::B); + break; + + case 2: + buttonPressed = unicorn.is_pressed(PicoUnicorn::X); + break; + + case 3: + buttonPressed = unicorn.is_pressed(PicoUnicorn::Y); + break; + + default: + mp_raise_ValueError("button not valid. Expected 0 to 3"); + break; + } + + return buttonPressed ? mp_const_true : mp_const_false; +} +} \ No newline at end of file diff --git a/micropython/modules/pico_unicorn/pico_unicorn.h b/micropython/modules/pico_unicorn/pico_unicorn.h new file mode 100644 index 00000000..cf3d43cc --- /dev/null +++ b/micropython/modules/pico_unicorn/pico_unicorn.h @@ -0,0 +1,13 @@ +// Include MicroPython API. +//#include "py/obj.h" +#include "py/runtime.h" + +// Declare the functions we'll make available in Python +extern mp_obj_t picounicorn_init(); +extern mp_obj_t picounicorn_get_width(); +extern mp_obj_t picounicorn_get_height(); +//extern mp_obj_t picounicorn_update(); +extern mp_obj_t picounicorn_set_pixel(mp_uint_t n_args, const mp_obj_t *args); +extern mp_obj_t picounicorn_set_pixel_value(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t v_obj); +extern mp_obj_t picounicorn_clear(); +extern mp_obj_t picounicorn_is_pressed(mp_obj_t button_obj); \ No newline at end of file