14#include "freertos/FreeRTOS.h"
15#include "freertos/semphr.h"
23constexpr uint8_t QR_VERSION_MAX = 20;
30 uint8_t* out =
nullptr;
36SemaphoreHandle_t s_lock =
nullptr;
37void lock_init() {
if (!s_lock) s_lock = xSemaphoreCreateMutex(); }
40 Guard() { lock_init();
if (s_lock) held = (xSemaphoreTake(s_lock, portMAX_DELAY) == pdTRUE); }
41 ~Guard() {
if (held) xSemaphoreGive(s_lock); }
44void raster_callback(esp_qrcode_handle_t qrcode) {
45 int size = esp_qrcode_get_size(qrcode);
47 if (s_ctx.sizing || !s_ctx.out)
return;
49 for (
int my = 0; my < size; my++) {
50 for (
int mx = 0; mx < size; mx++) {
51 if (!esp_qrcode_get_module(qrcode, mx, my))
continue;
52 packModule(s_ctx.out, s_ctx.stride, s_ctx.scale, s_ctx.quiet, mx, my);
57esp_qrcode_config_t make_cfg(uint8_t max_version, uint8_t ecc) {
58 esp_qrcode_config_t cfg = {};
59 cfg.display_func = raster_callback;
60 cfg.max_qrcode_version = (max_version >= 1 && max_version <= QR_VERSION_MAX)
61 ? max_version : QR_VERSION_MAX;
63 case 1: cfg.qrcode_ecc_level = ESP_QRCODE_ECC_MED;
break;
64 case 2: cfg.qrcode_ecc_level = ESP_QRCODE_ECC_QUART;
break;
65 case 3: cfg.qrcode_ecc_level = ESP_QRCODE_ECC_HIGH;
break;
66 default: cfg.qrcode_ecc_level = ESP_QRCODE_ECC_LOW;
break;
73int measure(
const char* data, uint8_t max_version, uint8_t ecc, uint16_t* out_modules) {
74 if (!data || !data[0] || !out_modules)
return -2;
78 esp_qrcode_config_t cfg = make_cfg(max_version, ecc);
79 if (esp_qrcode_generate(&cfg, data) != ESP_OK || s_ctx.modules <= 0)
return -1;
80 *out_modules =
static_cast<uint16_t
>(s_ctx.modules);
84int render(
const char* data, uint8_t max_version, uint8_t ecc,
85 uint8_t
scale, uint8_t quiet_modules,
86 uint8_t* out,
size_t out_size,
87 uint16_t* out_stride_bytes, uint16_t* out_height_px) {
88 if (!data || !data[0] || !out || !out_stride_bytes || !out_height_px)
return -2;
92 int rc =
measure(data, max_version, ecc, &modules);
93 if (rc != 0)
return rc;
95 const uint32_t side_px = (
static_cast<uint32_t
>(modules) + 2u * quiet_modules) *
scale;
97 const uint16_t stride =
static_cast<uint16_t
>((side_px + 7) / 8);
98 const size_t needed =
static_cast<size_t>(stride) * side_px;
99 if (out_size < needed)
return -3;
102 std::memset(out, 0, needed);
104 s_ctx.sizing =
false;
106 s_ctx.quiet = quiet_modules;
108 s_ctx.stride = stride;
109 s_ctx.side_px =
static_cast<uint16_t
>(side_px);
111 esp_qrcode_config_t cfg = make_cfg(max_version, ecc);
112 esp_err_t err = esp_qrcode_generate(&cfg, data);
114 if (err != ESP_OK)
return -1;
116 *out_stride_bytes = stride;
117 *out_height_px =
static_cast<uint16_t
>(side_px);
QR encoding into a caller-provided 1-bpp packed raster (no display).
void packModule(uint8_t *out, uint16_t stride, uint8_t scale, uint8_t quiet, int mx, int my)
Sets the packed pixels of one black QR module.
constexpr uint16_t QR_MAX_SIDE_PX
Hard cap on the rendered side length in pixels (incl. quiet zone, scaled).
int measure(const char *data, uint8_t max_version, uint8_t ecc, uint16_t *out_modules)
Measures the module count for data without rendering.