#pragma once #include #include #include #include // The serial commands (src/nano/README.md) that bring the Nano from the image `shown` to // `wanted`: over the rectangle that changed, one B command that switches dots off and one // that switches dots on, then D (or D1 when instant). Only the changed dots are in them, // so the Nano only touches those and the line stays short (scrolling text: a small // window). Without `shown` (nullptr): F0 and the whole image as one B command. // // Bitmaps in drawBitmap format: rows of (width + 7) / 8 bytes, the most significant bit // is the leftmost dot. `out(const char *)` gets the text in pieces. Returns the number of // characters sent, 0 when nothing changed (then nothing is sent, not even D). // Header only, so it is used by the ESP32 driver and tested with the Nano's parser. template size_t frameCommands(const uint8_t *wanted, const uint8_t *shown, uint8_t width, uint8_t height, bool instant, Out out) { const int row_bytes = (width + 7) / 8; auto dot = [row_bytes](const uint8_t *bitmap, int x, int y) { return (bitmap[y * row_bytes + x / 8] >> (7 - (x & 7))) & 1; }; size_t sent = 0; auto emit = [&](const char *text) { out(text); sent += strlen(text); }; int x0 = width, x1 = -1, y0 = height, y1 = -1; if (shown) { for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) if (dot(wanted, x, y) != dot(shown, x, y)) { x0 = x < x0 ? x : x0; x1 = x > x1 ? x : x1; y0 = y < y0 ? y : y0; y1 = y > y1 ? y : y1; } if (x1 < 0) return 0; } else { x0 = 0; y0 = 0; x1 = width - 1; y1 = height - 1; emit("F0\n"); } // B needs a width that is a multiple of 4; dots past the right edge are never set int w = (x1 - x0 + 4) / 4 * 4, h = y1 - y0 + 1; // Whether a dot is in the command for this color auto in = [&](int x, int y, int color) { if (x >= width || dot(wanted, x, y) != color) return false; return !shown || dot(shown, x, y) != color; }; for (int color = shown ? 0 : 1; color <= 1; color++) { bool any = false; for (int y = y0; y <= y1 && !any; y++) for (int x = x0; x <= x1 && !any; x++) any = in(x, y, color); if (!any) continue; char text[24]; snprintf(text, sizeof(text), "B%02x%02x%02x%02x%d", x0, y0, w, h, color); emit(text); for (int y = y0; y <= y1; y++) { char row[64 + 1]; // up to 256 dots int n = 0; for (int i = 0; i < w / 4; i++) { int nibble = 0; for (int k = 0; k < 4; k++) if (in(x0 + i * 4 + k, y, color)) nibble |= 8 >> k; row[n++] = "0123456789ABCDEF"[nibble]; } row[n] = '\0'; emit(row); } emit("\n"); } emit(instant ? "D1\n" : "D\n"); return sent; }