From 7ccaa6fbc97e2829aaa49542d2bee89c9f988618 Mon Sep 17 00:00:00 2001 From: fvanroie Date: Sun, 10 Jan 2021 06:27:03 +0100 Subject: [PATCH] Add Button Matrix --- src/hasp/hasp_attribute.cpp | 178 +++++++++++++++++++----------------- src/hasp/hasp_attribute.h | 2 +- src/hasp/hasp_object.cpp | 9 +- 3 files changed, 99 insertions(+), 90 deletions(-) diff --git a/src/hasp/hasp_attribute.cpp b/src/hasp/hasp_attribute.cpp index b40894f8..79cd9d3d 100644 --- a/src/hasp/hasp_attribute.cpp +++ b/src/hasp/hasp_attribute.cpp @@ -325,20 +325,92 @@ void my_obj_set_value_str_txt(lv_obj_t * obj, uint8_t part, lv_state_t state, co // Log.verbose(TAG_ATTR, "%s %d", __FILE__, __LINE__); } -void btnmatrix_clear_map(lv_obj_t * obj) +void my_btnmatrix_map_clear(lv_obj_t * obj) { lv_btnmatrix_ext_t * ext = (lv_btnmatrix_ext_t *)lv_obj_get_ext_attr(obj); + const char ** map_p_tmp = ext->map_p; // store current pointer + + Log.verbose(TAG_ATTR, "%s %d %x btn_cnt: %d", __FILE__, __LINE__, map_p_tmp, ext->btn_cnt); + if(ext->map_p && (ext->btn_cnt > 0)) { - const char ** ptr = ext->map_p; // The map exists and is not the default lvgl map anymore - if(ptr && btnmatrix_default_map && (ptr != btnmatrix_default_map)) { - lv_btnmatrix_set_map(obj, btnmatrix_default_map); // reset default btnmap - lv_mem_free(ptr); // destroy custom btnmap - } + if((map_p_tmp == NULL) || (btnmatrix_default_map == NULL) || (map_p_tmp == btnmatrix_default_map)) return; + + Log.verbose(TAG_ATTR, "%s %d %x", __FILE__, __LINE__, + *map_p_tmp); // label buffer reserved as a contiguous block + Log.verbose(TAG_ATTR, "%s %d %x", __FILE__, __LINE__, map_p_tmp); // label pointer array block + lv_btnmatrix_set_map(obj, btnmatrix_default_map); // reset to default btnmap pointer + + Log.verbose(TAG_ATTR, "%s %d", __FILE__, __LINE__); + lv_mem_free(*map_p_tmp); // free label buffer reserved as a contiguous block + Log.verbose(TAG_ATTR, "%s %d", __FILE__, __LINE__); + lv_mem_free(map_p_tmp); // free label pointer array block + Log.verbose(TAG_ATTR, "%s %d", __FILE__, __LINE__); } } +static void my_btnmatrix_map_create(lv_obj_t * obj, const char * payload) +{ + const char ** map_p = lv_btnmatrix_get_map_array(obj); + + // Create new map + // Reserve memory for JsonDocument + size_t maxsize = (128u * ((strlen(payload) / 128) + 1)) + 256; + DynamicJsonDocument map_doc(maxsize); + DeserializationError jsonError = deserializeJson(map_doc, payload); + + if(jsonError) { // Couldn't parse incoming JSON payload + return Log.warning(TAG_ATTR, F("JSON: Failed to parse incoming button map with error: %s"), jsonError.c_str()); + } + + JsonArray arr = map_doc.as(); // Parse payload + + size_t tot_len = sizeof(char *) * (arr.size() + 1); + const char ** map_data_str = (const char **)lv_mem_alloc(tot_len); + if(map_data_str == NULL) { + return Log.error(TAG_ATTR, F("Out of memory while creating button map")); + } + memset(map_data_str, 0, tot_len); + + // Create buffer + tot_len = 0; + for(JsonVariant btn : arr) { + tot_len += btn.as().length() + 1; + } + tot_len++; // trailing '\0' + Log.verbose(TAG_ATTR, F("Array Size = %d, Map Length = %d"), arr.size(), tot_len); + + char * buffer_addr = (char *)lv_mem_alloc(tot_len); + if(buffer_addr == NULL) { + lv_mem_free(map_data_str); + return Log.error(TAG_ATTR, F("Out of memory while creating button map")); + } + memset(buffer_addr, 0, tot_len); // Important, last index needs to be 0 => empty string "" + + /* Point of no return, destroy & free the previous map */ + Log.verbose(TAG_ATTR, "%s %d map addr: %x", __FILE__, __LINE__, map_data_str); + my_btnmatrix_map_clear(obj); // Free previous map + + // Fill buffer + size_t index = 0; + size_t pos = 0; + Log.verbose(TAG_ATTR, "%s %d lbl addr: %x", __FILE__, __LINE__, buffer_addr); + for(JsonVariant btn : arr) { + size_t len = btn.as().length() + 1; + Log.verbose(TAG_ATTR, F(" * Adding button: %s (%d bytes) %x"), btn.as().c_str(), len, + buffer_addr + pos); + memccpy(buffer_addr + pos, btn.as().c_str(), 0, len); // Copy the label text into the buffer + map_data_str[index++] = buffer_addr + pos; // save pointer to the label in the array + pos += len; + } + map_data_str[index] = buffer_addr + pos; // save pointer to the last \0 byte + + Log.verbose(TAG_ATTR, "%s %d", __FILE__, __LINE__); + lv_btnmatrix_set_map(obj, map_data_str); + Log.verbose(TAG_ATTR, "%s %d", __FILE__, __LINE__); +} + void line_clear_points(lv_obj_t * obj) { lv_line_ext_t * ext = (lv_line_ext_t *)lv_obj_get_ext_attr(obj); @@ -1258,82 +1330,6 @@ static void hasp_process_gauge_attribute(lv_obj_t * obj, const char * attr_p, ui Log.warning(TAG_ATTR, F("Unknown property %s"), attr_p); } -static void hasp_process_btnmatrix_attribute(lv_obj_t * obj, const char * attr_p, uint16_t attr_hash, - const char * payload, bool update) -{ - // We already know it's a btnmatrix object - char * attr = (char *)attr_p; - if(*attr == '.') attr++; // strip leading '.' - - switch(attr_hash) { - case ATTR_MAP: { - const char ** map_p = lv_btnmatrix_get_map_array(obj); - if(update) { - // Free previous map - btnmatrix_clear_map(obj); // delete btnmap - - // Create new map - - // Reserve memory for JsonDocument - size_t maxsize = (128u * ((strlen(payload) / 128) + 1)) + 256; - DynamicJsonDocument map_doc(maxsize); - DeserializationError jsonError = deserializeJson(map_doc, payload); - - if(jsonError) { // Couldn't parse incoming JSON payload - return Log.warning(TAG_ATTR, F("JSON: Failed to parse incoming button map with error: %s"), - jsonError.c_str()); - } - - JsonArray arr = map_doc.as(); // Parse payload - - size_t tot_len = sizeof(char *) * (arr.size() + 1); - const char ** map_arr = (const char **)lv_mem_alloc(tot_len); - if(map_arr == NULL) { - return Log.error(TAG_ATTR, F("Out of memory while creating button map")); - } - memset(map_arr, 0, tot_len); - - // Create buffer - tot_len = 0; - size_t pos = 0; - for(JsonVariant btn : arr) { - tot_len += btn.as().length() + 1; - } - tot_len++; // trailing '\0' - Log.verbose(TAG_ATTR, F("Array Size = %d, Map Length = %d"), arr.size(), tot_len); - - char * buffer = (char *)lv_mem_alloc(tot_len); - if(map_arr == NULL) { - lv_mem_free(map_arr); - return Log.error(TAG_ATTR, F("Out of memory while creating button map")); - } - memset(buffer, 0, tot_len); // Important, last index needs to be 0 - - // Fill buffer - size_t index = 0; - for(JsonVariant btn : arr) { - size_t len = btn.as().length() + 1; - Log.verbose(TAG_ATTR, F(" * Adding button: %s (%d bytes)"), btn.as().c_str(), len); - memccpy(buffer + pos, btn.as().c_str(), 0, len); // Copy the labels into the buffer - map_arr[index++] = buffer + pos; // save pointer to start of the label - pos += len; - } - map_arr[index] = buffer + pos; // save pointer to the last \0 byte - - lv_btnmatrix_set_map(obj, map_arr); - - // TO DO : free & destroy previous buttonmap! - - } else { - hasp_out_str(obj, attr, *map_p); - } - return; - } // ATTR_MAP - } - - Log.warning(TAG_ATTR, F("Unknown property %s"), attr_p); -} - // ##################### Common Attributes ######################################################## static void hasp_process_obj_attribute_txt(lv_obj_t * obj, const char * attr, const char * payload, bool update) @@ -1751,6 +1747,12 @@ void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char } else { hasp_out_str(obj, attr, lv_roller_get_options(obj)); } + } else if(check_obj_type(obj, LV_HASP_BTNMATRIX)) { + if(update) { + my_btnmatrix_map_create(obj, payload); + } else { + hasp_out_str(obj, attr_p, "Not implemented"); // TODO : Literal String + } } else { goto attribute_not_found; } @@ -1786,9 +1788,17 @@ void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char lv_obj_del_async(obj); break; // attribute_found - case ATTR_MAP: + case ATTR_RED: // TODO: remove temp RED if(check_obj_type(obj, LV_HASP_BTNMATRIX)) { - hasp_process_btnmatrix_attribute(obj, attr_p, attr_hash, payload, update); + my_btnmatrix_map_clear(obj); // TODO : remove this test property + } else { + goto attribute_not_found; + } + break; + + case ATTR_MAP: // TODO: remove temp MAP, use options instead + if(check_obj_type(obj, LV_HASP_BTNMATRIX)) { + my_btnmatrix_map_create(obj, payload); } else { goto attribute_not_found; } diff --git a/src/hasp/hasp_attribute.h b/src/hasp/hasp_attribute.h index e3273b14..a1ec4d41 100644 --- a/src/hasp/hasp_attribute.h +++ b/src/hasp/hasp_attribute.h @@ -21,7 +21,7 @@ extern "C" { lv_chart_series_t * my_chart_get_series(lv_obj_t * chart, uint8_t ser_num); void my_obj_set_value_str_txt(lv_obj_t * obj, uint8_t part, lv_state_t state, const char * text); -void btnmatrix_clear_map(lv_obj_t * obj); +void my_btnmatrix_map_clear(lv_obj_t * obj); void line_clear_points(lv_obj_t * obj); void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char * payload, bool update); diff --git a/src/hasp/hasp_object.cpp b/src/hasp/hasp_object.cpp index 39816f4e..fc4a1c39 100644 --- a/src/hasp/hasp_object.cpp +++ b/src/hasp/hasp_object.cpp @@ -866,16 +866,15 @@ void hasp_new_object(const JsonObject & config, uint8_t & saved_page_id) void hasp_object_delete(lv_obj_t * obj) { switch(obj->user_data.objid) { - case LV_HASP_LINE: { + case LV_HASP_LINE: line_clear_points(obj); break; - } + case LV_HASP_BTNMATRIX: - btnmatrix_clear_map(obj); + my_btnmatrix_map_clear(obj); break; } - // TODO: delete value_str data for all parts - + // TODO: delete value_str data for ALL parts my_obj_set_value_str_txt(obj, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, NULL); } \ No newline at end of file