#pragma once #include #include "hardware/pio.h" #include "piomatter/pins.h" #include "piomatter/buffer_manager.h" #include "piomatter/render.h" #include "piomatter/matrixmap.h" #include "piomatter/protomatter.pio.h" namespace piomatter { constexpr size_t MAX_XFER = 65532; void pio_sm_xfer_data_large(PIO pio, int sm, int direction, size_t size, uint32_t *databuf) { while(size) { size_t xfersize = std::min(size_t{MAX_XFER}, size); int r = pio_sm_xfer_data(pio, sm, direction, xfersize, databuf); if (r) { throw std::runtime_error("pio_sm_xfer_data (reboot may be required)"); } size -= xfersize; databuf += xfersize / sizeof(*databuf); } } struct piomatter_base { virtual ~piomatter_base() {} virtual void show() = 0; }; template struct piomatter : piomatter_base { using buffer_type = std::vector; piomatter(std::span framebuffer, const matrix_geometry &geometry) : framebuffer(framebuffer), geometry{geometry}, converter{}, blitter_thread{&piomatter::blit_thread, this} { if (geometry.n_addr_lines > std::size(pinout::PIN_ADDR)) { throw std::runtime_error("too many address lines requested"); } program_init(); show(); } void show() override { int buffer_idx = manager.get_free_buffer(); auto &buffer = buffers[buffer_idx]; auto converted = converter.convert(framebuffer); protomatter_render_rgb10(buffer, geometry, converted.data()); manager.put_filled_buffer(buffer_idx); } ~piomatter() { if (pio != NULL && sm >= 0) { pin_deinit_one(pinout::PIN_OE); pin_deinit_one(pinout::PIN_CLK); pin_deinit_one(pinout::PIN_LAT); for(const auto p : pinout::PIN_RGB) pin_deinit_one(p); for(size_t i=0; i framebuffer; buffer_type buffers[3]; buffer_manager manager{}; matrix_geometry geometry; colorspace converter; std::thread blitter_thread; }; }