From 053f1f91c85dd2f0a0a3220081e184078877f516 Mon Sep 17 00:00:00 2001 From: marsman7 Date: Wed, 13 Mar 2024 23:03:01 +0100 Subject: [PATCH] Add QR-code object --- lib/lv_lib_qrcode/lv_qrcode.c | 137 +++++++++++++++++++++++++++++-- lib/lv_lib_qrcode/lv_qrcode.h | 48 ++++++++++- src/hasp/hasp_attribute.cpp | 19 ++++- src/hasp/hasp_attribute_helper.h | 11 +++ src/hasp/hasp_event.cpp | 4 + src/hasp/hasp_object.cpp | 8 ++ src/hasp/hasp_object.h | 2 + src/hasplib.h | 4 + 8 files changed, 224 insertions(+), 9 deletions(-) diff --git a/lib/lv_lib_qrcode/lv_qrcode.c b/lib/lv_lib_qrcode/lv_qrcode.c index 77f2697e..34d1bdba 100644 --- a/lib/lv_lib_qrcode/lv_qrcode.c +++ b/lib/lv_lib_qrcode/lv_qrcode.c @@ -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) { @@ -109,11 +131,12 @@ lv_res_t lv_qrcode_update(lv_obj_t* qrcode, const void* data, uint32_t data_len) if(!ok) 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; + /*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 +144,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 +193,104 @@ 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)); +} + +/** + * 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 diff --git a/lib/lv_lib_qrcode/lv_qrcode.h b/lib/lv_lib_qrcode/lv_qrcode.h index 576cd445..dd84db3c 100644 --- a/lib/lv_lib_qrcode/lv_qrcode.h +++ b/lib/lv_lib_qrcode/lv_qrcode.h @@ -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,37 @@ 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); + +/** + * 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 diff --git a/src/hasp/hasp_attribute.cpp b/src/hasp/hasp_attribute.cpp index b903cc93..dd0eb83c 100644 --- a/src/hasp/hasp_attribute.cpp +++ b/src/hasp/hasp_attribute.cpp @@ -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; diff --git a/src/hasp/hasp_attribute_helper.h b/src/hasp/hasp_attribute_helper.h index ee078300..a82832a7 100644 --- a/src/hasp/hasp_attribute_helper.h +++ b/src/hasp/hasp_attribute_helper.h @@ -607,6 +607,17 @@ 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) +{ + 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 diff --git a/src/hasp/hasp_event.cpp b/src/hasp/hasp_event.cpp index 0b52e91b..cb7e112c 100644 --- a/src/hasp/hasp_event.cpp +++ b/src/hasp/hasp_event.cpp @@ -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; diff --git a/src/hasp/hasp_object.cpp b/src/hasp/hasp_object.cpp index 68b1f8eb..c8b989ce 100644 --- a/src/hasp/hasp_object.cpp +++ b/src/hasp/hasp_object.cpp @@ -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); diff --git a/src/hasp/hasp_object.h b/src/hasp/hasp_object.h index 5bfe157a..9a8b8169 100644 --- a/src/hasp/hasp_object.h +++ b/src/hasp/hasp_object.h @@ -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 diff --git a/src/hasplib.h b/src/hasplib.h index 05ce613c..3bed9382 100644 --- a/src/hasplib.h +++ b/src/hasplib.h @@ -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 \ No newline at end of file