diff --git a/drivers/st7789/st7789.cpp b/drivers/st7789/st7789.cpp index bd412252..251e8e90 100644 --- a/drivers/st7789/st7789.cpp +++ b/drivers/st7789/st7789.cpp @@ -140,7 +140,7 @@ namespace pimoroni { // gamma correct the provided 0-255 brightness value onto a // 0-65535 range for the pwm counter float gamma = 2.8; - uint16_t value = (uint16_t)(pow((float)(brightness) / 255.0f, gamma) * 65536.0f + 0.5f); + uint16_t value = (uint16_t)(pow((float)(brightness) / 255.0f, gamma) * 65535.0f + 0.5f); pwm_set_gpio_level(bl, value); } diff --git a/drivers/st7789/st7789.hpp b/drivers/st7789/st7789.hpp index a2ee83ff..d4b62bff 100644 --- a/drivers/st7789/st7789.hpp +++ b/drivers/st7789/st7789.hpp @@ -16,11 +16,11 @@ namespace pimoroni { uint16_t row_stride; // interface pins with our standard defaults where appropriate + int8_t cs = 17; + int8_t dc = 16; int8_t sck = 18; int8_t mosi = 19; int8_t miso = -1; // we generally don't use this pin - int8_t cs = 17; - int8_t dc = 16; int8_t bl = 20; int8_t vsync = -1; // only available on some products @@ -37,9 +37,9 @@ namespace pimoroni { ST7789(uint16_t width, uint16_t height, uint16_t *frame_buffer, spi_inst_t *spi, uint8_t cs, uint8_t dc, uint8_t sck, uint8_t mosi, uint8_t miso = -1) : - width(width), height(height), frame_buffer(frame_buffer), spi(spi), - cs(cs), dc(dc), sck(sck), mosi(mosi), miso(miso) {} + width(width), height(height), + cs(cs), dc(dc), sck(sck), mosi(mosi), miso(miso), frame_buffer(frame_buffer) {} void init(bool auto_init_sequence = true); diff --git a/examples/pico_display/demo.cpp b/examples/pico_display/demo.cpp index 2a2659c8..86b0801c 100644 --- a/examples/pico_display/demo.cpp +++ b/examples/pico_display/demo.cpp @@ -10,7 +10,8 @@ using namespace pimoroni; extern unsigned char image_tif[]; extern unsigned int image_tif_len; -PicoDisplay pico_display; +uint16_t buffer[PicoDisplay::WIDTH * PicoDisplay::HEIGHT]; +PicoDisplay pico_display(buffer); /* void pixel(int x, int y, uint16_t c) { x *= 2; @@ -70,6 +71,7 @@ void sprite(uint8_t *p, int x, int y, bool flip, uint16_t c) { }*/ int main() { + pico_display.init(); pico_display.set_backlight(100); // uint16_t white = pico_display.create_pen(255, 255, 255); diff --git a/examples/pico_explorer/demo.cpp b/examples/pico_explorer/demo.cpp index 629b7810..71fb7f58 100644 --- a/examples/pico_explorer/demo.cpp +++ b/examples/pico_explorer/demo.cpp @@ -10,7 +10,8 @@ using namespace pimoroni; extern unsigned char _binary_fox_tga_start[]; -PicoExplorer pico_explorer; +uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT]; +PicoExplorer pico_explorer(buffer); MSA301 msa301; uint8_t arrow[] = { @@ -54,6 +55,7 @@ void sprite(uint8_t *p, int x, int y, bool flip, uint16_t c) { }*/ int main() { + pico_explorer.init(); msa301.init(); bool a_pressed = false; diff --git a/libraries/pico_display/pico_display.cpp b/libraries/pico_display/pico_display.cpp index c8906c1d..9810e84f 100644 --- a/libraries/pico_display/pico_display.cpp +++ b/libraries/pico_display/pico_display.cpp @@ -1,4 +1,5 @@ #include +#include #include "hardware/pwm.h" @@ -10,9 +11,12 @@ const uint8_t LED_B = 8; namespace pimoroni { - PicoDisplay::PicoDisplay() - : screen(240, 135, __fb), PicoGraphics(240, 135, __fb) { + PicoDisplay::PicoDisplay(uint16_t *buf) + : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf) { + __fb = buf; + } + void PicoDisplay::init() { // setup the rgb led for pwm control pwm_config cfg = pwm_get_default_config(); pwm_config_set_output_polarity(&cfg, true, true); @@ -42,6 +46,14 @@ namespace pimoroni { screen.init(); } + void PicoDisplay::update() { + screen.update(); + } + + void PicoDisplay::set_backlight(uint8_t brightness) { + screen.set_backlight(brightness); + } + void PicoDisplay::set_led(uint8_t r, uint8_t g, uint8_t b) { // gamma correct the provided 0-255 brightness value onto a // 0-65535 range for the pwm counter @@ -50,15 +62,15 @@ namespace pimoroni { uint16_t value; // red - value = (uint16_t)(pow((float)(r) / 255.0f, gamma) * 65536.0f + 0.5f); + value = (uint16_t)(pow((float)(r) / 255.0f, gamma) * 65535.0f + 0.5f); pwm_set_gpio_level(LED_R, value); // green - value = (uint16_t)(pow((float)(g) / 255.0f, gamma) * 65536.0f + 0.5f); + value = (uint16_t)(pow((float)(g) / 255.0f, gamma) * 65535.0f + 0.5f); pwm_set_gpio_level(LED_G, value); // blue - value = (uint16_t)(pow((float)(b) / 255.0f, gamma) * 65536.0f + 0.5f); + value = (uint16_t)(pow((float)(b) / 255.0f, gamma) * 65535.0f + 0.5f); pwm_set_gpio_level(LED_B, value); } diff --git a/libraries/pico_display/pico_display.hpp b/libraries/pico_display/pico_display.hpp index b1c53d66..152c6e7c 100644 --- a/libraries/pico_display/pico_display.hpp +++ b/libraries/pico_display/pico_display.hpp @@ -6,22 +6,26 @@ namespace pimoroni { class PicoDisplay : public PicoGraphics { - uint16_t __fb[240 * 135]; - ST7789 screen; - public: - PicoDisplay(); - - void set_backlight(uint8_t brightness) {screen.set_backlight(brightness);} - void update() {screen.update();} - - void set_led(uint8_t r, uint8_t g, uint8_t b); - bool is_pressed(uint8_t button); - + static const int WIDTH = 240; + static const int HEIGHT = 135; static const uint8_t A = 12; static const uint8_t B = 13; static const uint8_t X = 14; static const uint8_t Y = 15; + + uint16_t *__fb; + private: + ST7789 screen; + + public: + PicoDisplay(uint16_t *buf); + + void init(); + void update(); + void set_backlight(uint8_t brightness); + void set_led(uint8_t r, uint8_t g, uint8_t b); + bool is_pressed(uint8_t button); }; } \ No newline at end of file diff --git a/libraries/pico_explorer/pico_explorer.cpp b/libraries/pico_explorer/pico_explorer.cpp index b2df3df0..6195c07f 100644 --- a/libraries/pico_explorer/pico_explorer.cpp +++ b/libraries/pico_explorer/pico_explorer.cpp @@ -1,4 +1,5 @@ #include +#include #include "hardware/pwm.h" #include "hardware/adc.h" @@ -12,9 +13,12 @@ const uint8_t MOTOR2P = 11; namespace pimoroni { - PicoExplorer::PicoExplorer() - : screen(240, 240, __fb), PicoGraphics(240, 240, __fb) { + PicoExplorer::PicoExplorer(uint16_t *buf) + : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf) { + __fb = buf; + } + void PicoExplorer::init() { // setup button inputs gpio_set_function(A, GPIO_FUNC_SIO); gpio_set_dir(A, GPIO_IN); gpio_pull_up(A); gpio_set_function(B, GPIO_FUNC_SIO); gpio_set_dir(B, GPIO_IN); gpio_pull_up(B); @@ -48,6 +52,14 @@ namespace pimoroni { screen.init(); } + void PicoExplorer::update() { + screen.update(); + } + + void PicoExplorer::set_backlight(uint8_t brightness) { + screen.set_backlight(brightness); + } + bool PicoExplorer::is_pressed(uint8_t button) { return !gpio_get(button); } diff --git a/libraries/pico_explorer/pico_explorer.hpp b/libraries/pico_explorer/pico_explorer.hpp index c44438e0..cb6b0551 100644 --- a/libraries/pico_explorer/pico_explorer.hpp +++ b/libraries/pico_explorer/pico_explorer.hpp @@ -6,25 +6,9 @@ namespace pimoroni { class PicoExplorer : public PicoGraphics { - uint16_t __fb[240 * 240]; - ST7789 screen; - int8_t audio_pin = -1; - public: - PicoExplorer(); - - void set_backlight(uint8_t brightness) {screen.set_backlight(brightness);} - void update() {screen.update();} - - bool is_pressed(uint8_t button); - - float get_adc(uint8_t channel); - - void set_motor(uint8_t channel, uint8_t action, float speed = 0.0f); - - void set_audio_pin(uint8_t pin); - void set_tone(uint16_t frequency, float duty = 0.2f); - + static const int WIDTH = 240; + static const int HEIGHT = 240; static const uint8_t A = 12; static const uint8_t B = 13; static const uint8_t X = 14; @@ -50,6 +34,25 @@ namespace pimoroni { static const uint8_t GP6 = 6; static const uint8_t GP7 = 7; + uint16_t *__fb; + private: + ST7789 screen; + int8_t audio_pin = -1; + + public: + PicoExplorer(uint16_t *buf); + + void init(); + void update(); + void set_backlight(uint8_t brightness); + bool is_pressed(uint8_t button); + + float get_adc(uint8_t channel); + + void set_motor(uint8_t channel, uint8_t action, float speed = 0.0f); + + void set_audio_pin(uint8_t pin); + void set_tone(uint16_t frequency, float duty = 0.2f); }; } \ No newline at end of file diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 6e2a8465..eba9f06d 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -18,8 +18,7 @@ namespace pimoroni { ((g & 0b11111100) << 3) | ((b & 0b11111000) >> 3); - // endian swap, this should be possible another way... - return ((p & 0xff00) >> 8) | ((p & 0xff) << 8); + return __builtin_bswap16(p); } void PicoGraphics::set_clip(const rect &r) { @@ -131,11 +130,9 @@ namespace pimoroni { } } - void PicoGraphics::text(const std::string &t, const point &p, int32_t wrap) { + void PicoGraphics::text(const std::string &t, const point &p, int32_t wrap, uint8_t scale) { uint32_t co = 0, lo = 0; // character and line (if wrapping) offset - uint8_t scale = 2; - size_t i = 0; while(i < t.length()) { // find length of current word diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 2aef657e..545ac9e5 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -39,11 +40,11 @@ namespace pimoroni { class PicoGraphics { public: + uint16_t *frame_buffer; + rect bounds; rect clip; - uint16_t *frame_buffer; - uint16_t pen; public: @@ -66,8 +67,8 @@ namespace pimoroni { void pixel_span(const point &p, int32_t l); void rectangle(const rect &r); void circle(const point &p, int32_t r); - void text(const std::string &t, const point &p, int32_t wrap); - void character(const char c, const point &p, uint8_t scale); + void character(const char c, const point &p, uint8_t scale = 2); + void text(const std::string &t, const point &p, int32_t wrap, uint8_t scale = 2); //void polygon(std::vector); }; diff --git a/libraries/pico_scroll/pico_scroll.cpp b/libraries/pico_scroll/pico_scroll.cpp index f04aabe9..4b36c47d 100644 --- a/libraries/pico_scroll/pico_scroll.cpp +++ b/libraries/pico_scroll/pico_scroll.cpp @@ -55,6 +55,10 @@ namespace pimoroni { gpio_set_function(pin::B, GPIO_FUNC_SIO); gpio_set_dir(pin::B, GPIO_IN); gpio_pull_up(pin::B); gpio_set_function(pin::X, GPIO_FUNC_SIO); gpio_set_dir(pin::X, GPIO_IN); gpio_pull_up(pin::X); gpio_set_function(pin::Y, GPIO_FUNC_SIO); gpio_set_dir(pin::Y, GPIO_IN); gpio_pull_up(pin::Y); + + // reset the screen + clear(); + update(); } void PicoScroll::set_pixel(uint8_t x, uint8_t y, uint8_t v) { diff --git a/micropython/examples/pico_display/demo.py b/micropython/examples/pico_display/demo.py new file mode 100644 index 00000000..9236d0b3 --- /dev/null +++ b/micropython/examples/pico_display/demo.py @@ -0,0 +1,49 @@ +import time, random +import picodisplay as display +display.init() +display.set_backlight(1.0) +i = 0 +width = display.get_width() +height = display.get_height() + +class Ball: + def __init__(self, x, y, r, dx, dy, pen): + self.x = x + self.y = y + self.r = r + self.dx = dx + self.dy = dy + self.pen = pen + +# initialise shapes +balls = [] +for i in range(0, 100): + balls.append( + Ball( + random.randint(0, width), + random.randint(0, height), + random.randint(0, 10) + 3, + random.randint(0, 255) / 128, + random.randint(0, 255) / 128, + display.create_pen(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)), + ) + ) + +while True: + display.set_pen(120, 40, 60) + display.clear() + + for ball in balls: + ball.x += ball.dx + ball.y += ball.dy + + if ball.x < 0 or ball.x > width: + ball.dx *= -1 + if ball.y < 0 or ball.y > height: + ball.dy *= -1 + + display.set_pen(ball.pen) + display.circle(int(ball.x), int(ball.y), int(ball.r)) + + display.update() + time.sleep(0.01) \ No newline at end of file diff --git a/micropython/examples/pico_scroll/demo.py b/micropython/examples/pico_scroll/demo.py new file mode 100644 index 00000000..4be9a55c --- /dev/null +++ b/micropython/examples/pico_scroll/demo.py @@ -0,0 +1,36 @@ +import time +import picoscroll as scroll + +scroll.init() +i = 0 +loop = 18 +br_mult = 1 +br_pressed = 32 +tail = 12 + +width = scroll.get_width() +height = scroll.get_height() +while True: + scroll.clear(); + for y in range(0, height): + for x in range(0, width): + if x < 3 and y < 3 and scroll.is_pressed(scroll.BUTTON_A): + scroll.set_pixel(x, y, br_pressed) + elif x < 3 and y > 3 and scroll.is_pressed(scroll.BUTTON_B): + scroll.set_pixel(x, y, br_pressed) + elif x > width - 4 and y < 3 and scroll.is_pressed(scroll.BUTTON_X): + scroll.set_pixel(x, y, br_pressed) + elif x > width - 4 and y > 3 and scroll.is_pressed(scroll.BUTTON_Y): + scroll.set_pixel(x, y, br_pressed) + else: + m = (x + (y * width)) % loop + for b in range(0, loop): + if m == (i + (loop - b)) % loop and b < tail: + scroll.set_pixel(x, y, br_mult * (tail - b)) + + + scroll.update() + i += 1 + if i >= loop: + i = 0 + time.sleep(0.02) diff --git a/micropython/modules/pico_display/micropython.mk b/micropython/modules/pico_display/micropython.mk new file mode 100755 index 00000000..a6faed27 --- /dev/null +++ b/micropython/modules/pico_display/micropython.mk @@ -0,0 +1,6 @@ +DISPLAY_MOD_DIR := $(USERMOD_DIR) +# Add all C files to SRC_USERMOD. +SRC_USERMOD += $(DISPLAY_MOD_DIR)/pico_display.c +# # We can add our module folder to include paths if needed +# # This is not actually needed in this example. +CFLAGS_USERMOD += -I$(DISPLAY_MOD_DIR) diff --git a/micropython/modules/pico_display/pico_display.c b/micropython/modules/pico_display/pico_display.c new file mode 100755 index 00000000..7678d78f --- /dev/null +++ b/micropython/modules/pico_display/pico_display.c @@ -0,0 +1,78 @@ +#include "pico_display.h" + +/***** Constants *****/ +enum buttons +{ + BUTTON_A = 0, + BUTTON_B, + BUTTON_X, + BUTTON_Y, +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// picodisplay Module +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/***** Module Functions *****/ +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picodisplay_init_obj, picodisplay_init); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay_get_width_obj, picodisplay_get_width); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay_get_height_obj, picodisplay_get_height); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay_update_obj, picodisplay_update); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picodisplay_set_backlight_obj, picodisplay_set_backlight); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(picodisplay_set_led_obj, picodisplay_set_led); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picodisplay_is_pressed_obj, picodisplay_is_pressed); + +//From PicoGraphics parent class +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay_set_pen_obj, 1, 3, picodisplay_set_pen); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(picodisplay_create_pen_obj, picodisplay_create_pen); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay_set_clip_obj, 4, 4, picodisplay_set_clip); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay_remove_clip_obj, picodisplay_remove_clip); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay_clear_obj, picodisplay_clear); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(picodisplay_pixel_obj, picodisplay_pixel); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(picodisplay_pixel_span_obj, picodisplay_pixel_span); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay_rectangle_obj, 4, 4, picodisplay_rectangle); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(picodisplay_circle_obj, picodisplay_circle); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay_character_obj, 3, 4, picodisplay_character); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay_text_obj, 4, 5, picodisplay_text); + + +/***** Globals Table *****/ +STATIC const mp_map_elem_t picodisplay_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picodisplay) }, + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&picodisplay_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&picodisplay_get_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&picodisplay_get_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&picodisplay_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&picodisplay_set_backlight_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_led), MP_ROM_PTR(&picodisplay_set_led_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_pressed), MP_ROM_PTR(&picodisplay_is_pressed_obj) }, + + { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&picodisplay_set_pen_obj) }, + { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&picodisplay_create_pen_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&picodisplay_set_clip_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove_clip), MP_ROM_PTR(&picodisplay_remove_clip_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&picodisplay_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&picodisplay_pixel_obj) }, + { MP_ROM_QSTR(MP_QSTR_pixel_span), MP_ROM_PTR(&picodisplay_pixel_span_obj) }, + { MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&picodisplay_rectangle_obj) }, + { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&picodisplay_circle_obj) }, + { MP_ROM_QSTR(MP_QSTR_character), MP_ROM_PTR(&picodisplay_character_obj) }, + { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&picodisplay_text_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_picodisplay_globals, picodisplay_globals_table); + +/***** Module Definition *****/ +const mp_obj_module_t picodisplay_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_picodisplay_globals, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +MP_REGISTER_MODULE(MP_QSTR_picodisplay, picodisplay_user_cmodule, MODULE_PICODISPLAY_ENABLED); +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/pico_display/pico_display.cpp b/micropython/modules/pico_display/pico_display.cpp new file mode 100644 index 00000000..79e9c79d --- /dev/null +++ b/micropython/modules/pico_display/pico_display.cpp @@ -0,0 +1,259 @@ +#include "hardware/spi.h" +#include "hardware/sync.h" +#include "pico/binary_info.h" + +#include "../../../pimoroni-pico/libraries/pico_display/pico_display.hpp" + +using namespace pimoroni; + +PicoDisplay *display; + + +extern "C" { +#include "pico_display.h" + +mp_obj_t picodisplay_buf_obj; + +mp_obj_t picodisplay_init(mp_obj_t buf_obj) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_obj, &bufinfo, MP_BUFFER_RW); + picodisplay_buf_obj = buf_obj; + display = new PicoDisplay((uint16_t *)bufinfo.buf); + display->init(); + return mp_const_none; +} + +mp_obj_t picodisplay_get_width() { + return mp_obj_new_int(PicoDisplay::WIDTH); +} + +mp_obj_t picodisplay_get_height() { + return mp_obj_new_int(PicoDisplay::HEIGHT); +} + +mp_obj_t picodisplay_update() { + display->update(); + return mp_const_none; +} + +mp_obj_t picodisplay_set_backlight(mp_obj_t brightness_obj) { + float brightness = mp_obj_get_float(brightness_obj); + + if(brightness < 0 || brightness > 1.0f) + mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); + else + display->set_backlight((uint8_t)(brightness * 255.0f)); + + return mp_const_none; +} + +mp_obj_t picodisplay_set_led(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj) { + int r = mp_obj_get_int(r_obj); + int g = mp_obj_get_int(g_obj); + int b = mp_obj_get_int(b_obj); + + 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 + display->set_led(r, g, b); + + return mp_const_none; +} + +mp_obj_t picodisplay_is_pressed(mp_obj_t button_obj) { + int buttonID = mp_obj_get_int(button_obj); + + bool buttonPressed = false; + switch(buttonID) + { + case 0: + buttonPressed = display->is_pressed(PicoDisplay::A); + break; + + case 1: + buttonPressed = display->is_pressed(PicoDisplay::B); + break; + + case 2: + buttonPressed = display->is_pressed(PicoDisplay::X); + break; + + case 3: + buttonPressed = display->is_pressed(PicoDisplay::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 picodisplay_set_pen(mp_uint_t n_args, const mp_obj_t *args) { + switch(n_args) + { + case 1: { + int p = mp_obj_get_int(args[0]); + + if(p < 0 || p > 0xffff) + mp_raise_ValueError("p is not a valid pen."); + else + display->set_pen(p); + } break; + + case 3: { + int r = mp_obj_get_int(args[0]); + int g = mp_obj_get_int(args[1]); + int b = mp_obj_get_int(args[2]); + + 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 + display->set_pen(r, g, b); + } break; + + default: { + char *buffer; + buffer = (char*)malloc(100); + sprintf(buffer, "function takes 1 or 3 (r,g,b) positional arguments but %d were given", n_args); + mp_raise_TypeError(buffer); + } break; + } + + return mp_const_none; +} + +mp_obj_t picodisplay_create_pen(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj) { + int r = mp_obj_get_int(r_obj); + int g = mp_obj_get_int(g_obj); + int b = mp_obj_get_int(b_obj); + + int pen = 0; + 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 + pen = display->create_pen(r, g, b); + + return mp_obj_new_int(pen); +} + +mp_obj_t picodisplay_set_clip(mp_uint_t n_args, const mp_obj_t *args) { + (void)n_args; //Unused input parameter, we know it's 4 + + int x = mp_obj_get_int(args[0]); + int y = mp_obj_get_int(args[1]); + int w = mp_obj_get_int(args[2]); + int h = mp_obj_get_int(args[3]); + + rect r(x, y, w, h); + display->set_clip(r); + + return mp_const_none; +} + +mp_obj_t picodisplay_remove_clip() { + display->remove_clip(); + return mp_const_none; +} + +mp_obj_t picodisplay_clear() { + display->clear(); + return mp_const_none; +} + +mp_obj_t picodisplay_pixel(mp_obj_t x_obj, mp_obj_t y_obj) { + int x = mp_obj_get_int(x_obj); + int y = mp_obj_get_int(y_obj); + + point p(x, y); + display->pixel(p); + + return mp_const_none; +} + +mp_obj_t picodisplay_pixel_span(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t l_obj) { + int x = mp_obj_get_int(x_obj); + int y = mp_obj_get_int(y_obj); + int l = mp_obj_get_int(l_obj); + + point p(x, y); + display->pixel_span(p, l); + + return mp_const_none; +} + +mp_obj_t picodisplay_rectangle(mp_uint_t n_args, const mp_obj_t *args) { + (void)n_args; //Unused input parameter, we know it's 4 + + int x = mp_obj_get_int(args[0]); + int y = mp_obj_get_int(args[1]); + int w = mp_obj_get_int(args[2]); + int h = mp_obj_get_int(args[3]); + + rect r(x, y, w, h); + display->rectangle(r); + + return mp_const_none; +} + +mp_obj_t picodisplay_circle(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t r_obj) { + int x = mp_obj_get_int(x_obj); + int y = mp_obj_get_int(y_obj); + int r = mp_obj_get_int(r_obj); + + point p(x, y); + display->circle(p, r); + + return mp_const_none; +} + +mp_obj_t picodisplay_character(mp_uint_t n_args, const mp_obj_t *args) { + int c = mp_obj_get_int(args[0]); + int x = mp_obj_get_int(args[1]); + int y = mp_obj_get_int(args[2]); + + point p(x, y); + if(n_args == 4) { + int scale = mp_obj_get_int(args[3]); + display->character((char)c, p, scale); + } + else + display->character((char)c, p); + + return mp_const_none; +} + +mp_obj_t picodisplay_text(mp_uint_t n_args, const mp_obj_t *args) { + mp_check_self(mp_obj_is_str_or_bytes(args[0])); + GET_STR_DATA_LEN(args[0], str, str_len); + + std::string t((const char*)str); + + int x = mp_obj_get_int(args[1]); + int y = mp_obj_get_int(args[2]); + int wrap = mp_obj_get_int(args[3]); + + point p(x, y); + if(n_args == 5) { + int scale = mp_obj_get_int(args[4]); + display->text(t, p, wrap, scale); + } + else + display->text(t, p, wrap); + + return mp_const_none; +} +} diff --git a/micropython/modules/pico_display/pico_display.h b/micropython/modules/pico_display/pico_display.h new file mode 100644 index 00000000..d93fc360 --- /dev/null +++ b/micropython/modules/pico_display/pico_display.h @@ -0,0 +1,25 @@ +// Include MicroPython API. +#include "py/runtime.h" +#include "py/objstr.h" + +// Declare the functions we'll make available in Python +extern mp_obj_t picodisplay_init(mp_obj_t buf_obj); +extern mp_obj_t picodisplay_get_width(); +extern mp_obj_t picodisplay_get_height(); +extern mp_obj_t picodisplay_set_backlight(mp_obj_t brightness_obj); +extern mp_obj_t picodisplay_update(); +extern mp_obj_t picodisplay_set_led(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj); +extern mp_obj_t picodisplay_is_pressed(mp_obj_t button_obj); + +// From PicoGraphics parent class +extern mp_obj_t picodisplay_set_pen(mp_uint_t n_args, const mp_obj_t *args); +extern mp_obj_t picodisplay_create_pen(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj); +extern mp_obj_t picodisplay_set_clip(mp_uint_t n_args, const mp_obj_t *args); +extern mp_obj_t picodisplay_remove_clip(); +extern mp_obj_t picodisplay_clear(); +extern mp_obj_t picodisplay_pixel(mp_obj_t x_obj, mp_obj_t y_obj); +extern mp_obj_t picodisplay_pixel_span(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t l_obj); +extern mp_obj_t picodisplay_rectangle(mp_uint_t n_args, const mp_obj_t *args); +extern mp_obj_t picodisplay_circle(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t r_obj); +extern mp_obj_t picodisplay_character(mp_uint_t n_args, const mp_obj_t *args); +extern mp_obj_t picodisplay_text(mp_uint_t n_args, const mp_obj_t *args); \ No newline at end of file diff --git a/micropython/modules/pico_display/usermod.cmake b/micropython/modules/pico_display/usermod.cmake new file mode 100644 index 00000000..f3e7d813 --- /dev/null +++ b/micropython/modules/pico_display/usermod.cmake @@ -0,0 +1,21 @@ +add_library(usermod_pico_display INTERFACE) + +target_sources(usermod_pico_display INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/pico_display.c + ${CMAKE_CURRENT_LIST_DIR}/pico_display.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_display/pico_display.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7789/st7789.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/types.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/font_data.cpp +) + +target_include_directories(usermod_pico_display INTERFACE + ${CMAKE_CURRENT_LIST_DIR} +) + +target_compile_definitions(usermod_pico_display INTERFACE + -DMODULE_PICODISPLAY_ENABLED=1 +) + +target_link_libraries(usermod INTERFACE usermod_pico_display) \ No newline at end of file diff --git a/micropython/modules/pico_explorer/micropython.mk b/micropython/modules/pico_explorer/micropython.mk new file mode 100755 index 00000000..275a59ee --- /dev/null +++ b/micropython/modules/pico_explorer/micropython.mk @@ -0,0 +1,6 @@ +EXPLORER_MOD_DIR := $(USERMOD_DIR) +# Add all C files to SRC_USERMOD. +SRC_USERMOD += $(EXPLORER_MOD_DIR)/pico_explorer.c +# # We can add our module folder to include paths if needed +# # This is not actually needed in this example. +CFLAGS_USERMOD += -I$(EXPLORER_MOD_DIR) diff --git a/micropython/modules/pico_explorer/pico_explorer.c b/micropython/modules/pico_explorer/pico_explorer.c new file mode 100644 index 00000000..e68fdbed --- /dev/null +++ b/micropython/modules/pico_explorer/pico_explorer.c @@ -0,0 +1,133 @@ +#include "pico_explorer.h" + +/***** Constants *****/ +enum buttons +{ + BUTTON_A = 0, + BUTTON_B, + BUTTON_X, + BUTTON_Y, +}; + +enum adcs +{ + ADC0 = 0, + ADC1, + ADC2, +}; + +enum motors +{ + MOTOR1 = 0, + MOTOR2, +}; + +enum motions +{ + FORWARD = 0, + REVERSE, + STOP, +}; + +enum gps +{ + GP0 = 0, + GP1, + GP2, + GP3, + GP4, + GP5, + GP6, + GP7, +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// picoexplorer Module +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/***** Module Functions *****/ +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoexplorer_init_obj, picoexplorer_init); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoexplorer_get_width_obj, picoexplorer_get_width); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoexplorer_get_height_obj, picoexplorer_get_height); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoexplorer_set_backlight_obj, picoexplorer_set_backlight); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoexplorer_update_obj, picoexplorer_update); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoexplorer_is_pressed_obj, picoexplorer_is_pressed); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoexplorer_get_adc_obj, picoexplorer_get_adc); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoexplorer_set_motor_obj, 2, 3, picoexplorer_set_motor); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoexplorer_set_audio_pin_obj, picoexplorer_set_audio_pin); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoexplorer_set_tone_obj, 1, 2, picoexplorer_set_tone); + +//From PicoGraphics parent class +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoexplorer_set_pen_obj, 1, 3, picoexplorer_set_pen); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(picoexplorer_create_pen_obj, picoexplorer_create_pen); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoexplorer_set_clip_obj, 4, 4, picoexplorer_set_clip); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoexplorer_remove_clip_obj, picoexplorer_remove_clip); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoexplorer_clear_obj, picoexplorer_clear); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(picoexplorer_pixel_obj, picoexplorer_pixel); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(picoexplorer_pixel_span_obj, picoexplorer_pixel_span); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoexplorer_rectangle_obj, 4, 4, picoexplorer_rectangle); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(picoexplorer_circle_obj, picoexplorer_circle); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoexplorer_character_obj, 3, 4, picoexplorer_character); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoexplorer_text_obj, 4, 5, picoexplorer_text); + + +/***** Globals Table *****/ +STATIC const mp_map_elem_t picoexplorer_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picoexplorer) }, + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&picoexplorer_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&picoexplorer_get_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&picoexplorer_get_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&picoexplorer_set_backlight_obj) }, + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&picoexplorer_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_pressed), MP_ROM_PTR(&picoexplorer_is_pressed_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_adc), MP_ROM_PTR(&picoexplorer_get_adc_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_motor), MP_ROM_PTR(&picoexplorer_set_motor_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_audio_pin), MP_ROM_PTR(&picoexplorer_set_audio_pin_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_tone), MP_ROM_PTR(&picoexplorer_set_tone_obj) }, + + { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&picoexplorer_set_pen_obj) }, + { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&picoexplorer_create_pen_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&picoexplorer_set_clip_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove_clip), MP_ROM_PTR(&picoexplorer_remove_clip_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&picoexplorer_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&picoexplorer_pixel_obj) }, + { MP_ROM_QSTR(MP_QSTR_pixel_span), MP_ROM_PTR(&picoexplorer_pixel_span_obj) }, + { MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&picoexplorer_rectangle_obj) }, + { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&picoexplorer_circle_obj) }, + { MP_ROM_QSTR(MP_QSTR_character), MP_ROM_PTR(&picoexplorer_character_obj) }, + { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&picoexplorer_text_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) }, + + { MP_ROM_QSTR(MP_QSTR_ADC0), MP_ROM_INT(ADC0) }, + { MP_ROM_QSTR(MP_QSTR_ADC1), MP_ROM_INT(ADC1) }, + { MP_ROM_QSTR(MP_QSTR_ADC2), MP_ROM_INT(ADC2) }, + { MP_ROM_QSTR(MP_QSTR_MOTOR1), MP_ROM_INT(MOTOR1) }, + { MP_ROM_QSTR(MP_QSTR_MOTOR2), MP_ROM_INT(MOTOR2) }, + { MP_ROM_QSTR(MP_QSTR_FORWARD), MP_ROM_INT(FORWARD) }, + { MP_ROM_QSTR(MP_QSTR_REVERSE), MP_ROM_INT(REVERSE) }, + { MP_ROM_QSTR(MP_QSTR_STOP), MP_ROM_INT(STOP) }, + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_INT(GP0) }, + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_INT(GP1) }, + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_INT(GP2) }, + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_INT(GP3) }, + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_INT(GP4) }, + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_INT(GP5) }, + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_INT(GP6) }, + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_INT(GP7) }, +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_picoexplorer_globals, picoexplorer_globals_table); + +/***** Module Definition *****/ +const mp_obj_module_t picoexplorer_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_picoexplorer_globals, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +MP_REGISTER_MODULE(MP_QSTR_picoexplorer, picoexplorer_user_cmodule, MODULE_PICOEXPLORER_ENABLED); +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/pico_explorer/pico_explorer.cpp b/micropython/modules/pico_explorer/pico_explorer.cpp new file mode 100644 index 00000000..b993960a --- /dev/null +++ b/micropython/modules/pico_explorer/pico_explorer.cpp @@ -0,0 +1,293 @@ +#include "hardware/spi.h" +#include "hardware/sync.h" +#include "pico/binary_info.h" + +#include "../../../pimoroni-pico/libraries/pico_explorer/pico_explorer.hpp" + +using namespace pimoroni; + +PicoExplorer *explorer; + + +extern "C" { +#include "pico_explorer.h" + +mp_obj_t picoexplorer_buf_obj; + +mp_obj_t picoexplorer_init(mp_obj_t buf_obj) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_obj, &bufinfo, MP_BUFFER_RW); + picoexplorer_buf_obj = buf_obj; + explorer = new PicoExplorer((uint16_t *)bufinfo.buf); + explorer->init(); + return mp_const_none; +} + +mp_obj_t picoexplorer_get_width() { + return mp_obj_new_int(PicoExplorer::WIDTH); +} + +mp_obj_t picoexplorer_get_height() { + return mp_obj_new_int(PicoExplorer::HEIGHT); +} + +mp_obj_t picoexplorer_update() { + explorer->update(); + return mp_const_none; +} + +mp_obj_t picoexplorer_set_backlight(mp_obj_t brightness_obj) { + float brightness = mp_obj_get_float(brightness_obj); + + if(brightness < 0 || brightness > 1.0f) + mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); + else + explorer->set_backlight((uint8_t)(brightness * 255.0f)); + + return mp_const_none; +} + +mp_obj_t picoexplorer_is_pressed(mp_obj_t button_obj) { + int buttonID = mp_obj_get_int(button_obj); + + bool buttonPressed = false; + switch(buttonID) + { + case 0: + buttonPressed = explorer->is_pressed(PicoExplorer::A); + break; + + case 1: + buttonPressed = explorer->is_pressed(PicoExplorer::B); + break; + + case 2: + buttonPressed = explorer->is_pressed(PicoExplorer::X); + break; + + case 3: + buttonPressed = explorer->is_pressed(PicoExplorer::Y); + break; + + default: + mp_raise_ValueError("button not valid. Expected 0 to 3"); + break; + } + + return buttonPressed ? mp_const_true : mp_const_false; +} + +extern mp_obj_t picoexplorer_get_adc(mp_obj_t channel_obj) { + int channel = mp_obj_get_int(channel_obj); + + float reading = 0.0f; + if(channel < 0 || channel > 2) + mp_raise_ValueError("adc channel not valid. Expected 0 to 2"); + else + reading = explorer->get_adc(channel); + + return mp_obj_new_float(reading); +} + +extern mp_obj_t picoexplorer_set_motor(mp_uint_t n_args, const mp_obj_t *args) { + int channel = mp_obj_get_int(args[0]); + int action = mp_obj_get_int(args[1]); + + if(channel < 0 || channel > 1) + mp_raise_ValueError("motor channel not valid. Expected 0 to 1"); + else if(action < 0 || action > 2) + mp_raise_ValueError("motor action not valid. Expected 0 to 2"); + else { + if(n_args == 3) { + float speed = mp_obj_get_float(args[2]); + explorer->set_motor(channel, action, speed); + } + else + explorer->set_motor(channel, action); + } + + return mp_const_none; +} + +extern mp_obj_t picoexplorer_set_audio_pin(mp_obj_t pin_obj) { + int pin = mp_obj_get_int(pin_obj); + explorer->set_audio_pin(pin); + return mp_const_none; +} + +extern mp_obj_t picoexplorer_set_tone(mp_uint_t n_args, const mp_obj_t *args) { + int frequency = mp_obj_get_int(args[0]); + + if(n_args == 2) { + float duty = mp_obj_get_int(args[1]); + explorer->set_tone(frequency, duty); + } + else + explorer->set_tone(frequency); + + return mp_const_none; +} + +mp_obj_t picoexplorer_set_pen(mp_uint_t n_args, const mp_obj_t *args) { + switch(n_args) + { + case 1: { + int p = mp_obj_get_int(args[0]); + + if(p < 0 || p > 0xffff) + mp_raise_ValueError("p is not a valid pen."); + else + explorer->set_pen(p); + } break; + + case 3: { + int r = mp_obj_get_int(args[0]); + int g = mp_obj_get_int(args[1]); + int b = mp_obj_get_int(args[2]); + + 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 + explorer->set_pen(r, g, b); + } break; + + default: { + char *buffer; + buffer = (char*)malloc(100); + sprintf(buffer, "function takes 1 or 3 (r,g,b) positional arguments but %d were given", n_args); + mp_raise_TypeError(buffer); + } break; + } + + return mp_const_none; +} + +mp_obj_t picoexplorer_create_pen(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj) { + int r = mp_obj_get_int(r_obj); + int g = mp_obj_get_int(g_obj); + int b = mp_obj_get_int(b_obj); + + int pen = 0; + 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 + pen = explorer->create_pen(r, g, b); + + return mp_obj_new_int(pen); +} + +mp_obj_t picoexplorer_set_clip(mp_uint_t n_args, const mp_obj_t *args) { + (void)n_args; //Unused input parameter, we know it's 4 + + int x = mp_obj_get_int(args[0]); + int y = mp_obj_get_int(args[1]); + int w = mp_obj_get_int(args[2]); + int h = mp_obj_get_int(args[3]); + + rect r(x, y, w, h); + explorer->set_clip(r); + + return mp_const_none; +} + +mp_obj_t picoexplorer_remove_clip() { + explorer->remove_clip(); + return mp_const_none; +} + +mp_obj_t picoexplorer_clear() { + explorer->clear(); + return mp_const_none; +} + +mp_obj_t picoexplorer_pixel(mp_obj_t x_obj, mp_obj_t y_obj) { + int x = mp_obj_get_int(x_obj); + int y = mp_obj_get_int(y_obj); + + point p(x, y); + explorer->pixel(p); + + return mp_const_none; +} + +mp_obj_t picoexplorer_pixel_span(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t l_obj) { + int x = mp_obj_get_int(x_obj); + int y = mp_obj_get_int(y_obj); + int l = mp_obj_get_int(l_obj); + + point p(x, y); + explorer->pixel_span(p, l); + + return mp_const_none; +} + +mp_obj_t picoexplorer_rectangle(mp_uint_t n_args, const mp_obj_t *args) { + (void)n_args; //Unused input parameter, we know it's 4 + + int x = mp_obj_get_int(args[0]); + int y = mp_obj_get_int(args[1]); + int w = mp_obj_get_int(args[2]); + int h = mp_obj_get_int(args[3]); + + rect r(x, y, w, h); + explorer->rectangle(r); + + return mp_const_none; +} + +mp_obj_t picoexplorer_circle(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t r_obj) { + int x = mp_obj_get_int(x_obj); + int y = mp_obj_get_int(y_obj); + int r = mp_obj_get_int(r_obj); + + point p(x, y); + explorer->circle(p, r); + + return mp_const_none; +} + +mp_obj_t picoexplorer_character(mp_uint_t n_args, const mp_obj_t *args) { + int c = mp_obj_get_int(args[0]); + int x = mp_obj_get_int(args[1]); + int y = mp_obj_get_int(args[2]); + + point p(x, y); + if(n_args == 4) { + int scale = mp_obj_get_int(args[3]); + explorer->character((char)c, p, scale); + } + else + explorer->character((char)c, p); + + return mp_const_none; +} + +mp_obj_t picoexplorer_text(mp_uint_t n_args, const mp_obj_t *args) { + mp_check_self(mp_obj_is_str_or_bytes(args[0])); + GET_STR_DATA_LEN(args[0], str, str_len); + + std::string t((const char*)str); + + int x = mp_obj_get_int(args[1]); + int y = mp_obj_get_int(args[2]); + int wrap = mp_obj_get_int(args[3]); + + point p(x, y); + if(n_args == 5) { + int scale = mp_obj_get_int(args[4]); + explorer->text(t, p, wrap, scale); + } + else + explorer->text(t, p, wrap); + + return mp_const_none; +} +} \ No newline at end of file diff --git a/micropython/modules/pico_explorer/pico_explorer.h b/micropython/modules/pico_explorer/pico_explorer.h new file mode 100644 index 00000000..b446b58b --- /dev/null +++ b/micropython/modules/pico_explorer/pico_explorer.h @@ -0,0 +1,28 @@ +// Include MicroPython API. +#include "py/runtime.h" +#include "py/objstr.h" + +// Declare the functions we'll make available in Python +extern mp_obj_t picoexplorer_init(mp_obj_t buf_obj); +extern mp_obj_t picoexplorer_get_width(); +extern mp_obj_t picoexplorer_get_height(); +extern mp_obj_t picoexplorer_set_backlight(mp_obj_t brightness_obj); +extern mp_obj_t picoexplorer_update(); +extern mp_obj_t picoexplorer_is_pressed(mp_obj_t button_obj); +extern mp_obj_t picoexplorer_get_adc(mp_obj_t channel_obj); +extern mp_obj_t picoexplorer_set_motor(mp_uint_t n_args, const mp_obj_t *args); +extern mp_obj_t picoexplorer_set_audio_pin(mp_obj_t pin_obj); +extern mp_obj_t picoexplorer_set_tone(mp_uint_t n_args, const mp_obj_t *args); + +// From PicoGraphics parent class +extern mp_obj_t picoexplorer_set_pen(mp_uint_t n_args, const mp_obj_t *args); +extern mp_obj_t picoexplorer_create_pen(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj); +extern mp_obj_t picoexplorer_set_clip(mp_uint_t n_args, const mp_obj_t *args); +extern mp_obj_t picoexplorer_remove_clip(); +extern mp_obj_t picoexplorer_clear(); +extern mp_obj_t picoexplorer_pixel(mp_obj_t x_obj, mp_obj_t y_obj); +extern mp_obj_t picoexplorer_pixel_span(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t l_obj); +extern mp_obj_t picoexplorer_rectangle(mp_uint_t n_args, const mp_obj_t *args); +extern mp_obj_t picoexplorer_circle(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t r_obj); +extern mp_obj_t picoexplorer_character(mp_uint_t n_args, const mp_obj_t *args); +extern mp_obj_t picoexplorer_text(mp_uint_t n_args, const mp_obj_t *args); \ No newline at end of file diff --git a/micropython/modules/pico_explorer/usermod.cmake b/micropython/modules/pico_explorer/usermod.cmake new file mode 100644 index 00000000..cae51ada --- /dev/null +++ b/micropython/modules/pico_explorer/usermod.cmake @@ -0,0 +1,21 @@ +add_library(usermod_pico_explorer INTERFACE) + +target_sources(usermod_pico_explorer INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/pico_explorer.c + ${CMAKE_CURRENT_LIST_DIR}/pico_explorer.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_explorer/pico_explorer.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7789/st7789.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/types.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/font_data.cpp +) + +target_include_directories(usermod_pico_explorer INTERFACE + ${CMAKE_CURRENT_LIST_DIR} +) + +target_compile_definitions(usermod_pico_explorer INTERFACE + -DMODULE_PICOEXPLORER_ENABLED=1 +) + +target_link_libraries(usermod INTERFACE usermod_pico_explorer) \ No newline at end of file diff --git a/micropython/modules/pico_rgb_keypad/usermod.cmake b/micropython/modules/pico_rgb_keypad/usermod.cmake new file mode 100644 index 00000000..4d961684 --- /dev/null +++ b/micropython/modules/pico_rgb_keypad/usermod.cmake @@ -0,0 +1,17 @@ +add_library(usermod_pico_rgb_keypad INTERFACE) + +target_sources(usermod_pico_rgb_keypad INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/pico_rgb_keypad.c + ${CMAKE_CURRENT_LIST_DIR}/pico_rgb_keypad.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_rgb_keypad/pico_rgb_keypad.cpp +) + +target_include_directories(usermod_pico_rgb_keypad INTERFACE + ${CMAKE_CURRENT_LIST_DIR} +) + +target_compile_definitions(usermod_pico_rgb_keypad INTERFACE + -DMODULE_PICOKEYPAD_ENABLED=1 +) + +target_link_libraries(usermod INTERFACE usermod_pico_rgb_keypad) \ No newline at end of file diff --git a/micropython/modules/pico_scroll/pico_scroll.c b/micropython/modules/pico_scroll/pico_scroll.c index d59b7008..61b3be46 100644 --- a/micropython/modules/pico_scroll/pico_scroll.c +++ b/micropython/modules/pico_scroll/pico_scroll.c @@ -20,7 +20,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoscroll_get_width_obj, picoscroll_get_width) STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoscroll_get_height_obj, picoscroll_get_height); STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoscroll_update_obj, picoscroll_update); STATIC MP_DEFINE_CONST_FUN_OBJ_3(picoscroll_set_pixel_obj, picoscroll_set_pixel); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoscroll_clear_obj, picoscroll_init); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoscroll_clear_obj, picoscroll_clear); STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll_is_pressed_obj, picoscroll_is_pressed); /***** Globals Table *****/ diff --git a/micropython/modules/pico_scroll/usermod.cmake b/micropython/modules/pico_scroll/usermod.cmake new file mode 100644 index 00000000..2a79f81c --- /dev/null +++ b/micropython/modules/pico_scroll/usermod.cmake @@ -0,0 +1,17 @@ +add_library(usermod_pico_scroll INTERFACE) + +target_sources(usermod_pico_scroll INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/pico_scroll.c + ${CMAKE_CURRENT_LIST_DIR}/pico_scroll.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_scroll/pico_scroll.cpp +) + +target_include_directories(usermod_pico_scroll INTERFACE + ${CMAKE_CURRENT_LIST_DIR} +) + +target_compile_definitions(usermod_pico_scroll INTERFACE + -DMODULE_PICOSCROLL_ENABLED=1 +) + +target_link_libraries(usermod INTERFACE usermod_pico_scroll) \ No newline at end of file diff --git a/micropython/modules/pico_unicorn/usermod.cmake b/micropython/modules/pico_unicorn/usermod.cmake new file mode 100644 index 00000000..3b59b135 --- /dev/null +++ b/micropython/modules/pico_unicorn/usermod.cmake @@ -0,0 +1,19 @@ +add_library(usermod_pico_unicorn INTERFACE) + +target_sources(usermod_pico_unicorn INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/pico_unicorn.c + ${CMAKE_CURRENT_LIST_DIR}/pico_unicorn.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_unicorn/pico_unicorn.cpp +) + +pico_generate_pio_header(usermod_pico_unicorn ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_unicorn/pico_unicorn.pio) + +target_include_directories(usermod_pico_unicorn INTERFACE + ${CMAKE_CURRENT_LIST_DIR} +) + +target_compile_definitions(usermod_pico_unicorn INTERFACE + -DMODULE_PICOUNICORN_ENABLED=1 +) + +target_link_libraries(usermod INTERFACE usermod_pico_unicorn) \ No newline at end of file diff --git a/micropython/modules/usermod.cmake b/micropython/modules/usermod.cmake new file mode 100644 index 00000000..44191c83 --- /dev/null +++ b/micropython/modules/usermod.cmake @@ -0,0 +1,4 @@ +include(${CMAKE_CURRENT_LIST_DIR}/pico_scroll/usermod.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/pico_rgb_keypad/usermod.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/pico_unicorn/usermod.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/pico_display/usermod.cmake) \ No newline at end of file