pimoroni-pico/micropython/modules/pico_scroll/pico_scroll.cpp

234 lines
6.8 KiB
C++

#include <cstdio>
#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;
}
}