From ca385fca8b13f969744703e35da7d28f2e3ec526 Mon Sep 17 00:00:00 2001 From: Thomas Sommer Date: Tue, 3 Aug 2021 21:53:47 +0200 Subject: [PATCH] added reusable MonchromeReader --- src/modm/driver/display/ili9341.hpp | 65 ++++--- src/modm/driver/display/ili9341_impl.hpp | 165 ++++++++--------- .../driver/display/ili9341_interface_spi.hpp | 13 +- src/modm/driver/display/sh1106.hpp | 12 +- src/modm/driver/display/sh1106_impl.hpp | 41 +---- src/modm/driver/display/ssd1306.hpp | 14 +- src/modm/driver/display/ssd1306_impl.hpp | 31 +--- src/modm/ui/graphic/buffer.hpp | 32 ++-- src/modm/ui/graphic/buffer_bool.hpp | 18 +- src/modm/ui/graphic/buffer_bool_impl.hpp | 167 ++++++------------ src/modm/ui/graphic/buffer_impl.hpp | 127 ++++++------- src/modm/ui/graphic/buffer_interface.hpp | 15 +- src/modm/ui/graphic/canvas.hpp | 103 +++++++++-- src/modm/ui/graphic/display.hpp | 4 +- src/modm/ui/graphic/scanner.hpp | 91 ---------- 15 files changed, 363 insertions(+), 535 deletions(-) delete mode 100644 src/modm/ui/graphic/scanner.hpp diff --git a/src/modm/driver/display/ili9341.hpp b/src/modm/driver/display/ili9341.hpp index 82afcd87b0..3f14896e2f 100644 --- a/src/modm/driver/display/ili9341.hpp +++ b/src/modm/driver/display/ili9341.hpp @@ -53,12 +53,12 @@ class Ili9341 : public Interface, using ReadCommand = ili9341_register::ReadCommand; public: - using colorType = color::Rgb565; + using C = color::Rgb565; template Ili9341(Args &&...args) : Interface(std::forward(args)...), - Display, true>(color::html::White) + Display, true>(color::html::White) { Reset::setOutput(modm::Gpio::High); } ~Ili9341(){}; @@ -105,41 +105,31 @@ class Ili9341 : public Interface, // Write from Pattern (compiletime poly) template // FIXME Concept not accepted - but why? - // requires std::derived_from> + // requires std::derived_from> modm::ResumableResult writePattern(Rectangle rectangle, P pattern); - // Write equal colored Buffer (compiletime poly) - template + // Write equal colored BufferInterface modm::ResumableResult - writeBuffer(const Buffer &buffer, Point origin = {0, 0}); + writeBuffer(const BufferInterface *buffer, Point origin = {0, 0}); - // Write equal colored BufferInterface (runtime poly) + // Write different colored BufferInterface + template modm::ResumableResult - writeBuffer(const BufferInterface *buffer, Point origin = {0, 0}); + writeBuffer(const BufferInterface *buffer, Point origin = {0, 0}); - // Write different colored Buffer (compiletime poly) - template - modm::ResumableResult - writeBuffer(const Buffer &buffer, Point origin = {0, 0}); - - // Write monochrome Buffer (compiletime poly) - template - modm::ResumableResult - writeBuffer(const Buffer &buffer, Point origin = {0, 0}); - - // Write monochrome BufferInterface (runtime poly) + // Write monochrome BufferInterface modm::ResumableResult writeBuffer(const BufferInterface *buffer, Point origin = {0, 0}); - // Write monochrome Flash (runtime poly) + // Write monochrome Flash modm::ResumableResult writeFlash(modm::accessor::Flash data, uint16_t width, uint16_t height, Point origin = {0, 0}) final; // Clear whole screen with color modm::ResumableResult - clear(colorType color = html::Black); + clear(C color = html::Black); // ################################################################## // HACK Can't inherit modm::graphic::RemotePainter using RF @@ -159,6 +149,9 @@ class Ili9341 : public Interface, protected: modm::ResumableResult drawQuadPoints(Point center, Point point); +private: + // Static variables for resumable functions + Section section; // ################################################################## protected: @@ -181,10 +174,17 @@ class Ili9341 : public Interface, modm::ResumableResult drawFast(Section section); - modm::ResumableResult + modm::ResumableResult getFast(Point point) const; +private: // Static variables for resumable functions + void scannerNextRow() { + p.scanner.x++; + p.scanner.y = this->clipping.topLeft.y; + } + + // OPTIMIZE make a final check, if the union/struct/union is great enough union { // Buffers for commands & configuration uint8_t buff_cmd8[15]; @@ -194,24 +194,19 @@ class Ili9341 : public Interface, // Parallel use in resumable function: don't overlap! struct { - uint16_t buff_cmd_clipping[2]; - - // Primary Pixelbuffer - colorType buffer[BC]; - size_t buffer_i; + MonochromeReader mono_reader; // Helper to read monochrome data - size_t pixels_to_write, pixel_bulk; + C buffer[BC]; // Bulk buffer + size_t i; // Bulk buffer index + Point scanner; // display index - // Keep track of current position in - Point scanner; - ScannerBufferBool bool_scanner; + size_t pixels; // Pixels of whole transaction + size_t pixels_bulk; // Pixels of current bulk - colorType temp_color; + uint16_t buff_cmd_clipping[2]; + C temp_color; // Temporary storage for a color } p; // p for parallel }; - - // BUG Static variables for resumable functions RemotePainter - Section section; }; } // namespace modm diff --git a/src/modm/driver/display/ili9341_impl.hpp b/src/modm/driver/display/ili9341_impl.hpp index 98dddef51a..8ae8c02d5d 100644 --- a/src/modm/driver/display/ili9341_impl.hpp +++ b/src/modm/driver/display/ili9341_impl.hpp @@ -231,7 +231,7 @@ modm::Ili9341::updateClipping() RF_CALL(this->writeCommand(Command::ColumnAddressSet, (uint8_t *)(p.buff_cmd_clipping), 4)); RF_CALL(this->writeCommand(Command::MemoryWrite)); - p.pixels_to_write = this->clipping.getPixels(); + p.pixels = this->clipping.getPixels(); RF_END(); } @@ -248,111 +248,109 @@ modm::Ili9341::writePattern(Rectangle rectangle, P pattern p.scanner = this->clipping.topLeft; - while (p.pixels_to_write) + while (p.pixels) { // Generate next bulk - for(p.buffer_i = 0; p.buffer_i < std::min(p.pixels_to_write, BC); p.buffer_i++) { + for(p.i = 0; p.i < std::min(p.pixels, BC); p.i++) { // OPTIMIZE inefficient, cause pattern recalculates color for each pixel - // Let's investigate a solution - p.buffer[p.buffer_i] = pattern(p.scanner); - - // Update scanner + // even when it could already know, under withc conditions the return-value changes! + // Need some kind of caching!? + p.buffer[p.i] = pattern(p.scanner); + if (++p.scanner.y == this->clipping.bottomRight.y) { - p.scanner.x++; - p.scanner.y = this->clipping.topLeft.y; + scannerNextRow(); } } - // Transfer - RF_CALL(this->writeData((uint8_t *)(p.buffer), 2 * p.buffer_i)); - - p.pixels_to_write-= p.buffer_i; + RF_CALL(this->writeData(p.buffer, p.i)); + p.pixels-= p.i; } RF_END(); } -// -- Write equal colored Buffer ---------------------------------- +// -- Write equal colored BufferInterface ----------------------------- template -template modm::ResumableResult modm::Ili9341::writeBuffer( - const Buffer &buffer, Point origin) -{ + const BufferInterface *buffer, Point origin) { RF_BEGIN(); - this->clipping = this->getIntersection(Rectangle(origin, R_::asPoint())); + this->layout = buffer->getLayout(); + + this->clipping = this->getIntersection(Rectangle(origin, this->layout.size)); RF_CALL(updateClipping()); - // FIXME take this->clipping into account - RF_CALL(this->writeData(buffer.getPlainBuffer(), p.pixels_to_write * 2)); + // Add left offset + if(origin.x < 0) + this->layout.buffer += -origin.x * this->layout.size.y * 2; + + // Check if we exceed the display vertically + if (origin.y < 0 or origin.y + this->layout.size.y != this->clipping.bottomRight.y) + { + // Add top offset + if(origin.y < 0) + this->layout.buffer += -origin.y * 2; + + // Can't transfer buffer continuously, send row by row + p.pixels_bulk = this->clipping.getHeight(); + while(p.pixels) { + RF_CALL(this->writeData((C*)(this->layout.buffer), p.pixels_bulk)); + this->layout.buffer += this->layout.size.y * 2; + p.pixels -= p.pixels_bulk; + } + } else + { + // Transfer buffer continuously in one shot + RF_CALL(this->writeData((C*)(this->layout.buffer), p.pixels)); + } + RF_END(); } -// -- Write equal colored BufferInterface ----------------------------- +// -- Write different colored BufferInterface ----------------------------- template +template modm::ResumableResult modm::Ili9341::writeBuffer( - const BufferInterface *buffer, Point origin) { + const BufferInterface *buffer, Point origin) { RF_BEGIN(); - this->clipping = this->getIntersection(Rectangle(origin, buffer->getResolution())); + this->clipping = this->getIntersection(Rectangle(origin, this->layout.size)); RF_CALL(updateClipping()); - - // Reload scanner - p.bool_scanner = ScannerBufferBool(origin); - p.bool_scanner.print_top(); - p.bool_scanner.print_state(); RF_END(); } -// -- Write monochrome Buffer ----------------------------- +// -- Write monochrome BufferInterface ------------------- template -template modm::ResumableResult modm::Ili9341::writeBuffer( - const Buffer &buffer, Point origin) -{ + const BufferInterface *buffer, Point origin) { RF_BEGIN(); - // Reload scanner - p.bool_scanner = ScannerBufferBool(buffer.getPlainBuffer(), origin); - p.bool_scanner.print_top(); - - this->clipping = this->getIntersection(Rectangle(origin, R_::asPoint())); + this->layout = buffer->getLayout(); + this->clipping = this->getIntersection(Rectangle(origin, this->layout.size)); RF_CALL(updateClipping()); - while (p.pixels_to_write) + p.mono_reader = MonochromeReader(this->layout.buffer, this->layout.size.x, origin); + p.scanner = this->clipping.topLeft; + + while (p.pixels) { - p.temp_color = html::Red; - // Convert next Bulk - p.pixel_bulk = std::min(p.pixels_to_write, BC); - for(p.buffer_i = 0; p.buffer_i < p.pixel_bulk; p.buffer_i++) { - // p.bool_scanner.print_state(); - // p.buffer[p.buffer_i] = p.bool_scanner() ? color : colorType(html::Black); - p.temp_color.color++; - p.buffer[p.buffer_i] = p.temp_color; + for(p.i = 0; p.i < std::min(p.pixels, BC); p.i++) { + p.buffer[p.i] = p.mono_reader() ? color : C(html::Black); + if (++p.scanner.y == this->clipping.bottomRight.y) { + scannerNextRow(); + p.mono_reader.nextRow(); + } } - // Transfer - RF_CALL(this->writeData((uint8_t *)(p.buffer), 2 * p.pixel_bulk)); - p.pixels_to_write -= p.pixel_bulk; + RF_CALL(this->writeData(p.buffer, p.i)); + p.pixels -= p.i; } - RF_END(); -} -// -- Write monochrome BufferInterface ------------------- -template -modm::ResumableResult -modm::Ili9341::writeBuffer( - const BufferInterface *buffer, Point origin) { - RF_BEGIN(); - - MODM_LOG_DEBUG << __FUNCTION__ << modm::endl; - MODM_LOG_DEBUG << "origin: " << origin << ", resolution: " << buffer->getResolution() << modm::endl; - RF_END(); } @@ -363,20 +361,29 @@ modm::Ili9341::writeFlash(modm::accessor::Flash d uint16_t width, uint16_t height, Point origin) { RF_BEGIN(); - this->clipping = this->getIntersection(Rectangle(origin, Point(width, height))); + this->clipping = this->getIntersection(Rectangle(origin, {width, height})); RF_CALL(updateClipping()); - // Reload scanner - // p.bool_scanner = ScannerBufferBool(data, origin); - // p.bool_scanner.print_top(); - // p.bool_scanner.print_state(); - - (void)data; - (void)width; - (void)height; - (void)origin; + // FIXME MonochromeReader must learn to handle modm::accessor::Flash + // p.mono_reader = MonochromeReader(data, width, origin); + p.scanner = this->clipping.topLeft; + + while (p.pixels) + { + // Convert next Bulk + for(p.i = 0; p.i < std::min(p.pixels, BC); p.i++) { + // p.buffer[p.i] = p.mono_reader() ? color : C(html::Black); + if (++p.scanner.y == this->clipping.bottomRight.y) { + scannerNextRow(); + // p.mono_reader.nextRow(); + } + } + // Transfer + RF_CALL(this->writeData(p.buffer, p.i)); + p.pixels -= p.i; + } - RF_END(); + RF_END(); } // -- Draw primitive Shapes ------------------------------ @@ -421,21 +428,21 @@ modm::Ili9341::drawFast(Section section) // See https://github.com/modm-io/modm/issues/666 // Without DMA, at least this could be parallelised to updateClipping(..) above - p.pixel_bulk = std::min(BC, p.pixels_to_write); - std::fill(p.buffer, p.buffer + p.pixel_bulk, color); + p.pixels_bulk = std::min(BC, p.pixels); + std::fill(p.buffer, p.buffer + p.pixels_bulk, color); - while (p.pixels_to_write) + while (p.pixels) { - p.pixels_to_write -= p.pixel_bulk; - RF_CALL(this->writeData((uint8_t *)(p.buffer), 2 * p.pixel_bulk)); - p.pixel_bulk = std::min(BC, p.pixels_to_write); + p.pixels -= p.pixels_bulk; + RF_CALL(this->writeData(p.buffer, p.pixels_bulk)); + p.pixels_bulk = std::min(BC, p.pixels); } RF_END(); } template modm::ResumableResult -modm::Ili9341::clear(colorType color) +modm::Ili9341::clear(C color) { // OPTIMIZE Make this impossible fast through use of DMA // See https://github.com/modm-io/modm/issues/666 diff --git a/src/modm/driver/display/ili9341_interface_spi.hpp b/src/modm/driver/display/ili9341_interface_spi.hpp index fd7d2df8c9..a45e388498 100644 --- a/src/modm/driver/display/ili9341_interface_spi.hpp +++ b/src/modm/driver/display/ili9341_interface_spi.hpp @@ -98,14 +98,14 @@ class Ili9341InterfaceSpi : public ili9341_register, public modm::SpiDevice< Spi } modm::ResumableResult - writeData(const uint8_t *data, size_t length) + writeData(const color::Rgb565 *pixels, size_t length) { RF_BEGIN(); RF_WAIT_UNTIL(this->acquireMaster()); Cs::reset(); - RF_CALL(SpiMaster::transfer(data, nullptr, length)); + RF_CALL(SpiMaster::transfer((uint8_t*)(pixels), nullptr, 2 * length)); if (this->releaseMaster()) Cs::set(); @@ -113,20 +113,15 @@ class Ili9341InterfaceSpi : public ili9341_register, public modm::SpiDevice< Spi RF_END(); } - // OPTIMIZE optimal implementation? modm::ResumableResult - writeData(color::Rgb565 rgb565) + writeData(color::Rgb565 pixel) { RF_BEGIN(); RF_WAIT_UNTIL(this->acquireMaster()); Cs::reset(); - RF_CALL(SpiMaster::transfer((uint8_t*)(&rgb565.color), nullptr, 2)); - - // Alternative - // RF_CALL(SpiMaster::transfer(rgb565.color >> 8)); - // RF_CALL(SpiMaster::transfer(rgb565.color & 0xFF)); + RF_CALL(SpiMaster::transfer((uint8_t*)(&pixel), nullptr, 2)); if (this->releaseMaster()) Cs::set(); diff --git a/src/modm/driver/display/sh1106.hpp b/src/modm/driver/display/sh1106.hpp index ff3ab51a64..83dc6b8214 100644 --- a/src/modm/driver/display/sh1106.hpp +++ b/src/modm/driver/display/sh1106.hpp @@ -33,20 +33,14 @@ template class Sh1106 : public Ssd1306 { public: - using colorType = Ssd1306::colorType; + using C = Ssd1306::C; Sh1106(uint8_t address = 0x3C) : Ssd1306(address) {} - // Write monochrome Buffer via BufferInterface + // Write monochrome BufferInterface // Caution: origin.y rounds to multiples of 8 modm::ResumableResult - writeBuffer(const BufferInterface *buffer, Point origin = {0, 0}); - - // Write monochrome Buffer - // Caution: origin.y rounds to multiples of 8 - template - modm::ResumableResult - writeBuffer(const Buffer &buffer, Point origin = {0, 0}); + writeBuffer(const BufferInterface *buffer, Point origin = {0, 0}); protected: modm::ResumableResult diff --git a/src/modm/driver/display/sh1106_impl.hpp b/src/modm/driver/display/sh1106_impl.hpp index a379b65dfc..87976e6ce5 100644 --- a/src/modm/driver/display/sh1106_impl.hpp +++ b/src/modm/driver/display/sh1106_impl.hpp @@ -46,10 +46,12 @@ modm::Sh1106::updateClipping() template modm::ResumableResult -modm::Sh1106::writeBuffer(const BufferInterface *buffer, Point origin) { +modm::Sh1106::writeBuffer(const BufferInterface *buffer, Point origin) { RF_BEGIN(); - this->clipping = Rectangle(origin, buffer->getResolution()); + this->layout = buffer->getLayout(); + // IMPLEMENT method with getIntersection() + this->clipping = Rectangle(origin, this->layout.size); if (this->pointInCanvas(this->clipping.bottomRight - Point(1, 1))) { @@ -63,7 +65,7 @@ modm::Sh1106::writeBuffer(const BufferInterface *buffer this->commandBuffer[2] = ssd1306::AdressingCommands::PageStartAddress | yd; this->transaction_success &= RF_CALL(this->writeCommands(3)); - RF_WAIT_UNTIL(this->transaction.configureDisplayWrite(buffer.getPlainBuffer() + (buffer->getResolution().x * yb++), buffer->getResolution())); + RF_WAIT_UNTIL(this->transaction.configureDisplayWrite(this->layout.buffer + (this->clipping.getWidth() * yb++), this->clipping.getWidth())); RF_WAIT_UNTIL(this->startTransaction()); RF_WAIT_WHILE(this->isTransactionRunning()); this->transaction_success &= this->wasTransactionSuccessful(); @@ -73,37 +75,4 @@ modm::Sh1106::writeBuffer(const BufferInterface *buffer this->transaction_success = false; } RF_END_RETURN(this->transaction_success); -} - -template -template -modm::ResumableResult -modm::Sh1106::writeBuffer(const Buffer &buffer, Point origin) -{ - RF_BEGIN(); - - this->clipping = Rectangle(origin, R_::asPoint()); - - if (this->pointInCanvas(this->clipping.bottomRight - Point(1, 1))) - { - RF_CALL(updateClipping()); - - this->transaction_success = true; - yb = 0; - - for (yd = yd_start; yd <= yd_end; yd++) - { - this->commandBuffer[2] = ssd1306::AdressingCommands::PageStartAddress | yd; - this->transaction_success &= RF_CALL(this->writeCommands(3)); - - RF_WAIT_UNTIL(this->transaction.configureDisplayWrite( - buffer.getPlainBuffer() + (R_::W * yb++), R_::W)); - RF_WAIT_UNTIL(this->startTransaction()); - RF_WAIT_WHILE(this->isTransactionRunning()); - this->transaction_success &= this->wasTransactionSuccessful(); - }; - } else { - this->transaction_success = false; - } - RF_END_RETURN(this->transaction_success); } \ No newline at end of file diff --git a/src/modm/driver/display/ssd1306.hpp b/src/modm/driver/display/ssd1306.hpp index 70724e493c..6de5d27aff 100644 --- a/src/modm/driver/display/ssd1306.hpp +++ b/src/modm/driver/display/ssd1306.hpp @@ -98,7 +98,7 @@ class Ssd1306 : public ssd1306, { static_assert((H == 64) or (H == 32), "Display height must be either 32 or 64 pixel!"); public: - using colorType = bool; + using C = bool; Ssd1306(uint8_t address = 0x3C) : Display, false>(true), I2cDevice(address) @@ -158,20 +158,14 @@ class Ssd1306 : public ssd1306, return writeCommands(1); } - // Write monochrome Buffer via BufferInterface + // Write monochrome BufferInterface // Caution: origin.y rounds to multiples of 8 modm::ResumableResult - writeBuffer(const BufferInterface *buffer, Point origin = {0, 0}); - - // Write monochrome Buffer - // Caution: origin.y rounds to multiples of 8 - template - modm::ResumableResult - writeBuffer(const Buffer &buffer, Point origin = {0, 0}); + writeBuffer(const BufferInterface *buffer, Point origin = {0, 0}); // Clear whole screen with color modm::ResumableResult - clear(colorType color = false); + clear(C color = false); protected: virtual modm::ResumableResult diff --git a/src/modm/driver/display/ssd1306_impl.hpp b/src/modm/driver/display/ssd1306_impl.hpp index a00bf9968b..f716d109cf 100644 --- a/src/modm/driver/display/ssd1306_impl.hpp +++ b/src/modm/driver/display/ssd1306_impl.hpp @@ -171,16 +171,18 @@ modm::ResumableResult modm::Ssd1306::writeBuffer(const BufferInterface *buffer, Point origin) { RF_BEGIN(); - this->clipping = Rectangle(origin, buffer->getResolution()); + this->layout = buffer->getLayout(); + this->clipping = Rectangle(origin, this->layout.size); - if(!this->pointInCanvas(this->bottom_right - Point(1, 1))) { + if(!this->pointInCanvas(this->clipping.bottomRight - Point(1, 1))) { MODM_LOG_ERROR << "buffer exceeds display border in " << __FUNCTION__ << modm::endl; RF_RETURN(false); } RF_CALL(updateClipping()); - RF_WAIT_UNTIL(this->transaction.configureDisplayWrite(buffer->getPlainBuffer(), buffer->getResolution().x * buffer->getResolution().y / 8)); + // FIXME Integrate this->clipping results + RF_WAIT_UNTIL(this->transaction.configureDisplayWrite(this->layout.buffer, this->clipping->getPixels() / 8)); this->startTransaction(); RF_WAIT_WHILE(this->isTransactionRunning()); @@ -188,31 +190,10 @@ modm::Ssd1306::writeBuffer(const BufferInterface *buffer, Po RF_END_RETURN(this->wasTransactionSuccessful()); } -template -template -modm::ResumableResult -modm::Ssd1306::writeBuffer(const Buffer &buffer, Point origin) -{ - RF_BEGIN(); - - this->clipping = Rectangle(origin, R_::asPoint()); - - if (this->clipping.bottomRight.x <= 128 && this->clipping.bottomRight.y <= H + 7) - { - RF_CALL(updateClipping()); - - RF_WAIT_UNTIL(this->transaction.configureDisplayWrite(buffer.getPlainBuffer(), R_::W * R_::H / 8)); - this->startTransaction(); - RF_WAIT_WHILE(this->isTransactionRunning()); - } - - RF_END_RETURN(this->wasTransactionSuccessful()); -} - // TODO Test in Hardware template modm::ResumableResult -modm::Ssd1306::clear(colorType color) +modm::Ssd1306::clear(C color) { // OPTIMIZE Make this impossible fast through use of DMA // See https://github.com/modm-io/modm/issues/666 diff --git a/src/modm/ui/graphic/buffer.hpp b/src/modm/ui/graphic/buffer.hpp index 12cc2e0a5d..fb5bc2f144 100644 --- a/src/modm/ui/graphic/buffer.hpp +++ b/src/modm/ui/graphic/buffer.hpp @@ -44,19 +44,19 @@ class Buffer : public BufferInterface, public Painter, public TextPainter // Construct from colored buffer of same size template - Buffer(const Buffer &other) + constexpr Buffer(const Buffer &other) : BufferInterface(other.color) { copyBufferFast(other); } // Construct from colored buffer of different size template - Buffer(const Buffer &other) + constexpr Buffer(const Buffer &other) : BufferInterface(other.color) { writeBuffer(other); } // Construct from monochrome Buffer of same size template - Buffer(const Buffer &other) + constexpr Buffer(const Buffer &other) : BufferInterface(html::White) { writeBuffer(other); } @@ -87,25 +87,23 @@ class Buffer : public BufferInterface, public Painter, public TextPainter } /** - * Write colored buffer + * Write colored BufferInterface * * @param other Other colored buffer * @param origin top left corner to copy to */ - template + template void - writeBuffer(const Buffer &other, shape::Point origin = {0, 0}); + writeBuffer(const BufferInterface *other, Point origin = {0, 0}); /** - * Write monochrome Buffer + * Write monochrome BufferInterface * * @param other Other monochrome Buffer * @param origin top left corner to copy to */ - template void - writeBuffer(const Buffer &other, - shape::Point origin = {0, 0}); + writeBuffer(const BufferInterface *other, Point origin = {0, 0}); /** * Write monochrome Flash image @@ -115,17 +113,15 @@ class Buffer : public BufferInterface, public Painter, public TextPainter */ void writeFlash(modm::accessor::Flash data, uint16_t width, uint16_t height, - shape::Point origin = {0, 0}) final; + Point origin = {0, 0}) final; void clear(C color = html::Black); void invert(); - uint8_t* getPlainBuffer() const final - { return (uint8_t*)(buffer); } - - Point getResolution() const final - { return R::asPoint(); } + BufferLayout + getLayout() const final + { return {(uint8_t*)(buffer), R::asPoint()}; } protected: C buffer[R::W][R::H]; @@ -139,7 +135,7 @@ class Buffer : public BufferInterface, public Painter, public TextPainter void drawFast(VLine vline) final; void drawFast(Section section) final; - bool getFast(shape::Point point) const + bool getFast(Point point) const { return buffer[point.x][point.y]; } private: @@ -147,7 +143,7 @@ class Buffer : public BufferInterface, public Painter, public TextPainter void copyBufferFast(const Buffer &other); - template + template friend class Buffer; }; } // namespace modm diff --git a/src/modm/ui/graphic/buffer_bool.hpp b/src/modm/ui/graphic/buffer_bool.hpp index 1a8b1b8083..ff15128395 100644 --- a/src/modm/ui/graphic/buffer_bool.hpp +++ b/src/modm/ui/graphic/buffer_bool.hpp @@ -41,22 +41,22 @@ class Buffer : public BufferInterface, public Painter, p // Construct from monochrome Buffer with same size template - Buffer(const Buffer &other) + constexpr Buffer(const Buffer &other) { copyBufferFast(other); } // Construct from monochrome Buffer with different size template - Buffer(const Buffer &other) + constexpr Buffer(const Buffer &other) { writeBuffer(other); } - // Draw monochrome Buffer with different size - template + // Write monochrome BufferInterface void - writeBuffer(const Buffer &other, + writeBuffer(const BufferInterface *other, shape::Point origin = {0, 0}); // IMPLEMENT Buffer copy and assignment constructors + // Write monochrome Flash void writeFlash(modm::accessor::Flash data, uint16_t width, uint16_t height, shape::Point origin = {0, 0}) final; @@ -68,11 +68,9 @@ class Buffer : public BufferInterface, public Painter, p void invert(); - Point getResolution() const final - { return R::asPoint(); } - - uint8_t* getPlainBuffer() const final - { return (uint8_t*)(buffer); } + BufferLayout + getLayout() const final + { return {(uint8_t*)(buffer), R::asPoint()}; } // ################################## // # Experimental Features diff --git a/src/modm/ui/graphic/buffer_bool_impl.hpp b/src/modm/ui/graphic/buffer_bool_impl.hpp index 71a21b9066..fb8e18ea10 100644 --- a/src/modm/ui/graphic/buffer_bool_impl.hpp +++ b/src/modm/ui/graphic/buffer_bool_impl.hpp @@ -28,136 +28,56 @@ using namespace modm::shape; namespace modm::graphic { -// Copy monochrome Buffer of same size -template -template -void -Buffer::copyBufferFast(const Buffer &other) -{ - size_t yb = 0; - size_t x = 0; - while (yb < R::H / 8) - { - while (x < R::W) - { - buffer[yb][x] = other.buffer[yb][x]; - x++; - } - x = 0; - yb++; - } -} - +// Write monochrome BufferInterface template -template void -Buffer::writeBuffer(const Buffer &other, shape::Point origin) +Buffer::writeBuffer(const BufferInterface *other, Point origin) { - const shape::Section intersection = this->getIntersection(Rectangle(origin, R_::asPoint())); - - // TODO may be required - // if(intersection.getPixels() == 0) return; - - const size_t yb_min = intersection.topLeft.y / 8; - size_t yb_max = (intersection.bottomRight.y - 1) / 8; - - /* shape::Point dataTopLeft = this->getSourceOrigin(origin); - size_t i_start = dataTopLeft.x + (dataTopLeft.y / 8) * width; - - if (origin.y % 8) - { - // Split bytes, shift and glue together + BufferLayout layout = other->getLayout(); + const Section clipping = this->getIntersection(Rectangle(origin, layout.size)); - if(intersection.bottomRight.y == int16_t(R::H)) yb_max++; - const uint8_t lshift_upper = origin.y & 0b111; - const uint8_t rshift_lower = 8 - lshift_upper; + //#region[monochrome_reader] - for (int16_t x = intersection.topLeft.x; x < intersection.bottomRight.x; x++) - { - size_t i = i_start++; - size_t yb = yb_min; + const size_t yb_min = clipping.topLeft.y / 8; + size_t yb_max = (clipping.bottomRight.y - 1) / 8; - if (intersection.topLeft.y > 0) - { - // if(x == intersection.topLeft.x) MODM_LOG_DEBUG << "t"; - // Preserve existing pixels on top - this->buffer[yb][x] &= 0xFF >> rshift_lower; - this->buffer[yb][x] |= data[i] << lshift_upper; - yb++; - } - while (yb < yb_max) - { - // if(x == intersection.topLeft.x) MODM_LOG_DEBUG << "m"; - this->buffer[yb][x] = data[i] >> rshift_lower; - i += width; - this->buffer[yb][x] |= data[i] << lshift_upper; - yb++; - } - if (intersection.bottomRight.y < int16_t(R::H)) - { - // if(x == intersection.topLeft.x) MODM_LOG_DEBUG << "b"; - // Preserve existing pixels on bottom - this->buffer[yb][x] &= 0xFF << lshift_upper; - this->buffer[yb][x] |= data[i] >> rshift_lower; - } - } - } else if (intersection.topLeft.y < intersection.bottomRight.y) - { - // Copy data to buffer as is - for (int16_t x = intersection.topLeft.x; x < intersection.bottomRight.x; x++) - { - size_t i = i_start++; - size_t yb = yb_min; - while (yb < yb_max) - { - // if(x == intersection.topLeft.x) MODM_LOG_DEBUG << "c"; - this->buffer[yb][x] = data[i]; - i += width; - yb++; - } - // if(x == intersection.topLeft.x) MODM_LOG_DEBUG << "c+"; + Point dataTopLeft = this->getSourceOrigin(origin); + size_t i_start = (dataTopLeft.y / 8) * layout.size.x + dataTopLeft.x; + //#endregion - // Preserve existing pixels on bottom - this->buffer[yb][x] &= 0xFF << (intersection.bottomRight.y % 8); - // Unused bits not set. No need to mask out end from data - // this->buffer[yb][x] |= data[i] & (0xFF >> (8 - (intersection.bottomRight.y % - 8))); this->buffer[yb][x] |= data[i]; - } - } */ + // ... same like writeFlash ... } -// ------------------------------------------------------------ - +// Write monochrome Flash template void Buffer::writeFlash(modm::accessor::Flash data, uint16_t width, - uint16_t height, shape::Point origin) + uint16_t height, Point origin) { - const Section intersection = this->getIntersection(Rectangle(origin, Point(width, height))); + const Section clipping = this->getIntersection(Rectangle(origin, {width, height})); - // TODO may be required - // if(intersection.getPixels() == 0) return; + //#region[monochrome_reader] + const size_t yb_min = clipping.topLeft.y / 8; + size_t yb_max = (clipping.bottomRight.y - 1) / 8; - const size_t yb_min = intersection.topLeft.y / 8; - size_t yb_max = (intersection.bottomRight.y - 1) / 8; - - shape::Point dataTopLeft = this->getSourceOrigin(origin); - size_t i_start = dataTopLeft.x + (dataTopLeft.y / 8) * width; + Point dataTopLeft = this->getSourceOrigin(origin); + size_t i_start = (dataTopLeft.y / 8) * width + dataTopLeft.x; + //#endregion if (origin.y % 8) { - // Split bytes, shift and glue together - if (intersection.bottomRight.y == int16_t(R::H)) yb_max++; + // Split bytes, shift and reassembly + if (clipping.bottomRight.y == int16_t(R::H)) yb_max++; const uint8_t lshift_upper = origin.y & 0b111; const uint8_t rshift_lower = 8 - lshift_upper; if(color) { - for (int16_t x = intersection.topLeft.x; x < intersection.bottomRight.x; x++) + for (int16_t x = clipping.topLeft.x; x < clipping.bottomRight.x; x++) { size_t i = i_start++; size_t yb = yb_min; - if (intersection.topLeft.y > 0) + if (clipping.topLeft.y > 0) { this->buffer[yb][x] |= data[i] << lshift_upper; yb++; @@ -169,16 +89,16 @@ Buffer::writeFlash(modm::accessor::Flash data, uint16 this->buffer[yb][x] |= data[i] << lshift_upper; yb++; } - if (intersection.bottomRight.y < int16_t(R::H)) + if (clipping.bottomRight.y < int16_t(R::H)) this->buffer[yb][x] |= data[i] >> rshift_lower; } } else { - for (int16_t x = intersection.topLeft.x; x < intersection.bottomRight.x; x++) + for (int16_t x = clipping.topLeft.x; x < clipping.bottomRight.x; x++) { size_t i = i_start++; size_t yb = yb_min; - if (intersection.topLeft.y > 0) + if (clipping.topLeft.y > 0) { this->buffer[yb][x] &= ~(data[i] << lshift_upper); yb++; @@ -190,15 +110,15 @@ Buffer::writeFlash(modm::accessor::Flash data, uint16 this->buffer[yb][x] &= ~(data[i] << lshift_upper); yb++; } - if (intersection.bottomRight.y < int16_t(R::H)) + if (clipping.bottomRight.y < int16_t(R::H)) this->buffer[yb][x] &= ~(data[i] >> rshift_lower); } } - } else if (intersection.topLeft.y < intersection.bottomRight.y) + } else if (clipping.topLeft.y < clipping.bottomRight.y) { - // Write data to buffer as is + // Copy bytes as they are if(color) { - for (int16_t x = intersection.topLeft.x; x < intersection.bottomRight.x; x++) + for (int16_t x = clipping.topLeft.x; x < clipping.bottomRight.x; x++) { size_t i = i_start++; size_t yb = yb_min; @@ -212,7 +132,7 @@ Buffer::writeFlash(modm::accessor::Flash data, uint16 this->buffer[yb][x] |= data[i]; } } else { - for (int16_t x = intersection.topLeft.x; x < intersection.bottomRight.x; x++) + for (int16_t x = clipping.topLeft.x; x < clipping.bottomRight.x; x++) { size_t i = i_start++; size_t yb = yb_min; @@ -229,6 +149,26 @@ Buffer::writeFlash(modm::accessor::Flash data, uint16 } } +// Copy monochrome Buffer of same size +template +template +void +Buffer::copyBufferFast(const Buffer &other) +{ + size_t yb = 0; + size_t x = 0; + while (yb < R::H / 8) + { + while (x < R::W) + { + buffer[yb][x] = other.buffer[yb][x]; + x++; + } + x = 0; + yb++; + } +} + template void Buffer::drawFast(Point point) @@ -249,7 +189,6 @@ Buffer::drawFast(HLine hline) size_t x = hline.start.x; - // OPTIMIZE Switch color in LocalPainter ? if(color) while (x < hline.end_x) buffer[yb][x++] |= byte; @@ -265,7 +204,6 @@ Buffer::drawFast(VLine vline) size_t yb = vline.start.y / 8; const size_t yb_max = vline.end_y / 8; - // OPTIMIZE Switch color in LocalPainter ? if (color) { uint8_t byte = 0xFF << vline.start.y % 8; // Mask out top end @@ -301,7 +239,6 @@ Buffer::drawFast(Section section) const size_t yb_max = section.bottomRight.y / 8; size_t yb = section.topLeft.y / 8; - // OPTIMIZE Switch color in LocalPainter if (color) { uint8_t byte = 0xFF << section.topLeft.y % 8; // Mask out top end diff --git a/src/modm/ui/graphic/buffer_impl.hpp b/src/modm/ui/graphic/buffer_impl.hpp index 1e011fc00b..7cb5d811b6 100644 --- a/src/modm/ui/graphic/buffer_impl.hpp +++ b/src/modm/ui/graphic/buffer_impl.hpp @@ -28,123 +28,104 @@ using namespace modm::shape; namespace modm::graphic { -// Copy buffer of same size -template -template -void -Buffer::copyBufferFast( - const Buffer &other) -{ - Point scanner{0, 0}; - while(scanner.y < R::H) { - while(scanner.x < R::W) { - setPixelFast(scanner, other.getPixelFast(scanner)); - scanner.x++; - } - scanner.x = 0; - scanner.y++; - } -} - -// Write buffer (of different size) to position +// Write colored BufferInterface template -template +template void Buffer::writeBuffer( - const Buffer &other, const Point origin) + const BufferInterface *other, const Point origin) { - const Section intersection = this->getIntersection(Rectangle(origin, R_::asPoint())); + const Section clipping = this->getIntersection(Rectangle(origin, other->getSize())); const Point otherTopLeft = this->getSourceOrigin(origin); - Point scanner = intersection.topLeft; + Point scanner = clipping.topLeft; Point scannerOther = otherTopLeft; - while (scanner.x < intersection.bottomRight.x) + while (scanner.x < clipping.bottomRight.x) { - while (scanner.y < intersection.bottomRight.y) + while (scanner.y < clipping.bottomRight.y) { - setPixelFast(scanner, other.getPixelFast(scannerOther)); + drawFast(scanner, other.getPixelFast(scannerOther)); scanner.y++; scannerOther.y++; } scanner.x++; - scanner.y = intersection.topLeft.y; + scanner.y = clipping.topLeft.y; scannerOther.x++; scannerOther.y = otherTopLeft.y; } } -// Write monochrome Buffer (of different size) to position +// Write monochrome BufferInterface template -template void Buffer::writeBuffer( - const Buffer &other, const Point origin) + const BufferInterface *other, const Point origin) { - // BUG Crashes when using this->getIntersection(..) - // Calculate start conditions - const Section intersection = this->BUGGYgetIntersection(Rectangle(origin, R_::asPoint())); - const Point otherTopLeft = this->getSourceOrigin(origin); - const uint8_t bit_top = std::rotl(Bit0, otherTopLeft.y % 8); - const size_t yb_other_top = otherTopLeft.y / 8; + BufferLayout layout = other->getLayout(); + const Section clipping = this->getIntersection(Rectangle(origin, layout.size)); + + MonochromeReader mono_reader(layout.buffer, layout.size.x, origin); + Point scanner = clipping.topLeft; - Point scanner = intersection.topLeft; - size_t x_other = otherTopLeft.x; - - while (scanner.x < intersection.bottomRight.x) + while (scanner.x < clipping.bottomRight.x) { - // Reset to first other row - uint8_t bit = bit_top; - size_t yb_other = yb_other_top; - while (scanner.y < intersection.bottomRight.y) - { - auto pixel = other.buffer[yb_other][x_other] & bit ? this->color : C(html::Black); - buffer[scanner.x][scanner.y] = pixel; + while (scanner.y < clipping.bottomRight.y) { + if(mono_reader()) drawFast(scanner); scanner.y++; - - // Increment other row - bit = std::rotl(bit, 1); - if (bit == Bit0) yb_other++; } + scanner.x++; - scanner.y = intersection.topLeft.y; - - // Increment other column - x_other++; + mono_reader.nextRow(); + scanner.y = clipping.topLeft.y; } } -// --------------------------------------------------- - +// Write monochrome Flash template void Buffer::writeFlash(modm::accessor::Flash data, uint16_t width, uint16_t height, Point origin) { - const Section intersection = this->getIntersection(Rectangle(origin, Point(width, height))); - - // TODO maybe a good thing - //if(intersection.getPixels() == 0) return; + const Section clipping = this->getIntersection(Rectangle(origin, {width, height})); - const Point dataTopLeft = this->getSourceOrigin(origin); - size_t byte_top = dataTopLeft.x + (dataTopLeft.y / 8) * width; - const uint8_t bit_top = std::rotl(Bit0, dataTopLeft.y % 8); + // FIXME MonochromeReader must learn to handle modm::accessor::Flash + // MonochromeReader mono_reader(data, width, origin); + Point scanner = clipping.topLeft; - for (int16_t x = intersection.topLeft.x; x < intersection.bottomRight.x; x++) + while (scanner.x < clipping.bottomRight.x) { - size_t byte = byte_top++; - uint8_t bit = bit_top; - for (int16_t y = intersection.topLeft.y; y < intersection.bottomRight.y; y++) - { - this->setPixelFast({x, y}, data[byte] & bit); + while (scanner.y < clipping.bottomRight.y) { + // if(mono_reader()) drawFast(scanner); + scanner.y++; + } + + scanner.x++; + // mono_reader.nextRow(); + scanner.y = clipping.topLeft.y; + } +} - bit = std::rotl(bit, 1); - if (bit == Bit0) byte += width; +// Copy buffer of same size +template +template +void +Buffer::copyBufferFast( + const Buffer &other) +{ + Point scanner{0, 0}; + while(scanner.y < R::H) { + while(scanner.x < R::W) { + drawFast(scanner, other.getPixelFast(scanner)); + scanner.x++; } + scanner.x = 0; + scanner.y++; } } + template void Buffer::drawFast(Point point) @@ -183,7 +164,7 @@ Buffer::drawFast(Section section) while (index.x < section.bottomRight.x) { - this->draw(VLine{index, length}); + this->drawFast(VLine(index, length)); index.x++; } } diff --git a/src/modm/ui/graphic/buffer_interface.hpp b/src/modm/ui/graphic/buffer_interface.hpp index a4898dd891..1c9b732521 100644 --- a/src/modm/ui/graphic/buffer_interface.hpp +++ b/src/modm/ui/graphic/buffer_interface.hpp @@ -7,17 +7,22 @@ namespace modm::graphic { + +// contains all needed, to copy or transfer buffers +struct BufferLayout { + uint8_t* buffer; + shape::Point size; +}; + template class BufferInterface { public: C color; - virtual shape::Point - getResolution() const = 0; - - virtual uint8_t* - getPlainBuffer() const = 0; + // All in the box, single vtable-lookup + virtual BufferLayout + getLayout() const = 0; protected: BufferInterface(C color) : color(color) {}; diff --git a/src/modm/ui/graphic/canvas.hpp b/src/modm/ui/graphic/canvas.hpp index 1eba645225..be2227dd2b 100644 --- a/src/modm/ui/graphic/canvas.hpp +++ b/src/modm/ui/graphic/canvas.hpp @@ -13,6 +13,10 @@ #include "../shape.hpp" +#include + +#include + using namespace modm::shape; namespace modm::graphic @@ -58,9 +62,6 @@ class Canvas constexpr uint32_t getPixels() const { return R::Pixels; } - // OPTIMIZE All of the following getters could be constexpr - // if Point could be constructed as constexpr - // Ther could be even modm::clamp(Point a, Point b, Point c); constexpr Section getIntersection(Section section) { return {{ @@ -73,18 +74,6 @@ class Canvas }}; } - constexpr Section - BUGGYgetIntersection(Section section) { - return {{ - std::clamp(section.topLeft.x, 0, R::W), - std::clamp(section.topLeft.y, 0, R::H) - }, - { - std::clamp(section.bottomRight.x, 0, R::W), - std::clamp(section.bottomRight.y, 0, R::H) - }}; - } - protected: static constexpr Point getSourceOrigin(Point origin) { @@ -94,16 +83,94 @@ class Canvas }; } - bool + constexpr bool xInCanvas(int16_t x) const { return x >= 0 and x < int16_t(getWidth()); } - bool + constexpr bool yInCanvas(int16_t y) const { return y >= 0 and y < int16_t(getHeight()); } - bool + constexpr bool pointInCanvas(Point position) const { return xInCanvas(position.x) and yInCanvas(position.y); } }; + +// Scanner for monochrome Image data +// Applied to convert Buffer or Flash to regular Bitmap + +//#region[monochrome_reader] +class MonochromeReader +{ + uint8_t* buffer; + size_t buffer_width; + + // Buffer vertical origin + size_t ybyte_top; + uint8_t ybit_top; + + // State + size_t x, ybyte; + uint8_t ybit; + +public: + MonochromeReader& + operator=(const MonochromeReader&) = default; + + constexpr MonochromeReader(uint8_t* buffer, size_t buffer_width, const Point origin) + : buffer(buffer), buffer_width(buffer_width) + { + // Calculate start conditions + const Point origin_buffer = { + origin.x < 0 ? -origin.x : 0, + origin.y < 0 ? -origin.y : 0 + }; + // Memorize vertical origin + ybyte_top = origin_buffer.y / 8; + ybit_top = std::rotl(Bit0, origin_buffer.y % 8); + + // Setup first row + nextRow(); + x = origin_buffer.x; + } + + // Get next pixel + bool + operator()() + { + const bool result = buffer[ybyte * buffer_width + x] & ybit; + + // Increment y + ybit = std::rotl(ybit, 1); + if (ybit == Bit0) ybyte++; + + return result; + } + + inline void nextRow() { + x++; + ybyte = ybyte_top; + ybit = ybit_top; + } + + #define MODM_LOG_DEBUG_VAR(var) MODM_LOG_DEBUG << #var << ":\t" << var << modm::endl + + void + print_top() + { + MODM_LOG_DEBUG << "Top ------ " << modm::endl; + MODM_LOG_DEBUG_VAR(ybyte_top); + MODM_LOG_DEBUG << "ybit_top:\t" << modm::bin << ybit_top << modm::endl; + } + + void + print_state() + { + MODM_LOG_DEBUG << "State ---- " << modm::endl; + MODM_LOG_DEBUG_VAR(x); + MODM_LOG_DEBUG_VAR(ybyte); + MODM_LOG_DEBUG << "ybit:\t" << modm::bin << ybit << modm::endl; + } + //#endregion +}; } // namespace modm::graphic \ No newline at end of file diff --git a/src/modm/ui/graphic/display.hpp b/src/modm/ui/graphic/display.hpp index a9307abd0d..48c5088dac 100644 --- a/src/modm/ui/graphic/display.hpp +++ b/src/modm/ui/graphic/display.hpp @@ -13,7 +13,6 @@ #include "canvas.hpp" #include "buffer.hpp" -#include "scanner.hpp" #include #include @@ -81,7 +80,8 @@ class Display : virtual public Canvas Orientation orientation = Orientation::Landscape0; - // OPTIMIZE Small displays like Ssd1306 would be fine with Vector as Point in shape::Section + // Static variables for Resumable Functions required for any Display-type + BufferLayout layout; shape::Section clipping; }; diff --git a/src/modm/ui/graphic/scanner.hpp b/src/modm/ui/graphic/scanner.hpp deleted file mode 100644 index ac9503d0f4..0000000000 --- a/src/modm/ui/graphic/scanner.hpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2021, Thomas Sommer - * - * This file is part of the modm project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -// ---------------------------------------------------------------------------- - -#pragma once - -#include - -#include "../shape.hpp" - -#include - -namespace modm::graphic -{ - -// Scanner for monochrome Image data -// Applied to convert Buffer or Flash to regular Bitmap -class ScannerBufferBool -{ - const uint8_t* buffer; - // Initial conditions - size_t ybyte_top; - uint8_t ybit_top; - - // State - size_t x, ybyte; - uint8_t ybit; - -public: - constexpr ScannerBufferBool(uint8_t* buffer, Point origin) : buffer(buffer) - { - const Point topLeft = {origin.x < 0 ? -origin.x : 0, origin.y < 0 ? -origin.y : 0}; - - ybyte_top = topLeft.y / 8; - ybit_top = std::rotl(Bit0, topLeft.y % 8); - - x = topLeft.x; - ybyte = ybyte_top; - ybit = ybit_top; - } - - // Return next pixel - bool - operator()() - { - uint8_t height = 64; - const bool result = buffer[height * x + ybyte] & ybit; - - // Goto next pixel - /* if(true) { - p.x_other++; - p.bit = p.bit_top; - p.yb_other = p.yb_other_top; - } - else { - // Increment buffer row - p.bit = std::rotl(p.bit, 1); - if (p.bit == Bit0) p.yb_other++; - } */ - - return result; - } - - #define MODM_LOG_DEBUG_VAR(var) MODM_LOG_DEBUG << #var << ":\t" << var << modm::endl - - void - print_top() - { - MODM_LOG_DEBUG << "Top ------ " << modm::endl; - MODM_LOG_DEBUG_VAR(ybyte_top); - MODM_LOG_DEBUG << "ybit_top:\t" << modm::bin << ybit_top << modm::endl; - } - - void - print_state() - { - MODM_LOG_DEBUG << "State ---- " << modm::endl; - MODM_LOG_DEBUG_VAR(x); - MODM_LOG_DEBUG_VAR(ybyte); - MODM_LOG_DEBUG << "ybit:\t" << modm::bin << ybit << modm::endl; - } -}; - -} // namespace modm::graphic \ No newline at end of file