#include #include "hardware/spi.h" #include "hardware/sync.h" #include "pico/binary_info.h" #include "pico/stdlib.h" #include "micropython/modules/util.hpp" #include "libraries/pico_scroll/pico_scroll.hpp" #include "libraries/pico_scroll/pico_scroll_font.hpp" using namespace pimoroni; PicoScroll *scroll = nullptr; extern "C" { #include "pico_scroll.h" #include "micropython/modules/pimoroni_i2c/pimoroni_i2c.h" #include "py/builtin.h" #define BUFFER_TOO_SMALL_MSG "bytearray too small: len(image) < width * height." #define INCORRECT_SIZE_MSG "Scroll height wrong: > 8 pixels." typedef struct _PicoScroll_obj_t { mp_obj_base_t base; PicoScroll* scroll; } PicoScroll_obj_t; // from picographics/picographics.cpp // used to support accepting a PicoGraphics class typedef struct _ModPicoGraphics_obj_t { mp_obj_base_t base; PicoGraphics *graphics; DisplayDriver *display; void *spritedata; void *buffer; _PimoroniI2C_obj_t *i2c; } ModPicoGraphics_obj_t; mp_obj_t picoscroll_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { _PicoScroll_obj_t *self = nullptr; self = m_new_obj_with_finaliser(PicoScroll_obj_t); self->base.type = &PicoScroll_type; self->scroll = m_new_class(PicoScroll); self->scroll->init(); return MP_OBJ_FROM_PTR(self); } mp_obj_t picoscroll___del__(mp_obj_t self_in) { PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t); m_del_class(PicoScroll, self->scroll); return mp_const_none; } mp_obj_t picoscroll_get_width(mp_obj_t self_in) { (void)self_in; return mp_obj_new_int(PicoScroll::WIDTH); } mp_obj_t picoscroll_get_height(mp_obj_t self_in) { (void)self_in; return mp_obj_new_int(PicoScroll::HEIGHT); } mp_obj_t picoscroll_show(mp_obj_t self_in) { PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t); self->scroll->update(); return mp_const_none; } mp_obj_t picoscroll_set_pixel(mp_uint_t n_args, const mp_obj_t *args) { (void)n_args; //Unused input parameter, we know it's self + 3 PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(args[0], PicoScroll_obj_t); int x = mp_obj_get_int(args[1]); int y = mp_obj_get_int(args[2]); int val = mp_obj_get_int(args[3]); if (x < 0 || x >= PicoScroll::WIDTH || y < 0 || y >= PicoScroll::HEIGHT) mp_raise_ValueError("x or y out of range."); if (val < 0 || val > 255) mp_raise_ValueError("val out of range. Expected 0 to 255"); self->scroll->set_pixel(x, y, val); return mp_const_none; } mp_obj_t picoscroll_scroll_text(mp_uint_t n_args, const mp_obj_t *args) { (void)n_args; //Unused input parameter, we know it's self + 3 PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(args[0], PicoScroll_obj_t); int brightness = mp_obj_get_int(args[2]); int delay_ms = mp_obj_get_int(args[3]); if(mp_obj_is_str_or_bytes(args[1])) { GET_STR_DATA_LEN(args[1], str, str_len); int draw_buffer_len = 6 * str_len; char *draw_buffer = m_new(char, draw_buffer_len); render_text((const char *)str, str_len, (unsigned char *)draw_buffer, draw_buffer_len); for (int offset = -PicoScroll::WIDTH; offset < draw_buffer_len; offset++) { self->scroll->clear(); self->scroll->set_bitmap_1d((const char *)draw_buffer, draw_buffer_len, brightness, offset); self->scroll->update(); MICROPY_EVENT_POLL_HOOK sleep_ms(delay_ms); } m_free(draw_buffer); self->scroll->clear(); self->scroll->update(); } return mp_const_none; } mp_obj_t picoscroll_show_text(mp_uint_t n_args, const mp_obj_t *args) { (void)n_args; //Unused input parameter, we know it's self + 3 PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(args[0], PicoScroll_obj_t); int brightness = mp_obj_get_int(args[2]); int offset = mp_obj_get_int(args[3]); if(mp_obj_is_str_or_bytes(args[1])) { GET_STR_DATA_LEN(args[1], str, str_len); int draw_buffer_len = 6 * str_len; char *draw_buffer = m_new(char, draw_buffer_len); render_text((const char *)str, str_len, (unsigned char *)draw_buffer, draw_buffer_len); self->scroll->set_bitmap_1d((const char *)draw_buffer, draw_buffer_len, brightness, offset); m_free(draw_buffer); } return mp_const_none; } mp_obj_t picoscroll_set_pixels(mp_obj_t self_in, mp_obj_t image_obj) { PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t); mp_buffer_info_t bufinfo; mp_get_buffer_raise(image_obj, &bufinfo, MP_BUFFER_RW); if (bufinfo.len < (PicoScroll::WIDTH * PicoScroll::HEIGHT)) { mp_raise_msg(&mp_type_IndexError, BUFFER_TOO_SMALL_MSG); } self->scroll->set_pixels((const char*)bufinfo.buf); return mp_const_none; } mp_obj_t picoscroll_show_bitmap_1d(mp_uint_t n_args, const mp_obj_t *args) { (void)n_args; //Unused input parameter, we know it's self + 3 PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(args[0], PicoScroll_obj_t); mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_RW); int offset = mp_obj_get_int(args[3]); int brightness = mp_obj_get_int(args[2]); int length = bufinfo.len; // clear the scroll, so only need to write visible bytes self->scroll->clear(); if ((offset < -PicoScroll::WIDTH) || (offset > length)) { return mp_const_none; } self->scroll->set_bitmap_1d((const char *)bufinfo.buf, bufinfo.len, brightness, offset); return mp_const_none; } mp_obj_t picoscroll_clear(mp_obj_t self_in) { PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t); self->scroll->clear(); return mp_const_none; } mp_obj_t picoscroll_is_pressed(mp_obj_t self_in, mp_obj_t button_obj) { PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t); bool buttonPressed = false; int buttonID = mp_obj_get_int(button_obj); switch(buttonID) { case 0: buttonPressed = self->scroll->is_pressed(PicoScroll::A); break; case 1: buttonPressed = self->scroll->is_pressed(PicoScroll::B); break; case 2: buttonPressed = self->scroll->is_pressed(PicoScroll::X); break; case 3: buttonPressed = self->scroll->is_pressed(PicoScroll::Y); break; default: mp_raise_ValueError("button not valid. Expected 0 to 3"); break; } return buttonPressed ? mp_const_true : mp_const_false; } mp_obj_t picoscroll_update(mp_obj_t self_in, mp_obj_t graphics_in) { PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t); ModPicoGraphics_obj_t *picographics = MP_OBJ_TO_PTR2(graphics_in, ModPicoGraphics_obj_t); if(picographics->base.type == &ModPicoGraphics_type) { self->scroll->update(picographics->graphics); } return mp_const_none; } }