Add third button: "scan to manage" QR overlay on the current photo
Pressing the manage button (GPIO1) overlays a small QR code -- "SCAN TO MANAGE" -- in the top-right corner of whatever photo is currently on screen, linking to the server's config page, then reverts to the plain photo after 30 seconds. The overlay is spliced into the existing streaming fetch as chunks pass through (frame_client.c's http_read_fn), rather than buffering the full 192,000-byte frame in RAM: only the small overlay rectangle itself (~30KB) is ever held in memory, generated via new stride-parameterized drawing helpers (epd_draw_*_ex in epd_draw.c) that let the existing QR/text drawing code target an arbitrarily-sized buffer instead of a full-frame one. epd7in3e.c is untouched -- it has no idea an overlay exists.
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_check.h"
|
||||
|
||||
#include "epd7in3e.h"
|
||||
#include "epd_draw.h"
|
||||
#include "fonts.h"
|
||||
#include "qrcodegen.h"
|
||||
|
||||
#include "manage_qr_overlay.h"
|
||||
|
||||
static const char *TAG = "manage_qr_overlay";
|
||||
|
||||
#define QR_MAX_VERSION 10
|
||||
#define QR_BUFFER_LEN qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)
|
||||
/* Smaller than qr_onboarding.c's QR_MODULE_PX (8) -- this is a compact
|
||||
* corner popup, not a full-screen setup step. */
|
||||
#define QR_MODULE_PX 4
|
||||
#define PADDING 16
|
||||
#define QR_TEXT_GAP 8
|
||||
#define LINE_GAP 4
|
||||
/* Distance from the panel's top/right edges to the overlay box. Combined
|
||||
* with EPD_WIDTH and the forced-even box width below, this guarantees
|
||||
* x0 is always even -- required so the overlay's columns land on frame
|
||||
* byte boundaries (2px/byte) when spliced into the fetch stream. */
|
||||
#define PANEL_MARGIN 20
|
||||
|
||||
static void draw_qr(uint8_t *buf, int stride, int width, int height, const uint8_t *qrcode, int origin_x,
|
||||
int origin_y)
|
||||
{
|
||||
int size = qrcodegen_getSize(qrcode);
|
||||
for (int y = 0; y < size; y++) {
|
||||
for (int x = 0; x < size; x++) {
|
||||
epd_color_t color = qrcodegen_getModule(qrcode, x, y) ? EPD_COLOR_BLACK : EPD_COLOR_WHITE;
|
||||
for (int dy = 0; dy < QR_MODULE_PX; dy++) {
|
||||
for (int dx = 0; dx < QR_MODULE_PX; dx++) {
|
||||
epd_draw_pixel_ex(buf, stride, width, height, origin_x + x * QR_MODULE_PX + dx,
|
||||
origin_y + y * QR_MODULE_PX + dy, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t manage_qr_overlay_render(const char *management_url, manage_qr_overlay_t *out)
|
||||
{
|
||||
uint8_t temp_buffer[QR_BUFFER_LEN];
|
||||
uint8_t qrcode[QR_BUFFER_LEN];
|
||||
bool ok = qrcodegen_encodeText(management_url, temp_buffer, qrcode, qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN,
|
||||
QR_MAX_VERSION, qrcodegen_Mask_AUTO, true);
|
||||
ESP_RETURN_ON_FALSE(ok, ESP_FAIL, TAG, "QR encoding failed for '%s' (too long for max version)", management_url);
|
||||
|
||||
int qr_size = qrcodegen_getSize(qrcode);
|
||||
int qr_px = qr_size * QR_MODULE_PX;
|
||||
|
||||
/* Font24 (32x41px uppercase glyphs) is the only font vendored into
|
||||
* this project -- see components/epaper_fonts. "SCAN TO MANAGE" on
|
||||
* one line would be 448px wide, too wide for a compact corner box,
|
||||
* so it's wrapped across two lines here instead. */
|
||||
static const char *line1 = "SCAN TO";
|
||||
static const char *line2 = "MANAGE";
|
||||
int line1_w = (int)strlen(line1) * Font24.Width;
|
||||
int line2_w = (int)strlen(line2) * Font24.Width;
|
||||
int text_w = line1_w > line2_w ? line1_w : line2_w;
|
||||
|
||||
int content_w = qr_px > text_w ? qr_px : text_w;
|
||||
int content_h = qr_px + QR_TEXT_GAP + Font24.Height + LINE_GAP + Font24.Height;
|
||||
|
||||
int w = content_w + PADDING * 2;
|
||||
int h = content_h + PADDING * 2;
|
||||
w += w % 2; /* keep byte-aligned (2px/byte) */
|
||||
|
||||
int stride = w / 2;
|
||||
uint8_t *buf = malloc((size_t)stride * h);
|
||||
ESP_RETURN_ON_FALSE(buf != NULL, ESP_ERR_NO_MEM, TAG, "Failed to allocate overlay buffer");
|
||||
memset(buf, (EPD_COLOR_WHITE << 4) | EPD_COLOR_WHITE, (size_t)stride * h);
|
||||
|
||||
int center_x = w / 2;
|
||||
int y = PADDING;
|
||||
draw_qr(buf, stride, w, h, qrcode, center_x - qr_px / 2, y);
|
||||
y += qr_px + QR_TEXT_GAP;
|
||||
epd_draw_text_centered_ex(buf, stride, w, h, &Font24, line1, center_x, y);
|
||||
y += Font24.Height + LINE_GAP;
|
||||
epd_draw_text_centered_ex(buf, stride, w, h, &Font24, line2, center_x, y);
|
||||
|
||||
out->buf = buf;
|
||||
out->w = w;
|
||||
out->h = h;
|
||||
out->x0 = EPD_WIDTH - PANEL_MARGIN - w;
|
||||
out->y0 = PANEL_MARGIN;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void manage_qr_overlay_free(manage_qr_overlay_t *overlay)
|
||||
{
|
||||
free(overlay->buf);
|
||||
overlay->buf = NULL;
|
||||
}
|
||||
Reference in New Issue
Block a user