kopia lustrzana https://github.com/pimoroni/pimoroni-pico
				
				
				
			ST7789/PicoGraphics: Templated framebuffer formats.
							rodzic
							
								
									dbed4a463f
								
							
						
					
					
						commit
						7e4725d1cd
					
				|  | @ -9,4 +9,4 @@ target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) | |||
| target_include_directories(st7789 INTERFACE ${CMAKE_CURRENT_LIST_DIR}) | ||||
| 
 | ||||
| # Pull in pico libraries that we need | ||||
| target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib pimoroni_bus hardware_spi hardware_pwm hardware_dma) | ||||
| target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib pimoroni_bus hardware_spi hardware_pwm hardware_dma pico_graphics) | ||||
|  |  | |||
|  | @ -200,7 +200,102 @@ namespace pimoroni { | |||
| 
 | ||||
|     gpio_put(cs, 1); | ||||
|   } | ||||
|    | ||||
|   void ST7789::update(PicoGraphics<PenRGB565> *graphics) { | ||||
|     command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)graphics->get_data()); | ||||
|   } | ||||
| 
 | ||||
|   void ST7789::update(PicoGraphics<PenRGB332> *graphics) { | ||||
|     uint8_t command = reg::RAMWR; | ||||
| 
 | ||||
|     gpio_put(dc, 0); // command mode
 | ||||
| 
 | ||||
|     gpio_put(cs, 0); | ||||
| 
 | ||||
|     if(spi) { | ||||
|       spi_write_blocking(spi, &command, 1); | ||||
|     } else { | ||||
|       write_blocking_parallel(&command, 1); | ||||
|     } | ||||
| 
 | ||||
|     gpio_put(dc, 1); // data mode
 | ||||
| 
 | ||||
|     uint16_t row_buf[width]; | ||||
| 
 | ||||
|     for(auto y = 0u; y < height; y++) { | ||||
|       graphics->get_data(y, &row_buf); | ||||
|       // TODO: Add DMA->SPI / PIO while we prep the next row
 | ||||
|       if(spi) { | ||||
|         spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); | ||||
|       } else { | ||||
|         write_blocking_parallel((const uint8_t*)row_buf, width * sizeof(uint16_t)); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     gpio_put(cs, 1); | ||||
|   } | ||||
| 
 | ||||
|   void ST7789::update(PicoGraphics<PenP8> *graphics) { | ||||
|     uint8_t command = reg::RAMWR; | ||||
| 
 | ||||
|     gpio_put(dc, 0); // command mode
 | ||||
| 
 | ||||
|     gpio_put(cs, 0); | ||||
| 
 | ||||
|     if(spi) { | ||||
|       spi_write_blocking(spi, &command, 1); | ||||
|     } else { | ||||
|       write_blocking_parallel(&command, 1); | ||||
|     } | ||||
|    | ||||
|     gpio_put(dc, 1); // data mode
 | ||||
| 
 | ||||
|     uint16_t row_buf[width]; | ||||
| 
 | ||||
|     for(auto y = 0u; y < height; y++) { | ||||
|       graphics->get_data(y, &row_buf); | ||||
|       // TODO: Add DMA->SPI / PIO while we prep the next row
 | ||||
|       if(spi) { | ||||
|         spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); | ||||
|       } else { | ||||
|         write_blocking_parallel((const uint8_t*)row_buf, width * sizeof(uint16_t)); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     gpio_put(cs, 1); | ||||
|   } | ||||
| 
 | ||||
|   void ST7789::update(PicoGraphics<PenP4> *graphics) { | ||||
|     uint8_t command = reg::RAMWR; | ||||
| 
 | ||||
|     gpio_put(dc, 0); // command mode
 | ||||
| 
 | ||||
|     gpio_put(cs, 0); | ||||
| 
 | ||||
|     if(spi) { | ||||
|       spi_write_blocking(spi, &command, 1); | ||||
|     } else { | ||||
|       write_blocking_parallel(&command, 1); | ||||
|     } | ||||
| 
 | ||||
|     gpio_put(dc, 1); // data mode
 | ||||
| 
 | ||||
|     uint16_t row_buf[width]; | ||||
| 
 | ||||
|     for(auto y = 0u; y < height; y++) { | ||||
|       graphics->get_data(y, &row_buf); | ||||
|       // TODO: Add DMA->SPI / PIO while we prep the next row
 | ||||
|       if(spi) { | ||||
|         spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); | ||||
|       } else { | ||||
|         write_blocking_parallel((const uint8_t*)row_buf, width * sizeof(uint16_t)); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     gpio_put(cs, 1); | ||||
|   } | ||||
| 
 | ||||
| /*
 | ||||
|   // Native 16-bit framebuffer update
 | ||||
|   void ST7789::update() { | ||||
|     command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)frame_buffer); | ||||
|  | @ -238,6 +333,7 @@ namespace pimoroni { | |||
| 
 | ||||
|     gpio_put(cs, 1); | ||||
|   } | ||||
|   */ | ||||
| 
 | ||||
|   void ST7789::set_backlight(uint8_t brightness) { | ||||
|     // gamma correct the provided 0-255 brightness value onto a
 | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
| #include "hardware/pwm.h" | ||||
| #include "common/pimoroni_common.hpp" | ||||
| #include "common/pimoroni_bus.hpp" | ||||
| #include "libraries/pico_graphics/pico_graphics.hpp" | ||||
| 
 | ||||
| #include <algorithm> | ||||
| 
 | ||||
|  | @ -41,15 +42,11 @@ namespace pimoroni { | |||
| 
 | ||||
| 
 | ||||
|   public: | ||||
|    | ||||
|     // frame buffer where pixel data is stored
 | ||||
|     void *frame_buffer; | ||||
| 
 | ||||
|     // Parallel init
 | ||||
|     ST7789(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins pins) : | ||||
|       spi(nullptr), | ||||
|       width(width), height(height), rotation(rotation), round(false), | ||||
|       cs(pins.cs), dc(pins.dc), wr_sck(pins.wr_sck), rd_sck(pins.rd_sck), d0(pins.d0), bl(pins.bl), frame_buffer(frame_buffer) { | ||||
|       cs(pins.cs), dc(pins.dc), wr_sck(pins.wr_sck), rd_sck(pins.rd_sck), d0(pins.d0), bl(pins.bl) { | ||||
|    | ||||
|       gpio_set_function(wr_sck, GPIO_FUNC_SIO); | ||||
|       gpio_set_dir(wr_sck, GPIO_OUT); | ||||
|  | @ -71,7 +68,7 @@ namespace pimoroni { | |||
|     ST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins pins) : | ||||
|       spi(pins.spi), | ||||
|       width(width), height(height), rotation(rotation), round(round), | ||||
|       cs(pins.cs), dc(pins.dc), wr_sck(pins.sck), d0(pins.mosi), bl(pins.bl), frame_buffer(frame_buffer) { | ||||
|       cs(pins.cs), dc(pins.dc), wr_sck(pins.sck), d0(pins.mosi), bl(pins.bl) { | ||||
| 
 | ||||
|       // configure spi interface and pins
 | ||||
|       spi_init(spi, SPI_BAUD); | ||||
|  | @ -86,17 +83,15 @@ namespace pimoroni { | |||
|     void command(uint8_t command, size_t len = 0, const char *data = NULL); | ||||
|     void set_backlight(uint8_t brightness); | ||||
| 
 | ||||
|     void update(); | ||||
|     void update(uint16_t *palette); | ||||
|     void update(PicoGraphics<PenRGB565> *graphics); | ||||
|     void update(PicoGraphics<PenRGB332> *graphics); | ||||
|     void update(PicoGraphics<PenP8> *graphics); | ||||
|     void update(PicoGraphics<PenP4> *graphics); | ||||
| 
 | ||||
|   private: | ||||
|     void configure_display(Rotation rotate); | ||||
|     void write_blocking_parallel(const uint8_t *src, size_t len); | ||||
|     void common_init() { | ||||
|         if(!this->frame_buffer) { | ||||
|           this->frame_buffer = new uint8_t[width * height]; | ||||
|         } | ||||
| 
 | ||||
|         gpio_set_function(dc, GPIO_FUNC_SIO); | ||||
|         gpio_set_dir(dc, GPIO_OUT); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,135 +1,40 @@ | |||
| #include "pico_graphics.hpp" | ||||
| 
 | ||||
| namespace pimoroni { | ||||
|   PicoGraphics::PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer) | ||||
|   : frame_buffer((Pen *)frame_buffer), bounds(0, 0, width, height), clip(0, 0, width, height) { | ||||
|     set_font(&font6); | ||||
|     set_palette_mode(PaletteModeRGB332); | ||||
|   }; | ||||
| 
 | ||||
|   void PicoGraphics::set_font(const bitmap::font_t *font){ | ||||
|   template<class T> | ||||
|   void PicoGraphics<T>::set_font(const bitmap::font_t *font){ | ||||
|     this->font = font; | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::set_pen(Pen p) { | ||||
|     pen = p; | ||||
|   template<class T> | ||||
|   void PicoGraphics<T>::set_pen(uint16_t p) { | ||||
|     pen.set_color(p); | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::set_palette_mode(PaletteMode mode) { | ||||
|     palette_mode = mode; | ||||
|     if(mode == PaletteModeRGB332) { | ||||
|       rgb332_palette(); | ||||
|     } else { | ||||
|       empty_palette(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   int PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b) { | ||||
|     if (palette_mode == PaletteModeRGB332) { | ||||
|       return rgb_to_rgb332_index(r, g, b); // Fast pack RGB into palette index
 | ||||
|     } else { | ||||
|       RGB565 c = create_pen_rgb565(r, g, b); | ||||
|       int result = search_palette(c); | ||||
| 
 | ||||
|       if (result == -1) { | ||||
|         result = put_palette(create_pen_rgb565(r, g, b)); | ||||
|       } | ||||
| 
 | ||||
|       return result; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::set_pen(uint8_t r, uint8_t g, uint8_t b) { | ||||
|     int result = create_pen(r, g, b); | ||||
|     (void)result; | ||||
|   } | ||||
| 
 | ||||
|   int PicoGraphics::search_palette(RGB565 c) { | ||||
|     for(auto i = 0u; i < 256; i++) { | ||||
|       if((palette_status[i] & PaletteStatusUsed) && palette[i] == c) return i; | ||||
|     } | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   int PicoGraphics::put_palette(RGB565 c) { | ||||
|     if(palette_mode != PaletteModeUSER) return -1; | ||||
| 
 | ||||
|     for(auto i = 0u; i < 256; i++) { | ||||
|       if(!(palette_status[i] & (PaletteStatusUsed | PaletteStatusReserved))) { | ||||
|         palette[i] = c; | ||||
|         palette_status[i] = PaletteStatusUsed; | ||||
|         return i; | ||||
|       } | ||||
|     } | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::set_palette(uint8_t i, RGB565 c) { | ||||
|     if(palette_mode != PaletteModeUSER) return; | ||||
| 
 | ||||
|     palette[i] = c; | ||||
|     palette_status[i] |= PaletteStatusUsed; | ||||
|   } | ||||
| 
 | ||||
|   int PicoGraphics::reserve_palette() { | ||||
|     if(palette_mode != PaletteModeUSER) return - 1; | ||||
| 
 | ||||
|     for (auto i = 0u; i < 256; i++) { | ||||
|       if (!palette_status[i]) { | ||||
|         palette_status[i] = PaletteStatusReserved; | ||||
|         return i; | ||||
|       } | ||||
|     } | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::empty_palette() { | ||||
|     for (auto i = 0u; i < 256; i++) { | ||||
|       palette[i] = 0; | ||||
|       palette_status[i] = 0; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::rgb332_palette() { | ||||
|     for (auto i = 0u; i < 256; i++) { | ||||
|       // Convert the implicit RGB332 (i) into RGB565
 | ||||
|       // 0b11100 000 0b00011100 0b00000011
 | ||||
|       palette[i] = ((i & 0b11100000) << 8) | ((i & 0b00011100) << 6) | ((i & 0b00000011) << 3); | ||||
|       palette[i] = __builtin_bswap16(palette[i]); | ||||
|       palette_status[i] = PaletteStatusUsed; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::set_clip(const Rect &r) { | ||||
|   template<class T> | ||||
|   void PicoGraphics<T>::set_clip(const Rect &r) { | ||||
|     clip = bounds.intersection(r); | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::remove_clip() { | ||||
|   template<class T> | ||||
|   void PicoGraphics<T>::remove_clip() { | ||||
|     clip = bounds; | ||||
|   } | ||||
| 
 | ||||
|   Pen* PicoGraphics::ptr(const Rect &r) { | ||||
|     return frame_buffer + r.x + r.y * bounds.w; | ||||
|   } | ||||
| 
 | ||||
|   Pen* PicoGraphics::ptr(const Point &p) { | ||||
|     return frame_buffer + p.x + p.y * bounds.w; | ||||
|   } | ||||
| 
 | ||||
|   Pen* PicoGraphics::ptr(int32_t x, int32_t y) { | ||||
|     return frame_buffer + x + y * bounds.w; | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::clear() { | ||||
|   template<class T> | ||||
|   void PicoGraphics<T>::clear() { | ||||
|     rectangle(clip); | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::pixel(const Point &p) { | ||||
|   template<class T> | ||||
|   void PicoGraphics<T>::pixel(const Point &p) { | ||||
|     if(!clip.contains(p)) return; | ||||
|     *ptr(p) = pen; | ||||
|     pen.set_pixel(frame_buffer, p.x, p.y, bounds.w); | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::pixel_span(const Point &p, int32_t l) { | ||||
|   template<class T> | ||||
|   void PicoGraphics<T>::pixel_span(const Point &p, int32_t l) { | ||||
|     // check if span in bounds
 | ||||
|     if( p.x + l < clip.x || p.x >= clip.x + clip.w || | ||||
|         p.y     < clip.y || p.y >= clip.y + clip.h) return; | ||||
|  | @ -139,31 +44,36 @@ namespace pimoroni { | |||
|     if(clipped.x     <  clip.x)           {l += clipped.x - clip.x; clipped.x = clip.x;} | ||||
|     if(clipped.x + l >= clip.x + clip.w)  {l  = clip.x + clip.w - clipped.x;} | ||||
| 
 | ||||
|     Pen *dest = ptr(clipped); | ||||
|     Point dest(clipped.x, clipped.y); | ||||
|     while(l--) { | ||||
|       *dest++ = pen; | ||||
|         pen.set_pixel(frame_buffer, dest.x, dest.y, bounds.w); | ||||
|         dest.x++; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::rectangle(const Rect &r) { | ||||
|   template<class T> | ||||
|   void PicoGraphics<T>::rectangle(const Rect &r) { | ||||
|     // clip and/or discard depending on rectangle visibility
 | ||||
|     Rect clipped = r.intersection(clip); | ||||
| 
 | ||||
|     if(clipped.empty()) return; | ||||
| 
 | ||||
|     Pen *dest = ptr(clipped); | ||||
|     Point dest(clipped.x, clipped.y); | ||||
|     while(clipped.h--) { | ||||
|       // draw span of pixels for this row
 | ||||
|       for(int32_t i = 0; i < clipped.w; i++) { | ||||
|         *dest++ = pen; | ||||
|       } | ||||
|       pixel_span(dest, clipped.w); | ||||
|       /*for(int32_t i = 0; i < clipped.w; i++) {
 | ||||
|         pen.set_pixel(frame_buffer, dest.x, dest.y, bounds.w); | ||||
|         dest.x++; | ||||
|       }*/ | ||||
| 
 | ||||
|       // move to next scanline
 | ||||
|       dest += bounds.w - clipped.w; | ||||
|       dest.y++; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::circle(const Point &p, int32_t radius) { | ||||
|   template<class T> | ||||
|   void PicoGraphics<T>::circle(const Point &p, int32_t radius) { | ||||
|     // circle in screen bounds?
 | ||||
|     Rect bounds = Rect(p.x - radius, p.y - radius, radius * 2, radius * 2); | ||||
|     if(!bounds.intersects(clip)) return; | ||||
|  | @ -191,19 +101,22 @@ namespace pimoroni { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::character(const char c, const Point &p, uint8_t scale) { | ||||
|   template<class T> | ||||
|   void PicoGraphics<T>::character(const char c, const Point &p, uint8_t scale) { | ||||
|     bitmap::character(font, [this](int32_t x, int32_t y, int32_t w, int32_t h){ | ||||
|       rectangle(Rect(x, y, w, h)); | ||||
|     }, c, p.x, p.y, scale); | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale) { | ||||
|   template<class T> | ||||
|   void PicoGraphics<T>::text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale) { | ||||
|     bitmap::text(font, [this](int32_t x, int32_t y, int32_t w, int32_t h){ | ||||
|       rectangle(Rect(x, y, w, h)); | ||||
|     }, t, p.x, p.y, wrap, scale); | ||||
|   } | ||||
| 
 | ||||
|   int32_t PicoGraphics::measure_text(const std::string &t, uint8_t scale) { | ||||
|   template<class T> | ||||
|   int32_t PicoGraphics<T>::measure_text(const std::string &t, uint8_t scale) { | ||||
|     return bitmap::measure_text(font, t, scale); | ||||
|   } | ||||
| 
 | ||||
|  | @ -215,7 +128,8 @@ namespace pimoroni { | |||
|     return (p1.y == p2.y && p1.x > p2.x) || (p1.y < p2.y); | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::triangle(Point p1, Point p2, Point p3) { | ||||
|   template<class T> | ||||
|   void PicoGraphics<T>::triangle(Point p1, Point p2, Point p3) { | ||||
|     Rect triangle_bounds( | ||||
|       Point(std::min(p1.x, std::min(p2.x, p3.x)), std::min(p1.y, std::min(p2.y, p3.y))), | ||||
|       Point(std::max(p1.x, std::max(p2.x, p3.x)), std::max(p1.y, std::max(p2.y, p3.y)))); | ||||
|  | @ -257,13 +171,13 @@ namespace pimoroni { | |||
|       int32_t w1 = w1row; | ||||
|       int32_t w2 = w2row; | ||||
| 
 | ||||
|       Pen *dest = ptr(triangle_bounds.x, triangle_bounds.y + y); | ||||
|       Point dest = Point(triangle_bounds.x, triangle_bounds.y + y); | ||||
|       for (int32_t x = 0; x < triangle_bounds.w; x++) { | ||||
|         if ((w0 | w1 | w2) >= 0) { | ||||
|           *dest = pen; | ||||
|           pen.set_pixel(frame_buffer, dest.x, dest.y, bounds.w); | ||||
|         } | ||||
| 
 | ||||
|         dest++; | ||||
|         dest.x++; | ||||
| 
 | ||||
|         w0 += a12; | ||||
|         w1 += a20; | ||||
|  | @ -276,7 +190,8 @@ namespace pimoroni { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::polygon(const std::vector<Point> &points) { | ||||
|   template<class T> | ||||
|   void PicoGraphics<T>::polygon(const std::vector<Point> &points) { | ||||
|     static int32_t nodes[64]; // maximum allowed number of nodes per scanline for polygon rendering
 | ||||
| 
 | ||||
|     int32_t miny = points[0].y, maxy = points[0].y; | ||||
|  | @ -322,7 +237,8 @@ namespace pimoroni { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::line(Point p1, Point p2) { | ||||
|   template<class T> | ||||
|   void PicoGraphics<T>::line(Point p1, Point p2) { | ||||
|     // fast horizontal line
 | ||||
|     if(p1.y == p2.y) { | ||||
|       int32_t start = std::max(clip.x, std::min(p1.x, p2.x)); | ||||
|  | @ -335,10 +251,10 @@ namespace pimoroni { | |||
|     if(p1.x == p2.x) { | ||||
|       int32_t start  = std::max(clip.y, std::min(p1.y, p2.y)); | ||||
|       int32_t length = std::min(clip.y + clip.h, std::max(p1.y, p2.y)) - start; | ||||
|       Pen *dest = ptr(p1.x, start); | ||||
|       Point dest(p1.x, start); | ||||
|       while(length--) { | ||||
|         *dest = pen; | ||||
|         dest += bounds.w; | ||||
|         pen.set_pixel(frame_buffer, dest.x, dest.y, bounds.w); | ||||
|         dest.y++; | ||||
|       } | ||||
|       return; | ||||
|     } | ||||
|  | @ -357,7 +273,7 @@ namespace pimoroni { | |||
|       int32_t x = p1.x; | ||||
|       int32_t y = p1.y << 16; | ||||
|       while(s--) { | ||||
|         pixel(Point(x, y >> 16)); | ||||
|         pen.set_pixel(frame_buffer, x, y >> 16, bounds.w); | ||||
|         y += sy; | ||||
|         x += sx; | ||||
|       } | ||||
|  | @ -369,7 +285,7 @@ namespace pimoroni { | |||
|       int32_t y = p1.y; | ||||
|       int32_t x = p1.x << 16; | ||||
|       while(s--) { | ||||
|         pixel(Point(x >> 16, y)); | ||||
|         pen.set_pixel(frame_buffer, x >> 16, y, bounds.w); | ||||
|         y += sy; | ||||
|         x += sx; | ||||
|       } | ||||
|  |  | |||
|  | @ -9,9 +9,9 @@ | |||
| // a tiny little graphics library for our Pico products
 | ||||
| // supports only 16-bit (565) RGB framebuffers
 | ||||
| namespace pimoroni { | ||||
| 
 | ||||
|   typedef uint8_t Pen; | ||||
|   typedef uint8_t RGB332; | ||||
|   typedef uint16_t RGB565; | ||||
|   typedef int Pen; | ||||
| 
 | ||||
|   struct Rect; | ||||
| 
 | ||||
|  | @ -44,59 +44,255 @@ namespace pimoroni { | |||
|     void deflate(int32_t v); | ||||
|   }; | ||||
| 
 | ||||
|   class PicoGraphicsPenType { | ||||
|       public: | ||||
| 
 | ||||
|         struct PaletteEntry { | ||||
|           RGB565 color; | ||||
|           bool used; | ||||
|         }; | ||||
| 
 | ||||
|         static constexpr RGB332 rgb_to_rgb332(uint8_t r, uint8_t g, uint8_t b) { | ||||
|           return (r & 0b11100000) | ((g & 0b11100000) >> 3) | ((b & 0b11000000) >> 6); | ||||
|         } | ||||
| 
 | ||||
|         static constexpr RGB565 rgb332_to_rgb565(RGB332 c) { | ||||
|           uint16_t p = ((c & 0b11100000) << 8) | | ||||
|                        ((c & 0b00011100) << 6) | | ||||
|                        ((c & 0b00000011) << 3); | ||||
|           return __builtin_bswap16(p); | ||||
|         } | ||||
| 
 | ||||
|         static constexpr RGB565 rgb_to_rgb565(uint8_t r, uint8_t g, uint8_t b) { | ||||
|           uint16_t p = ((r & 0b11111000) << 8) | | ||||
|                        ((g & 0b11111100) << 3) | | ||||
|                        ((b & 0b11111000) >> 3); | ||||
| 
 | ||||
|           return __builtin_bswap16(p); | ||||
|         } | ||||
| 
 | ||||
|         virtual void set_pixel(void *frame_buffer, uint x, uint y, uint stride); | ||||
|         virtual int create(uint8_t r, uint8_t g, uint8_t b); | ||||
|         virtual void set_color(uint c); | ||||
|         virtual void set_color(uint8_t r, uint8_t g, uint8_t b); | ||||
|         virtual void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b); | ||||
| 
 | ||||
|         virtual void palette_lookup(void *frame_buffer, void *result, uint offset, uint length); | ||||
|         static size_t buffer_size(uint w, uint h); // Must be static, since user must know required size to alloc framebuffer
 | ||||
|   }; | ||||
| 
 | ||||
|   class PenP4 : public PicoGraphicsPenType { | ||||
|     public: | ||||
|       uint8_t color; | ||||
|       PaletteEntry palette[8]; | ||||
|       PenP4() { | ||||
|         palette[0].color = rgb_to_rgb565(57, 48, 57);     // Black
 | ||||
|         palette[1].color = rgb_to_rgb565(255, 255, 255);  // White
 | ||||
|         palette[2].color = rgb_to_rgb565(58, 91, 70);     // Green
 | ||||
|         palette[3].color = rgb_to_rgb565(61, 59, 94);     // Blue
 | ||||
|         palette[4].color = rgb_to_rgb565(156, 72, 75);    // Red
 | ||||
|         palette[5].color = rgb_to_rgb565(208, 190, 71);   // Yellow
 | ||||
|         palette[6].color = rgb_to_rgb565(177, 106, 73);   // Orange
 | ||||
|         palette[7].color = rgb_to_rgb565(255, 255, 255);  // Clear
 | ||||
|       } | ||||
|       void set_color(uint c) { | ||||
|         color = c & 0xf; | ||||
|       } | ||||
|       void set_color(uint8_t r, uint8_t g, uint8_t b) override { | ||||
|         // TODO look up closest palette colour, or just NOOP?
 | ||||
|       } | ||||
|       void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b) {} | ||||
|       void reset_color(uint8_t i) {} | ||||
|       int create(uint8_t r, uint8_t g, uint8_t b) override { | ||||
|         return -1; // Can never create new colours, fixed palette!
 | ||||
|       } | ||||
|       void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { | ||||
|         // pointer to byte in framebuffer that contains this pixel
 | ||||
|         uint8_t *buf = (uint8_t *)frame_buffer; | ||||
|         uint8_t *p = &buf[(x / 2) + (y * stride / 2)]; | ||||
| 
 | ||||
|         uint8_t  o = (~x & 0b1) * 4; // bit offset within byte
 | ||||
|         uint8_t  m = ~(0b1111 << o); // bit mask for byte
 | ||||
|         uint8_t  b = color << o;     // bit value shifted to position
 | ||||
| 
 | ||||
|         *p &= m; // clear bits
 | ||||
|         *p |= b; // set value
 | ||||
|       } | ||||
|       void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override { | ||||
|         uint8_t *src = (uint8_t *)frame_buffer; | ||||
|         uint16_t *dst = (uint16_t *)result; | ||||
|         for(auto x = 0u; x < length; x++) { | ||||
|           uint8_t c = src[(offset / 2) + (x / 2)]; | ||||
|           uint8_t  o = (~x & 0b1) * 4; // bit offset within byte
 | ||||
|           uint8_t  b = (c >> o) & 0xf; // bit value shifted to position
 | ||||
|           dst[x] = palette[b].color; | ||||
|         } | ||||
|       } | ||||
|       static size_t buffer_size(uint w, uint h) { | ||||
|         return w * h / 2; | ||||
|       } | ||||
|   }; | ||||
| 
 | ||||
|   class PenP8 : public PicoGraphicsPenType { | ||||
|     public: | ||||
|       uint8_t color; | ||||
|       PaletteEntry palette[256]; | ||||
|       PenP8() { | ||||
|         for(auto i = 0u; i < 256; i++) { | ||||
|           reset_color(i); | ||||
|         } | ||||
|       } | ||||
|       void set_color(uint c) override { | ||||
|         color = c; | ||||
|       } | ||||
|       void set_color(uint8_t r, uint8_t g, uint8_t b) override { | ||||
|         // TODO look up closest palette colour, or just NOOP?
 | ||||
|       } | ||||
|       void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b) { | ||||
|         palette[i].color = rgb_to_rgb565(r, g, b); | ||||
|         palette[i].used = true; | ||||
|       } | ||||
|       void reset_color(uint8_t i) { | ||||
|         palette[i].color = 0; | ||||
|         palette[i].used = false; | ||||
|       } | ||||
|       int create(uint8_t r, uint8_t g, uint8_t b) override { | ||||
|         // Create a colour and place it in the palette if there's space
 | ||||
|         RGB565 c = rgb_to_rgb565(r, g, b); | ||||
|         for(auto i = 0u; i < 256u; i++) { | ||||
|           if(!palette[i].used) { | ||||
|             palette[i].color = c; | ||||
|             palette[i].used = true; | ||||
|             return i; | ||||
|           } | ||||
|         } | ||||
|         return -1; | ||||
|       } | ||||
|       void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { | ||||
|         uint8_t *buf = (uint8_t *)frame_buffer; | ||||
|         buf[y * stride + x] = color; | ||||
|       } | ||||
|       void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override { | ||||
|         uint8_t *src = (uint8_t *)frame_buffer; | ||||
|         uint16_t *dst = (uint16_t *)result; | ||||
|         for(auto x = 0u; x < length; x++) { | ||||
|           dst[x] = palette[src[offset + x]].color; | ||||
|         } | ||||
|       } | ||||
|       static size_t buffer_size(uint w, uint h) { | ||||
|         return w * h; | ||||
|       } | ||||
|   }; | ||||
| 
 | ||||
|   class PenRGB332 : public PicoGraphicsPenType { | ||||
|     public: | ||||
|       RGB332 color; | ||||
|       PaletteEntry palette[256]; | ||||
|       PenRGB332() { | ||||
|         for(auto i = 0u; i < 256; i++) { | ||||
|           reset_color(i); | ||||
|         } | ||||
|       } | ||||
|       void set_color(uint c) { | ||||
|         color = c; | ||||
|       } | ||||
|       void set_color(uint8_t r, uint8_t g, uint8_t b) override { | ||||
|         color = rgb_to_rgb332(r, g, b); | ||||
|       } | ||||
|       void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b) { | ||||
|         palette[i].color = rgb_to_rgb565(r, g, b); | ||||
|         palette[i].used = true; | ||||
|       } | ||||
|       void reset_color(uint8_t i) { | ||||
|         palette[i].color = rgb332_to_rgb565(i); | ||||
|         palette[i].used = true; | ||||
|       } | ||||
|       int create(uint8_t r, uint8_t g, uint8_t b) override { | ||||
|         return rgb_to_rgb332(r, g, b); | ||||
|       } | ||||
|       void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { | ||||
|         uint8_t *buf = (uint8_t *)frame_buffer; | ||||
|         buf[y * stride + x] = color; | ||||
|       } | ||||
|       void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override { | ||||
|         uint8_t *src = (uint8_t *)frame_buffer; | ||||
|         uint16_t *dst = (uint16_t *)result; | ||||
|         for(auto x = 0u; x < length; x++) { | ||||
|           dst[x] = palette[src[offset + x]].color; | ||||
|         } | ||||
|       } | ||||
|       static size_t buffer_size(uint w, uint h) { | ||||
|         return w * h; | ||||
|       } | ||||
|   }; | ||||
| 
 | ||||
|   class PenRGB565 : public PicoGraphicsPenType { | ||||
|     public: | ||||
|       uint16_t color; | ||||
|       void set_color(uint c) override { | ||||
|         color = c; | ||||
|       } | ||||
|       void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b) { | ||||
|         // Palette only. Does nothing.
 | ||||
|       } | ||||
|       void reset_color(uint8_t i) { | ||||
|         // Palette only. Does nothing.
 | ||||
|       } | ||||
|       void set_color(uint8_t r, uint8_t g, uint8_t b) override { | ||||
|         color = rgb_to_rgb565(r, g, b); | ||||
|       } | ||||
|       int create(uint8_t r, uint8_t g, uint8_t b) override { | ||||
|         return rgb_to_rgb565(r, g, b); | ||||
|       } | ||||
|       void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { | ||||
|         uint16_t *buf = (uint16_t *)frame_buffer; | ||||
|         buf[y * stride + x] = color; | ||||
|       } | ||||
|       void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override { | ||||
|       } | ||||
|       static size_t buffer_size(uint w, uint h) { | ||||
|         return w * h * sizeof(RGB565); | ||||
|       } | ||||
|   }; | ||||
| 
 | ||||
|   template <class T=PicoGraphicsPenType> | ||||
|   class PicoGraphics { | ||||
|   public: | ||||
|     Pen *frame_buffer; | ||||
|     void *frame_buffer; | ||||
| 
 | ||||
|     Rect      bounds; | ||||
|     Rect      clip; | ||||
| 
 | ||||
|     Pen       pen; | ||||
| 
 | ||||
|     const bitmap::font_t *font; | ||||
| 
 | ||||
|     RGB565 palette[256]; | ||||
|     uint8_t palette_status[256]; | ||||
| 
 | ||||
|     enum PaletteMode { | ||||
|       PaletteModeRGB332 = 0, | ||||
|       PaletteModeUSER = 1 | ||||
|     }; | ||||
| 
 | ||||
|     enum PaletteStatus : uint8_t { | ||||
|       PaletteStatusReserved = 1, | ||||
|       PaletteStatusUsed = 2 | ||||
|     }; | ||||
| 
 | ||||
|     PaletteMode palette_mode = PaletteModeRGB332; | ||||
|     T pen; | ||||
| 
 | ||||
|   public: | ||||
|     PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer); | ||||
|     PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer) | ||||
|     : frame_buffer(frame_buffer), bounds(0, 0, width, height), clip(0, 0, width, height) { | ||||
|       set_font(&font6); | ||||
|       if(frame_buffer == nullptr) { | ||||
|         frame_buffer = (void *)(new uint8_t[pen.buffer_size(width, height)]); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     void set_font(const bitmap::font_t *font); | ||||
|     void set_pen(Pen p); | ||||
|     void set_palette_mode(PaletteMode mode); | ||||
|     void set_pen(uint16_t p); | ||||
| 
 | ||||
|     [[deprecated("Use uint8_t create_pen(uint8_t, uint8_t, uint8_t).")]] | ||||
|     void set_pen(uint8_t r, uint8_t g, uint8_t b); | ||||
| 
 | ||||
|     static constexpr Pen rgb_to_rgb332_index(uint8_t r, uint8_t g, uint8_t b) { | ||||
|       return (r & 0b11100000) | ((g & 0b11100000) >> 3) | ((b & 0b11000000) >> 6); | ||||
|     int create_pen(uint8_t r, uint8_t g, uint8_t b) { | ||||
|       return pen.create(r, g, b); | ||||
|     } | ||||
| 
 | ||||
|     static constexpr RGB565 create_pen_rgb565(uint8_t r, uint8_t g, uint8_t b) { | ||||
|       uint16_t p = ((r & 0b11111000) << 8) | | ||||
|                    ((g & 0b11111100) << 3) | | ||||
|                    ((b & 0b11111000) >> 3); | ||||
| 
 | ||||
|       return __builtin_bswap16(p); | ||||
|     void set_pen(uint8_t r, uint8_t g, uint8_t b) { | ||||
|       pen.set_color(r, g, b); | ||||
|     } | ||||
|    | ||||
|     static constexpr RGB565 create_pen_rgb332(uint8_t r, uint8_t g, uint8_t b) { | ||||
|       uint16_t p = ((r & 0b11100000) << 8) | | ||||
|                    ((g & 0b11100000) << 3) | | ||||
|                    ((b & 0b11000000) >> 3); | ||||
| 
 | ||||
|       return __builtin_bswap16(p); | ||||
|     void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) { | ||||
|       pen.update_color(i, r, g, b); | ||||
|     } | ||||
| 
 | ||||
|     void reset_pen(uint8_t i) { | ||||
|       pen.reset_color(i); | ||||
|     } | ||||
| 
 | ||||
|     void set_dimensions(int width, int height) { | ||||
|  | @ -106,23 +302,16 @@ namespace pimoroni { | |||
|       clip.h = height; | ||||
|     } | ||||
| 
 | ||||
|     int create_pen(uint8_t r, uint8_t g, uint8_t b); | ||||
| 
 | ||||
|     int reserve_palette(); | ||||
|     void empty_palette(); | ||||
|     void rgb332_palette(); | ||||
| 
 | ||||
|     int search_palette(RGB565 c); | ||||
|     int get_palette(uint8_t i); | ||||
|     void set_palette(uint8_t i, RGB565 c); | ||||
|     int put_palette(RGB565 c); | ||||
| 
 | ||||
|     void set_clip(const Rect &r); | ||||
|     void remove_clip(); | ||||
| 
 | ||||
|     Pen* ptr(const Point &p); | ||||
|     Pen* ptr(const Rect &r); | ||||
|     Pen* ptr(int32_t x, int32_t y); | ||||
|     void* get_data() { | ||||
|       return frame_buffer; | ||||
|     } | ||||
| 
 | ||||
|     void get_data(uint y, void *row_buf) { | ||||
|       pen.palette_lookup(frame_buffer, row_buf, y * bounds.w, bounds.w); | ||||
|     } | ||||
| 
 | ||||
|     void clear(); | ||||
|     void pixel(const Point &p); | ||||
|  | @ -137,4 +326,9 @@ namespace pimoroni { | |||
|     void line(Point p1, Point p2); | ||||
|   }; | ||||
| 
 | ||||
|   template class PicoGraphics<PenP4>; | ||||
|   template class PicoGraphics<PenP8>; | ||||
|   template class PicoGraphics<PenRGB332>; | ||||
|   template class PicoGraphics<PenRGB565>; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -5,11 +5,5 @@ | |||
| 
 | ||||
| 
 | ||||
| namespace pimoroni { | ||||
|   void PicoGraphicsST7789::update() { | ||||
|     st7789.update(palette); | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphicsST7789::set_backlight(uint8_t brightness) { | ||||
|     st7789.set_backlight(brightness); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -6,42 +6,46 @@ | |||
| 
 | ||||
| namespace pimoroni { | ||||
| 
 | ||||
|   class PicoGraphicsST7789 : public PicoGraphics { | ||||
|   template <class T=PicoGraphicsPenType> | ||||
|   class PicoGraphicsST7789 : public PicoGraphics<T> { | ||||
|   private: | ||||
|     ST7789 st7789; | ||||
| 
 | ||||
|   public: | ||||
|     PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, bool round=false, void *frame_buffer=nullptr) : | ||||
|       PicoGraphics(width, height, frame_buffer), | ||||
|       PicoGraphics<T>(width, height, frame_buffer), | ||||
|       st7789(width, height, rotation, round, frame_buffer, get_spi_pins(BG_SPI_FRONT)) { | ||||
|               common_init(); | ||||
|            }; | ||||
| 
 | ||||
|     PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins bus_pins) : | ||||
|       PicoGraphics(width, height, frame_buffer), | ||||
|       PicoGraphics<T>(width, height, frame_buffer), | ||||
|       st7789(width, height, rotation, round, frame_buffer, bus_pins) { | ||||
|               common_init(); | ||||
|            }; | ||||
| 
 | ||||
|     PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins bus_pins) : | ||||
|       PicoGraphics(width, height, frame_buffer), | ||||
|       PicoGraphics<T>(width, height, frame_buffer), | ||||
|       st7789(width, height, rotation, frame_buffer, bus_pins) { | ||||
|               common_init(); | ||||
|            }; | ||||
| 
 | ||||
|     void common_init() { | ||||
|       this->frame_buffer = (Pen *)st7789.frame_buffer; | ||||
|       this->st7789.init(); | ||||
|       this->set_dimensions(this->st7789.width, this->st7789.height); | ||||
|       this->st7789.update(palette); | ||||
|       st7789.init(); | ||||
|       this->set_dimensions(st7789.width, st7789.height); | ||||
|       st7789.update(this); | ||||
|     } | ||||
| 
 | ||||
|     void update() { | ||||
|       st7789.update(this); | ||||
|     } | ||||
| 
 | ||||
|     void set_backlight(uint8_t brightness) { | ||||
|       st7789.set_backlight(brightness); | ||||
|     } | ||||
| 
 | ||||
|     void update(); | ||||
|     void set_backlight(uint8_t brightness); | ||||
|     void configure_display(bool rotate180); | ||||
|     void set_framebuffer(void* frame_buffer) { | ||||
|       this->frame_buffer = (Pen *)frame_buffer; | ||||
|       st7789.frame_buffer = frame_buffer; | ||||
|       this->frame_buffer = frame_buffer; | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -10,9 +10,8 @@ MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_backlight_obj, GenericST7789_set_bac | |||
| MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_framebuffer_obj, GenericST7789_set_framebuffer); | ||||
| 
 | ||||
| // Palette management
 | ||||
| MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_palette_mode_obj, GenericST7789_set_palette_mode); | ||||
| MP_DEFINE_CONST_FUN_OBJ_3(GenericST7789_set_palette_obj, GenericST7789_set_palette); | ||||
| MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_reserve_palette_obj, GenericST7789_reserve_palette); | ||||
| MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_update_pen_obj, 4, GenericST7789_update_pen); | ||||
| MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_reset_pen_obj, GenericST7789_reset_pen); | ||||
| 
 | ||||
| // Pen
 | ||||
| MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_pen_obj, GenericST7789_set_pen); | ||||
|  | @ -41,9 +40,8 @@ STATIC const mp_rom_map_elem_t GenericST7789_locals_dict_table[] = { | |||
|     { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&GenericST7789_set_pen_obj) }, | ||||
|     { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&GenericST7789_update_obj) }, | ||||
| 
 | ||||
|     { MP_ROM_QSTR(MP_QSTR_set_palette_mode), MP_ROM_PTR(&GenericST7789_set_palette_mode_obj) }, | ||||
|     { MP_ROM_QSTR(MP_QSTR_set_palette), MP_ROM_PTR(&GenericST7789_set_palette_obj) }, | ||||
|     { MP_ROM_QSTR(MP_QSTR_reserve_palette), MP_ROM_PTR(&GenericST7789_reserve_palette_obj) }, | ||||
|     { MP_ROM_QSTR(MP_QSTR_update_pen), MP_ROM_PTR(&GenericST7789_update_pen_obj) }, | ||||
|     { MP_ROM_QSTR(MP_QSTR_reset_pen), MP_ROM_PTR(&GenericST7789_reset_pen_obj) }, | ||||
| 
 | ||||
|     { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&GenericST7789_set_backlight_obj) }, | ||||
|     { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&GenericST7789_create_pen_obj) }, | ||||
|  |  | |||
|  | @ -4,7 +4,9 @@ | |||
| 
 | ||||
| #include "micropython/modules/util.hpp" | ||||
| 
 | ||||
| 
 | ||||
| #ifndef PICO_GRAPHICS_PEN_TYPE | ||||
| #define PICO_GRAPHICS_PEN_TYPE PenP4 | ||||
| #endif | ||||
| 
 | ||||
| using namespace pimoroni; | ||||
| 
 | ||||
|  | @ -14,7 +16,7 @@ extern "C" { | |||
| 
 | ||||
| typedef struct _GenericST7789_obj_t { | ||||
|     mp_obj_base_t base; | ||||
|     PicoGraphicsST7789 *st7789; | ||||
|     PicoGraphicsST7789<PICO_GRAPHICS_PEN_TYPE> *st7789; | ||||
|     void *buffer; | ||||
| } GenericST7789_obj_t; | ||||
| 
 | ||||
|  | @ -66,32 +68,34 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t | |||
|             break; | ||||
|     } | ||||
| 
 | ||||
|     size_t required_size = PICO_GRAPHICS_PEN_TYPE::buffer_size(width, height); | ||||
| 
 | ||||
|     if (args[ARG_buffer].u_obj != mp_const_none) { | ||||
|         mp_buffer_info_t bufinfo; | ||||
|         mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); | ||||
|         self->buffer = bufinfo.buf; | ||||
|         if(bufinfo.len < (size_t)(width * height * sizeof(Pen))) { | ||||
|         if(bufinfo.len < (size_t)(required_size)) { | ||||
|             mp_raise_ValueError("Supplied buffer is too small!"); | ||||
|         } | ||||
|     } else { | ||||
|         self->buffer = m_new(uint8_t, width * height * sizeof(Pen)); | ||||
|         self->buffer = m_new(uint8_t, required_size); | ||||
|     } | ||||
| 
 | ||||
|     if (display == DISPLAY_TUFTY_2040) { | ||||
|         if (args[ARG_bus].u_obj == mp_const_none) { | ||||
|             self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, self->buffer, {10, 11, 12, 13, 14, 2}); | ||||
|             self->st7789 = m_new_class(PicoGraphicsST7789<PICO_GRAPHICS_PEN_TYPE>, width, height, rotate, self->buffer, {10, 11, 12, 13, 14, 2}); | ||||
|         } else if (mp_obj_is_type(args[ARG_bus].u_obj, &ParallelPins_type)) { | ||||
|             _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj); | ||||
|             self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, self->buffer, *(ParallelPins *)(bus->pins)); | ||||
|             self->st7789 = m_new_class(PicoGraphicsST7789<PICO_GRAPHICS_PEN_TYPE>, width, height, rotate, self->buffer, *(ParallelPins *)(bus->pins)); | ||||
|         } else { | ||||
|             mp_raise_ValueError("ParallelBus expected!"); | ||||
|         } | ||||
|     } else { | ||||
|         if (args[ARG_bus].u_obj == mp_const_none) { | ||||
|             self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, round, self->buffer, get_spi_pins(BG_SPI_FRONT)); | ||||
|             self->st7789 = m_new_class(PicoGraphicsST7789<PICO_GRAPHICS_PEN_TYPE>, width, height, rotate, round, self->buffer, get_spi_pins(BG_SPI_FRONT)); | ||||
|         } else if (mp_obj_is_type(args[ARG_bus].u_obj, &SPIPins_type)) { | ||||
|             _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj); | ||||
|             self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, round, self->buffer, *(SPIPins *)(bus->pins)); | ||||
|             self->st7789 = m_new_class(PicoGraphicsST7789<PICO_GRAPHICS_PEN_TYPE>, width, height, rotate, round, self->buffer, *(SPIPins *)(bus->pins)); | ||||
|         } else { | ||||
|             mp_raise_ValueError("SPIBus expected!"); | ||||
|         } | ||||
|  | @ -146,7 +150,7 @@ mp_obj_t GenericST7789_set_backlight(mp_obj_t self_in, mp_obj_t brightness) { | |||
| } | ||||
| 
 | ||||
| mp_obj_t GenericST7789_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b) { | ||||
|     return mp_obj_new_int(PicoGraphicsST7789::create_pen_rgb332( | ||||
|     return mp_obj_new_int(PicoGraphicsPenType::rgb_to_rgb332( | ||||
|         mp_obj_get_int(r), | ||||
|         mp_obj_get_int(g), | ||||
|         mp_obj_get_int(b) | ||||
|  | @ -154,7 +158,7 @@ mp_obj_t GenericST7789_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b) { | |||
| } | ||||
| 
 | ||||
| mp_obj_t GenericST7789_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b) { | ||||
|     return mp_obj_new_int(PicoGraphicsST7789::create_pen_rgb565( | ||||
|     return mp_obj_new_int(PicoGraphicsPenType::rgb_to_rgb565( | ||||
|         mp_obj_get_int(r), | ||||
|         mp_obj_get_int(g), | ||||
|         mp_obj_get_int(b) | ||||
|  | @ -164,40 +168,44 @@ mp_obj_t GenericST7789_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b) { | |||
| mp_obj_t GenericST7789_set_pen(mp_obj_t self_in, mp_obj_t pen) { | ||||
|     GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); | ||||
| 
 | ||||
|     self->st7789->set_pen(mp_obj_get_int(pen) & 0xff); | ||||
|     self->st7789->set_pen(mp_obj_get_int(pen)); | ||||
| 
 | ||||
|     return mp_const_none; | ||||
| } | ||||
| 
 | ||||
| mp_obj_t GenericST7789_set_palette_mode(mp_obj_t self_in, mp_obj_t mode) { | ||||
| mp_obj_t GenericST7789_reset_pen(mp_obj_t self_in, mp_obj_t pen) { | ||||
|     GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); | ||||
| 
 | ||||
|     self->st7789->set_palette_mode((PicoGraphicsST7789::PaletteMode)mp_obj_get_int(mode)); | ||||
|     self->st7789->reset_pen(mp_obj_get_int(pen)); | ||||
| 
 | ||||
|     return mp_const_none; | ||||
| } | ||||
| 
 | ||||
| mp_obj_t GenericST7789_set_palette(mp_obj_t self_in, mp_obj_t index, mp_obj_t colour) { | ||||
|     GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); | ||||
| mp_obj_t GenericST7789_update_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { | ||||
|     enum { ARG_self, ARG_i, ARG_r, ARG_g, ARG_b }; | ||||
|     static const mp_arg_t allowed_args[] = { | ||||
|         { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, | ||||
|         { MP_QSTR_i, MP_ARG_REQUIRED | MP_ARG_INT }, | ||||
|         { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, | ||||
|         { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, | ||||
|         { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT } | ||||
|     }; | ||||
| 
 | ||||
|     self->st7789->set_palette( | ||||
|         mp_obj_get_int(index) & 0xff, | ||||
|         mp_obj_get_int(colour) & 0xffff | ||||
|     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; | ||||
|     mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); | ||||
| 
 | ||||
|     GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); | ||||
| 
 | ||||
|     self->st7789->update_pen( | ||||
|         args[ARG_i].u_int & 0xff, | ||||
|         args[ARG_r].u_int & 0xff, | ||||
|         args[ARG_g].u_int & 0xff, | ||||
|         args[ARG_b].u_int & 0xff | ||||
|     ); | ||||
| 
 | ||||
|     return mp_const_none; | ||||
| } | ||||
| 
 | ||||
| mp_obj_t GenericST7789_reserve_palette(mp_obj_t self_in) { | ||||
|     GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); | ||||
| 
 | ||||
|     int result = self->st7789->reserve_palette(); | ||||
| 
 | ||||
|     if (result == -1) mp_raise_ValueError("reserve_palette failed. No space in palette!"); | ||||
| 
 | ||||
|     return mp_obj_new_int(result); | ||||
| } | ||||
| 
 | ||||
| mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { | ||||
|     enum { ARG_self, ARG_r, ARG_g, ARG_b }; | ||||
|     static const mp_arg_t allowed_args[] = { | ||||
|  |  | |||
|  | @ -27,9 +27,8 @@ extern mp_obj_t GenericST7789_update(mp_obj_t self_in); | |||
| extern mp_obj_t GenericST7789_set_backlight(mp_obj_t self_in, mp_obj_t brightness); | ||||
| 
 | ||||
| // Palette management
 | ||||
| extern mp_obj_t GenericST7789_set_palette_mode(mp_obj_t self_in, mp_obj_t mode); | ||||
| extern mp_obj_t GenericST7789_set_palette(mp_obj_t self_in, mp_obj_t index, mp_obj_t colour); | ||||
| extern mp_obj_t GenericST7789_reserve_palette(mp_obj_t self_in); | ||||
| extern mp_obj_t GenericST7789_update_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); | ||||
| extern mp_obj_t GenericST7789_reset_pen(mp_obj_t self_in, mp_obj_t pen); | ||||
| 
 | ||||
| // Pen
 | ||||
| extern mp_obj_t GenericST7789_set_pen(mp_obj_t self_in, mp_obj_t pen); | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 Phil Howard
						Phil Howard