Public Access
Send only the changed dots of a frame to the Nano
Frames were sent as F0 plus one s command per yellow dot (thousands of characters). During scrolling that overran the Nano's serial buffer, and half-received frames redrew the whole screen. showBitmap() now sends two B commands over the changed rectangle (dots off, dots on), or one B command for a full frame, and the pacing counts the characters sent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
89001ddbc6
commit
47ef65ee7d
8 files changed
+262
-25
No files matched your search
@@ -23,6 +23,38 @@ void BROSE9323::begin(Stream *s)
|
||||
{
|
||||
stream = s;
|
||||
}
|
||||
|
||||
size_t BROSE9323::showBitmap(const uint8_t *bitmap, bool changes_only, bool instant)
|
||||
{
|
||||
// What the Nano shows now, in drawBitmap format (the buffers keep the bits the other
|
||||
// way around)
|
||||
uint8_t *shown = (uint8_t *)malloc(_buffer_size);
|
||||
if (!shown)
|
||||
return 0;
|
||||
for (uint16_t i = 0; i < _buffer_size; i++)
|
||||
{
|
||||
uint8_t b = _old_buffer[i], r = 0;
|
||||
for (uint8_t k = 0; k < 8; k++)
|
||||
if (b & (1 << k))
|
||||
r |= 0x80 >> k;
|
||||
shown[i] = r;
|
||||
}
|
||||
size_t sent = frameCommands(bitmap, changes_only ? shown : nullptr, width(), height(), instant,
|
||||
[this](const char *text) { stream->print(text); });
|
||||
free(shown);
|
||||
|
||||
for (uint8_t y = 0; y < height(); y++)
|
||||
for (uint8_t x = 0; x < width(); x++)
|
||||
{
|
||||
uint8_t &byte = _new_buffer[y * _buffer_width + x / 8];
|
||||
if (bitmap[y * _buffer_width + x / 8] & (0x80 >> (x & 7)))
|
||||
byte |= 1 << (x & 7);
|
||||
else
|
||||
byte &= ~(1 << (x & 7));
|
||||
}
|
||||
memcpy(_old_buffer, _new_buffer, _buffer_size);
|
||||
return sent;
|
||||
}
|
||||
#else
|
||||
void BROSE9323::begin(void)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#include <Adafruit_GFX.h>
|
||||
|
||||
#include "dot_sequence.h"
|
||||
#ifdef ESPSERIAL
|
||||
#include "frame_commands.h"
|
||||
#endif
|
||||
|
||||
//#define FLIPDOT_PLCC_ADAPTER
|
||||
// ESPSERIAL is set per target via build_flags in platformio.ini (-D ESPSERIAL for the ESP32)
|
||||
@@ -103,6 +106,11 @@ public:
|
||||
BROSE9323(uint8_t, uint8_t, uint8_t, uint16_t ft = 280);
|
||||
#ifdef ESPSERIAL
|
||||
void begin(Stream * = &Serial);
|
||||
// Shows a full screen bitmap (drawBitmap format) and ends the frame (D, or D1 when
|
||||
// instant). changes_only: only the dots that differ from the last frame are sent
|
||||
// (frame_commands.h); otherwise the whole screen. Returns the characters sent (0:
|
||||
// nothing changed, nothing sent).
|
||||
size_t showBitmap(const uint8_t *bitmap, bool changes_only, bool instant = false);
|
||||
#endif
|
||||
void begin(void);
|
||||
// Shows the buffer: the changed dots, all with force. instant: without the refresh
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// 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 <typename Out>
|
||||
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;
|
||||
}
|
||||
Reference in new issue
Block a user