Merge pull request #674 from marsman7/master

Add QR-code object
This commit is contained in:
fvanroie 2024-03-24 14:01:45 +01:00 committed by GitHub
commit 7dbf52734a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 291 additions and 12 deletions

View File

@ -16,6 +16,7 @@
* DEFINES
*********************/
#define QR_SIZE 150
#define LV_OBJX_NAME "lv_qrcode"
/**********************
* TYPEDEFS
@ -47,18 +48,39 @@
*/
lv_obj_t* lv_qrcode_create(lv_obj_t* parent, lv_coord_t size, lv_color_t dark_color, lv_color_t light_color)
{
LV_LOG_INFO("qrcode create started");
/*Create a basic object*/
lv_obj_t* new_qrcode = lv_canvas_create(parent, NULL);
LV_ASSERT_MEM(new_qrcode);
if(new_qrcode == NULL) return NULL;
/*Extend the canvas ext attr to qrcode ext attr*/
lv_qrcode_ext_t * ext = lv_obj_allocate_ext_attr(new_qrcode, sizeof(lv_qrcode_ext_t));
LV_ASSERT_MEM(ext);
if(ext == NULL) {
lv_obj_del(new_qrcode);
return NULL;
}
ext->text = NULL;
ext->static_txt = 0;
ext->dot.tmp_ptr = NULL;
ext->dot_tmp_alloc = 0;
/*Allocate QR bitmap buffer*/
uint32_t buf_size = LV_CANVAS_BUF_SIZE_INDEXED_1BIT(size, size);
uint8_t* buf = lv_mem_alloc(buf_size);
LV_ASSERT_MEM(buf);
if(buf == NULL) return NULL;
lv_obj_t* canvas = lv_canvas_create(parent, NULL);
lv_canvas_set_buffer(new_qrcode, buf, size, size, LV_IMG_CF_INDEXED_1BIT);
lv_canvas_set_palette(new_qrcode, 0, dark_color);
lv_canvas_set_palette(new_qrcode, 1, light_color);
lv_canvas_set_buffer(canvas, buf, size, size, LV_IMG_CF_INDEXED_1BIT);
lv_canvas_set_palette(canvas, 0, dark_color);
lv_canvas_set_palette(canvas, 1, light_color);
LV_LOG_INFO("qrcode create ready");
return canvas;
return new_qrcode;
// lv_img_dsc_t * img_buf = lv_img_buf_alloc(20, 20, LV_IMG_CF_TRUE_COLOR);
// if(img_buf == NULL) {
@ -97,6 +119,8 @@ lv_res_t lv_qrcode_update(lv_obj_t* qrcode, const void* data, uint32_t data_len)
lv_canvas_fill_bg(qrcode, c, 0);
// lv_canvas_zoom();
LV_LOG_INFO("Update QR-code text with length : %d", data_len);
if(data_len > qrcodegen_BUFFER_LEN_MAX) return LV_RES_INV;
uint8_t qr0[qrcodegen_BUFFER_LEN_MAX];
@ -106,14 +130,20 @@ lv_res_t lv_qrcode_update(lv_obj_t* qrcode, const void* data, uint32_t data_len)
bool ok = qrcodegen_encodeBinary(data_tmp, data_len, qr0, qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN,
qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
if(!ok) return LV_RES_INV;
if(!ok) {
LV_LOG_WARN("QR-code encoding error");
return LV_RES_INV;
}
lv_coord_t obj_w = lv_obj_get_width(qrcode);
int qr_size = qrcodegen_getSize(qr0);
int scale = obj_w / qr_size;
int qr_size = qrcodegen_getSize(qr0); // Number of vertical QR blocks
int scale = obj_w / (qr_size + 2); // +2 guaranteed a minimum of 1 block margin all round
int scaled = qr_size * scale;
int margin = (obj_w - scaled) / 2;
LV_LOG_INFO("Update QR-code data : obj_w[%d] QR moduls[%d] scale factor[%d]", obj_w, qr_size, scale);
/*Expand the qr encodet binary to canvas size*/
for(int y = 0; y < scaled; y++) {
for(int x = 0; x < scaled; x++) {
c.full = qrcodegen_getModule(qr0, x / scale, y / scale) ? 0 : 1;
@ -121,6 +151,8 @@ lv_res_t lv_qrcode_update(lv_obj_t* qrcode, const void* data, uint32_t data_len)
}
}
qrcode->signal_cb(qrcode, LV_SIGNAL_CLEANUP, NULL);
return LV_RES_OK;
}
@ -168,6 +200,118 @@ lv_res_t lv_qrcode_update2(lv_obj_t* qrcode, const void* data, uint32_t data_len
return LV_RES_OK;
}
/**
* Set the data of a QR code object
* @param qrcode pointer to aQ code object
* @param text data to display, '\0' terminated character string. NULL to refresh with the current text.
* @return LV_RES_OK: if no error; LV_RES_INV: on error
*/
lv_res_t lv_qrcode_set_text(lv_obj_t * qrcode, const void * text)
{
LV_ASSERT_OBJ(qrcode, LV_OBJX_NAME);
lv_qrcode_ext_t * ext = lv_obj_get_ext_attr(qrcode);
/*If text is NULL then just refresh with the current text */
if(text == NULL) text = ext->text;
LV_ASSERT_STR(text);
if(ext->text == text && ext->static_txt == 0) {
/*If set its own text then reallocate it (maybe its size changed)*/
ext->text = lv_mem_realloc(ext->text, strlen(ext->text) + 1);
LV_ASSERT_MEM(ext->text);
if(ext->text == NULL) return LV_RES_INV;
}
else {
/*Free the old text*/
if(ext->text != NULL && ext->static_txt == 0) {
lv_mem_free(ext->text);
ext->text = NULL;
}
/*Get the size of the text*/
size_t len = strlen(text) + 1;
/*Allocate space for the new text*/
ext->text = lv_mem_alloc(len);
LV_ASSERT_MEM(ext->text);
if(ext->text == NULL) return LV_RES_INV;
strcpy(ext->text, text);
/*Now the text is dynamically allocated*/
ext->static_txt = 0;
}
return lv_qrcode_update(qrcode, ext->text, strlen(ext->text));
}
/**
* Set the data of a QR code object
* @param qrcode pointer to aQ code object
* @param text data to display, '\0' terminated character string. NULL to refresh with the current text.
* @return LV_RES_OK: if no error; LV_RES_INV: on error
*/
lv_res_t lv_qrcode_set_text_static(lv_obj_t * qrcode, const void * text)
{
LV_ASSERT_OBJ(qrcode, LV_OBJX_NAME);
lv_qrcode_ext_t * ext = lv_obj_get_ext_attr(qrcode);
if(ext->static_txt == 0 && ext->text != NULL) {
lv_mem_free(ext->text);
ext->text = NULL;
}
if(text != NULL) {
ext->static_txt = 1;
ext->text = (char *)text;
}
return lv_qrcode_update(qrcode, text, strlen(text));
}
/**
* Get the text of a qrcode
* @param qrcode pointer to a qrcode object
* @return the text of the qrcode
*/
char * lv_qrcode_get_text(const lv_obj_t * qrcode)
{
LV_ASSERT_OBJ(qrcode, LV_OBJX_NAME);
lv_qrcode_ext_t * ext = lv_obj_get_ext_attr(qrcode);
return ext->text;
}
/**
* Set the data of a QR code object
* @param qrcode pointer to aQ code object
* @param size width and height of the QR code
* @return LV_RES_OK: if no error; LV_RES_INV: on error
*/
lv_res_t lv_qrcode_set_size(lv_obj_t * qrcode, lv_coord_t size)
{
LV_ASSERT_OBJ(qrcode, LV_OBJX_NAME);
lv_qrcode_ext_t * ext = lv_obj_get_ext_attr(qrcode);
/*Reallocate QR bitmap buffer*/
uint32_t new_buf_size = LV_CANVAS_BUF_SIZE_INDEXED_1BIT(size, size);
uint8_t* buf = lv_mem_realloc((void *)ext->canvas.dsc.data, new_buf_size);
LV_ASSERT_MEM(buf);
if(buf == NULL) return LV_RES_INV;
lv_canvas_set_buffer(qrcode, buf, size, size, LV_IMG_CF_INDEXED_1BIT);
lv_qrcode_update(qrcode, ext->text, strlen(ext->text));
// qrcode->signal_cb(qrcode, LV_SIGNAL_CLEANUP, NULL);
return LV_RES_OK;
}
/**
* Delete a QR code object
* @param qrcode pointer to a QR code obejct

View File

@ -23,6 +23,28 @@ extern "C" {
* TYPEDEFS
**********************/
/** Data of qrcode*/
typedef struct {
/*Data of canvas, copyed from lv_canvas_ext_t*/
lv_canvas_ext_t canvas;
// lv_img_ext_t img; /*Ext. of ancestor*/
// lv_img_dsc_t dsc;
/*Inherited from 'base_obj' so no inherited ext.*/ /*Ext. of ancestor*/
/*New data for this type */
char * text; /*Text of the label*/
union {
char * tmp_ptr; /* Pointer to the allocated memory containing the character which are replaced by dots (Handled
by the library)*/
char tmp[4]; /* Directly store the characters if <=4 characters */
} dot;
uint8_t static_txt : 1; /*Flag to indicate the text is static*/
uint8_t dot_tmp_alloc : 1; /*True if dot_tmp has been allocated. False if dot_tmp directly holds up to 4 bytes of
characters */
} lv_qrcode_ext_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
@ -39,13 +61,44 @@ lv_obj_t * lv_qrcode_create(lv_obj_t * parent, lv_coord_t size, lv_color_t dark_
/**
* Set the data of a QR code object
* @param qrcode pointer to aQ code object
* @param qrcode pointer to QR code object
* @param data data to display
* @param data_len length of data in bytes
* @return LV_RES_OK: if no error; LV_RES_INV: on error
*/
lv_res_t lv_qrcode_update(lv_obj_t * qrcode, const void * data, uint32_t data_len);
/**
* Set the data of a QR code object
* @param qrcode pointer to QR code object
* @param text data to display, '\0' terminated character string. NULL to refresh with the current text.
* @return LV_RES_OK: if no error; LV_RES_INV: on error
*/
lv_res_t lv_qrcode_set_text(lv_obj_t * qrcode, const void * text);
/**
* Set the data of a QR code object
* @param qrcode pointer to QR code object
* @param text data to display, '\0' terminated character string. NULL to refresh with the current text.
* @return LV_RES_OK: if no error; LV_RES_INV: on error
*/
lv_res_t lv_qrcode_set_text_static(lv_obj_t * qrcode, const void * text);
/**
* Get the text of a qrcode
* @param qrcode pointer to a qrcode object
* @return the text of the qrcode
*/
char * lv_qrcode_get_text(const lv_obj_t * qrcode);
/**
* Set the data of a QR code object
* @param qrcode pointer to QR code object
* @param size width and height of the QR code
* @return LV_RES_OK: if no error; LV_RES_INV: on error
*/
lv_res_t lv_qrcode_set_size(lv_obj_t * qrcode, lv_coord_t size);
/**
* Delete a QR code object
* @param qrcode pointer to a QR code object

View File

@ -138,6 +138,11 @@ static const int PENALTY_N4 = 10;
bool qrcodegen_encodeText(const char* text, uint8_t tempBuffer[], uint8_t qrcode[], enum qrcodegen_Ecc ecl,
int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl)
{
/* preventing crashes */
if (maxVersion > qrcodegen_VERSION_MAX_LIMIT) {
qrcode[0] = 0; // Set size to invalid value for safety
return false;
}
size_t textLen = strlen(text);
if(textLen == 0)
@ -172,6 +177,11 @@ fail:
bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[], enum qrcodegen_Ecc ecl,
int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl)
{
/* preventing crashes */
if (maxVersion > qrcodegen_VERSION_MAX_LIMIT) {
qrcode[0] = 0; // Set size to invalid value for safety
return false;
}
struct qrcodegen_Segment seg;
seg.mode = qrcodegen_Mode_BYTE;

View File

@ -122,8 +122,23 @@ struct qrcodegen_Segment
/*---- Macro constants and functions ----*/
#define qrcodegen_VERSION_MIN 1 // The minimum version number supported in the QR Code Model 2 standard
#define qrcodegen_VERSION_MAX 3 // The maximum version number supported in the QR Code Model 2 standard
/* Version number supported in the QR Code Model 2 standard
* higher version numbers can process longer texts but require more memory and computing time.
*
* VERSION_MAX = 3 : max text length to encode 42 alphanumeric characters
* VERSION_MAX = 5 : max text length to encode 85 alphanumeric characters
* VERSION_MAX = 7 : max text length to encode 122 alphanumeric characters
* VERSION_MAX = 9 : max text length to encode 180 alphanumeric characters
* VERSION_MAX = 11 : max text length to encode 251 alphanumeric characters
* VERSION_MAX = 15 : max text length to encode 412 alphanumeric characters
* and so on
* 25 is the highest posible version, see below
*/
#define qrcodegen_VERSION_MIN 1 // The minimum version number
#ifndef qrcodegen_VERSION_MAX
#define qrcodegen_VERSION_MAX 7 // The maximum version number
#endif
#define qrcodegen_VERSION_MAX_LIMIT 25
// Calculates the number of bytes needed to store any QR Code up to and including the given version number,
// as a compile-time constant. For example, 'uint8_t buffer[qrcodegen_BUFFER_LEN_FOR_VERSION(25)];'

View File

@ -15,6 +15,10 @@
#endif
/*** Image Improvement ***/
#if HASP_USE_QRCODE > 0
#include "lv_qrcode.h"
#endif
LV_FONT_DECLARE(unscii_8_icon);
extern const char** btnmatrix_default_map; // memory pointer to lvgl default btnmatrix map
extern const char* msgbox_default_map[]; // memory pointer to lvgl default btnmatrix map
@ -394,6 +398,7 @@ static void hasp_attribute_get_part_state_new(lv_obj_t* obj, const char* attr_in
case LV_HASP_IMGBTN:
case LV_HASP_OBJECT:
case LV_HASP_TAB:
case LV_HASP_QRCODE:
part = LV_BTN_PART_MAIN;
break;
@ -1752,7 +1757,8 @@ static hasp_attribute_type_t attribute_common_text(lv_obj_t* obj, uint16_t attr_
#if LV_USE_WIN != 0
{LV_HASP_WINDOW, ATTR_TEXT, lv_win_set_title, lv_win_get_title},
#endif
{LV_HASP_MSGBOX, ATTR_TEXT, my_msgbox_set_text, lv_msgbox_get_text}
{LV_HASP_MSGBOX, ATTR_TEXT, my_msgbox_set_text, lv_msgbox_get_text},
{LV_HASP_QRCODE, ATTR_TEXT, my_qrcode_set_text, my_qrcode_get_text}
};
for(int i = 0; i < sizeof(list) / sizeof(list[0]); i++) {
@ -2446,6 +2452,16 @@ static hasp_attribute_type_t attribute_common_int(lv_obj_t* obj, uint16_t attr_h
val = lv_obj_get_ext_click_pad_top(obj);
break; // attribute_found
case ATTR_SIZE:
if(obj_check_type(obj, LV_HASP_QRCODE)) {
if(update) {
lv_qrcode_set_size(obj, val);
} else {
val = lv_obj_get_width(obj);
}
}
break;
default:
return HASP_ATTR_TYPE_NOT_FOUND; // attribute_not found
}
@ -2648,6 +2664,7 @@ void hasp_process_obj_attribute(lv_obj_t* obj, const char* attribute, const char
case ATTR_OPACITY:
case ATTR_EXT_CLICK_H:
case ATTR_EXT_CLICK_V:
case ATTR_SIZE:
val = strtol(payload, nullptr, DEC);
ret = attribute_common_int(obj, attr_hash, val, update);
break;

View File

@ -607,6 +607,28 @@ static inline void my_btn_set_text(lv_obj_t* obj, const char* value)
}
}
// OK - lvgl does not return a const char *
static const char* my_qrcode_get_text(const lv_obj_t* obj)
{
if(!obj) {
LOG_WARNING(TAG_ATTR, F("QR-code not defined"));
return NULL;
}
if(obj) {
if(obj_check_type(obj, LV_HASP_QRCODE)) return lv_qrcode_get_text(obj);
} else {
LOG_WARNING(TAG_ATTR, F("my_qrcode_get_text NULL Pointer encountered"));
}
return NULL;
}
static void my_qrcode_set_text(lv_obj_t* obj, const char* text)
{
lv_qrcode_set_text(obj, text);
}
/**
* Get the value_str for an object part and state.
* @param obj pointer to a object

View File

@ -86,6 +86,10 @@ void delete_event_handler(lv_obj_t* obj, lv_event_t event)
my_image_release_resources(obj);
break;
case LV_HASP_QRCODE:
lv_qrcode_delete(obj);
break;
case LV_HASP_GAUGE:
break;

View File

@ -377,6 +377,14 @@ void hasp_new_object(const JsonObject& config, uint8_t& saved_page_id)
}
break;
case LV_HASP_QRCODE:
case HASP_OBJ_QRCODE:
obj = lv_qrcode_create(parent_obj, 140, LV_COLOR_BLACK, LV_COLOR_WHITE);
if(obj) {
obj->user_data.objid = LV_HASP_QRCODE;
}
break;
case LV_HASP_ARC:
case HASP_OBJ_ARC:
obj = lv_arc_create(parent_obj, NULL);

View File

@ -88,6 +88,7 @@ enum lv_hasp_obj_type_t {
LV_HASP_ANIMIMAGE = 38, // placeholder
LV_HASP_CANVAS = 39, // placeholder
LV_HASP_MASK = 40, // placeholder
LV_HASP_QRCODE = 41, // placeholder
/* Custom */
LV_HASP_ALARM = 60,
@ -170,6 +171,7 @@ inline bool obj_check_type(const lv_obj_t* obj, lv_hasp_obj_type_t haspobjtype)
#define HASP_OBJ_SPINBOX 25641
#define HASP_OBJ_CALENDAR 30334
#define HASP_OBJ_IMG 30499
#define HASP_OBJ_QRCODE 50958
#define HASP_OBJ_GAUGE 33145
#define HASP_OBJ_CHART 34654
#define HASP_OBJ_LINE 34804

View File

@ -64,6 +64,10 @@
#include "lv_sjpg.h"
#endif
#if HASP_USE_QRCODE > 0
#include "lv_qrcode.h"
#endif
#if defined(HASP_USE_CUSTOM)
#include "custom/my_custom.h"
#endif