Add custom data tag for objects #195

This commit is contained in:
fvanroie 2022-01-26 03:42:38 +01:00
parent 9dfb039247
commit 239c56f243
5 changed files with 178 additions and 96 deletions

View File

@ -650,6 +650,7 @@ typedef struct {
uint8_t actionid:4;
uint8_t groupid:4;
uint8_t swipeid:4;
void* tag;
} lv_obj_user_data_t;
/*1: enable `lv_obj_realaign()` based on `lv_obj_align()` parameters*/

View File

@ -33,7 +33,7 @@ void my_image_release_resources(lv_obj_t* obj)
switch(src_type) {
case LV_IMG_SRC_VARIABLE: {
lv_img_set_src(obj, LV_SYMBOL_DUMMY); // empty symbol to clear the image
lv_img_cache_invalidate_src(src); // remove src from cache
lv_img_cache_invalidate_src(src); // remove src from image cache
lv_img_dsc_t* img_dsc = (lv_img_dsc_t*)src;
hasp_free((uint8_t*)img_dsc->data); // free image data
@ -42,7 +42,7 @@ void my_image_release_resources(lv_obj_t* obj)
}
case LV_IMG_SRC_FILE:
lv_img_cache_invalidate_src(src); // remove src from cache
lv_img_cache_invalidate_src(src); // remove src from image cache
break;
default:
@ -1082,7 +1082,7 @@ static hasp_attribute_type_t special_attribute_src(lv_obj_t* obj, const char* pa
if(httpCode == HTTP_CODE_OK) {
int total = http.getSize();
int url_len = strlen(payload) + 1;
int buf_len = total - sizeof(lv_img_header_t);
int buf_len = total;
int dsc_len = sizeof(lv_img_dsc_t) + url_len;
if(buf_len <= 0) { // header could not fit
@ -1103,8 +1103,9 @@ static hasp_attribute_type_t special_attribute_src(lv_obj_t* obj, const char* pa
}
char* url = ((char*)img_dsc) + sizeof(lv_img_dsc_t);
uint8_t* img_buf = (uint8_t*)(buf_len > 0 ? hasp_malloc(buf_len) : NULL);
if(!img_buf) {
uint8_t* img_buf_start = (uint8_t*)(buf_len > 0 ? hasp_malloc(buf_len) : NULL);
uint8_t* img_buf_pos = img_buf_start;
if(!img_buf_start) {
lv_mem_free(img_dsc); // destroy header too
LOG_ERROR(TAG_ATTR, "img buffer creation failed %d", buf_len);
return HASP_ATTR_TYPE_STR;
@ -1113,65 +1114,59 @@ static hasp_attribute_type_t special_attribute_src(lv_obj_t* obj, const char* pa
// LOG_VERBOSE(TAG_ATTR, "img buffers created of %d and %d bytes", dsc_len, buf_len);
LOG_VERBOSE(TAG_ATTR, "img Content-Type: %s", http.header((size_t)0).c_str());
memset(img_buf, 0, buf_len); // empty data buffer
memset(img_dsc, 0, dsc_len); // empty img descriptor + url
strncpy(url, payload, url_len); // store the url behind the img_dsc data
img_dsc->data = img_buf; // store pointer to the start of the data buffer
// Initialize the buffers
memset(img_buf_start, 0, buf_len); // empty data buffer
memset(img_dsc, 0, dsc_len); // empty img descriptor + url
strncpy(url, payload, url_len); // store the url behind the img_dsc data
img_dsc->data = img_buf_start; // store pointer to the start of the data buffer
img_dsc->header.always_zero = 0;
// LOG_WARNING(TAG_ATTR, "%s %d %x == %x", __FILE__, __LINE__, img_dsc->data, img_buf);
int read = 0;
// while(http.connected() && (buf_len > 0 || buf_len == -1)) {
while(http.connected() && (buf_len > 0)) {
if(size_t size = stream->available()) {
int c = 0;
if(read != 0) { // header has already been read, read data
c = stream->readBytes(img_buf, size);
LOG_WARNING(TAG_ATTR, "%s %d %x -> %x", __FILE__, __LINE__, img_dsc->data, img_buf);
img_buf += c;
buf_len -= c;
LOG_VERBOSE(TAG_ATTR, D_BULLET "IMG DATA: %d bytes read=%d buf_len=%d", c, read, buf_len);
} else if(read == 0 && size >= sizeof(lv_img_header_t)) { // read 4-byte header first
c = stream->readBytes((uint8_t*)img_dsc, sizeof(lv_img_header_t));
LOG_VERBOSE(TAG_ATTR, D_BULLET "IMG HEADER: %d bytes w=%d h=%d", c, img_dsc->header.w,
img_dsc->header.h);
}
int c = stream->readBytes(img_buf_pos, size > buf_len ? buf_len : size); // don't read too far
// LOG_WARNING(TAG_ATTR, "%s %d %x -> %x", __FILE__, __LINE__, img_dsc->data, img_buf);
img_buf_pos += c;
buf_len -= c;
LOG_VERBOSE(TAG_ATTR, D_BULLET "IMG DATA: %d bytes read=%d buf_len=%d", c, read, buf_len);
read += c;
} else {
delay(2); // wait for data
delay(1); // wait for data
}
}
LOG_VERBOSE(TAG_ATTR, D_BULLET "HTTP TOTAL READ: %d bytes, %d expected, %d buffered", read,
img_dsc->header.w * img_dsc->header.h * 2 + sizeof(lv_img_header_t),
img_buf - img_dsc->data);
LOG_VERBOSE(TAG_ATTR, D_BULLET "HTTP TOTAL READ: %d bytes, %d buffered", read,
img_buf_pos - img_buf_start);
const uint8_t png_magic[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
if(total > 16 && !memcmp(png_magic, img_dsc->data, sizeof(png_magic))) {
// PNG format, get image size from header
img_dsc->header.always_zero = 0;
img_dsc->header.w = img_buf_start[19] + (img_buf_start[18] << 8);
img_dsc->header.h = img_buf_start[23] + (img_buf_start[22] << 8);
img_dsc->data_size = img_buf_pos - img_buf_start; // end of buffer - start of buffer
img_dsc->header.cf = LV_IMG_CF_RAW_ALPHA;
// img_dsc->data = img_dsc->data; // already set
LOG_VERBOSE(TAG_ATTR, D_BULLET "PNG image: w=%d h=%d cf=%d len=%d", img_dsc->header.w,
img_dsc->header.h, img_dsc->header.cf, img_dsc->data_size);
} else {
// BIN format, includes a header
lv_img_header_t* header = (lv_img_header_t*)img_buf_start;
img_dsc->header.always_zero = 0;
img_dsc->header.w = header->w;
img_dsc->header.h = header->h;
img_dsc->header.cf = header->cf;
img_dsc->data = img_buf_start + sizeof(lv_img_header_t); // start of buf + skip header
img_dsc->data_size = img_buf_pos - img_buf_start - sizeof(lv_img_header_t); // end buf - start buf
LOG_VERBOSE(TAG_ATTR, D_BULLET "BIN image: w=%d h=%d cf=%d len=%d", img_dsc->header.w,
img_dsc->header.h, img_dsc->header.cf, img_dsc->data_size);
}
img_dsc->data_size = img_buf - img_dsc->data; // end of buffer - start of buffer
lv_img_set_src(obj, img_dsc);
LOG_WARNING(TAG_ATTR, "%s %d %x -> %x", __FILE__, __LINE__, img_dsc->data, img_buf);
// /*Decode the PNG image*/
// unsigned char* png_decoded; /*Will be pointer to the decoded image*/
// uint32_t png_width; /*Will be the width of the decoded image*/
// uint32_t png_height; /*Will be the width of the decoded image*/
// /*Decode the loaded image in ARGB8888 */
// uint32_t error = lodepng_decode32(&png_decoded, &png_width, &png_height, img_buf, (size_t)total);
// if(error) {
// LOG_ERROR(TAG_ATTR, "error %u: %s\n", error, lodepng_error_text(error));
// } else {
// img_dsc->header.always_zero = 0; /*It must be zero*/
// img_dsc->header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA; /*Set the color format*/
// img_dsc->header.w = png_width;
// img_dsc->header.h = png_height;
// img_dsc->data_size = png_width * png_height * 3;
// img_dsc->data = png_decoded;
// lv_img_set_src(obj, img_dsc);
// }
// LOG_WARNING(TAG_ATTR, "%s %d %x -> %x", __FILE__, __LINE__, img_buf_start, img_buf_start_pos);
} else {
LOG_WARNING(TAG_ATTR, "HTTP result %d", httpCode);
@ -1322,6 +1317,24 @@ static hasp_attribute_type_t attribute_common_mode(lv_obj_t* obj, const char* pa
return HASP_ATTR_TYPE_NOT_FOUND;
}
static hasp_attribute_type_t attribute_common_tag(lv_obj_t* obj, uint16_t attr_hash, const char* payload, char** text,
bool update)
{
switch(attr_hash) {
case ATTR_TAG:
if(update)
my_obj_set_tag(obj, payload);
else
*text = (char*)my_obj_get_tag(obj);
break; // attribute_found
default:
return HASP_ATTR_TYPE_NOT_FOUND;
}
return HASP_ATTR_TYPE_JSON;
}
static hasp_attribute_type_t attribute_common_text(lv_obj_t* obj, const char* attr, const char* payload, char** text,
bool update)
{
@ -2116,58 +2129,56 @@ static hasp_attribute_type_t attribute_common_bool(lv_obj_t* obj, uint16_t attr_
// ##################### Default Attributes ########################################################
void attr_out_str(lv_obj_t* obj, const char* attribute, const char* data)
void attr_out(lv_obj_t* obj, const char* attribute, const char* data, bool is_json)
{
uint8_t pageid;
uint8_t objid;
if(!attribute || !hasp_find_id_from_obj(obj, &pageid, &objid)) return;
const size_t size = 32 + strlen(attribute) + strlen(data);
size_t len = 10;
if(data) {
len = strlen(data); // crashes if NULL
}
const size_t size = 32 + strlen(attribute) + len;
char payload[size];
{
StaticJsonDocument<64> doc; // Total (recommended) size for const char*
if(data)
doc[attribute].set(data);
if(is_json)
doc[attribute].set(serialized(data));
else
doc[attribute].set(data);
else
doc[attribute].set(nullptr);
serializeJson(doc, payload, size);
}
object_dispatch_state(pageid, objid, payload);
}
void attr_out_str(lv_obj_t* obj, const char* attribute, const char* data)
{
attr_out(obj, attribute, data, false);
}
void attr_out_json(lv_obj_t* obj, const char* attribute, const char* data)
{
attr_out(obj, attribute, data, true);
}
void attr_out_int(lv_obj_t* obj, const char* attribute, int32_t val)
{
uint8_t pageid;
uint8_t objid;
if(!attribute || !hasp_find_id_from_obj(obj, &pageid, &objid)) return;
const size_t size = 32 + strlen(attribute);
char payload[size];
{
StaticJsonDocument<64> doc; // Total (recommended) size for const char*
doc[attribute].set(val);
serializeJson(doc, payload, size);
}
object_dispatch_state(pageid, objid, payload);
char data[9];
itoa(val, data, sizeof(data));
attr_out(obj, attribute, data, true);
}
void attr_out_bool(lv_obj_t* obj, const char* attribute, bool val)
{
uint8_t pageid;
uint8_t objid;
if(!attribute || !hasp_find_id_from_obj(obj, &pageid, &objid)) return;
const size_t size = 32 + strlen(attribute);
char payload[size];
{
StaticJsonDocument<64> doc; // Total (recommended) size for const char*
doc[attribute].set(val);
serializeJson(doc, payload, size);
}
object_dispatch_state(pageid, objid, payload);
attr_out(obj, attribute, val ? "true" : "false", true);
}
void attr_out_color(lv_obj_t* obj, const char* attribute, lv_color_t color)
@ -2266,6 +2277,9 @@ void hasp_process_obj_attribute(lv_obj_t* obj, const char* attribute, const char
case ATTR_ALIGN:
ret = attribute_common_align(obj, attribute, payload, &text, update);
break;
case ATTR_TAG:
ret = attribute_common_tag(obj, attr_hash, payload, &text, update);
break;
case ATTR_OBJ:
text = (char*)obj_get_type_name(obj);
@ -2309,7 +2323,7 @@ void hasp_process_obj_attribute(lv_obj_t* obj, const char* attribute, const char
ret = attribute_common_method(obj, attr_hash, attribute, payload);
break;
case ATTR_COMMENT:
case ATTR_COMMENT: // skip this key
ret = HASP_ATTR_TYPE_METHOD_OK;
break;
@ -2446,6 +2460,12 @@ void hasp_process_obj_attribute(lv_obj_t* obj, const char* attribute, const char
attr_out_str(obj, attribute, text);
break;
case HASP_ATTR_TYPE_JSON_READONLY:
LOG_WARNING(TAG_ATTR, F(D_ATTRIBUTE_READ_ONLY), attribute);
case HASP_ATTR_TYPE_JSON:
attr_out_json(obj, attribute, text);
break;
case HASP_ATTR_TYPE_COLOR_INVALID:
LOG_WARNING(TAG_ATTR, F(D_ATTRIBUTE_COLOR_INVALID), payload);
break;

View File

@ -15,6 +15,8 @@ lv_chart_series_t* my_chart_get_series(lv_obj_t* chart, uint8_t ser_num);
#endif
void my_obj_set_value_str_text(lv_obj_t* obj, uint8_t part, lv_state_t state, const char* text);
void my_obj_set_tag(lv_obj_t* obj, const char* tag);
const char* my_obj_get_tag(lv_obj_t* obj);
void my_btnmatrix_map_clear(lv_obj_t* obj);
void my_msgbox_map_clear(lv_obj_t* obj);
void my_line_clear_points(lv_obj_t* obj);
@ -25,6 +27,7 @@ void hasp_process_obj_attribute(lv_obj_t* obj, const char* attr_p, const char* p
bool attribute_set_normalized_value(lv_obj_t* obj, hasp_update_value_t& value);
void attr_out_str(lv_obj_t* obj, const char* attribute, const char* data);
void attr_out_json(lv_obj_t* obj, const char* attribute, const char* data);
void attr_out_int(lv_obj_t* obj, const char* attribute, int32_t val);
void attr_out_color(lv_obj_t* obj, const char* attribute, lv_color_t color);
@ -36,8 +39,9 @@ typedef enum {
HASP_ATTR_TYPE_LONG_MODE_INVALID = -10,
HASP_ATTR_TYPE_RANGE_ERROR = -9,
HASP_ATTR_TYPE_METHOD_INVALID_FOR_PAGE = -8,
HASP_ATTR_TYPE_ALIGN_INVALID = -5,
HASP_ATTR_TYPE_COLOR_INVALID = -4,
HASP_ATTR_TYPE_ALIGN_INVALID = -6,
HASP_ATTR_TYPE_COLOR_INVALID = -5,
HASP_ATTR_TYPE_JSON_READONLY = -4,
HASP_ATTR_TYPE_STR_READONLY = -3,
HASP_ATTR_TYPE_BOOL_READONLY = -2,
HASP_ATTR_TYPE_INT_READONLY = -1,
@ -45,6 +49,7 @@ typedef enum {
HASP_ATTR_TYPE_INT,
HASP_ATTR_TYPE_BOOL,
HASP_ATTR_TYPE_STR,
HASP_ATTR_TYPE_JSON,
HASP_ATTR_TYPE_COLOR,
HASP_ATTR_TYPE_ALIGN,
HASP_ATTR_TYPE_DIRECTION_XY,
@ -418,6 +423,7 @@ _HASP_ATTRIBUTE(SCALE_END_LINE_WIDTH, scale_end_line_width, lv_style_int_t)
#define ATTR_ANIM_SPEED 281
#define ATTR_START_VALUE 11828
#define ATTR_COMMENT 62559
#define ATTR_TAG 7866
// methods
#define ATTR_DELETE 50027

View File

@ -3,6 +3,47 @@
#include "hasplib.h"
// the tag data is stored as SERIALIZED JSON data
void my_obj_set_tag(lv_obj_t* obj, const char* tag)
{
size_t len = tag ? strlen(tag) : 0;
// release old tag
if(obj->user_data.tag) {
lv_mem_free(obj->user_data.tag);
obj->user_data.tag = NULL;
}
// new tag is blank
if(tag == NULL || tag[0] == '\0') return;
// create new tag
{
StaticJsonDocument<512> doc;
// check if it is a proper JSON object
DeserializationError error = deserializeJson(doc, tag, len);
if(error != DeserializationError::Ok) doc.set(tag); // use tag as-is
const size_t size = measureJson(doc) + 1;
if(char* str = (char*)lv_mem_alloc(size)) {
len = serializeJson(doc, str, size); // tidy-up the json object
obj->user_data.tag = (void*)str;
LOG_VERBOSE(TAG_ATTR, "new json: %s", str);
}
}
}
// the tag data is stored as SERIALIZED JSON data
const char* my_obj_get_tag(lv_obj_t* obj)
{
if(obj->user_data.tag) {
return (char*)obj->user_data.tag;
} else {
return "null";
}
}
lv_label_align_t my_textarea_get_text_align(lv_obj_t* ta)
{
lv_textarea_ext_t* ext = (lv_textarea_ext_t*)lv_obj_get_ext_attr(ta);

View File

@ -68,6 +68,7 @@ void delete_event_handler(lv_obj_t* obj, lv_event_t event)
// TODO: delete value_str data for ALL parts
my_obj_set_value_str_text(obj, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, NULL);
my_obj_set_tag(obj, (char*)NULL);
}
/* ============================== Timer Event ============================ */
@ -222,22 +223,34 @@ static void event_send_object_data(lv_obj_t* obj, const char* data)
// Send out events with a val attribute
static void event_object_val_event(lv_obj_t* obj, uint8_t eventid, int16_t val)
{
char data[40];
char eventname[8];
char data[512];
{
// StaticJsonDocument<96> doc; // allocate on stack
Parser::get_event_name(eventid, eventname, sizeof(eventname));
snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d}"), eventname, val);
char eventname[8];
Parser::get_event_name(eventid, eventname, sizeof(eventname));
// doc["event"] = eventname;
// doc["val"] = val;
// if(obj->user_data.tag) doc["tag"] = serialized((const char*)obj->user_data.tag);
// serializeJson(doc, data);
const char* tag = my_obj_get_tag(obj);
snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"tag\":%s}"), eventname, val, tag);
}
event_send_object_data(obj, data);
}
// Send out events with a val and text attribute
static void event_object_selection_changed(lv_obj_t* obj, uint8_t eventid, int16_t val, const char* text)
{
char data[200];
char data[512];
char eventname[8];
const char* tag = my_obj_get_tag(obj);
Parser::get_event_name(eventid, eventname, sizeof(eventname));
snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"text\":\"%s\"}"), eventname, val, text);
snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"text\":\"%s\",\"tag\":%s}"), eventname, val,
text, tag);
event_send_object_data(obj, data);
}
@ -465,7 +478,8 @@ void generic_event_handler(lv_obj_t* obj, lv_event_t event)
char data[40];
char eventname[8];
Parser::get_event_name(last_value_sent, eventname, sizeof(eventname));
snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\"}"), eventname);
const char* tag = my_obj_get_tag(obj);
snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"tag\":%s}"), eventname, tag);
event_send_object_data(obj, data);
}
@ -609,15 +623,13 @@ void btnmatrix_event_handler(lv_obj_t* obj, lv_event_t event)
if(!translate_event(obj, event, hasp_event_id)) return; // Use LV_EVENT_VALUE_CHANGED
/* Get the new value */
char buffer[128];
uint16_t val = 0;
char buffer[128] = "";
uint16_t val = 0;
val = lv_btnmatrix_get_active_btn(obj);
if(val != LV_BTNMATRIX_BTN_NONE) {
const char* txt = lv_btnmatrix_get_btn_text(obj, val);
strncpy(buffer, txt, sizeof(buffer));
} else {
buffer[0] = 0; // empty string
}
if(hasp_event_id == HASP_EVENT_CHANGED && last_value_sent == val) return; // same value as before
@ -723,13 +735,15 @@ void cpicker_event_handler(lv_obj_t* obj, lv_event_t event)
char data[100];
char eventname[8];
Parser::get_event_name(hasp_event_id, eventname, sizeof(eventname));
const char* tag = my_obj_get_tag(obj);
lv_color32_t c32;
c32.full = lv_color_to32(color);
last_color_sent = color;
snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"color\":\"#%02x%02x%02x\",\"r\":%d,\"g\":%d,\"b\":%d}"),
eventname, c32.ch.red, c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue);
snprintf_P(data, sizeof(data),
PSTR("{\"event\":\"%s\",\"color\":\"#%02x%02x%02x\",\"r\":%d,\"g\":%d,\"b\":%d,\"tag\":%s}"), eventname,
c32.ch.red, c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue, tag);
event_send_object_data(obj, data);
// event_update_group(obj->user_data.groupid, obj, val, min, max);