From cc9b1467130b5ae881766768b07f6727443d36e9 Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Thu, 28 Oct 2021 10:35:45 +0200 Subject: [PATCH] Output widget colors as such --- radio/src/gui/colorlcd/zone.h | 6 ++- .../conversions/conversions_220_221.cpp | 12 ++++- .../yaml/yaml_datastructs_funcs.cpp | 19 +++++++- .../yaml/yaml_datastructs_nv14.cpp | 2 + .../conversions/yaml/yaml_datastructs_x10.cpp | 2 + .../yaml/yaml_datastructs_x12s.cpp | 2 + radio/src/storage/conversions/yaml/zone_220.h | 3 +- radio/src/storage/yaml/yaml_bits.cpp | 48 +++++++++++++++++++ radio/src/storage/yaml/yaml_bits.h | 5 ++ .../storage/yaml/yaml_datastructs_funcs.cpp | 27 +++++++++++ .../storage/yaml/yaml_datastructs_nv14.cpp | 2 + .../src/storage/yaml/yaml_datastructs_x10.cpp | 2 + .../storage/yaml/yaml_datastructs_x12s.cpp | 2 + radio/src/tests/conversions.cpp | 4 ++ 14 files changed, 132 insertions(+), 4 deletions(-) diff --git a/radio/src/gui/colorlcd/zone.h b/radio/src/gui/colorlcd/zone.h index 85d6d3e85..11554173d 100644 --- a/radio/src/gui/colorlcd/zone.h +++ b/radio/src/gui/colorlcd/zone.h @@ -46,6 +46,7 @@ union ZoneOptionValue uint32_t boolValue; char stringValue[LEN_ZONE_OPTION_STRING]; CUST_ATTR(source, r_zov_source, w_zov_source); + CUST_ATTR(color, r_zov_color, w_zov_color); }; enum ZoneOptionValueEnum { @@ -53,7 +54,8 @@ enum ZoneOptionValueEnum { ZOV_Signed, ZOV_Bool, ZOV_String, - ZOV_Source + ZOV_Source, + ZOV_Color }; struct ZoneOption @@ -101,6 +103,8 @@ inline ZoneOptionValueEnum zoneValueEnumFromType(ZoneOption::Type type) return ZOV_Source; case ZoneOption::Color: + return ZOV_Color; + case ZoneOption::Timer: case ZoneOption::Switch: case ZoneOption::TextSize: diff --git a/radio/src/storage/conversions/conversions_220_221.cpp b/radio/src/storage/conversions/conversions_220_221.cpp index f4bc9884b..4a2693b88 100644 --- a/radio/src/storage/conversions/conversions_220_221.cpp +++ b/radio/src/storage/conversions/conversions_220_221.cpp @@ -78,8 +78,18 @@ void patchWidgetOptions(ZonePersistentData* zones, unsigned n_zones) if (widgetName.empty()) continue; - if (widgetName == "Value" || widgetName == "Gauge") { + if (widgetName == "Value") { zone.widgetData.options[0].type = ZOV_Source; + zone.widgetData.options[1].type = ZOV_Color; + } else if (widgetName == "Gauge") { + zone.widgetData.options[0].type = ZOV_Source; + zone.widgetData.options[3].type = ZOV_Color; + } else if (widgetName == "Outputs") { + zone.widgetData.options[2].type = ZOV_Color; + zone.widgetData.options[3].type = ZOV_Color; + zone.widgetData.options[4].type = ZOV_Color; + } else if (widgetName == "Text") { + zone.widgetData.options[1].type = ZOV_Color; } } } diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_funcs.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_funcs.cpp index e5b13c6ac..1dd2dcfc7 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_funcs.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_funcs.cpp @@ -168,7 +168,7 @@ uint8_t select_zov(void* user, uint8_t* data, uint32_t bitoffs) data += bitoffs >> 3UL; data -= sizeof(ZoneOptionValueEnum); ZoneOptionValueEnum* p_zovt = (ZoneOptionValueEnum*)data; - if (*p_zovt > ZOV_Source) return 0; + if (*p_zovt > ZOV_Color) return 0; return *p_zovt; } @@ -181,6 +181,23 @@ bool w_zov_source(void* user, uint8_t* data, uint32_t bitoffs, auto p_val = reinterpret_cast(data); return w_mixSrcRaw(nullptr, p_val->unsignedValue, wf, opaque); } + +#include "colors.h" +#define r_zov_color nullptr + +bool w_zov_color(void* user, uint8_t* data, uint32_t bitoffs, + yaml_writer_func wf, void* opaque) +{ + data += bitoffs >> 3UL; + auto p_val = reinterpret_cast(data); + + uint32_t color = (uint32_t)GET_RED(p_val->unsignedValue) << 16 | + (uint32_t)GET_GREEN(p_val->unsignedValue) << 8 | + (uint32_t)GET_BLUE(p_val->unsignedValue); + + if (!wf(opaque, "0x", 2)) return false; + return wf(opaque, yaml_rgb2hex(color), 3 * 2); +} #endif uint8_t select_mod_type(void* user, uint8_t* data, uint32_t bitoffs) diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_nv14.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_nv14.cpp index 0f4e22c39..4143fdc10 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_nv14.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_nv14.cpp @@ -85,6 +85,7 @@ const struct YamlIdStr enum_ZoneOptionValueEnum[] = { { ZOV_Bool, "Bool" }, { ZOV_String, "String" }, { ZOV_Source, "Source" }, + { ZOV_Color, "Color" }, { 0, NULL } }; const struct YamlIdStr enum_TimerModes[] = { @@ -336,6 +337,7 @@ static const struct YamlNode union_ZoneOptionValue_elmts[] = { YAML_UNSIGNED( "boolValue", 32 ), YAML_STRING("stringValue", 8), YAML_CUSTOM("source",r_zov_source,w_zov_source), + YAML_CUSTOM("color",r_zov_color,w_zov_color), YAML_END }; static const struct YamlNode struct_ZoneOptionValueTyped[] = { diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_x10.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_x10.cpp index 1bbe398ee..7a8f14fbe 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_x10.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_x10.cpp @@ -85,6 +85,7 @@ const struct YamlIdStr enum_ZoneOptionValueEnum[] = { { ZOV_Bool, "Bool" }, { ZOV_String, "String" }, { ZOV_Source, "Source" }, + { ZOV_Color, "Color" }, { 0, NULL } }; const struct YamlIdStr enum_TimerModes[] = { @@ -357,6 +358,7 @@ static const struct YamlNode union_ZoneOptionValue_elmts[] = { YAML_UNSIGNED( "boolValue", 32 ), YAML_STRING("stringValue", 8), YAML_CUSTOM("source",r_zov_source,w_zov_source), + YAML_CUSTOM("color",r_zov_color,w_zov_color), YAML_END }; static const struct YamlNode struct_ZoneOptionValueTyped[] = { diff --git a/radio/src/storage/conversions/yaml/yaml_datastructs_x12s.cpp b/radio/src/storage/conversions/yaml/yaml_datastructs_x12s.cpp index 8ac5fb23d..1bc3b82e3 100644 --- a/radio/src/storage/conversions/yaml/yaml_datastructs_x12s.cpp +++ b/radio/src/storage/conversions/yaml/yaml_datastructs_x12s.cpp @@ -85,6 +85,7 @@ const struct YamlIdStr enum_ZoneOptionValueEnum[] = { { ZOV_Bool, "Bool" }, { ZOV_String, "String" }, { ZOV_Source, "Source" }, + { ZOV_Color, "Color" }, { 0, NULL } }; const struct YamlIdStr enum_TimerModes[] = { @@ -357,6 +358,7 @@ static const struct YamlNode union_ZoneOptionValue_elmts[] = { YAML_UNSIGNED( "boolValue", 32 ), YAML_STRING("stringValue", 8), YAML_CUSTOM("source",r_zov_source,w_zov_source), + YAML_CUSTOM("color",r_zov_color,w_zov_color), YAML_END }; static const struct YamlNode struct_ZoneOptionValueTyped[] = { diff --git a/radio/src/storage/conversions/yaml/zone_220.h b/radio/src/storage/conversions/yaml/zone_220.h index 3150b3fe6..694ea6425 100644 --- a/radio/src/storage/conversions/yaml/zone_220.h +++ b/radio/src/storage/conversions/yaml/zone_220.h @@ -37,7 +37,8 @@ enum ZoneOptionValueEnum { ZOV_Bool, ZOV_String, // added for conversion: - ZOV_Source + ZOV_Source, + ZOV_Color }; struct ZoneOption diff --git a/radio/src/storage/yaml/yaml_bits.cpp b/radio/src/storage/yaml/yaml_bits.cpp index 28a1d350d..321a830ec 100644 --- a/radio/src/storage/yaml/yaml_bits.cpp +++ b/radio/src/storage/yaml/yaml_bits.cpp @@ -163,6 +163,29 @@ uint32_t yaml_str2uint(const char* val, uint8_t val_len) return yaml_str2uint_ref(val, val_len); } +uint32_t yaml_hex2uint(const char* val, uint8_t val_len) +{ + uint32_t i_val = 0; + + while(val_len > 0) { + if (*val >= '0' && *val <= '9') { + i_val <<= 4; + i_val |= (*val - '0') & 0xF; + } else if (*val >= 'A' && *val <= 'F') { + i_val <<= 4; + i_val |= (*val - 'A' + 10) & 0xF; + } else if (*val >= 'a' && *val <= 'f') { + i_val <<= 4; + i_val |= (*val - 'a' + 10) & 0xF; + } else { + break; + } + val++; val_len--; + } + + return i_val; +} + static char int2str_buffer[MAX_STR] = {0}; static const char _int2str_lookup[] = { '0', '1', '2', '3', '4', '5', '6' , '7', '8', '9' }; @@ -188,6 +211,31 @@ char* yaml_signed2str(int32_t i) return yaml_unsigned2str((uint32_t)i); } +static const char _int2hex_lookup[] = {'0', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', 'A', 'B', + 'C', 'D', 'E', 'F'}; + +char* yaml_unsigned2hex(uint32_t i) +{ + char* c = int2str_buffer; + for (int n = sizeof(uint32_t) * 2; n > 0; n--) { + *(c++) = _int2hex_lookup[(i >> ((n - 1) * 4)) & 0xF]; + } + *c = '\0'; + return int2str_buffer; +} + +char* yaml_rgb2hex(uint32_t i) +{ + char* c = int2str_buffer; + for (int n = 3 * 2; n > 0; n--) { + *(c++) = _int2hex_lookup[(i >> ((n - 1) * 4)) & 0xF]; + } + *c = '\0'; + return int2str_buffer; +} + int32_t yaml_to_signed(uint32_t i, uint32_t bits) { if (i & (1 << (bits-1))) { diff --git a/radio/src/storage/yaml/yaml_bits.h b/radio/src/storage/yaml/yaml_bits.h index 81f462b36..14458d1be 100644 --- a/radio/src/storage/yaml/yaml_bits.h +++ b/radio/src/storage/yaml/yaml_bits.h @@ -36,9 +36,14 @@ uint32_t yaml_str2uint_ref(const char* val, uint8_t val_len); int32_t yaml_str2int(const char* val, uint8_t val_len); uint32_t yaml_str2uint(const char* val, uint8_t val_len); +uint32_t yaml_hex2uint(const char* val, uint8_t val_len); + char* yaml_unsigned2str(uint32_t i); char* yaml_signed2str(int32_t i); +char* yaml_unsigned2hex(uint32_t i); +char* yaml_rgb2hex(uint32_t i); + int32_t yaml_to_signed(uint32_t i, uint32_t bits); #endif diff --git a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp index 5647e6ca5..b1144b278 100644 --- a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp @@ -73,6 +73,9 @@ namespace yaml_conv_220 { bool w_zov_source(void* user, uint8_t* data, uint32_t bitoffs, yaml_writer_func wf, void* opaque); + + bool w_zov_color(void* user, uint8_t* data, uint32_t bitoffs, + yaml_writer_func wf, void* opaque); }; // @@ -284,6 +287,30 @@ bool w_zov_source(void* user, uint8_t* data, uint32_t bitoffs, { return yaml_conv_220::w_zov_source(user, data, bitoffs, wf, opaque); } + +void r_zov_color(void* user, uint8_t* data, uint32_t bitoffs, + const char* val, uint8_t val_len) +{ + if (val_len < sizeof("0xFFFFFF")-1 + || val[0] != '0' + || val[1] != 'x') + return; + + val += 2; val_len -= 2; + + data += bitoffs >> 3UL; + auto p_val = reinterpret_cast(data); + + auto rgb24 = yaml_hex2uint(val, val_len); + p_val->unsignedValue = + RGB((rgb24 & 0xFF0000) >> 16, (rgb24 & 0xFF00) >> 8, rgb24 & 0xFF); +} + +bool w_zov_color(void* user, uint8_t* data, uint32_t bitoffs, + yaml_writer_func wf, void* opaque) +{ + return yaml_conv_220::w_zov_color(user, data, bitoffs, wf, opaque); +} #endif static uint8_t select_mod_type(void* user, uint8_t* data, uint32_t bitoffs) diff --git a/radio/src/storage/yaml/yaml_datastructs_nv14.cpp b/radio/src/storage/yaml/yaml_datastructs_nv14.cpp index 0f4e22c39..4143fdc10 100644 --- a/radio/src/storage/yaml/yaml_datastructs_nv14.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_nv14.cpp @@ -85,6 +85,7 @@ const struct YamlIdStr enum_ZoneOptionValueEnum[] = { { ZOV_Bool, "Bool" }, { ZOV_String, "String" }, { ZOV_Source, "Source" }, + { ZOV_Color, "Color" }, { 0, NULL } }; const struct YamlIdStr enum_TimerModes[] = { @@ -336,6 +337,7 @@ static const struct YamlNode union_ZoneOptionValue_elmts[] = { YAML_UNSIGNED( "boolValue", 32 ), YAML_STRING("stringValue", 8), YAML_CUSTOM("source",r_zov_source,w_zov_source), + YAML_CUSTOM("color",r_zov_color,w_zov_color), YAML_END }; static const struct YamlNode struct_ZoneOptionValueTyped[] = { diff --git a/radio/src/storage/yaml/yaml_datastructs_x10.cpp b/radio/src/storage/yaml/yaml_datastructs_x10.cpp index 1bbe398ee..7a8f14fbe 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x10.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x10.cpp @@ -85,6 +85,7 @@ const struct YamlIdStr enum_ZoneOptionValueEnum[] = { { ZOV_Bool, "Bool" }, { ZOV_String, "String" }, { ZOV_Source, "Source" }, + { ZOV_Color, "Color" }, { 0, NULL } }; const struct YamlIdStr enum_TimerModes[] = { @@ -357,6 +358,7 @@ static const struct YamlNode union_ZoneOptionValue_elmts[] = { YAML_UNSIGNED( "boolValue", 32 ), YAML_STRING("stringValue", 8), YAML_CUSTOM("source",r_zov_source,w_zov_source), + YAML_CUSTOM("color",r_zov_color,w_zov_color), YAML_END }; static const struct YamlNode struct_ZoneOptionValueTyped[] = { diff --git a/radio/src/storage/yaml/yaml_datastructs_x12s.cpp b/radio/src/storage/yaml/yaml_datastructs_x12s.cpp index 8ac5fb23d..1bc3b82e3 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x12s.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x12s.cpp @@ -85,6 +85,7 @@ const struct YamlIdStr enum_ZoneOptionValueEnum[] = { { ZOV_Bool, "Bool" }, { ZOV_String, "String" }, { ZOV_Source, "Source" }, + { ZOV_Color, "Color" }, { 0, NULL } }; const struct YamlIdStr enum_TimerModes[] = { @@ -357,6 +358,7 @@ static const struct YamlNode union_ZoneOptionValue_elmts[] = { YAML_UNSIGNED( "boolValue", 32 ), YAML_STRING("stringValue", 8), YAML_CUSTOM("source",r_zov_source,w_zov_source), + YAML_CUSTOM("color",r_zov_color,w_zov_color), YAML_END }; static const struct YamlNode struct_ZoneOptionValueTyped[] = { diff --git a/radio/src/tests/conversions.cpp b/radio/src/tests/conversions.cpp index 462a90bcc..7fb4608b1 100644 --- a/radio/src/tests/conversions.cpp +++ b/radio/src/tests/conversions.cpp @@ -420,6 +420,10 @@ TEST(Conversions, ConversionTX16SFrom25) const auto& top_option = top_widget.widgetData.options[0]; EXPECT_EQ(ZOV_Source, top_option.type); EXPECT_EQ(MIXSRC_TX_VOLTAGE, top_option.value.unsignedValue); + + const auto& color_option = top_widget.widgetData.options[1]; + EXPECT_EQ(ZOV_Color, color_option.type); + EXPECT_EQ(0xFFFF, color_option.value.unsignedValue); } #endif