2023-03-13 19:39:33 +00:00
|
|
|
#include <cstdio>
|
2021-01-19 18:43:43 +00:00
|
|
|
#include "hardware/spi.h"
|
|
|
|
#include "hardware/sync.h"
|
|
|
|
#include "pico/binary_info.h"
|
2021-04-16 06:33:39 +01:00
|
|
|
#include "pico/stdlib.h"
|
2021-01-19 18:43:43 +00:00
|
|
|
|
2023-03-13 13:36:04 +00:00
|
|
|
#include "micropython/modules/util.hpp"
|
2021-05-13 12:06:01 +01:00
|
|
|
#include "libraries/pico_scroll/pico_scroll.hpp"
|
2023-03-13 19:39:33 +00:00
|
|
|
#include "libraries/pico_scroll/pico_scroll_font.hpp"
|
2021-01-19 18:43:43 +00:00
|
|
|
|
|
|
|
using namespace pimoroni;
|
|
|
|
|
2021-02-11 15:45:39 +00:00
|
|
|
PicoScroll *scroll = nullptr;
|
2021-01-19 18:43:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
#include "pico_scroll.h"
|
2023-03-16 16:59:31 +00:00
|
|
|
#include "micropython/modules/pimoroni_i2c/pimoroni_i2c.h"
|
|
|
|
#include "py/builtin.h"
|
2021-01-19 18:43:43 +00:00
|
|
|
|
2021-04-07 16:01:50 +01:00
|
|
|
#define BUFFER_TOO_SMALL_MSG "bytearray too small: len(image) < width * height."
|
2021-04-08 06:25:50 +01:00
|
|
|
#define INCORRECT_SIZE_MSG "Scroll height wrong: > 8 pixels."
|
2021-04-07 16:01:50 +01:00
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
typedef struct _PicoScroll_obj_t {
|
|
|
|
mp_obj_base_t base;
|
|
|
|
PicoScroll* scroll;
|
|
|
|
} PicoScroll_obj_t;
|
|
|
|
|
2023-03-16 16:59:31 +00:00
|
|
|
// 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;
|
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
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);
|
2021-01-19 18:43:43 +00:00
|
|
|
return mp_const_none;
|
|
|
|
}
|
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
mp_obj_t picoscroll_get_width(mp_obj_t self_in) {
|
|
|
|
(void)self_in;
|
2021-01-19 18:43:43 +00:00
|
|
|
return mp_obj_new_int(PicoScroll::WIDTH);
|
|
|
|
}
|
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
mp_obj_t picoscroll_get_height(mp_obj_t self_in) {
|
|
|
|
(void)self_in;
|
2021-01-19 18:43:43 +00:00
|
|
|
return mp_obj_new_int(PicoScroll::HEIGHT);
|
|
|
|
}
|
|
|
|
|
2023-03-16 16:59:31 +00:00
|
|
|
mp_obj_t picoscroll_show(mp_obj_t self_in) {
|
2023-03-13 19:39:33 +00:00
|
|
|
PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t);
|
|
|
|
self->scroll->update();
|
2021-01-19 18:43:43 +00:00
|
|
|
return mp_const_none;
|
|
|
|
}
|
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
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);
|
2021-01-19 18:43:43 +00:00
|
|
|
|
|
|
|
return mp_const_none;
|
|
|
|
}
|
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
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);
|
2021-04-16 06:33:39 +01:00
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
render_text((const char *)str, str_len, (unsigned char *)draw_buffer, draw_buffer_len);
|
2021-04-21 14:35:26 +01:00
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
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();
|
2024-01-08 10:33:26 +00:00
|
|
|
mp_event_handle_nowait();
|
2023-03-13 19:39:33 +00:00
|
|
|
sleep_ms(delay_ms);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_free(draw_buffer);
|
|
|
|
|
|
|
|
self->scroll->clear();
|
|
|
|
self->scroll->update();
|
2021-04-16 06:33:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return mp_const_none;
|
|
|
|
}
|
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
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);
|
2021-04-15 20:01:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return mp_const_none;
|
|
|
|
}
|
2021-04-16 06:13:36 +01:00
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
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);
|
2021-04-07 16:01:50 +01:00
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
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);
|
|
|
|
}
|
2021-04-07 16:01:50 +01:00
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
self->scroll->set_pixels((const char*)bufinfo.buf);
|
2021-04-07 15:21:01 +01:00
|
|
|
|
|
|
|
return mp_const_none;
|
|
|
|
}
|
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
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);
|
2021-04-16 06:13:36 +01:00
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
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;
|
2021-04-16 06:13:36 +01:00
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
// clear the scroll, so only need to write visible bytes
|
|
|
|
self->scroll->clear();
|
2021-04-16 06:13:36 +01:00
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
if ((offset < -PicoScroll::WIDTH) || (offset > length)) {
|
|
|
|
return mp_const_none;
|
2021-04-08 06:25:50 +01:00
|
|
|
}
|
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
self->scroll->set_bitmap_1d((const char *)bufinfo.buf, bufinfo.len, brightness, offset);
|
|
|
|
|
2021-04-08 06:25:50 +01:00
|
|
|
return mp_const_none;
|
|
|
|
}
|
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
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();
|
2021-01-19 18:43:43 +00:00
|
|
|
return mp_const_none;
|
|
|
|
}
|
|
|
|
|
2023-03-13 19:39:33 +00:00
|
|
|
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);
|
|
|
|
|
2021-01-19 18:43:43 +00:00
|
|
|
bool buttonPressed = false;
|
2023-03-13 19:39:33 +00:00
|
|
|
|
|
|
|
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;
|
2021-01-19 18:43:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return buttonPressed ? mp_const_true : mp_const_false;
|
|
|
|
}
|
2023-03-16 16:59:31 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2021-04-07 15:21:01 +01:00
|
|
|
}
|