diff --git a/src/hasp/hasp.h b/src/hasp/hasp.h index efec4b2a..7e258b47 100644 --- a/src/hasp/hasp.h +++ b/src/hasp/hasp.h @@ -4,6 +4,8 @@ #ifndef HASP_H #define HASP_H +#define NORMALIZE(a, b, c) map(a, b, c, 0, 0xFFFFU) + #include #include "lvgl.h" #include "hasp_conf.h" diff --git a/src/hasp/hasp_attribute.cpp b/src/hasp/hasp_attribute.cpp index 518b1e3a..2556cdd9 100644 --- a/src/hasp/hasp_attribute.cpp +++ b/src/hasp/hasp_attribute.cpp @@ -260,16 +260,16 @@ 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) { - // Log.verbose(TAG_ATTR, "%s %d", __FILE__, __LINE__); + // Log.verbose(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); const void * value_str_p = lv_obj_get_style_value_str(obj, part); lv_obj_invalidate(obj); if(text == NULL || text[0] == 0) { - Log.verbose(TAG_ATTR, "%s %d", __FILE__, __LINE__); + // Log.verbose(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); lv_obj_set_style_local_value_str(obj, part, state, NULL); lv_mem_free(value_str_p); - Log.verbose(TAG_ATTR, "%s %d", __FILE__, __LINE__); + // Log.verbose(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); return; } @@ -280,15 +280,15 @@ void my_obj_set_value_str_txt(lv_obj_t * obj, uint8_t part, lv_state_t state, co size_t len = strlen(text) + 1; /*Allocate space for the new text*/ - // Log.verbose(TAG_ATTR, "%s %d", __FILE__, __LINE__); + // Log.verbose(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); value_str_p = (char *)lv_mem_alloc(len); LV_ASSERT_MEM(value_str_p); if(value_str_p == NULL) return; - // Log.verbose(TAG_ATTR, "%s %d", __FILE__, __LINE__); + // Log.verbose(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); strncpy((char *)value_str_p, text, len); lv_obj_set_style_local_value_str(obj, part, state, (char *)value_str_p); - Log.verbose(TAG_ATTR, "%s %d", __FILE__, __LINE__); + // Log.verbose(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); return; } @@ -306,10 +306,10 @@ void my_obj_set_value_str_txt(lv_obj_t * obj, uint8_t part, lv_state_t state, co } else { /*Free the old text*/ if(value_str_p != NULL) { - // Log.verbose(TAG_ATTR, "%s %d", __FILE__, __LINE__); + // Log.verbose(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); lv_mem_free(value_str_p); value_str_p = NULL; - // Log.verbose(TAG_ATTR, "%s %d", __FILE__, __LINE__); + // Log.verbose(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); } /*Get the size of the text*/ @@ -322,7 +322,7 @@ void my_obj_set_value_str_txt(lv_obj_t * obj, uint8_t part, lv_state_t state, co lv_obj_set_style_local_value_str(obj, part, state, (char *)value_str_p); } - // Log.verbose(TAG_ATTR, "%s %d", __FILE__, __LINE__); + // Log.verbose(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); } void my_btnmatrix_map_clear(lv_obj_t * obj) @@ -342,11 +342,11 @@ void my_btnmatrix_map_clear(lv_obj_t * obj) 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__); + Log.verbose(TAG_ATTR, F("%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__); + Log.verbose(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); lv_mem_free(map_p_tmp); // free label pointer array block - Log.verbose(TAG_ATTR, "%s %d", __FILE__, __LINE__); + Log.verbose(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); } } @@ -389,13 +389,13 @@ static void my_btnmatrix_map_create(lv_obj_t * obj, const char * payload) 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); + Log.verbose(TAG_ATTR, F("%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); + Log.verbose(TAG_ATTR, F("%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, @@ -406,9 +406,9 @@ static void my_btnmatrix_map_create(lv_obj_t * obj, const char * payload) } map_data_str[index] = buffer_addr + pos; // save pointer to the last \0 byte - Log.verbose(TAG_ATTR, "%s %d", __FILE__, __LINE__); + Log.verbose(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); lv_btnmatrix_set_map(obj, map_data_str); - Log.verbose(TAG_ATTR, "%s %d", __FILE__, __LINE__); + Log.verbose(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); } void line_clear_points(lv_obj_t * obj) @@ -497,140 +497,155 @@ static bool haspPayloadToColor(const char * payload, lv_color_t & color) uint8_t G8 = (G6 * 259 + 33) >> 6; uint8_t B8 = (B5 * 527 + 23) >> 6; color = lv_color_make(R8, G8, B8); + } else { /* Named Color Scheme*/ - switch(hasp_util_get_sdbm(payload)) { - case ATTR_RED: - color = lv_color_make(0xFF, 0x00, 0x00); - break; - case ATTR_TAN: - color = lv_color_make(0xD2, 0xB4, 0x8C); - break; - case ATTR_BLUE: - color = lv_color_make(0x00, 0x00, 0xFF); - break; - case ATTR_AQUA: - case ATTR_CYAN: - color = lv_color_make(0x00, 0xFF, 0xFF); - break; - case ATTR_GOLD: - color = lv_color_make(0xFF, 0xD7, 0x00); - break; - case ATTR_GRAY: - case ATTR_GREY: - color = lv_color_make(0x80, 0x80, 0x80); - break; - case ATTR_LIME: - color = lv_color_make(0x00, 0xFF, 0x00); - break; - case ATTR_NAVY: - color = lv_color_make(0x00, 0x00, 0x80); - break; - case ATTR_PERU: - color = lv_color_make(0xCD, 0x85, 0x3F); - break; - case ATTR_PINK: - color = lv_color_make(0xFF, 0xC0, 0xCB); - break; - case ATTR_PLUM: - color = lv_color_make(0xDD, 0xA0, 0xDD); - break; - case ATTR_SNOW: - color = lv_color_make(0xFF, 0xFA, 0xFA); - break; - case ATTR_TEAL: - color = lv_color_make(0x00, 0x80, 0x80); - break; - case ATTR_AZURE: - color = lv_color_make(0xF0, 0xFF, 0xFF); - break; - case ATTR_BEIGE: - color = lv_color_make(0xF5, 0xF5, 0xDC); - break; - case ATTR_BLACK: - color = lv_color_make(0x00, 0x00, 0x00); - break; - case ATTR_BLUSH: - color = lv_color_make(0xB0, 0x00, 0x00); - break; - case ATTR_BROWN: - color = lv_color_make(0xA5, 0x2A, 0x2A); - break; - case ATTR_CORAL: - color = lv_color_make(0xFF, 0x7F, 0x50); - break; - case ATTR_GREEN: - color = lv_color_make(0x00, 0x80, 0x00); - break; - case ATTR_IVORY: - color = lv_color_make(0xFF, 0xFF, 0xF0); - break; - case ATTR_KHAKI: - color = lv_color_make(0xF0, 0xE6, 0x8C); - break; - case ATTR_LINEN: - color = lv_color_make(0xFA, 0xF0, 0xE6); - break; - case ATTR_OLIVE: - color = lv_color_make(0x80, 0x80, 0x00); - break; - case ATTR_WHEAT: - color = lv_color_make(0xF5, 0xDE, 0xB3); - break; - case ATTR_WHITE: - color = lv_color_make(0xFF, 0xFF, 0xFF); - break; - case ATTR_BISQUE: - color = lv_color_make(0xFF, 0xE4, 0xC4); - break; - case ATTR_INDIGO: - color = lv_color_make(0x4B, 0x00, 0x82); - break; - case ATTR_MAROON: - color = lv_color_make(0x80, 0x00, 0x00); - break; - case ATTR_ORANGE: - color = lv_color_make(0xFF, 0xA5, 0x00); - break; - case ATTR_ORCHID: - color = lv_color_make(0xDA, 0x70, 0xD6); - break; - case ATTR_PURPLE: - color = lv_color_make(0x80, 0x00, 0x80); - break; - case ATTR_SALMON: - color = lv_color_make(0xFA, 0x80, 0x72); - break; - case ATTR_SIENNA: - color = lv_color_make(0xA0, 0x52, 0x2D); - break; - case ATTR_SILVER: - color = lv_color_make(0xC0, 0xC0, 0xC0); - break; - case ATTR_TOMATO: - color = lv_color_make(0xFF, 0x63, 0x47); - break; - case ATTR_VIOLET: - color = lv_color_make(0xEE, 0x82, 0xEE); - break; - case ATTR_YELLOW: - color = lv_color_make(0xFF, 0xFF, 0x00); - break; - case ATTR_FUCHSIA: - case ATTR_MAGENTA: - color = lv_color_make(0xFF, 0x00, 0xFF); - break; + // switch(hasp_util_get_sdbm(payload)) { + // case ATTR_RED: + // color = lv_color_make(0xFF, 0x00, 0x00); + // break; + // case ATTR_TAN: + // color = lv_color_make(0xD2, 0xB4, 0x8C); + // break; + // case ATTR_BLUE: + // color = lv_color_make(0x00, 0x00, 0xFF); + // break; + // case ATTR_AQUA: + // case ATTR_CYAN: + // color = lv_color_make(0x00, 0xFF, 0xFF); + // break; + // case ATTR_GOLD: + // color = lv_color_make(0xFF, 0xD7, 0x00); + // break; + // case ATTR_GRAY: + // case ATTR_GREY: + // color = lv_color_make(0x80, 0x80, 0x80); + // break; + // case ATTR_LIME: + // color = lv_color_make(0x00, 0xFF, 0x00); + // break; + // case ATTR_NAVY: + // color = lv_color_make(0x00, 0x00, 0x80); + // break; + // case ATTR_PERU: + // color = lv_color_make(0xCD, 0x85, 0x3F); + // break; + // case ATTR_PINK: + // color = lv_color_make(0xFF, 0xC0, 0xCB); + // break; + // case ATTR_PLUM: + // color = lv_color_make(0xDD, 0xA0, 0xDD); + // break; + // case ATTR_SNOW: + // color = lv_color_make(0xFF, 0xFA, 0xFA); + // break; + // case ATTR_TEAL: + // color = lv_color_make(0x00, 0x80, 0x80); + // break; + // case ATTR_AZURE: + // color = lv_color_make(0xF0, 0xFF, 0xFF); + // break; + // case ATTR_BEIGE: + // color = lv_color_make(0xF5, 0xF5, 0xDC); + // break; + // case ATTR_BLACK: + // color = lv_color_make(0x00, 0x00, 0x00); + // break; + // case ATTR_BLUSH: + // color = lv_color_make(0xB0, 0x00, 0x00); + // break; + // case ATTR_BROWN: + // color = lv_color_make(0xA5, 0x2A, 0x2A); + // break; + // case ATTR_CORAL: + // color = lv_color_make(0xFF, 0x7F, 0x50); + // break; + // case ATTR_GREEN: + // color = lv_color_make(0x00, 0x80, 0x00); + // break; + // case ATTR_IVORY: + // color = lv_color_make(0xFF, 0xFF, 0xF0); + // break; + // case ATTR_KHAKI: + // color = lv_color_make(0xF0, 0xE6, 0x8C); + // break; + // case ATTR_LINEN: + // color = lv_color_make(0xFA, 0xF0, 0xE6); + // break; + // case ATTR_OLIVE: + // color = lv_color_make(0x80, 0x80, 0x00); + // break; + // case ATTR_WHEAT: + // color = lv_color_make(0xF5, 0xDE, 0xB3); + // break; + // case ATTR_WHITE: + // color = lv_color_make(0xFF, 0xFF, 0xFF); + // break; + // case ATTR_BISQUE: + // color = lv_color_make(0xFF, 0xE4, 0xC4); + // break; + // case ATTR_INDIGO: + // color = lv_color_make(0x4B, 0x00, 0x82); + // break; + // case ATTR_MAROON: + // color = lv_color_make(0x80, 0x00, 0x00); + // break; + // case ATTR_ORANGE: + // color = lv_color_make(0xFF, 0xA5, 0x00); + // break; + // case ATTR_ORCHID: + // color = lv_color_make(0xDA, 0x70, 0xD6); + // break; + // case ATTR_PURPLE: + // color = lv_color_make(0x80, 0x00, 0x80); + // break; + // case ATTR_SALMON: + // color = lv_color_make(0xFA, 0x80, 0x72); + // break; + // case ATTR_SIENNA: + // color = lv_color_make(0xA0, 0x52, 0x2D); + // break; + // case ATTR_SILVER: + // color = lv_color_make(0xC0, 0xC0, 0xC0); + // break; + // case ATTR_TOMATO: + // color = lv_color_make(0xFF, 0x63, 0x47); + // break; + // case ATTR_VIOLET: + // color = lv_color_make(0xEE, 0x82, 0xEE); + // break; + // case ATTR_YELLOW: + // color = lv_color_make(0xFF, 0xFF, 0x00); + // break; + // case ATTR_FUCHSIA: + // case ATTR_MAGENTA: + // color = lv_color_make(0xFF, 0x00, 0xFF); + // break; - default: - /* Unknown color name */ - Log.warning(TAG_ATTR, F("Invalid color %s"), payload); - return false; + // default: + // /* Unknown color name */ + // Log.warning(TAG_ATTR, F("Invalid color %s"), payload); + // return false; + // } + // } + + size_t numColors = sizeof(haspNamedColors) / sizeof(haspNamedColors[0]); + uint16_t sdbm = hasp_util_get_sdbm(payload); + + for(size_t i = 0; i < numColors; i++) { + if(sdbm == (uint16_t)pgm_read_word_near(&(haspNamedColors[i].hash))) { + uint8_t r = (uint16_t)pgm_read_byte_near(&(haspNamedColors[i].r)); + uint8_t g = (uint16_t)pgm_read_byte_near(&(haspNamedColors[i].g)); + uint8_t b = (uint16_t)pgm_read_byte_near(&(haspNamedColors[i].b)); + color = lv_color_make(r, g, b); + return true; /* Color found */ + } } + return false; /* Color not found */ } - /* Unknown color scheme */ - return true; + return true; /* Color found */ } static lv_font_t * haspPayloadToFont(const char * payload) @@ -1034,7 +1049,7 @@ static void hasp_local_style_attr(lv_obj_t * obj, const char * attr_p, uint16_t case ATTR_TEXT_FONT: { lv_font_t * font = haspPayloadToFont(payload); if(font) { - uint8_t count; + uint8_t count = 3; if(check_obj_type(obj, LV_HASP_ROLLER)) count = my_roller_get_visible_row_count(obj); lv_obj_set_style_local_text_font(obj, part, state, font); if(check_obj_type(obj, LV_HASP_ROLLER)) lv_roller_set_visible_row_count(obj, count); @@ -1390,100 +1405,59 @@ static void hasp_process_obj_attribute_txt(lv_obj_t * obj, const char * attr, co Log.warning(TAG_ATTR, F("Unknown property %s"), attr); } -static void hasp_process_obj_attribute_val(lv_obj_t * obj, const char * attr, const char * payload, bool update) +bool hasp_process_obj_attribute_val(lv_obj_t * obj, const char * attr, const char * payload, bool update) { int16_t intval = atoi(payload); - uint16_t val = atoi(payload); - /* Attributes depending on objecttype */ - // lv_obj_type_t list; - // lv_obj_get_type(obj, &list); - // const char * objtype = list.type[0]; - - if(check_obj_type(obj, LV_HASP_BUTTON) && lv_btn_get_checkable(obj)) { - if(update) { - lv_btn_state_t state; - switch(val) { - case 0: - state = LV_BTN_STATE_RELEASED; - break; - case 1: - state = LV_BTN_STATE_CHECKED_RELEASED; - break; - case 3: - state = LV_BTN_STATE_CHECKED_DISABLED; - break; - default: - state = LV_BTN_STATE_DISABLED; - }; - return lv_btn_set_state(obj, state); - } else { - lv_btn_state_t state = lv_btn_get_state(obj); - switch(state) { - case LV_BTN_STATE_RELEASED: - case LV_BTN_STATE_PRESSED: - return hasp_out_int(obj, attr, 0); - case LV_BTN_STATE_CHECKED_RELEASED: - case LV_BTN_STATE_CHECKED_PRESSED: - return hasp_out_int(obj, attr, 1); - case LV_BTN_STATE_DISABLED: - return hasp_out_int(obj, attr, 2); - case LV_BTN_STATE_CHECKED_DISABLED: - return hasp_out_int(obj, attr, 3); + if(check_obj_type(obj, LV_HASP_BUTTON)) { + if(lv_btn_get_checkable(obj)) { + if(update) { + if(intval) + lv_obj_add_state(obj, LV_STATE_CHECKED); + else + lv_obj_clear_state(obj, LV_STATE_CHECKED); + } else { + hasp_out_int(obj, attr, lv_obj_get_state(obj, LV_BTN_PART_MAIN) & LV_STATE_CHECKED); } - } - } - - if(check_obj_type(obj, LV_HASP_CHECKBOX)) { - return update ? lv_checkbox_set_checked(obj, hasp_util_is_true(payload)) - : hasp_out_int(obj, attr, lv_checkbox_is_checked(obj)); - } - if(check_obj_type(obj, LV_HASP_SWITCH)) { - if(update) { - return hasp_util_is_true(payload) ? lv_switch_on(obj, LV_ANIM_ON) : lv_switch_off(obj, LV_ANIM_ON); } else { - return hasp_out_int(obj, attr, lv_switch_get_state(obj)); + return false; // not checkable } - + } else if(check_obj_type(obj, LV_HASP_CHECKBOX)) { + update ? lv_checkbox_set_checked(obj, hasp_util_is_true(payload)) + : hasp_out_int(obj, attr, lv_checkbox_is_checked(obj)); + } else if(check_obj_type(obj, LV_HASP_SWITCH)) { + if(update) + hasp_util_is_true(payload) ? lv_switch_on(obj, LV_ANIM_ON) : lv_switch_off(obj, LV_ANIM_ON); + else + hasp_out_int(obj, attr, lv_switch_get_state(obj)); } else if(check_obj_type(obj, LV_HASP_DDLIST)) { - lv_dropdown_set_selected(obj, val); - return; - + lv_dropdown_set_selected(obj, (uint16_t)intval); } else if(check_obj_type(obj, LV_HASP_LMETER)) { - return update ? lv_linemeter_set_value(obj, intval) : hasp_out_int(obj, attr, lv_linemeter_get_value(obj)); - + update ? lv_linemeter_set_value(obj, intval) : hasp_out_int(obj, attr, lv_linemeter_get_value(obj)); } else if(check_obj_type(obj, LV_HASP_SLIDER)) { - return update ? lv_slider_set_value(obj, intval, LV_ANIM_ON) - : hasp_out_int(obj, attr, lv_slider_get_value(obj)); - + update ? lv_slider_set_value(obj, intval, LV_ANIM_ON) : hasp_out_int(obj, attr, lv_slider_get_value(obj)); } else if(check_obj_type(obj, LV_HASP_LED)) { - return update ? lv_led_set_bright(obj, (uint8_t)val) : hasp_out_int(obj, attr, lv_led_get_bright(obj)); - + update ? lv_led_set_bright(obj, (uint8_t)intval) : hasp_out_int(obj, attr, lv_led_get_bright(obj)); } else if(check_obj_type(obj, LV_HASP_ARC)) { - return update ? lv_arc_set_value(obj, intval) : hasp_out_int(obj, attr, lv_arc_get_value(obj)); - + update ? lv_arc_set_value(obj, intval) : hasp_out_int(obj, attr, lv_arc_get_value(obj)); } else if(check_obj_type(obj, LV_HASP_GAUGE)) { - return update ? lv_gauge_set_value(obj, 0, intval) : hasp_out_int(obj, attr, lv_gauge_get_value(obj, 0)); - + update ? lv_gauge_set_value(obj, 0, intval) : hasp_out_int(obj, attr, lv_gauge_get_value(obj, 0)); } else if(check_obj_type(obj, LV_HASP_ROLLER)) { - lv_roller_set_selected(obj, val, LV_ANIM_ON); - return; - + lv_roller_set_selected(obj, (uint16_t)intval, LV_ANIM_ON); } else if(check_obj_type(obj, LV_HASP_BAR)) { - return update ? lv_bar_set_value(obj, intval, LV_ANIM_ON) : hasp_out_int(obj, attr, lv_bar_get_value(obj)); - + update ? lv_bar_set_value(obj, intval, LV_ANIM_ON) : hasp_out_int(obj, attr, lv_bar_get_value(obj)); } else if(check_obj_type(obj, LV_HASP_CPICKER)) { if(update) { lv_color_t color; - if(!haspPayloadToColor(payload, color)) return; - lv_cpicker_set_color(obj, color); + if(haspPayloadToColor(payload, color)) lv_cpicker_set_color(obj, color); } else { hasp_out_color(obj, attr, lv_cpicker_get_color(obj)); } - return; + } else { + return false; } - Log.warning(TAG_ATTR, F("Unknown property %s"), attr); + return true; } static void hasp_process_obj_attribute_range(lv_obj_t * obj, const char * attr, const char * payload, bool update, @@ -1639,7 +1613,7 @@ void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char break; // attribute_found case ATTR_VAL: - hasp_process_obj_attribute_val(obj, attr, payload, update); + if(!hasp_process_obj_attribute_val(obj, attr, payload, update)) goto attribute_not_found; break; // attribute_found case ATTR_MIN: @@ -1832,5 +1806,5 @@ attribute_found: return; attribute_not_found: - Log.verbose(TAG_ATTR, F("%s (%d)"), attr_p, attr_hash); + Log.warning(TAG_ATTR, F("Unknown property %s (%d)"), attr_p, attr_hash); } \ No newline at end of file diff --git a/src/hasp/hasp_attribute.h b/src/hasp/hasp_attribute.h index a1ec4d41..d4b5af63 100644 --- a/src/hasp/hasp_attribute.h +++ b/src/hasp/hasp_attribute.h @@ -25,6 +25,7 @@ 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); +bool hasp_process_obj_attribute_val(lv_obj_t * obj, const char * attr, const char * payload, bool update); #ifdef __cplusplus } /* extern "C" */ @@ -342,4 +343,28 @@ _HASP_ATTRIBUTE(SCALE_END_LINE_WIDTH, scale_end_line_width, lv_style_int_t) #define ATTR_FUCHSIA 5463 #define ATTR_MAGENTA 49385 +struct hasp_color_t +{ + uint16_t hash; + uint8_t r, g, b; +}; + +/* Named COLOR lookup table */ +const hasp_color_t haspNamedColors[] PROGMEM = { + {ATTR_RED, 0xFF, 0x00, 0x00}, {ATTR_TAN, 0xD2, 0xB4, 0x8C}, {ATTR_AQUA, 0x00, 0xFF, 0xFF}, + {ATTR_BLUE, 0x00, 0x00, 0xFF}, {ATTR_CYAN, 0x00, 0xFF, 0xFF}, {ATTR_GOLD, 0xFF, 0xD7, 0x00}, + {ATTR_GRAY, 0x80, 0x80, 0x80}, {ATTR_GREY, 0x80, 0x80, 0x80}, {ATTR_LIME, 0x00, 0xFF, 0x00}, + {ATTR_NAVY, 0x00, 0x00, 0x80}, {ATTR_PERU, 0xCD, 0x85, 0x3F}, {ATTR_PINK, 0xFF, 0xC0, 0xCB}, + {ATTR_PLUM, 0xDD, 0xA0, 0xDD}, {ATTR_SNOW, 0xFF, 0xFA, 0xFA}, {ATTR_TEAL, 0x00, 0x80, 0x80}, + {ATTR_AZURE, 0xF0, 0xFF, 0xFF}, {ATTR_BEIGE, 0xF5, 0xF5, 0xDC}, {ATTR_BLACK, 0x00, 0x00, 0x00}, + {ATTR_BLUSH, 0xB0, 0x00, 0x00}, {ATTR_BROWN, 0xA5, 0x2A, 0x2A}, {ATTR_CORAL, 0xFF, 0x7F, 0x50}, + {ATTR_GREEN, 0x00, 0x80, 0x00}, {ATTR_IVORY, 0xFF, 0xFF, 0xF0}, {ATTR_KHAKI, 0xF0, 0xE6, 0x8C}, + {ATTR_LINEN, 0xFA, 0xF0, 0xE6}, {ATTR_OLIVE, 0x80, 0x80, 0x00}, {ATTR_WHEAT, 0xF5, 0xDE, 0xB3}, + {ATTR_WHITE, 0xFF, 0xFF, 0xFF}, {ATTR_BISQUE, 0xFF, 0xE4, 0xC4}, {ATTR_INDIGO, 0x4B, 0x00, 0x82}, + {ATTR_MAROON, 0x80, 0x00, 0x00}, {ATTR_ORANGE, 0xFF, 0xA5, 0x00}, {ATTR_ORCHID, 0xDA, 0x70, 0xD6}, + {ATTR_PURPLE, 0x80, 0x00, 0x80}, {ATTR_SALMON, 0xFA, 0x80, 0x72}, {ATTR_SIENNA, 0xA0, 0x52, 0x2D}, + {ATTR_SILVER, 0xC0, 0xC0, 0xC0}, {ATTR_TOMATO, 0xFF, 0x63, 0x47}, {ATTR_VIOLET, 0xEE, 0x82, 0xEE}, + {ATTR_YELLOW, 0xFF, 0xFF, 0x00}, {ATTR_FUCHSIA, 0xFF, 0x00, 0xFF}, {ATTR_MAGENTA, 0xFF, 0x00, 0xFF}, +}; + #endif diff --git a/src/hasp/hasp_dispatch.cpp b/src/hasp/hasp_dispatch.cpp index 4e1e89b2..eedb531c 100644 --- a/src/hasp/hasp_dispatch.cpp +++ b/src/hasp/hasp_dispatch.cpp @@ -37,7 +37,7 @@ uint8_t nCommands = 0; haspCommand_t commands[16]; static void dispatch_config(const char * topic, const char * payload); -static void dispatch_group_state(uint8_t groupid, uint8_t eventid, lv_obj_t * obj); +// void dispatch_group_value(uint8_t groupid, int16_t state, lv_obj_t * obj); static inline void dispatch_state_msg(const __FlashStringHelper * subtopic, const char * payload); void dispatch_screenshot(const char *, const char * filename) @@ -101,6 +101,18 @@ inline void dispatch_process_button_attribute(String strTopic, const char * payl if(pageid >= 0 && pageid <= 255 && objid >= 0 && objid <= 255) { hasp_process_attribute((uint8_t)pageid, (uint8_t)objid, strAttr.c_str(), payload); } // valid page + + } else { + + unsigned int pageid, objid; + const char * topic_p = strTopic.c_str(); + + if(sscanf(topic_p, "p%ub%u.", &pageid, &objid) == 2) { // Literal String + size_t offset = 0; + while(topic_p[offset++] != '.') { + } + hasp_process_attribute((uint8_t)pageid, (uint8_t)objid, topic_p + offset, payload); + } } } @@ -121,8 +133,8 @@ void dispatch_command(const char * topic, const char * payload) /* =============================== Not standard payload commands ===================================== */ if(strlen(topic) == 7 && topic == strstr_P(topic, PSTR("output"))) { - dispatch_group_state(atoi(topic + 6), hasp_util_is_true(payload) ? HASP_EVENT_ON : HASP_EVENT_OFF, - NULL); // + 6 => trim 'output' from the topic + int16_t state = atoi(payload); + dispatch_normalized_group_value(atoi(topic + 6), state, NULL); // + 6 => trim 'output' from the topic // } else if(strcasecmp_P(topic, PSTR("screenshot")) == 0) { // guiTakeScreenshot("/screenshot.bmp"); // Literal String @@ -243,8 +255,20 @@ void dispatch_output_idle_state(uint8_t state) dispatch_state_msg(F("idle"), payload); } +void dispatch_output_group_state(uint8_t groupid, uint16_t state) +{ + char payload[64]; + char number[16]; // Return the current state + itoa(state, number, DEC); + snprintf_P(payload, sizeof(payload), PSTR("{\"group\":%d,\"state\":\"%s\"}"), groupid, number); + + dispatch_state_msg(F("output"), payload); +} + void IRAM_ATTR dispatch_send_obj_attribute_str(uint8_t pageid, uint8_t btnid, const char * attribute, const char * data) { + if(!attribute || !data) return; + char topic[12]; char payload[32 + strlen(data) + strlen(attribute)]; // snprintf_P(payload, sizeof(payload), PSTR("{\"page\":%u,\"id\":%u,\"%s\":\"%s\"}"), pageid, btnid, attribute, @@ -399,7 +423,7 @@ static void dispatch_get_event_name(uint8_t eventid, char * buffer, size_t size) } #if HASP_USE_GPIO > 0 -void dispatch_gpio_event(uint8_t pin, uint8_t group, uint8_t eventid) +void dispatch_gpio_input_event(uint8_t pin, uint8_t group, uint8_t eventid) { char payload[64]; char event[8]; @@ -411,7 +435,7 @@ void dispatch_gpio_event(uint8_t pin, uint8_t group, uint8_t eventid) #endif // update outputstates - dispatch_group_state(group, dispatch_get_event_state(eventid), NULL); + // dispatch_group_onoff(group, dispatch_get_event_state(eventid), NULL); } #endif @@ -428,9 +452,16 @@ void dispatch_object_event(lv_obj_t * obj, uint8_t eventid) dispatch_send_obj_attribute_str(pageid, objid, topic, payload); } - if(obj->user_data.groupid > 0) { - dispatch_group_state(obj->user_data.groupid, eventid, obj); - } + // dispatch_group_onoff(obj->user_data.groupid, dispatch_get_event_state(eventid), obj); +} + +void dispatch_object_value_changed(lv_obj_t * obj, int16_t state) +{ + char topic[4]; + + hasp_update_sleep_state(); // wakeup? + snprintf_P(topic, sizeof(topic), PSTR("val")); + hasp_send_obj_attribute_int(obj, topic, state); } /********************************************** Output States ******************************************/ @@ -448,21 +479,39 @@ static inline void dispatch_state_msg(const __FlashStringHelper * subtopic, cons #endif } -void dispatch_group_state(uint8_t groupid, uint8_t eventid, lv_obj_t * obj) +// void dispatch_group_onoff(uint8_t groupid, uint16_t eventid, lv_obj_t * obj) +// { +// if((eventid == HASP_EVENT_LONG) || (eventid == HASP_EVENT_HOLD)) return; // don't send repeat events + +// if(groupid >= 0) { +// bool state = dispatch_get_event_state(eventid); +// gpio_set_group_onoff(groupid, state); +// object_set_group_state(groupid, eventid, obj); +// } + +// char payload[8]; +// dispatch_get_event_name(eventid, payload, sizeof(payload)); +// // dispatch_output_group_state(groupid, payload); +// } + +// void dispatch_group_value(uint8_t groupid, int16_t state, lv_obj_t * obj) +// { +// if(groupid >= 0) { +// gpio_set_group_value(groupid, state); +// object_set_group_state(groupid, state, obj); +// } + +// char payload[8]; +// // dispatch_output_group_state(groupid, payload); +// } + +void dispatch_normalized_group_value(uint8_t groupid, uint16_t value, lv_obj_t * obj) { - if((eventid == HASP_EVENT_LONG) || (eventid == HASP_EVENT_HOLD)) return; // don't send repeat events - - if(groupid >= 0) { - gpio_set_group_state(groupid, eventid); - object_set_group_state(groupid, eventid, obj); + if(groupid > 0) { + Log.verbose(TAG_MSGR, F("GROUP %d value %d"), groupid, value); + gpio_set_normalized_group_value(groupid, value); + // object_set_group_state(groupid, value, obj); } - - char payload[64]; - char state[4]; // Return the current state - memcpy_P(state, dispatch_get_event_state(eventid) ? PSTR("ON") : PSTR("OFF"), sizeof(state)); - snprintf_P(payload, sizeof(payload), PSTR("{\"group\":%d,\"state\":\"%s\"}"), groupid, state); - - dispatch_state_msg(F("output"), payload); } /********************************************** Native Commands ****************************************/ diff --git a/src/hasp/hasp_dispatch.h b/src/hasp/hasp_dispatch.h index 7e95c544..9f6ff358 100644 --- a/src/hasp/hasp_dispatch.h +++ b/src/hasp/hasp_dispatch.h @@ -47,9 +47,12 @@ void dispatch_output_idle_state(uint8_t state); void dispatch_output_statusupdate(const char *, const char *); void dispatch_output_current_page(); -void dispatch_gpio_event(uint8_t pin, uint8_t group, uint8_t eventid); +void dispatch_gpio_input_event(uint8_t pin, uint8_t group, uint8_t eventid); void dispatch_object_event(lv_obj_t * obj, uint8_t eventid); bool dispatch_get_event_state(uint8_t eventid); +void dispatch_object_value_changed(lv_obj_t * obj, int16_t state); + +void dispatch_normalized_group_value(uint8_t groupid, uint16_t value, lv_obj_t * obj); void IRAM_ATTR dispatch_send_obj_attribute_str(uint8_t pageid, uint8_t btnid, const char * attribute, const char * data); diff --git a/src/hasp/hasp_object.cpp b/src/hasp/hasp_object.cpp index d0ca7b31..97026007 100644 --- a/src/hasp/hasp_object.cpp +++ b/src/hasp/hasp_object.cpp @@ -48,7 +48,6 @@ lv_obj_t * hasp_find_obj_from_parent_id(lv_obj_t * parent, uint8_t objid) /* check tabs */ if(check_obj_type(child, LV_HASP_TABVIEW)) { - //#if LVGL_VERSION_MAJOR == 7 uint16_t tabcount = lv_tabview_get_tab_count(child); for(uint16_t i = 0; i < tabcount; i++) { lv_obj_t * tab = lv_tabview_get_tab(child, i); @@ -59,7 +58,6 @@ lv_obj_t * hasp_find_obj_from_parent_id(lv_obj_t * parent, uint8_t objid) grandchild = hasp_find_obj_from_parent_id(tab, objid); if(grandchild) return grandchild; /* grandchild found, return it */ } - //#endif } /* try next sibling */ @@ -231,6 +229,7 @@ void hasp_send_obj_attribute_color(lv_obj_t * obj, const char * attribute, lv_co { char buffer[40]; // "#ffffff","r":"255","g":"255","b":"255" lv_color32_t c32; + c32.full = lv_color_to32(color); snprintf_P(buffer, sizeof(buffer), PSTR("#%02x%02x%02x\",\"r\":\"%d\",\"g\":\"%d\",\"b\":\"%d"), c32.ch.red, c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue); @@ -239,31 +238,32 @@ void hasp_send_obj_attribute_color(lv_obj_t * obj, const char * attribute, lv_co // ##################### Value Senders ######################################################## -static void hasp_send_obj_attribute_P(lv_obj_t * obj, const char * attr, const char * data) -{ - char * buffer; - buffer = (char *)malloc(strlen_P(attr) + 1); - strcpy_P(buffer, attr); - hasp_send_obj_attribute_str(obj, buffer, data); - free(buffer); -} +// static void hasp_send_obj_attribute_P(lv_obj_t * obj, const char * attr, const char * data) +// { +// char * buffer; +// buffer = (char *)malloc(strlen_P(attr) + 1); +// strcpy_P(buffer, attr); +// hasp_send_obj_attribute_str(obj, buffer, data); +// free(buffer); +// } -static inline void hasp_send_obj_attribute_val(lv_obj_t * obj, int32_t val) -{ - char data[32]; - itoa(val, data, DEC); - hasp_send_obj_attribute_P(obj, PSTR("val"), data); -} +// static inline void hasp_obj_value_changed(lv_obj_t * obj, int32_t val) +// { +// dispatch_object_value_changed(obj, val); +// char data[32]; +// itoa(val, data, DEC); +// hasp_send_obj_attribute_P(obj, PSTR("val"), data); +//} -static inline void hasp_send_obj_attribute_event(lv_obj_t * obj, const char * event) -{ - hasp_send_obj_attribute_P(obj, PSTR("event"), event); -} +// static inline void hasp_send_obj_attribute_event(lv_obj_t * obj, const char * event) +// { +// hasp_send_obj_attribute_P(obj, PSTR("event"), event); +// } -static inline void hasp_send_obj_attribute_txt(lv_obj_t * obj, const char * txt) -{ - hasp_send_obj_attribute_P(obj, PSTR("txt"), txt); -} +// static inline void hasp_send_obj_attribute_txt(lv_obj_t * obj, const char * txt) +// { +// hasp_send_obj_attribute_P(obj, PSTR("txt"), txt); +// } // ##################### Event Handlers ######################################################## @@ -272,7 +272,7 @@ static inline void hasp_send_obj_attribute_txt(lv_obj_t * obj, const char * txt) * @param obj pointer to a button object * @param event type of event that occured */ -void IRAM_ATTR generic_event_handler(lv_obj_t * obj, lv_event_t event) +void generic_event_handler(lv_obj_t * obj, lv_event_t event) { uint8_t eventid; @@ -333,6 +333,7 @@ void IRAM_ATTR generic_event_handler(lv_obj_t * obj, lv_event_t event) hasp_update_sleep_state(); // wakeup? dispatch_object_event(obj, eventid); // send object event + dispatch_normalized_group_value(obj->user_data.groupid, NORMALIZE(dispatch_get_event_state(eventid), 0, 1), obj); } /** @@ -349,31 +350,39 @@ void wakeup_event_handler(lv_obj_t * obj, lv_event_t event) } /** - * Called when a toggle button is clicked - * @param obj pointer to a button - * @param event type of event that occured - */ -void IRAM_ATTR toggle_event_handler(lv_obj_t * obj, lv_event_t event) -{ - if(event == LV_EVENT_VALUE_CHANGED) { - hasp_update_sleep_state(); // wakeup? - hasp_send_obj_attribute_val(obj, lv_checkbox_is_checked(obj)); - } else if(event == LV_EVENT_DELETE) { - Log.verbose(TAG_HASP, F("Object deleted Event %d occured"), event); - hasp_object_delete(obj); - } -} - -/** - * Called when a switch is toggled + * Called when a object state is toggled on/off * @param obj pointer to a switch object * @param event type of event that occured */ -static void switch_event_handler(lv_obj_t * obj, lv_event_t event) +void toggle_event_handler(lv_obj_t * obj, lv_event_t event) { if(event == LV_EVENT_VALUE_CHANGED) { + char property[4]; + bool val = 0; hasp_update_sleep_state(); // wakeup? - hasp_send_obj_attribute_val(obj, lv_switch_get_state(obj)); + + switch(obj->user_data.objid) { + case LV_HASP_SWITCH: + val = lv_switch_get_state(obj); + break; + + case LV_HASP_CHECKBOX: + val = lv_checkbox_is_checked(obj); + break; + + case LV_HASP_BUTTON: { + val = lv_obj_get_state(obj, LV_BTN_PART_MAIN) & LV_STATE_CHECKED; + break; + } + + default: + return; + } + + snprintf_P(property, sizeof(property), PSTR("val")); + hasp_send_obj_attribute_int(obj, property, val); + dispatch_normalized_group_value(obj->user_data.groupid, NORMALIZE(val, 0, 1), obj); + } else if(event == LV_EVENT_DELETE) { Log.verbose(TAG_HASP, F("Object deleted Event %d occured"), event); hasp_object_delete(obj); @@ -381,22 +390,7 @@ static void switch_event_handler(lv_obj_t * obj, lv_event_t event) } /** - * Called when a checkboxed is clicked - * @param obj pointer to a checkbox - * @param event type of event that occured - */ -static void checkbox_event_handler(lv_obj_t * obj, lv_event_t event) -{ - if(event == LV_EVENT_VALUE_CHANGED) { - hasp_send_obj_attribute_val(obj, lv_checkbox_is_checked(obj)); - } else if(event == LV_EVENT_DELETE) { - Log.verbose(TAG_HASP, F("Object deleted Event %d occured"), event); - hasp_object_delete(obj); - } -} - -/** - * Called when a dropdown or roller list is clicked + * Called when a range value has changed * @param obj pointer to a dropdown list or roller * @param event type of event that occured */ @@ -406,17 +400,19 @@ static void selector_event_handler(lv_obj_t * obj, lv_event_t event) char buffer[128]; char property[36]; uint16_t val = 0; - + uint16_t max = 0; hasp_update_sleep_state(); // wakeup? switch(obj->user_data.objid) { case LV_HASP_DDLIST: val = lv_dropdown_get_selected(obj); + max = lv_dropdown_get_option_cnt(obj) - 1; lv_dropdown_get_selected_str(obj, buffer, sizeof(buffer)); break; case LV_HASP_ROLLER: val = lv_roller_get_selected(obj); + max = lv_roller_get_option_cnt(obj) - 1; lv_roller_get_selected_str(obj, buffer, sizeof(buffer)); break; @@ -436,17 +432,19 @@ static void selector_event_handler(lv_obj_t * obj, lv_event_t event) strncpy(buffer, txt, sizeof(buffer)); snprintf_P(property, sizeof(property), PSTR("row\":%d,\"col\":%d,\"txt"), row, col); - goto property_set; + hasp_send_obj_attribute_str(obj, property, buffer); + return; } default: return; } + // set the property snprintf_P(property, sizeof(property), PSTR("val\":%d,\"txt"), val); - - property_set: hasp_send_obj_attribute_str(obj, property, buffer); + if(max > 0) dispatch_normalized_group_value(obj->user_data.groupid, NORMALIZE(val, 0, max), obj); + } else if(event == LV_EVENT_DELETE) { Log.verbose(TAG_HASP, F("Object deleted Event %d occured"), event); hasp_object_delete(obj); @@ -474,15 +472,23 @@ void slider_event_handler(lv_obj_t * obj, lv_event_t event) } */ - int16_t val; + int16_t val = 0; + int16_t min = 0; + int16_t max = 0; + if(obj->user_data.objid == LV_HASP_SLIDER) { val = lv_slider_get_value(obj); + min = lv_slider_get_min_value(obj); + max = lv_slider_get_max_value(obj); } else if(obj->user_data.objid == LV_HASP_ARC) { val = lv_arc_get_value(obj); + min = lv_arc_get_min_value(obj); + max = lv_arc_get_max_value(obj); } else { return; } - hasp_send_obj_attribute_val(obj, lv_slider_get_value(obj)); + dispatch_object_value_changed(obj, val); + dispatch_normalized_group_value(obj->user_data.groupid, NORMALIZE(val, min, max), obj); } else if(event == LV_EVENT_DELETE) { Log.verbose(TAG_HASP, F("Object deleted Event %d occured"), event); @@ -501,6 +507,7 @@ static void cpicker_event_handler(lv_obj_t * obj, lv_event_t event) snprintf_P(color, sizeof(color), PSTR("color")); if(event == LV_EVENT_VALUE_CHANGED) { + hasp_update_sleep_state(); // wakeup? hasp_send_obj_attribute_color(obj, color, lv_cpicker_get_color(obj)); } else if(event == LV_EVENT_DELETE) { Log.verbose(TAG_HASP, F("Object deleted Event %d occured"), event); @@ -513,18 +520,60 @@ static void cpicker_event_handler(lv_obj_t * obj, lv_event_t event) // TODO make this a recursive function that goes over all objects only ONCE void object_set_group_state(uint8_t groupid, uint8_t eventid, lv_obj_t * src_obj) { + if(groupid == 0) return; bool state = dispatch_get_event_state(eventid); + for(uint8_t page = 0; page < HASP_NUM_PAGES; page++) { - uint8_t startid = 100 + groupid * 10; // groups start at id 100 - for(uint8_t objid = startid; objid < (startid + 10); objid++) { + uint8_t startid = 1; + for(uint8_t objid = startid; objid < 20; objid++) { lv_obj_t * obj = hasp_find_obj_from_parent_id(get_page_obj(page), objid); - if(obj && obj != src_obj) { // skip source object, if set + if(obj && obj != src_obj && obj->user_data.groupid == groupid) { // skip source object, if set lv_obj_set_state(obj, state ? LV_STATE_PRESSED | LV_STATE_CHECKED : LV_STATE_DEFAULT); } } } } +void object_set_group_value(lv_obj_t * parent, uint8_t groupid, const char * payload) +{ + if(groupid == 0 || parent == nullptr) return; + + lv_obj_t * child; + child = lv_obj_get_child(parent, NULL); + while(child) { + /* child found, update it */ + if(groupid == child->user_data.groupid) hasp_process_obj_attribute_val(child, NULL, payload, true); + + /* update grandchildren */ + object_set_group_value(child, groupid, payload); + + /* check tabs */ + if(check_obj_type(child, LV_HASP_TABVIEW)) { + //#if LVGL_VERSION_MAJOR == 7 + uint16_t tabcount = lv_tabview_get_tab_count(child); + for(uint16_t i = 0; i < tabcount; i++) { + lv_obj_t * tab = lv_tabview_get_tab(child, i); + Log.verbose(TAG_HASP, F("Found tab %i"), i); + if(tab->user_data.groupid && groupid == tab->user_data.groupid) + hasp_process_obj_attribute_val(tab, NULL, payload, true); /* tab found, update it */ + + /* check grandchildren */ + object_set_group_value(tab, groupid, payload); + } + //#endif + } + + /* try next sibling */ + child = lv_obj_get_child(parent, child); + } +} + +void object_set_group_value(uint8_t groupid, int16_t state) +{ + char payload[16]; + itoa(state, payload, DEC); +} + //////////////////////////////////////////////////////////////////////////////////////////////////// // Used in the dispatcher & hasp_new_object @@ -633,7 +682,7 @@ void hasp_new_object(const JsonObject & config, uint8_t & saved_page_id) case HASP_OBJ_CB: obj = lv_checkbox_create(parent_obj, NULL); if(obj) { - lv_obj_set_event_cb(obj, checkbox_event_handler); + lv_obj_set_event_cb(obj, toggle_event_handler); obj->user_data.objid = LV_HASP_CHECKBOX; } break; @@ -859,7 +908,7 @@ void hasp_new_object(const JsonObject & config, uint8_t & saved_page_id) case HASP_OBJ_SWITCH: obj = lv_switch_create(parent_obj, NULL); if(obj) { - lv_obj_set_event_cb(obj, switch_event_handler); + lv_obj_set_event_cb(obj, toggle_event_handler); obj->user_data.objid = LV_HASP_SWITCH; } break; diff --git a/src/hasp/hasp_object.h b/src/hasp/hasp_object.h index 30728dff..0d60f7c8 100644 --- a/src/hasp/hasp_object.h +++ b/src/hasp/hasp_object.h @@ -70,8 +70,8 @@ void hasp_process_attribute(uint8_t pageid, uint8_t objid, const char * attr, co void object_set_group_state(uint8_t groupid, uint8_t eventid, lv_obj_t * src_obj); -void IRAM_ATTR generic_event_handler(lv_obj_t * obj, lv_event_t event); -void IRAM_ATTR toggle_event_handler(lv_obj_t * obj, lv_event_t event); +void generic_event_handler(lv_obj_t * obj, lv_event_t event); +void toggle_event_handler(lv_obj_t * obj, lv_event_t event); void slider_event_handler(lv_obj_t * obj, lv_event_t event); void wakeup_event_handler(lv_obj_t * obj, lv_event_t event); diff --git a/src/hasp_gpio.cpp b/src/hasp_gpio.cpp index 66aeb956..d412e47e 100644 --- a/src/hasp_gpio.cpp +++ b/src/hasp_gpio.cpp @@ -49,30 +49,44 @@ static void gpio_event_handler(AceButton * button, uint8_t eventType, uint8_t bu { uint8_t btnid = button->getId(); uint8_t eventid; + bool state = false; switch(eventType) { case AceButton::kEventPressed: - eventid = HASP_EVENT_DOWN; + if(gpioConfig[btnid].type == HASP_GPIO_SWITCH || gpioConfig[btnid].type == HASP_GPIO_SWITCH_INVERTED) { + eventid = HASP_EVENT_ON; + } else { + eventid = HASP_EVENT_DOWN; + } + state = true; break; case 2: // AceButton::kEventClicked: eventid = HASP_EVENT_SHORT; break; - case AceButton::kEventDoubleClicked: - eventid = HASP_EVENT_DOUBLE; - break; + // case AceButton::kEventDoubleClicked: + // eventid = HASP_EVENT_DOUBLE; + // break; case AceButton::kEventLongPressed: eventid = HASP_EVENT_LONG; + // state = true; // do not repeat DOWN + LONG break; - case AceButton::kEventRepeatPressed: - // return; // Fix needed for switches - eventid = HASP_EVENT_HOLD; - break; + // case AceButton::kEventRepeatPressed: + // eventid = HASP_EVENT_HOLD; + // state = true; // do not repeat DOWN + LONG + HOLD + // break; case AceButton::kEventReleased: - eventid = HASP_EVENT_UP; + if(gpioConfig[btnid].type == HASP_GPIO_SWITCH || gpioConfig[btnid].type == HASP_GPIO_SWITCH_INVERTED) { + eventid = HASP_EVENT_OFF; + } else { + eventid = HASP_EVENT_UP; + } break; default: eventid = HASP_EVENT_LOST; } - dispatch_gpio_event(gpioConfig[btnid].pin, gpioConfig[btnid].group, eventid); + + dispatch_gpio_input_event(gpioConfig[btnid].pin, gpioConfig[btnid].group, eventid); + if(eventid != HASP_EVENT_LONG) // do not repeat DOWN + LONG + dispatch_normalized_group_value(gpioConfig[btnid].group, NORMALIZE(state, 0, 1), NULL); } void aceButtonSetup(void) @@ -81,8 +95,8 @@ void aceButtonSetup(void) buttonConfig->setEventHandler(gpio_event_handler); // Features - buttonConfig->setFeature(ButtonConfig::kFeatureClick); - buttonConfig->setFeature(ButtonConfig::kFeatureLongPress); + // buttonConfig->setFeature(ButtonConfig::kFeatureClick); + // buttonConfig->setFeature(ButtonConfig::kFeatureLongPress); // buttonConfig->setFeature(ButtonConfig::kFeatureRepeatPress); // buttonConfig->setFeature(ButtonConfig::kFeatureDoubleClick); // buttonConfig->setFeature(ButtonConfig::kFeatureSuppressClickBeforeDoubleClick); @@ -98,7 +112,7 @@ void aceButtonSetup(void) void IRAM_ATTR gpioLoop(void) { // Should be called every 4-5ms or faster, for the default debouncing time of ~20ms. - for(uint32_t i = 0; i < gpioUsedInputCount; i++) { + for(uint8_t i = 0; i < gpioUsedInputCount; i++) { if(button[i]) button[i]->check(); } } @@ -113,19 +127,19 @@ void gpioAddButton(uint8_t pin, uint8_t input_mode, uint8_t default_state, uint8 input_mode, default_state); button[i] = new AceButton(pin, default_state, index); - // button[i]->init(pin, default_state, index); if(button[i]) { - //pinMode(pin, input_mode); + // pinMode(pin, input_mode); ButtonConfig * buttonConfig = button[i]->getButtonConfig(); buttonConfig->setEventHandler(gpio_event_handler); buttonConfig->setFeature(ButtonConfig::kFeatureClick); buttonConfig->clearFeature(ButtonConfig::kFeatureDoubleClick); buttonConfig->setFeature(ButtonConfig::kFeatureLongPress); - //buttonConfig->clearFeature(ButtonConfig::kFeatureRepeatPress); + // buttonConfig->clearFeature(ButtonConfig::kFeatureRepeatPress); buttonConfig->clearFeature( ButtonConfig::kFeatureSuppressClickBeforeDoubleClick); // Causes annoying pauses + buttonConfig->setFeature(ButtonConfig::kFeatureSuppressAfterClick); Log.trace(TAG_GPIO, F("Button%d created on pin %d (index %d) mode %d default %d"), i, pin, index, input_mode, default_state); @@ -138,6 +152,35 @@ void gpioAddButton(uint8_t pin, uint8_t input_mode, uint8_t default_state, uint8 index, HASP_NUM_INPUTS); } +void gpioAddSwitch(uint8_t pin, uint8_t input_mode, uint8_t default_state, uint8_t index) +{ + uint8_t i; + for(i = 0; i < HASP_NUM_INPUTS; i++) { + + if(!button[i]) { + Log.notice(TAG_GPIO, F("Creating Switch%d on pin %d (index %d) mode %d default %d"), i, pin, index, + input_mode, default_state); + + button[i] = new AceButton(pin, default_state, index); + + if(button[i]) { + // pinMode(pin, input_mode); + + ButtonConfig * buttonConfig = button[i]->getButtonConfig(); + buttonConfig->setEventHandler(gpio_event_handler); + buttonConfig->setFeature(ButtonConfig::kFeatureSuppressAll); + + Log.trace(TAG_GPIO, F("Button%d switch on pin %d (index %d) mode %d default %d"), i, pin, index, + input_mode, default_state); + gpioUsedInputCount = i + 1; + return; + } + } + } + Log.error(TAG_GPIO, F("Failed to create Button%d pin %d (index %d). All %d slots available are in use!"), i, pin, + index, HASP_NUM_INPUTS); +} + void gpioAddTouchButton(uint8_t pin, uint8_t input_mode, uint8_t default_state, uint8_t index) { uint8_t i; @@ -173,7 +216,7 @@ void gpioSetup() { aceButtonSetup(); - for(uint32_t i = 0; i < HASP_NUM_GPIO_CONFIG; i++) { + for(uint8_t i = 0; i < HASP_NUM_GPIO_CONFIG; i++) { uint8_t input_mode; switch(gpioConfig[i].gpio_function) { case OUTPUT: @@ -193,29 +236,36 @@ void gpioSetup() switch(gpioConfig[i].type) { case HASP_GPIO_SWITCH: + gpioAddSwitch(gpioConfig[i].pin, input_mode, HIGH, i); + pinMode(gpioConfig[i].pin, INPUT_PULLUP); + break; case HASP_GPIO_BUTTON: gpioAddButton(gpioConfig[i].pin, input_mode, HIGH, i); pinMode(gpioConfig[i].pin, INPUT_PULLUP); break; case HASP_GPIO_SWITCH_INVERTED: + gpioAddSwitch(gpioConfig[i].pin, input_mode, LOW, i); + pinMode(gpioConfig[i].pin, INPUT_PULLDOWN); + break; case HASP_GPIO_BUTTON_INVERTED: gpioAddButton(gpioConfig[i].pin, input_mode, LOW, i); + pinMode(gpioConfig[i].pin, INPUT_PULLDOWN); break; case HASP_GPIO_RELAY: case HASP_GPIO_RELAY_INVERTED: - case HASP_GPIO_LED: - case HASP_GPIO_LED_INVERTED: pinMode(gpioConfig[i].pin, OUTPUT); break; + case HASP_GPIO_LED: + case HASP_GPIO_LED_INVERTED: case HASP_GPIO_PWM: case HASP_GPIO_PWM_INVERTED: // case HASP_GPIO_BACKLIGHT: pinMode(gpioConfig[i].pin, OUTPUT); #if defined(ARDUINO_ARCH_ESP32) // configure LED PWM functionalitites - ledcSetup(gpioConfig[i].group, 20000, 10); + ledcSetup(gpioConfig[i].group, 20000, 12); // attach the channel to the GPIO to be controlled ledcAttachPin(gpioConfig[i].pin, gpioConfig[i].group); #endif @@ -224,57 +274,76 @@ void gpioSetup() } } -void gpio_set_state(hasp_gpio_config_t gpio, bool state) +/* ********************************* State Setters *************************************** */ +void gpio_set_normalized_value(hasp_gpio_config_t gpio, uint16_t state) { switch(gpio.type) { case HASP_GPIO_RELAY: - case HASP_GPIO_LED: - digitalWrite(gpio.pin, state ? HIGH : LOW); + gpio.val = state >= 0x8000U ? HIGH : LOW; + digitalWrite(gpio.pin, gpio.val); break; case HASP_GPIO_RELAY_INVERTED: - case HASP_GPIO_LED_INVERTED: - digitalWrite(gpio.pin, state ? LOW : HIGH); + gpio.val = state >= 0x8000U ? LOW : HIGH; + digitalWrite(gpio.pin, gpio.val); break; #if defined(ARDUINO_ARCH_ESP32) + case HASP_GPIO_LED: case HASP_GPIO_PWM: - ledcWrite(gpio.group, map(state, 0, 1, 0, 1023)); // ledChannel and value + gpio.val = map(state, 0, 0xFFFFU, 0, 4095); + ledcWrite(gpio.group, gpio.val); // ledChannel and value break; + case HASP_GPIO_LED_INVERTED: case HASP_GPIO_PWM_INVERTED: - ledcWrite(gpio.group, map(!state, 0, 1, 0, 1023)); // ledChannel and value + gpio.val = map(0xFFFFU - state, 0, 0xFFFFU, 0, 4095); + ledcWrite(gpio.group, gpio.val); // ledChannel and value break; #else + case HASP_GPIO_LED: case HASP_GPIO_PWM: - analogWrite(gpio.pin, map(state, 0, 1, 0, 1023)); + analogWrite(gpio.pin, map(state, 0, 0xFFFFU, 0, 1023)); break; + case HASP_GPIO_LED_INVERTED: case HASP_GPIO_PWM_INVERTED: - analogWrite(gpio.pin, map(!state, 0, 1, 0, 1023)); + analogWrite(gpio.pin, map(0xFFFFU - state, 0, 0xFFFFU, 0, 1023)); break; #endif - default:; - } -} - -void gpio_set_group_state(uint8_t groupid, uint8_t eventid) -{ - bool state = dispatch_get_event_state(eventid); - for(uint32_t i = 0; i < HASP_NUM_GPIO_CONFIG; i++) { - if(gpioConfig[i].group == groupid) { - gpio_set_state(gpioConfig[i], state); - } - } -} - -void gpio_set_gpio_state(uint8_t pin, uint8_t eventid) -{ - bool state = dispatch_get_event_state(eventid); - for(uint32_t i = 0; i < HASP_NUM_GPIO_CONFIG; i++) { - if(gpioConfig[i].pin == pin) { - gpio_set_state(gpioConfig[i], state); + default: return; + } + Log.verbose(TAG_GPIO, F(" * Group %d - Pin %d = %d"), gpio.group, gpio.pin, gpio.val); +} + +// void gpio_set_group_onoff(uint8_t groupid, bool ison) +// { +// for(uint8_t i = 0; i < HASP_NUM_GPIO_CONFIG; i++) { +// if(gpioConfig[i].group == groupid) { +// gpio_set_value(gpioConfig[i], ison ? gpioConfig[i].max : 0); +// } +// } +// } + +void gpio_set_normalized_group_value(uint8_t groupid, uint16_t state) +{ + // bool state = dispatch_get_event_state(eventid); + for(uint8_t i = 0; i < HASP_NUM_GPIO_CONFIG; i++) { + if(gpioConfig[i].group == groupid) { + gpio_set_normalized_value(gpioConfig[i], state); } } } +// not used +// void gpio_set_gpio_value(uint8_t pin, uint16_t state) +// { +// // bool state = dispatch_get_event_state(eventid); +// for(uint8_t i = 0; i < HASP_NUM_GPIO_CONFIG; i++) { +// if(gpioConfig[i].pin == pin) { +// gpio_set_value(gpioConfig[i], state); +// return; +// } +// } +// } + bool gpioIsSystemPin(uint8_t gpio) { if((gpio >= NUM_DIGITAL_PINS) // invalid pins @@ -376,9 +445,9 @@ bool gpioIsSystemPin(uint8_t gpio) #ifdef ARDUINO_ARCH_ESP8266 if((gpio >= 6) && (gpio <= 11)) return true; // VSPI -#ifndef TFT_SPI_OVERLAP + #ifndef TFT_SPI_OVERLAP if((gpio >= 12) && (gpio <= 14)) return true; // HSPI -#endif + #endif #endif return false; @@ -386,8 +455,8 @@ bool gpioIsSystemPin(uint8_t gpio) bool gpioInUse(uint8_t gpio) { - for(uint32_t i = 0; i < HASP_NUM_GPIO_CONFIG; i++) { - if(gpioConfigInUse(i) && (gpioConfig[i].pin == gpio)) { + for(uint8_t i = 0; i < HASP_NUM_GPIO_CONFIG; i++) { + if((gpioConfig[i].pin == gpio) && gpioConfigInUse(i)) { return true; // pin matches and is in use } } @@ -397,7 +466,7 @@ bool gpioInUse(uint8_t gpio) bool gpioSavePinConfig(uint8_t config_num, uint8_t pin, uint8_t type, uint8_t group, uint8_t pinfunc) { - // Input validation + // TODO: Input validation // ESP8266: Only Pullups except on gpio16 @@ -463,7 +532,7 @@ bool gpioGetConfig(const JsonObject & settings) /* Build new Gpio array if the count is not correct */ if(i != HASP_NUM_GPIO_CONFIG) { array = settings[FPSTR(F_GPIO_CONFIG)].to(); // Clear JsonArray - for(uint32_t i = 0; i < HASP_NUM_GPIO_CONFIG; i++) { + for(uint8_t i = 0; i < HASP_NUM_GPIO_CONFIG; i++) { uint32_t cur_val = gpioConfig[i].pin | (gpioConfig[i].group << 8) | (gpioConfig[i].type << 16) | (gpioConfig[i].gpio_function << 24); array.add(cur_val); diff --git a/src/hasp_gpio.h b/src/hasp_gpio.h index 8de46c2a..32730057 100644 --- a/src/hasp_gpio.h +++ b/src/hasp_gpio.h @@ -16,13 +16,15 @@ struct hasp_gpio_config_t uint8_t group; // groupid uint8_t type; // switch, button, ... uint8_t gpio_function; // INPUT, OUTPUT, PULLUP, etc + uint16_t val; }; void gpioSetup(void); void IRAM_ATTR gpioLoop(void); -void gpio_set_group_state(uint8_t groupid, uint8_t eventid); -void gpio_set_gpio_state(uint8_t pin, uint8_t eventid); +// void gpio_set_group_onoff(uint8_t groupid, bool ison); +void gpio_set_normalized_group_value(uint8_t groupid, uint16_t state); +// void gpio_set_gpio_state(uint8_t pin, uint16_t state); bool gpioSavePinConfig(uint8_t config_num, uint8_t pin, uint8_t type, uint8_t group, uint8_t pinfunc); bool gpioIsSystemPin(uint8_t gpio); diff --git a/src/svc/hasp_http.cpp b/src/svc/hasp_http.cpp index 619e7456..608e4815 100644 --- a/src/svc/hasp_http.cpp +++ b/src/svc/hasp_http.cpp @@ -1261,25 +1261,25 @@ void webHandleGpioConfig() httpMessage += halGpioName(gpio); httpMessage += F(""); - switch(conf.type) { + switch(conf.type & 0xfe) { case HASP_GPIO_SWITCH: - case HASP_GPIO_SWITCH_INVERTED: + // case HASP_GPIO_SWITCH_INVERTED: httpMessage += F("Switch"); break; case HASP_GPIO_BUTTON: - case HASP_GPIO_BUTTON_INVERTED: + // case HASP_GPIO_BUTTON_INVERTED: httpMessage += F("Button"); break; case HASP_GPIO_LED: - case HASP_GPIO_LED_INVERTED: + // case HASP_GPIO_LED_INVERTED: httpMessage += F("Led"); break; case HASP_GPIO_RELAY: - case HASP_GPIO_RELAY_INVERTED: + // case HASP_GPIO_RELAY_INVERTED: httpMessage += F("Relay"); break; case HASP_GPIO_PWM: - case HASP_GPIO_PWM_INVERTED: + // case HASP_GPIO_PWM_INVERTED: httpMessage += F("PWM"); break; default: @@ -1290,14 +1290,12 @@ void webHandleGpioConfig() httpMessage += conf.group; httpMessage += F(""); - bool inverted = (conf.type == HASP_GPIO_BUTTON_INVERTED) || - (conf.type == HASP_GPIO_SWITCH_INVERTED) || (conf.type == HASP_GPIO_LED_INVERTED) || - (conf.type == HASP_GPIO_RELAY_INVERTED) || (conf.type == HASP_GPIO_PWM_INVERTED); - if(inverted) { - httpMessage += F("High"); - } else { - httpMessage += F("Low"); - } + // bool inverted = (conf.type == HASP_GPIO_BUTTON_INVERTED) || + // (conf.type == HASP_GPIO_SWITCH_INVERTED) || (conf.type == HASP_GPIO_LED_INVERTED) + // || (conf.type == HASP_GPIO_RELAY_INVERTED) || (conf.type == + // HASP_GPIO_PWM_INVERTED); + + httpMessage += (conf.type & 0x1) ? F("High") : F("Low"); httpMessage += F("