From 1696ed1d5417f84a39356272f49f60f7f37d9960 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Thu, 1 Jan 2026 04:32:31 +0700 Subject: [PATCH 001/160] Subghz counter editor refactor --- .../scenes/subghz_scene_signal_settings.c | 192 +++--------------- lib/subghz/blocks/generic.c | 29 +++ lib/subghz/blocks/generic.h | 30 +++ lib/subghz/protocols/alutech_at_4n.c | 19 +- lib/subghz/protocols/base.c | 3 + lib/subghz/protocols/came_atomo.c | 19 +- lib/subghz/protocols/faac_slh.c | 53 +++-- lib/subghz/protocols/hay21.c | 18 +- lib/subghz/protocols/keeloq.c | 19 +- lib/subghz/protocols/kia.c | 3 + lib/subghz/protocols/kinggates_stylo_4k.c | 17 +- lib/subghz/protocols/nice_flor_s.c | 17 +- lib/subghz/protocols/phoenix_v2.c | 18 +- lib/subghz/protocols/scher_khan.c | 4 + lib/subghz/protocols/secplus_v1.c | 45 ++-- lib/subghz/protocols/secplus_v2.c | 42 ++-- lib/subghz/protocols/somfy_keytis.c | 17 +- lib/subghz/protocols/somfy_telis.c | 18 +- lib/subghz/protocols/star_line.c | 17 +- targets/f7/api_symbols.csv | 6 +- 20 files changed, 295 insertions(+), 291 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_signal_settings.c b/applications/main/subghz/scenes/subghz_scene_signal_settings.c index f5dbfea58..7d5d3f1ae 100644 --- a/applications/main/subghz/scenes/subghz_scene_signal_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_signal_settings.c @@ -4,16 +4,15 @@ #include #include #include +#include #define TAG "SubGhzSceneSignalSettings" static uint32_t counter_mode = 0xff; -static uint32_t loaded_counter32 = 0x0; static uint32_t counter32 = 0x0; static uint16_t counter16 = 0x0; static uint8_t byte_count = 0; static uint8_t* byte_ptr = NULL; -static uint8_t hex_char_lenght = 0; static FuriString* byte_input_text; #define COUNTER_MODE_COUNT 7 @@ -52,55 +51,6 @@ static Protocols protocols[] = { #define PROTOCOLS_COUNT (sizeof(protocols) / sizeof(Protocols)); -// our special case function based on strint_to_uint32 from strint.c -StrintParseError strint_to_uint32_base16(const char* str, uint32_t* out, uint8_t* lenght) { - // skip whitespace - while(((*str >= '\t') && (*str <= '\r')) || *str == ' ') { - str++; - } - - // read digits - uint32_t limit = UINT32_MAX; - uint32_t mul_limit = limit / 16; - uint32_t result = 0; - int read_total = 0; - - while(*str != 0) { - int digit_value; - if(*str >= '0' && *str <= '9') { - digit_value = *str - '0'; - } else if(*str >= 'A' && *str <= 'Z') { - digit_value = *str - 'A' + 10; - } else if(*str >= 'a' && *str <= 'z') { - digit_value = *str - 'a' + 10; - } else { - break; - } - - if(digit_value >= 16) { - break; - } - - if(result > mul_limit) return StrintParseOverflowError; - result *= 16; - if(result > limit - digit_value) return StrintParseOverflowError; //-V658 - result += digit_value; - - read_total++; - str++; - } - - if(read_total == 0) { - result = 0; - *lenght = 0; - return StrintParseAbsentError; - } - - if(out) *out = result; - if(lenght) *lenght = read_total; - return StrintParseNoError; -} - void subghz_scene_signal_settings_counter_mode_changed(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, counter_mode_text[index]); @@ -117,8 +67,8 @@ void subghz_scene_signal_settings_variable_item_list_enter_callback(void* contex // when we click OK on "Edit counter" item if(index == 1) { - furi_string_cat_printf(byte_input_text, "%i", hex_char_lenght * 4); - furi_string_cat_str(byte_input_text, "-bit counter in HEX"); + furi_string_cat_printf(byte_input_text, "%i", subghz_block_generic_global.cnt_lenght_bit); + furi_string_cat_str(byte_input_text, "-bits counter in HEX"); // Setup byte_input view ByteInput* byte_input = subghz->byte_input; @@ -174,21 +124,18 @@ void subghz_scene_signal_settings_on_enter(void* context) { } } } - FURI_LOG_D(TAG, "Current CounterMode value %li", counter_mode); + FURI_LOG_D(TAG, "Loaded CounterMode value %li", counter_mode); flipper_format_file_close(fff_data_file); flipper_format_free(fff_data_file); furi_record_close(RECORD_STORAGE); // ### Counter edit section ### - FuriString* textCnt = furi_string_alloc_set_str(""); byte_input_text = furi_string_alloc_set_str("Enter "); - furi_string_reset(tmp_text); - bool counter_not_available = true; SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(subghz->txrx); - // deserialaze and decode loaded sugbhz file and take information string from decoder + // deserialaze and decode loaded sugbhz file and push data to subghz_block_generic_global variable if(subghz_protocol_decoder_base_deserialize(decoder, subghz_txrx_get_fff_data(subghz->txrx)) == SubGhzProtocolStatusOk) { subghz_protocol_decoder_base_get_string(decoder, tmp_text); @@ -196,72 +143,26 @@ void subghz_scene_signal_settings_on_enter(void* context) { FURI_LOG_E(TAG, "Cant deserialize this subghz file"); } - // In protocols output we allways have HEX format for "Cnt:" output (text formating like ...Cnt:%05lX\r\n") - // we take 8 simbols starting from "Cnt:........" - // at first we search "Cnt:????" that mean for this protocol counter cannot be decoded - - int8_t place = furi_string_search_str(tmp_text, "Cnt:??", 0); - if(place > 0) { + if(!subghz_block_generic_global.cnt_is_available) { counter_mode = 0xff; - FURI_LOG_D( - TAG, "Founded Cnt:???? - Counter mode and edit not available for this protocol"); + FURI_LOG_D(TAG, "Counter mode and edit not available for this protocol"); } else { - place = furi_string_search_str(tmp_text, "Cnt:", 0); - if(place > 0) { - // defence from memory leaks. Check can we take 8 symbols after 'Cnt:' ? - // if from current place to end of stirngs more than 8 symbols - ok, if not - just take symbols from current place to end of string. - // +4 - its 'Cnt:' lenght - uint8_t n_symbols_taken = 8; - if(sizeof(tmp_text) - (place + 4) < 8) { - n_symbols_taken = sizeof(tmp_text) - (place + 4); - } - furi_string_set_n(textCnt, tmp_text, place + 4, n_symbols_taken); - furi_string_trim(textCnt); - FURI_LOG_D( - TAG, - "Taked 8 bytes hex value starting after 'Cnt:' - %s", - furi_string_get_cstr(textCnt)); - - // trim and convert 8 simbols string to uint32 by base 16 (hex); - // later we use loaded_counter in subghz_scene_signal_settings_on_event to check is there 0 or not - special case - - if(strint_to_uint32_base16( - furi_string_get_cstr(textCnt), &loaded_counter32, &hex_char_lenght) == - StrintParseNoError) { - counter_not_available = false; - - // calculate and roundup number of hex bytes do display counter in byte_input (every 2 hex simbols = 1 byte for view) - // later must be used in byte_input to restrict number of available byte to edit - // cnt_byte_count = (hex_char_lenght + 1) / 2; - - FURI_LOG_D( - TAG, - "Result of conversion from String to uint_32 DEC %li, HEX %lX, HEX lenght %i symbols", - loaded_counter32, - loaded_counter32, - hex_char_lenght); - - // Check is there byte_count more than 2 hex bytes long (16 bit) or not (32bit) - // To show hex value we must correct revert bytes for ByteInput view - if(hex_char_lenght > 4) { - counter32 = loaded_counter32; - furi_string_printf(tmp_text, "%lX", counter32); - counter32 = __bswap32(counter32); - byte_ptr = (uint8_t*)&counter32; - byte_count = 4; - } else { - counter16 = loaded_counter32; - furi_string_printf(tmp_text, "%X", counter16); - counter16 = __bswap16(counter16); - byte_ptr = (uint8_t*)&counter16; - byte_count = 2; - } - } else { - FURI_LOG_E(TAG, "Cant convert text counter value"); - }; + counter_not_available = false; + // Check is there byte_count more than 2 hex bytes long or not + // To show hex value we must correct revert bytes for ByteInput view with __bswapХХ + if(subghz_block_generic_global.cnt_lenght_bit > 16) { + counter32 = subghz_block_generic_global.current_cnt; + furi_string_printf(tmp_text, "%lX", counter32); + counter32 = __bswap32(counter32); + byte_ptr = (uint8_t*)&counter32; + byte_count = 4; } else { - FURI_LOG_D(TAG, "Counter editor not available for this protocol"); + counter16 = subghz_block_generic_global.current_cnt; + furi_string_printf(tmp_text, "%X", counter16); + counter16 = __bswap16(counter16); + byte_ptr = (uint8_t*)&counter16; + byte_count = 2; } } @@ -273,9 +174,6 @@ void subghz_scene_signal_settings_on_enter(void* context) { int32_t value_index; VariableItem* item; - // variable_item_list_set_selected_item(subghz->variable_item_list, 0); - // variable_item_list_reset(subghz->variable_item_list); - variable_item_list_set_enter_callback( variable_item_list, subghz_scene_signal_settings_variable_item_list_enter_callback, @@ -299,71 +197,29 @@ void subghz_scene_signal_settings_on_enter(void* context) { variable_item_set_locked(item, (counter_not_available), "Not available\nfor this\nprotocol !"); furi_string_free(tmp_text); - furi_string_free(textCnt); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); } bool subghz_scene_signal_settings_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; - int32_t tmp_counter = 0; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventByteInputDone) { switch(byte_count) { case 2: - // when signal has Cnt:00 we can step only to 0000+FFFF = FFFF, but we need 0000 for next step - // for this case we must use +1 additional step to increace Cnt from FFFF to 0000. - - // save current user definded counter increase value (mult) - tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); - - // increase signal counter to max value - at result it must be 0000 in most cases - // but can be FFFF in case Cnt:0000 (for this we have +1 additional step below) - furi_hal_subghz_set_rolling_counter_mult(0xFFFF); - subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); - subghz_txrx_stop(subghz->txrx); - - // if file Cnt:00 then do +1 additional step - if(loaded_counter32 == 0) { - furi_hal_subghz_set_rolling_counter_mult(1); - subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); - subghz_txrx_stop(subghz->txrx); - } - - // at this point we must have signal Cnt:00 - // convert back after byte_input and do one send with our new mult (counter16) - at end we must have signal Cnt = counter16 + // set new cnt value and override_flag to global variable and call transmit to generate and save subghz signal counter16 = __bswap16(counter16); - - furi_hal_subghz_set_rolling_counter_mult(counter16); + subghz_block_generic_global_counter_override_set(counter16); subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); subghz_txrx_stop(subghz->txrx); - - // restore user definded counter increase value (mult) - furi_hal_subghz_set_rolling_counter_mult(tmp_counter); - break; case 4: // the same for 32 bit Counter - tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); - - furi_hal_subghz_set_rolling_counter_mult(0xFFFFFFF); - subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); - subghz_txrx_stop(subghz->txrx); - - if(loaded_counter32 == 0) { - furi_hal_subghz_set_rolling_counter_mult(1); - subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); - subghz_txrx_stop(subghz->txrx); - } - counter32 = __bswap32(counter32); - - furi_hal_subghz_set_rolling_counter_mult((counter32 & 0xFFFFFFF)); + subghz_block_generic_global_counter_override_set(counter32); subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); subghz_txrx_stop(subghz->txrx); - - furi_hal_subghz_set_rolling_counter_mult(tmp_counter); break; default: break; diff --git a/lib/subghz/blocks/generic.c b/lib/subghz/blocks/generic.c index b659e7947..5b1969ec0 100644 --- a/lib/subghz/blocks/generic.c +++ b/lib/subghz/blocks/generic.c @@ -4,6 +4,35 @@ #define TAG "SubGhzBlockGeneric" +// Main things: subghz protocols working (serialize, deserialize, decode and encode) +// with flipper_format data isolated from upper level subghz functions and structures. +// So if we need change something inside of protocol data - we need use this API from protocols to get and set data + +SubGhzBlockGenericGlobal subghz_block_generic_global; //global structure for subghz + +void subghz_block_generic_global_counter_override_set(uint32_t counter) { + subghz_block_generic_global.new_cnt = counter; // set global variable + subghz_block_generic_global.cnt_need_override = true; // set flag for protocols +} + +bool subghz_block_generic_global_counter_override_get(uint32_t* counter) { + // if override flag was enabled then return succes TRUE and return overrided counter, else return success = FALSE + // we cut counter bit lenght to available protocol bits lenght by the logical AND function + if(subghz_block_generic_global.cnt_need_override) { + *counter = subghz_block_generic_global.new_cnt & + ((0xFFFFFFFF >> (32 - subghz_block_generic_global.cnt_lenght_bit))); + subghz_block_generic_global.cnt_need_override = false; + return true; + } else { + return false; + } +} + +void subghz_block_generic_global_reset(void* p) { + UNUSED(p); + memset(&subghz_block_generic_global, 0, sizeof(subghz_block_generic_global)); +} + void subghz_block_generic_get_preset_name(const char* preset_name, FuriString* preset_str) { const char* preset_name_temp; if(!strcmp(preset_name, "AM270")) { diff --git a/lib/subghz/blocks/generic.h b/lib/subghz/blocks/generic.h index 77aaf3a03..081f05fd3 100644 --- a/lib/subghz/blocks/generic.h +++ b/lib/subghz/blocks/generic.h @@ -27,6 +27,36 @@ struct SubGhzBlockGeneric { uint32_t seed; }; +typedef struct SubGhzBlockGenericGlobal SubGhzBlockGenericGlobal; + +struct SubGhzBlockGenericGlobal { + uint32_t current_cnt; // global counter value; + uint32_t new_cnt; // global counter value; + bool cnt_need_override; // flag for protocols to override signals counter inside of protocols + uint8_t cnt_lenght_bit; // counter lenght in bytes (used in counter editor giu) + bool cnt_is_available; // is there counter available for protocol (used in counter editor giu) +}; + +extern SubGhzBlockGenericGlobal subghz_block_generic_global; //global structure for subghz + +/** + * Setup SubGhzBlockGenericGlobal.cnt and cnt_need_override flag to be used in protocols; + * @param counter new counter value; + */ +void subghz_block_generic_global_counter_override_set(uint32_t counter); + +/** + * Return true if incomming variable was overrided by SubGhzBlockGenericGlobal.cnt + * else return false and not change incomming variable + * @param counter pointer to counter variable that must be changed + */ +bool subghz_block_generic_global_counter_override_get(uint32_t* counter); + +/** + * Reset subghz_block_generic global structure; + */ +void subghz_block_generic_global_reset(void* p); + /** * Get name preset. * @param preset_name name preset diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 730f68f2b..7fc8c4aa7 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -278,12 +278,17 @@ static bool subghz_protocol_alutech_at_4n_gen_data( if(alutech_at4n_counter_mode == 0) { // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { - if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { - instance->generic.cnt = 0; - } else { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } } else { + //OFFEX mode if((instance->generic.cnt + 0x1) > 0xFFFF) { instance->generic.cnt = 0; } else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xFFFE) { @@ -870,6 +875,12 @@ void subghz_protocol_decoder_alutech_at_4n_get_string(void* context, FuriString* uint32_t code_found_hi = instance->generic.data >> 32; uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; + // push protocol data to global variable + subghz_block_generic_global.cnt_is_available = true; + subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.current_cnt = instance->generic.cnt; + // + furi_string_cat_printf( output, "%s\r\n" diff --git a/lib/subghz/protocols/base.c b/lib/subghz/protocols/base.c index 99af45bb2..acbdfe2b9 100644 --- a/lib/subghz/protocols/base.c +++ b/lib/subghz/protocols/base.c @@ -1,5 +1,6 @@ #include "base.h" #include "registry.h" +#include "../blocks/generic.h" void subghz_protocol_decoder_base_set_decoder_callback( SubGhzProtocolDecoderBase* decoder_base, @@ -17,6 +18,8 @@ bool subghz_protocol_decoder_base_get_string( furi_check(decoder_base); furi_check(output); + subghz_block_generic_global_reset(0); + bool status = false; if(decoder_base->protocol && decoder_base->protocol->decoder && diff --git a/lib/subghz/protocols/came_atomo.c b/lib/subghz/protocols/came_atomo.c index 1343f2c45..077195f28 100644 --- a/lib/subghz/protocols/came_atomo.c +++ b/lib/subghz/protocols/came_atomo.c @@ -190,12 +190,17 @@ static void subghz_protocol_encoder_came_atomo_get_upload( if(came_atomo_counter_mode == 0) { // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { - if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { - instance->generic.cnt = 0; - } else { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } } else { + //OFFEX mode if((instance->generic.cnt + 0x1) > 0xFFFF) { instance->generic.cnt = 0; } else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xFFFE) { @@ -820,6 +825,12 @@ void subghz_protocol_decoder_came_atomo_get_string(void* context, FuriString* ou uint32_t code_found_hi = instance->generic.data >> 32; uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; + // push protocol data to global variable + subghz_block_generic_global.cnt_is_available = true; + subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.current_cnt = instance->generic.cnt; + // + furi_string_cat_printf( output, "%s %db\r\n" diff --git a/lib/subghz/protocols/faac_slh.c b/lib/subghz/protocols/faac_slh.c index 5f0a217f4..62005d276 100644 --- a/lib/subghz/protocols/faac_slh.c +++ b/lib/subghz/protocols/faac_slh.c @@ -138,17 +138,19 @@ static bool subghz_protocol_faac_slh_gen_data(SubGhzProtocolEncoderFaacSLH* inst uint8_t data_prg[8]; data_prg[0] = 0x00; - // faac slh protocol have 20-bit counter so we take only 20 bits from mult (by AND 0xFFFFF) if(allow_zero_seed || (instance->generic.seed != 0x0)) { // check OFEX mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { - if((instance->generic.cnt + - (furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFF)) > 0xFFFFF) { - instance->generic.cnt = 0; - } else { - instance->generic.cnt += - (furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFF); + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > + 0xFFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } } else { // to do OFEX mode @@ -158,12 +160,15 @@ static bool subghz_protocol_faac_slh_gen_data(SubGhzProtocolEncoderFaacSLH* inst if(temp_counter_backup != 0x0) { // check OFEX mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { - if((temp_counter_backup + - (furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFF)) > 0xFFFFF) { - temp_counter_backup = 0; - } else { - temp_counter_backup += - (furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFF); + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&temp_counter_backup)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((temp_counter_backup + furi_hal_subghz_get_rolling_counter_mult()) > + 0xFFFFF) { + temp_counter_backup = 0; + } else { + temp_counter_backup += furi_hal_subghz_get_rolling_counter_mult(); + } } } else { // todo OFEX mode @@ -234,17 +239,19 @@ static bool subghz_protocol_faac_slh_gen_data(SubGhzProtocolEncoderFaacSLH* inst fixx[i] = (fix >> (shiftby -= 4)) & 0xF; } - // faac slh protocol have 20-bit counter so we take only 20 bits from mult (by AND 0xFFFFF) if(allow_zero_seed || (instance->generic.seed != 0x0)) { // check OFEX mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { - if((instance->generic.cnt + (furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFF)) > - 0xFFFFF) { - instance->generic.cnt = 0; - } else { - instance->generic.cnt += (furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFF); + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > + 0xFFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } - } else { // OFEX mode if(instance->generic.cnt < 0xFFFFF) { @@ -745,6 +752,12 @@ void subghz_protocol_decoder_faac_slh_get_string(void* context, FuriString* outp instance->generic.btn, instance->generic.serial); } else { + // push protocol data to global variable + subghz_block_generic_global.cnt_is_available = true; + subghz_block_generic_global.cnt_lenght_bit = 20; + subghz_block_generic_global.current_cnt = instance->generic.cnt; + // + furi_string_cat_printf( output, "%s %dbit\r\n" diff --git a/lib/subghz/protocols/hay21.c b/lib/subghz/protocols/hay21.c index d397148bb..895a709e1 100644 --- a/lib/subghz/protocols/hay21.c +++ b/lib/subghz/protocols/hay21.c @@ -147,11 +147,14 @@ static void subghz_protocol_encoder_hay21_get_upload(SubGhzProtocolEncoderHay21* // Counter increment // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { - //not matter how big and long mult - we take only 4 bits ( AND 0xF) beacose hay21 counter have only 4 bits long (0..F) - if((instance->generic.cnt + (furi_hal_subghz_get_rolling_counter_mult() & 0xF)) > 0xF) { - instance->generic.cnt = 0; - } else { - instance->generic.cnt += (furi_hal_subghz_get_rolling_counter_mult() & 0xF); + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } } else { // OFEX mode @@ -460,6 +463,11 @@ void subghz_protocol_decoder_hay21_get_string(void* context, FuriString* output) // Parse serial, button, counter subghz_protocol_hay21_remote_controller(&instance->generic); + // push protocol data to global variable + subghz_block_generic_global.cnt_is_available = true; + subghz_block_generic_global.cnt_lenght_bit = 8; + subghz_block_generic_global.current_cnt = instance->generic.cnt; + furi_string_cat_printf( output, "%s - %dbit\r\n" diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 70de346ad..76dbc8436 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -187,10 +187,15 @@ static bool subghz_protocol_keeloq_gen_data( if(keeloq_counter_mode == 0) { // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { - if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { - instance->generic.cnt = 0; - } else { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > + 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } } else { if((instance->generic.cnt + 0x1) > 0xFFFF) { @@ -1424,6 +1429,9 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; if(strcmp(instance->manufacture_name, "BFT") == 0) { + subghz_block_generic_global.cnt_is_available = true; + subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.current_cnt = instance->generic.cnt; furi_string_cat_printf( output, "%s %dbit\r\n" @@ -1459,6 +1467,9 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output instance->generic.btn, instance->manufacture_name); } else { + subghz_block_generic_global.cnt_is_available = true; + subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.current_cnt = instance->generic.cnt; furi_string_cat_printf( output, "%s %dbit\r\n" diff --git a/lib/subghz/protocols/kia.c b/lib/subghz/protocols/kia.c index 0c9394827..d273e91f1 100644 --- a/lib/subghz/protocols/kia.c +++ b/lib/subghz/protocols/kia.c @@ -257,6 +257,9 @@ void subghz_protocol_decoder_kia_get_string(void* context, FuriString* output) { uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; // use 'Cntr:' instead of 'Cnt:' to exclude this protocol counter from Counter edit + subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.current_cnt = instance->generic.cnt; + furi_string_cat_printf( output, "%s %dbit\r\n" diff --git a/lib/subghz/protocols/kinggates_stylo_4k.c b/lib/subghz/protocols/kinggates_stylo_4k.c index 2a34cc522..49c1d2c6d 100644 --- a/lib/subghz/protocols/kinggates_stylo_4k.c +++ b/lib/subghz/protocols/kinggates_stylo_4k.c @@ -157,10 +157,14 @@ static bool subghz_protocol_kinggates_stylo_4k_gen_data( // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { - if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { - instance->generic.cnt = 0; - } else { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } } else { if((instance->generic.cnt + 0x1) > 0xFFFF) { @@ -580,6 +584,11 @@ void subghz_protocol_decoder_kinggates_stylo_4k_get_string(void* context, FuriSt SubGhzProtocolDecoderKingGates_stylo_4k* instance = context; subghz_protocol_kinggates_stylo_4k_remote_controller(&instance->generic, instance->keystore); + // push protocol data to global variable + subghz_block_generic_global.cnt_is_available = true; + subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.current_cnt = instance->generic.cnt; + furi_string_cat_printf( output, "%s\r\n" diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index aebb97029..36099c0cf 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -155,10 +155,14 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload( if(nice_flors_counter_mode == 0) { // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { - if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { - instance->generic.cnt = 0; - } else { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } } else { if((instance->generic.cnt + 0x1) > 0xFFFF) { @@ -910,6 +914,11 @@ void subghz_protocol_decoder_nice_flor_s_get_string(void* context, FuriString* o subghz_protocol_nice_flor_s_remote_controller( &instance->generic, instance->nice_flor_s_rainbow_table_file_name); + // push protocol data to global variable + subghz_block_generic_global.cnt_is_available = true; + subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.current_cnt = instance->generic.cnt; + if(instance->generic.data_count_bit == NICE_ONE_COUNT_BIT) { furi_string_cat_printf( output, diff --git a/lib/subghz/protocols/phoenix_v2.c b/lib/subghz/protocols/phoenix_v2.c index 892d44a02..a36e0ad0e 100644 --- a/lib/subghz/protocols/phoenix_v2.c +++ b/lib/subghz/protocols/phoenix_v2.c @@ -254,10 +254,14 @@ static bool // Reconstruction of the data // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { - if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { - instance->generic.cnt = 0; - } else { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } } else { if((instance->generic.cnt + 0x1) > 0xFFFF) { @@ -588,6 +592,12 @@ void subghz_protocol_decoder_phoenix_v2_get_string(void* context, FuriString* ou furi_assert(context); SubGhzProtocolDecoderPhoenix_V2* instance = context; subghz_protocol_phoenix_v2_check_remote_controller(&instance->generic); + + // push protocol data to global variable + subghz_block_generic_global.cnt_is_available = true; + subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.current_cnt = instance->generic.cnt; + furi_string_cat_printf( output, "V2 Phoenix %dbit\r\n" diff --git a/lib/subghz/protocols/scher_khan.c b/lib/subghz/protocols/scher_khan.c index b4cf1af54..98c064c22 100644 --- a/lib/subghz/protocols/scher_khan.c +++ b/lib/subghz/protocols/scher_khan.c @@ -298,6 +298,10 @@ void subghz_protocol_decoder_scher_khan_get_string(void* context, FuriString* ou &instance->generic, &instance->protocol_name); // use 'Cntr:' instead of 'Cnt:' to exclude this protocol counter from Counter edit + // push protocol data to global variable + subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.current_cnt = instance->generic.cnt; + furi_string_cat_printf( output, "%s %dbit\r\n" diff --git a/lib/subghz/protocols/secplus_v1.c b/lib/subghz/protocols/secplus_v1.c index 9f3be96f7..99bf61fec 100644 --- a/lib/subghz/protocols/secplus_v1.c +++ b/lib/subghz/protocols/secplus_v1.c @@ -220,43 +220,19 @@ static bool subghz_protocol_secplus_v1_encode(SubGhzProtocolEncoderSecPlus_v1* i //increment the counter //rolling += 2; - old way // Experemental case - we dont know counter size exactly, so just will be think that it is in range of 0xE6000000 - 0xFFFFFFFF - // one case when we have mult = 0xFFFFFFFF - its when we reset counter before applying new cnt value - // so at first step we reset cnt to 0 and now we sure here will be second step (set new cnt value); - // at second step check what user set for new Cnt (and correct it if cnt less than 0xE6000000 or more than 0xFFFFFFFF) - int32_t multicntr = (furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFFFF); - // Adjust for negative multiplier - if(furi_hal_subghz_get_rolling_counter_mult() < 0) { - multicntr = furi_hal_subghz_get_rolling_counter_mult(); - } - if(multicntr == 1) { - multicntr = 2; // to keep old behaviour when mult = 1 - } + // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { - if((furi_hal_subghz_get_rolling_counter_mult() == (int32_t)0xFFFFFFF) & (rolling != 0)) { - rolling = 0; - } else { - // if cnt was reset to 0 on previous step and user want new Cnt then set it to 0xE6000000 or 0xFFFFFFFF or new user value - if(rolling == 0) { - if((furi_hal_subghz_get_rolling_counter_mult()) < (int32_t)0x6000000) { - rolling = 0xE6000000; - } else { - if((furi_hal_subghz_get_rolling_counter_mult()) >= (int32_t)0xFFFFFFF) { - rolling = 0xFFFFFFFF; - } else { - rolling = 0xE0000000; - rolling += multicntr; - } - } + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&rolling)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((rolling + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFFFFFF) { + rolling = 0xE6000000; } else { - // if we have not special cases - so work as standart mode - if((rolling + multicntr) > 0xFFFFFFFF) { - rolling = 0xE6000000; - } else { - rolling += multicntr; - } + rolling += furi_hal_subghz_get_rolling_counter_mult(); } } + if(rolling < 0xE6000000) rolling = 0xE6000000; } else { // OFEX (overflow experimental) mode if((rolling + 0x1) > 0xFFFFFFFF) { @@ -605,6 +581,11 @@ void subghz_protocol_decoder_secplus_v1_get_string(void* context, FuriString* ou uint8_t id1 = (fixed / 9) % 3; uint16_t pin = 0; + // push protocol data to global variable + subghz_block_generic_global.cnt_is_available = true; + subghz_block_generic_global.cnt_lenght_bit = 32; + subghz_block_generic_global.current_cnt = instance->generic.cnt; + furi_string_cat_printf( output, "%s %db\r\n" diff --git a/lib/subghz/protocols/secplus_v2.c b/lib/subghz/protocols/secplus_v2.c index c1165ca85..4fc6cfcf9 100644 --- a/lib/subghz/protocols/secplus_v2.c +++ b/lib/subghz/protocols/secplus_v2.c @@ -402,40 +402,19 @@ static void subghz_protocol_secplus_v2_encode(SubGhzProtocolEncoderSecPlus_v2* i uint8_t roll_2[9] = {0}; // Experemental case - we dont know counter size exactly, so just will be think that it is in range of 0xE500000 - 0xFFFFFFF - // one case when we have mult = 0xFFFFFFFF - its when we reset counter before applying new cnt value - // so at first step we reset cnt to 0 and now we sure here will be second step (set new cnt value); - // at second step check what user set for new Cnt (and correct it if cnt less than 0xE500000 or more than 0xFFFFFFF) - int32_t multicntr = (furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFFFF); - // Adjust for negative multiplier - if(furi_hal_subghz_get_rolling_counter_mult() < 0) { - multicntr = furi_hal_subghz_get_rolling_counter_mult(); - } + // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { - if((furi_hal_subghz_get_rolling_counter_mult() == (int32_t)0xFFFFFFF) & - (instance->generic.cnt != 0)) { - instance->generic.cnt = 0; - } else { - // if cnt was reset to 0 on previous step and user want new Cnt then set it to 0xE500000 or 0xFFFFFFF or new user value - if(instance->generic.cnt == 0) { - if(furi_hal_subghz_get_rolling_counter_mult() < (int32_t)0xE500000) { - instance->generic.cnt = 0xE500000; - } else { - if(furi_hal_subghz_get_rolling_counter_mult() >= (int32_t)0xFFFFFFF) { - instance->generic.cnt = 0xFFFFFFF; - } else { - instance->generic.cnt += multicntr; - } - } + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFFFFF) { + instance->generic.cnt = 0xE500000; } else { - // if we have not special cases - so work as standart mode - if((instance->generic.cnt + multicntr) > 0xFFFFFFF) { - instance->generic.cnt = 0xE500000; - } else { - instance->generic.cnt += multicntr; - } + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } } + if(instance->generic.cnt < 0xE500000) instance->generic.cnt = 0xE500000; } else { // OFEX (overflow experimental) mode if((instance->generic.cnt + 0x1) > 0xFFFFFFF) { @@ -982,6 +961,11 @@ void subghz_protocol_decoder_secplus_v2_get_string(void* context, FuriString* ou subghz_protocol_secplus_v2_remote_controller(&instance->generic, instance->secplus_packet_1); // need to research or practice check how much bits in counter + // push protocol data to global variable + subghz_block_generic_global.cnt_is_available = true; + subghz_block_generic_global.cnt_lenght_bit = 28; + subghz_block_generic_global.current_cnt = instance->generic.cnt; + furi_string_cat_printf( output, "%s %db\r\n" diff --git a/lib/subghz/protocols/somfy_keytis.c b/lib/subghz/protocols/somfy_keytis.c index a66ba2b15..5f4c8aa9b 100644 --- a/lib/subghz/protocols/somfy_keytis.c +++ b/lib/subghz/protocols/somfy_keytis.c @@ -132,10 +132,14 @@ static bool // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { - if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { - instance->generic.cnt = 0; - } else { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } } else { if((instance->generic.cnt + 0x1) > 0xFFFF) { @@ -792,6 +796,11 @@ void subghz_protocol_decoder_somfy_keytis_get_string(void* context, FuriString* subghz_protocol_somfy_keytis_check_remote_controller(&instance->generic); + // push protocol data to global variable + subghz_block_generic_global.cnt_is_available = true; + subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.current_cnt = instance->generic.cnt; + furi_string_cat_printf( output, "%s %db\r\n" diff --git a/lib/subghz/protocols/somfy_telis.c b/lib/subghz/protocols/somfy_telis.c index d8ae9ad28..d2b35b3fd 100644 --- a/lib/subghz/protocols/somfy_telis.c +++ b/lib/subghz/protocols/somfy_telis.c @@ -126,10 +126,14 @@ static bool subghz_protocol_somfy_telis_gen_data( // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { - if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { - instance->generic.cnt = 0; - } else { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } } else { if((instance->generic.cnt + 0x1) > 0xFFFF) { @@ -748,6 +752,12 @@ void subghz_protocol_decoder_somfy_telis_get_string(void* context, FuriString* o SubGhzProtocolDecoderSomfyTelis* instance = context; subghz_protocol_somfy_telis_check_remote_controller(&instance->generic); + + // push protocol data to global variable + subghz_block_generic_global.cnt_is_available = true; + subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.current_cnt = instance->generic.cnt; + furi_string_cat_printf( output, "%s %db\r\n" diff --git a/lib/subghz/protocols/star_line.c b/lib/subghz/protocols/star_line.c index 4f5834d17..e5009b9af 100644 --- a/lib/subghz/protocols/star_line.c +++ b/lib/subghz/protocols/star_line.c @@ -131,10 +131,14 @@ static bool subghz_protocol_star_line_gen_data(SubGhzProtocolEncoderStarLine* instance, uint8_t btn) { // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { - if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { - instance->generic.cnt = 0; - } else { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } } else { if((instance->generic.cnt + 0x1) > 0xFFFF) { @@ -719,6 +723,11 @@ void subghz_protocol_decoder_star_line_get_string(void* context, FuriString* out uint32_t code_found_reverse_hi = code_found_reverse >> 32; uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; + // push protocol data to global variable + subghz_block_generic_global.cnt_is_available = true; + subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.current_cnt = instance->generic.cnt; + furi_string_cat_printf( output, "%s %dbit\r\n" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 1213d09e7..8fbdab108 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,87.1,, +Version,+,87.2,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -3564,6 +3564,9 @@ Function,-,strxfrm_l,size_t,"char*, const char*, size_t, locale_t" Function,+,subghz_block_generic_deserialize,SubGhzProtocolStatus,"SubGhzBlockGeneric*, FlipperFormat*" Function,+,subghz_block_generic_deserialize_check_count_bit,SubGhzProtocolStatus,"SubGhzBlockGeneric*, FlipperFormat*, uint16_t" Function,+,subghz_block_generic_get_preset_name,void,"const char*, FuriString*" +Function,+,subghz_block_generic_global_counter_override_get,_Bool,uint32_t* +Function,+,subghz_block_generic_global_counter_override_set,void,uint32_t +Function,+,subghz_block_generic_global_reset,void,void* Function,+,subghz_block_generic_serialize,SubGhzProtocolStatus,"SubGhzBlockGeneric*, FlipperFormat*, SubGhzRadioPreset*" Function,+,subghz_custom_btn_get,uint8_t, Function,+,subghz_custom_btn_get_original,uint8_t, @@ -4273,6 +4276,7 @@ Variable,+,sequence_single_vibro,const NotificationSequence, Variable,+,sequence_solid_yellow,const NotificationSequence, Variable,+,sequence_success,const NotificationSequence, Variable,+,simple_array_config_uint8_t,const SimpleArrayConfig, +Variable,+,subghz_block_generic_global,SubGhzBlockGenericGlobal, Variable,-,subghz_device_cc1101_int,const SubGhzDevice, Variable,+,subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs,const uint8_t[], Variable,+,subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs,const uint8_t[], From bf812630abab571653b716fc1739632b6c302f86 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 1 Jan 2026 22:45:21 +0300 Subject: [PATCH 002/160] Handle PPS request in ISO14443-4 layer by WillyJL --- lib/nfc/helpers/iso14443_4_layer.c | 39 ++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/lib/nfc/helpers/iso14443_4_layer.c b/lib/nfc/helpers/iso14443_4_layer.c index 1d76f4bf3..4a92956a9 100644 --- a/lib/nfc/helpers/iso14443_4_layer.c +++ b/lib/nfc/helpers/iso14443_4_layer.c @@ -35,6 +35,14 @@ #define ISO14443_4_BLOCK_PCB_S_CID_MASK (1U << ISO14443_4_BLOCK_PCB_R_CID_OFFSET) #define ISO14443_4_BLOCK_PCB_S_WTX_DESELECT_MASK (3U << ISO14443_4_BLOCK_PCB_S_WTX_DESELECT_OFFSET) +#define ISO14443_4_BLOCK_PPS_START (0xD0) +#define ISO14443_4_BLOCK_PPS_START_MASK (0xF0) + +#define ISO14443_4_BLOCK_PPS_0_HAS_PPS1 (1U << 4) + +#define ISO14443_4_BLOCK_PPS_1_DSI_MASK (3U << 2) +#define ISO14443_4_BLOCK_PPS_1_DRI_MASK (3U << 0) + #define ISO14443_4_BLOCK_CID_MASK (0x0F) #define ISO14443_4_BLOCK_PCB_BITS_ACTIVE(pcb, mask) (((pcb) & (mask)) == (mask)) @@ -58,6 +66,9 @@ #define ISO14443_4_LAYER_NAD_NOT_SUPPORTED ((uint8_t) - 1) #define ISO14443_4_LAYER_NAD_NOT_SET ((uint8_t) - 2) +#define ISO14443_4_BLOCK_PPS_IS_START(pps) \ + ((pps & ISO14443_4_BLOCK_PPS_START_MASK) == ISO14443_4_BLOCK_PPS_START) + struct Iso14443_4Layer { uint8_t pcb; uint8_t pcb_prev; @@ -65,6 +76,7 @@ struct Iso14443_4Layer { // Listener specific uint8_t cid; uint8_t nad; + bool can_pps; }; static inline void iso14443_4_layer_update_pcb(Iso14443_4Layer* instance, bool toggle_num) { @@ -93,6 +105,7 @@ void iso14443_4_layer_reset(Iso14443_4Layer* instance) { instance->cid = ISO14443_4_LAYER_CID_NOT_SUPPORTED; instance->nad = ISO14443_4_LAYER_NAD_NOT_SUPPORTED; + instance->can_pps = true; } void iso14443_4_layer_set_i_block(Iso14443_4Layer* instance, bool chaining, bool CID_present) { @@ -234,6 +247,32 @@ Iso14443_4LayerResult iso14443_4_layer_decode_command( BitBuffer* block_data) { furi_assert(instance); + uint8_t ppss = bit_buffer_get_byte(input_data, 0); + if(ISO14443_4_BLOCK_PPS_IS_START(ppss)) { + if(instance->can_pps) { + const uint8_t cid = ppss & ISO14443_4_BLOCK_CID_MASK; + if(instance->cid != ISO14443_4_LAYER_CID_NOT_SUPPORTED && cid != instance->cid) { + return Iso14443_4LayerResultSkip; + } + instance->can_pps = false; + uint8_t pps0 = bit_buffer_get_byte(input_data, 1); + if(pps0 & ISO14443_4_BLOCK_PPS_0_HAS_PPS1) { + uint8_t pps1 = bit_buffer_get_byte(input_data, 2); + uint8_t dsi = pps1 & ISO14443_4_BLOCK_PPS_1_DSI_MASK; + uint8_t dri = pps1 & ISO14443_4_BLOCK_PPS_1_DRI_MASK; + // TODO: do we need to change bit timings somehow? DRI and DSI mean different bit timing divisors + UNUSED(dsi); + UNUSED(dri); + } + bit_buffer_reset(block_data); + bit_buffer_append_byte(block_data, ppss); + return Iso14443_4LayerResultSend; + } else { + return Iso14443_4LayerResultSkip; + } + } + instance->can_pps = false; + uint8_t prologue_len = 0; instance->pcb = bit_buffer_get_byte(input_data, prologue_len++); From cf51ce866f8ed858f0d707b1792450466481259b Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 1 Jan 2026 22:45:59 +0300 Subject: [PATCH 003/160] upd changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a8e401c0..94cfe2c43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## Main changes - Current API: 87.1 +* NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes * Nothing yet. From 0490c316986276ca67bb846b384f3aa53ec0c405 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 1 Jan 2026 22:50:02 +0300 Subject: [PATCH 004/160] clangd config update by WillyJL --- .clangd | 4 ++++ CHANGELOG.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.clangd b/.clangd index 12e13751d..70a1bf4bb 100644 --- a/.clangd +++ b/.clangd @@ -4,6 +4,10 @@ CompileFlags: - -Wno-format Remove: - -mword-relocations + CompilationDatabase: "./build/latest" + +Completion: + HeaderInsertion: Never Diagnostics: ClangTidy: diff --git a/CHANGELOG.md b/CHANGELOG.md index 94cfe2c43..25c1e5036 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes -* Nothing yet. +* Clangd: Add clangd parameters in IDE agnostic config file (by @WillyJL)

#### Known NFC post-refactor regressions list: - Mifare Mini clones reading is broken (original mini working fine) (OFW) From 7987b6e22dcf9840b8afa1e45104915300667111 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Fri, 2 Jan 2026 23:36:53 +0100 Subject: [PATCH 005/160] NFC: Fix some typos in Type4Tag protocol --nobuild --- .../nfc/helpers/protocol_support/type_4_tag/type_4_tag.c | 2 +- lib/nfc/protocols/type_4_tag/type_4_tag_poller.c | 6 +++--- lib/nfc/protocols/type_4_tag/type_4_tag_poller.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/type_4_tag/type_4_tag.c b/applications/main/nfc/helpers/protocol_support/type_4_tag/type_4_tag.c index 3b1fc91f6..3fa6b2593 100644 --- a/applications/main/nfc/helpers/protocol_support/type_4_tag/type_4_tag.c +++ b/applications/main/nfc/helpers/protocol_support/type_4_tag/type_4_tag.c @@ -184,7 +184,7 @@ static NfcCommand nfc_device_get_data(instance->nfc_device, NfcProtocolType4Tag); furi_string_reset(instance->text_box_store); view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventCardDetected); - } else if(type_4_tag_event->type == Type4TagPollerEventTypeWriteFail) { + } else if(type_4_tag_event->type == Type4TagPollerEventTypeWriteFailed) { const char* error_str = type_4_tag_event->data->error == Type4TagErrorCardLocked ? "Card does not\nallow writing\nnew data" : "Failed to\nwrite new data"; diff --git a/lib/nfc/protocols/type_4_tag/type_4_tag_poller.c b/lib/nfc/protocols/type_4_tag/type_4_tag_poller.c index 0291d2df9..639f3f1db 100644 --- a/lib/nfc/protocols/type_4_tag/type_4_tag_poller.c +++ b/lib/nfc/protocols/type_4_tag/type_4_tag_poller.c @@ -4,7 +4,7 @@ #define TAG "Type4TagPoller" -typedef NfcCommand (*Type4TagPollerReadHandler)(Type4TagPoller* instance); +typedef NfcCommand (*Type4TagPollerStateHandler)(Type4TagPoller* instance); static const Type4TagData* type_4_tag_poller_get_data(Type4TagPoller* instance) { furi_assert(instance); @@ -191,7 +191,7 @@ static NfcCommand type_4_tag_poller_handler_failed(Type4TagPoller* instance) { iso14443_4a_poller_halt(instance->iso14443_4a_poller); instance->type_4_tag_event.type = instance->mode == Type4TagPollerModeRead ? Type4TagPollerEventTypeReadFailed : - Type4TagPollerEventTypeWriteFail; + Type4TagPollerEventTypeWriteFailed; instance->type_4_tag_event.data->error = instance->error; NfcCommand command = instance->callback(instance->general_event, instance->context); instance->state = Type4TagPollerStateIdle; @@ -208,7 +208,7 @@ static NfcCommand type_4_tag_poller_handler_success(Type4TagPoller* instance) { return command; } -static const Type4TagPollerReadHandler type_4_tag_poller_read_handler[Type4TagPollerStateNum] = { +static const Type4TagPollerStateHandler type_4_tag_poller_read_handler[Type4TagPollerStateNum] = { [Type4TagPollerStateIdle] = type_4_tag_poller_handler_idle, [Type4TagPollerStateRequestMode] = type_4_tag_poller_handler_request_mode, [Type4TagPollerStateDetectPlatform] = type_4_tag_poller_handler_detect_platform, diff --git a/lib/nfc/protocols/type_4_tag/type_4_tag_poller.h b/lib/nfc/protocols/type_4_tag/type_4_tag_poller.h index 5ac4fd0f2..8263e3790 100644 --- a/lib/nfc/protocols/type_4_tag/type_4_tag_poller.h +++ b/lib/nfc/protocols/type_4_tag/type_4_tag_poller.h @@ -19,7 +19,7 @@ typedef enum { Type4TagPollerEventTypeReadSuccess, /**< Card was read successfully. */ Type4TagPollerEventTypeReadFailed, /**< Poller failed to read card. */ Type4TagPollerEventTypeWriteSuccess, /**< Poller wrote card successfully. */ - Type4TagPollerEventTypeWriteFail, /**< Poller failed to write card. */ + Type4TagPollerEventTypeWriteFailed, /**< Poller failed to write card. */ } Type4TagPollerEventType; /** From ab86d3325e8361154b90aa2a1dde7162205bd6ba Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 5 Jan 2026 21:13:43 +0300 Subject: [PATCH 006/160] subghz: add fsk12k deviation, cardin s449 full support + thanks @zero-mega :)) --- .../cc1101_ext/cc1101_ext_interconnect.c | 4 + .../main/subghz/helpers/subghz_custom_event.h | 1 + .../main/subghz/helpers/subghz_gen_info.c | 10 ++ .../main/subghz/helpers/subghz_txrx.c | 2 + .../resources/subghz/assets/keeloq_mfcodes | 133 +++++++++--------- .../subghz/scenes/subghz_scene_set_type.c | 1 + applications/main/subghz/subghz_cli.c | 2 + .../main/subghz/subghz_last_settings.c | 2 +- .../main/subghz/subghz_last_settings.h | 2 +- .../js_app/modules/js_subghz/js_subghz.c | 2 + .../file_formats/SubGhzFileFormats.md | 1 + lib/subghz/blocks/generic.c | 2 + lib/subghz/devices/cc1101_configs.c | 71 ++++++++++ lib/subghz/devices/cc1101_configs.h | 1 + .../cc1101_int/cc1101_int_interconnect.c | 3 + lib/subghz/devices/preset.h | 1 + lib/subghz/protocols/keeloq.c | 6 +- lib/subghz/subghz_setting.c | 2 + targets/f7/api_symbols.csv | 3 +- 19 files changed, 179 insertions(+), 70 deletions(-) diff --git a/applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.c b/applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.c index eef92dbe8..6cf9f90b1 100644 --- a/applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.c +++ b/applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.c @@ -43,6 +43,10 @@ static void subghz_device_cc1101_ext_interconnect_load_preset( subghz_device_cc1101_ext_load_custom_preset( subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs); break; + case FuriHalSubGhzPreset2FSKDev12KAsync: + subghz_device_cc1101_ext_load_custom_preset( + subghz_device_cc1101_preset_2fsk_dev12khz_async_regs); + break; case FuriHalSubGhzPreset2FSKDev476Async: subghz_device_cc1101_ext_load_custom_preset( subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs); diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index 41e704ea5..33a70fd57 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -103,6 +103,7 @@ typedef enum { SetTypeJCM_433_92, SetTypeNovoferm_433_92, SetTypeHormannEcoStar_433_92, + SetTypeCardinS449_433FM, SetTypeFAACRCXT_433_92, SetTypeFAACRCXT_868, SetTypeGeniusBravo433, diff --git a/applications/main/subghz/helpers/subghz_gen_info.c b/applications/main/subghz/helpers/subghz_gen_info.c index fe5cd0e8a..5f1021ddd 100644 --- a/applications/main/subghz/helpers/subghz_gen_info.c +++ b/applications/main/subghz/helpers/subghz_gen_info.c @@ -643,6 +643,16 @@ void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType ty .keeloq.cnt = 0x03, .keeloq.manuf = "EcoStar"}; break; + case SetTypeCardinS449_433FM: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "FM12K", + .freq = 433920000, + .keeloq.serial = (key & 0x000FFFFF), + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Cardin_S449"}; + break; case SetTypeFAACRCXT_433_92: gen_info = (GenInfo){ .type = GenKeeloq, diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index 8e00bd6af..8abf373f4 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -116,6 +116,8 @@ const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset preset_name = "AM650"; } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) { preset_name = "FM238"; + } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev12KAsync")) { + preset_name = "FM12K"; } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { preset_name = "FM476"; } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) { diff --git a/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes b/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes index 62135c0b9..b146d0ded 100644 --- a/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes +++ b/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes @@ -1,69 +1,70 @@ Filetype: Flipper SubGhz Keystore File Version: 0 Encryption: 1 -IV: 46 75 72 72 79 20 52 6F 63 6B 65 74 21 21 21 30 -05176EEFAC177FE261FE3EB5C8E103BE7CF9F2FEB32BDD6BB63D22EE9C17B9D2 -B645E3CAC0D5E26891249D326BCEB09850E4FB8F8E86A466E97E83437A9E0041 -AA4255FFA1ADE8FB840F80A93F8F1A2D1E39051131D24DE7258D66A8CF2066CF -13ACA390FD5254B024084D5D1F41B8DDF5304FF00C3C85A9C26CD13A7A268654 -4CFBF498D5E2C85496985E83D91B0F4229A925E16A90C6712750032C3699EE0AA5D04123E579B6121573FC61766E89AD -93DADC2AE4235470E171E0E85D24D04A84C37187284C38D1CBB48666FDA8CD6C -DB13D8CCC0CB07685F29F33AE07DA2FD14C2AE4F4D001DB88465D5CFE8CFDAA9 -E51CD1B5074B63D26E274218A0AB3B2E435454EE094DCA5679F35477658A72F9 -10AFD5FD9C296E67EDD9504A60BA9EF84556F40213DEC4DE44F99B088BCC6A57 -EF7AA55F6A473DE093D648240D5FCEB05F8B3295DC37B3E83239A4AF320CD688 -A22892E71B9D0D7FAF92B27C724E76C4A6824DBE5F083F1006D11E42D153C4AC98D0A11C6A8D62F5921A24ECC7437485 -7A25416E390D81DA68A59C3BA30D4B7FC8269B5E0DAF77CA3A857B6F478A050585918485AEE72D375F02D177CB296E31 -94004BA0BB1E47965E60025949EF4CC2738C463F57C97FD2A89C76CCCDEA5397 -111CB1C19863A0165521D974F838CE718DA07948A8D9A8A7490E75032A62ECA2 -17B6E27C69FA002F6CF23D719DFE595140BEFA5083D12E774CF89E2CED53D68D -73311E0FF8ABB3E9461AD14A4F52791647A50E2102D3B74188A73C35BC14EB55 -54E15840A6A6DCA85275E38E4218EE2B539E9E468E24C49428DA363C955C5FC81ACEE79EEB941B83EE4147A0817043BD -7D0FBB417B99B3C6AB18C7B2DC82582D2DCD1E10515028874E73254188F7FEE9 -3F6E89BBCC133B85945234A8201539ECD8796909CC81FE67673F8DE1ECA63045 -39554C0DC1C3694FAAFF65537FF710D9593B7B461E011FC39D014F253F0432533A40276D8259AFD8C957A378237D574F -E60F6CD7063B85F0F20ACB7E7A42B03DE4A9F6CCA54CB7F036AFA23A27D3E9E006BD523E5356260AA78206D9276E6E57 -9EB252EDA9352B966EC4F053D5B013772361D2AD4B217EF33F46A5CEC97A00F3 -AA6773E79BC6D76314BB523FDF203358E01ECB2BBCF3B5DD1EBD043663C74B05 -29B29A50F3F27F4D8C7B0FADA98CC004A7871078DAD1CBAC4846862C3DF82E02 -6E3A479D4334FF05606899B0383116125056A316621B279F904A02B842918C59 -3991732015F4A213E9912E34AC92515D88010C07DA0B118AD6F64A05DC38D2C5 -550B1866F7493C75812DF85DDADC38AF21D9B58189E4EE99A021328523881A9D -77960CA031D28362586100F17DF94FF4E7D6EFAFAF23952887F9DF0507825A99 -01E6FC89E97B7729BF4D1ED8041F69005181BF3639F939C5833B009E96B9F2F7 -D1CC7C536706ECFC5826C8933135D2B110996F1CB13388A702B8453DA40E40AD -B64D2F1E1A80E6DAB92283A512B40DB7FFC519F394AA94CC86C8532F69949723 -6399409A0AC0298DEDA76037C83042FC0870132CFF7F82E54AD0966BE16AC882 -D310536FA78F95BB0B408676990AA937117717BADE9D3B975C0ECE10FB586A1B -A8149C0581DCC291D037E96EF321DB6214BD7CB25F1696226A9FE750AA23B334 -BA3BEBD564D8F571202CD6FE89BC33F89C8E01C03AE0814F2BEF37C33CE874B4 -88CD81AC7605A7F6EFF85FD62C65E0C9945335CFC085B92B27B69648C6E5BF6B -8057C7CB5071DFFFAE4804FD9EC1EC1D3F54D06514906A34B17F6B6CB45A9D473992DF6BC8A9F9E146E39D6163209CC6 -9ABC8814C8FD1AB254374150177616F5C7B43049473C84329BEC855578B96002 -8BCA39A498B00245C71D94E3160CEE8ACA5BEB18AE0AD64A385AFCC018E99744 -5AD75C51CA5AE5FA9BBC6A41576C745F265CC28FC4DA2AD230B6692CF151FD61 -E86092E04CD72D874A92DE838035E811E75E411049C0A7BD0FE2AA9C802BE5AB -CE70ADB22E85747FDC064F0B5974385CD57D41D376CE1C7490C1BEC8A3FC5A7A -8F096E0A11682DB315825213D3DB5D725555C1CDF444169EB919E47E0F0FA6F7 -AD9C9A694D807BA77E5A54B248A88B55000757203D931506255BF8F4215C00D3 -F0E804B6C6B6E91916CB73EB44FB2D1992400BC90ED8B22DF5D038317588341207D74E08C00E529DF2CF2A64F2C7C0FF -72212FCEED35E9C3A176B67DCDB84B284F4DFDCD0ECE8D3F6089C58C2B8A616C -000F9F746BFB47FC10B23E3F08C2A84BCB3870D0C5AE974472849699884BC929 -7B8F9AB04E5F86D6DDCF6164A25EA927788A03F57977FC5C55E1D565279B09C4 -0E9CDCD07D1D4F1429E59F81B524960A75F19A464798C7E822E52728AC83784A -F2DE2B108A1476BB6F85DD3CCB0F0527627B45179092BA7A56D5971490E3875C -7F307358D988FEA12648739F58DD249EBDF0B1C44B73BA547C50EB576C071DAE -2DFBA988592CEF3B62A76183DBA727E734359B89F53AFF3160441EF8709FC633 -57F7DC38DDC87C19CE956BC44C638DEF34D814A7BAB0AC8AD61855143FD984FD -A8AADB687251FA6AC2BBC8EF1E3FA621893293DFBD8C1D07971BF82F22A00DC3 -65AEA1EE34E316C769E551AC2309D07FC2ED92EA044674E3A99CD7B543C730EB -968ECC790E5590E7EB22AFD3546C28F4EB87EA4CEE35F72DDFE7153F74611EAA -0F937930D4E1BDF0B729277CF94A47064BCB959938C70CDB3AC3C65DA68DA1FB -A8AB66375D59E112104CD81B819D618BE43D6A6F159BAD35583653EF3547D25D -A81D5DE2102F05D50750DC37C26E9C9502FA89EF98A2EB1EA546EE48C628E9C4 -EAFDE0A8936AF8EF718027937BC17CEF691E570996B403CF4762240D267EB305 -C48686348F0A94B07BC60AB825C1A0791C20DBBDD7DAE0ED47E8A7FBD9334EACF8E33DCEC36963E87929260DF769520B -493D53BD7BB2B3E081AE793A3BADB3AB0F33C95B83677715D6DE2922F2BEC892 -63FFD3D8CAB980E45D49253A69C99A6813CBE6013992EFBC862173BAD0E26373 -2EF88F43C5A76EC87E02B780585B10957F4EA386F96710FAB98BC2C1E214DBFA -A021CFA0E72AADFD75BC67FBE9345082B0A8B31782E933E81196F84B1797D83E8B2F81E1CF5C3F026D11B9DFC95222E2 +IV: 41 20 46 75 72 72 79 20 48 41 4C 21 4F 77 4F 21 +2CAD19E0C7E482D138AD8EC452C5D9175534F5FD5B8DAB0FF2082A75A9410C60 +87341133DBC22CC39E1952466C1FA6F7DA4215FB3B9D6975CDA16CD0211AEC7E +8D60AA06878EA9EE24D3F2CDC0166373E3CD131CAD016976758B4F5F0DCC4A36 +E455A4EF9016D5682815F4714A678833CD09D6CED6D9D3D796CC700B0FFB79CC +FD5A46DF885486EE89F867BF629B63940AE8A1D0695BE93FCE4385AF523F8809145A3381F2F3F578A38FD40B2546A423 +84F8D5D63DC863490A0B36BC6102FFAA4D0852DE5E92B567B39F0C6F90454029 +8D1A3A7BE24A6F96B3401944435FF5441628B3E60C1CA29F54650BF5912C7E00 +4F2A1A51AC845F91CC8F0AC693CC8D95C4FCF2524317F2576BF1B426332257F2 +6482B6BC4C59F14FC414C4A1E8DEE687E3263FC575646287CF07CE21D5356CB9 +B98C8FE2030F448F80F075EC844311F503B8B4A1048F3EF761AFC695BED8767D +426044078972749851904C762094DC45D8E6DEEEB36232A1489BFBEDC15F6EA0308756673C7494241BCA9BF6216B0C63 +7446FBF891E79C130550E5AEC07BCD6605AB16A16123C7F58B34BA8243567CD29EFBFF44730F36E86A17B97B4CA86BCD +3F76A9C0273C7A344244703F24F625091B1F599A2DDFBD698F33CF7BF7765BD4 +AC491FF039EE8D1548F127AA11863B8CD6B67C37F5DE55D810C04AA1A0207D7D +E14027E544A3B867402F1FD496AD8E173CB6FC55053C3846142882D746C8A3BA +182599DE46C923C4A2A8B1CB07165A8FD5F571BE95A32DA4D517B99378AF618C +5AE341DCF8BFDBA55301555D3300946352CA174F5B0DF6EB239EE997C0E093D1930F6A75996B149199DFFE78B25F5BD5 +A495E957DBE11937C967CEBF99BCFE85CE2E2FFBBD6952352EC7E59FD9ABDC2D +F1F924BD569DD0E6AB7EEC7C880EDE0CE53757A2A183EED3674C10FDE4ADFF17 +B6E32951F4C886371968E5BED5711C05648E87F36FC397E2455B8DD5AFF3865D3BADADF7626D071F792712F6B0FD115B +BC88789A8C037EBCA6F9F6A0FC616D3512474AED1C96270845171CF76F7CDA6D4D2CD42CB8463CE706398B0A9DBEA87A +4A8686B20E1339C81AAE8BBF1C9EABA5BEB61D0A394F314958546FA14A67DEE7 +CA71F413EC992ACFEB03EE1760BE683050FF4D1E1B65ACF9E3A4964F2B3C2B01 +0E05B3BD4854604B6FB82900A13051C0377E85C49A293A39C2A8C75B904D8102 +C9EDE274DD3C5B6DF276565FEE81ED060F0C3BD0CB72EA3E49E9595FAFE77F5C +A33A4B9AD451ACDB5EC4830EFE421AE8929E024108C34343D3D55F098CDE5B0B +9C5C17D4FB32DDD18D88A2B358786E9A941931BE9D645B379412F2E187020C14 +2626DD2FCE983EA3DEAB2FE2A5F378250F1644BE24BDCC2C5FAFDBA68D4F1872 +9F1E27964102BFCEFBF6F5FE7DA8C3B102E97ED0CEE074625175FB02674D5EF2 +7E1745495E213781ABCA814552046470EA41F0EBE8BDD64592DDFA7319AFCD69 +EB6C3B1F4265C71A0DD74847588A89CCF57539CF20711233A221C9BE1F9EB6C9 +4C1A2768E44F9DD2E4AEE9C18DE5449B92CD4DFE5BDA7F65F5A654C86544B2E1 +4F1835CDBDA4128324F4B92E709201502852892699EC0C84B1E4A4B841542C3C +E0EBE4B259B61F05475FFE07EAC8E2A9D013D4471DC7CF3481E1334006F7FB02 +20342B2D84CD3936DEA5058CE07F3F3DB6178C6BF0AC72CF8F807503B3AC8F88 +DC775129215670CD8B81A5335190F6544687D38A70E758348578B0B3A1389300 +208F0D588404D9BDD6E310F16B7460BDB2A8B284CA6E59E24F5FACFD55D48AACC5D86C886A9EF5F06DC2AADE76EFF35F +5CD70EFEAB4B5345531102A0DA1453F857AC93F3456E81C305111626CE084627 +341E61A3AB6BA3F71F5215905149E2D3E84260CC77C068C92D71C6DD9067F633 +0342C01D966663D7542F2D5D7635758EC65CDDE5E7FD5884846D675D06C59363 +2E9F77AD044F9C8C23CA239E71303D6682A2A86C3B4D44831DB4B1BC377043CD +3A11CBA6703808A36911F036E9042198950C2C82269D892F5C87DFD32C101BCA +6E75A69923DFC22957705A624368CFB657B77C11D7F831704BCC76A87377AB26 +21F70436CF950862D306829B542E307EF327F23870D4FBF42869A3BF0891F9DB +4A00DFB119C12D86B953BEC9F41DFB3D4AE3A9BE984CD8C3606CC1ED4B9020ED82922BCED5AE8A2A88DD2995A0D28EFE +12E2B40E49B0FC157203286B39ED852EDC2B444527472A8C07E78A70722DB825 +91A106AF60685D56D19D2E58C9F902F2B3B80A1CFCBC1B84316FBAF69DB47730 +58B5AF1BB0EF318CC3026041A3403B025980FB4DE06C3F2B804800B8578295B7 +FA7C4461C2F0BECADB414694B04E7A89BC99433A635E2905DC3A40A947EC9846 +DF356AFF3212088F223EC32E5FE9D5D73701F25B2075BC50E0F0B45195F28365 +2D099AE3FB0AE7B92976E02E2F01A9D6821D7C15CC04DCA881E05D50BC46EB11 +1FE9F8D29A77CD399B068A8AD890ECB85A957438855F85223B16E3B83A655213 +07DFA64C22CF6DB1E36D16F763BDD822AF3991BDE07C30B4F4084BD13CDEF012 +3BA563F522243D807151BC2EF1B524C174058888D9DE852AA0E9C15F1EA22950 +475979BC2EA05EE2443F65F2372E36D780A34EC8AC1D70BB2480FF519C6C84C1 +7275E88766DCA0EB3725641E950EEC094129361D280AE963D89A9B5403136B06 +65202C209229A36A2B80ED69DEEA285A7273BAA007365AC2E7F438C7AE428BBA +C83ABA33828918FB80D92D8217BB8AE6B5AA4017D0CD7F37C39925F7F96B9BD2 +AAEF1B708581570F87D1FB016FE23FF2804CB6942E576C40165D9F81A4E7AB04 +F7434FBA076E677D71A584341A77D54BFEF4DEBDCADA67D23DB50AA5902DA4EE +5480CB40AB7CA50ABA5EED094281282D5302C38E5EF0B8AF7AE51B5C702574F2 +1C90B716E8AF97DEADB0199C4BBDE7E3669FB4D6794A27F716D523DDFC74905ECEB64509C073405B38A271B7FBFEA3DD +36036999661471644E50D56532DA3D82F2713035BDBDA399E6B121B15E2FDCD5 +DCD61BB556CD42849B99C7A1916005305E57723555CD24F6F1D67D30224A275F +4E3662D52FB2396DCC0D76E7ECFFECF5E581492FA520D8427F772C61435FF925 +7F33462CB81E81DDF8284A6EA121401EEA6301277ABDF2D5C39EDB818AE973F0D51527BA6146C3178624F61E38F220D2 diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 8ca5b95ab..731da6f3f 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -50,6 +50,7 @@ static const char* submenu_names[SetTypeMAX] = { [SetTypeJCM_433_92] = "KL: JCM Tech 433MHz", [SetTypeNovoferm_433_92] = "KL: Novoferm 433MHz", [SetTypeHormannEcoStar_433_92] = "KL: Hor. EcoStar 433MHz", + [SetTypeCardinS449_433FM] = "KL: Cardin S449 433MHz", [SetTypeFAACRCXT_433_92] = "KL: FAAC RC,XT 433MHz", [SetTypeFAACRCXT_868] = "KL: FAAC RC,XT 868MHz", [SetTypeGeniusBravo433] = "KL: Genius Bravo 433MHz", diff --git a/applications/main/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c index 88b5f7f0d..2c6c6b908 100644 --- a/applications/main/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -574,6 +574,8 @@ static FuriHalSubGhzPreset subghz_cli_get_preset_name(const char* preset_name) { preset = FuriHalSubGhzPresetOok650Async; } else if(!strcmp(preset_name, "FuriHalSubGhzPreset2FSKDev238Async")) { preset = FuriHalSubGhzPreset2FSKDev238Async; + } else if(!strcmp(preset_name, "FuriHalSubGhzPreset2FSKDev12KAsync")) { + preset = FuriHalSubGhzPreset2FSKDev12KAsync; } else if(!strcmp(preset_name, "FuriHalSubGhzPreset2FSKDev476Async")) { preset = FuriHalSubGhzPreset2FSKDev476Async; } else if(!strcmp(preset_name, "FuriHalSubGhzPresetCustom")) { diff --git a/applications/main/subghz/subghz_last_settings.c b/applications/main/subghz/subghz_last_settings.c index 6ffdc858e..0a4783a23 100644 --- a/applications/main/subghz/subghz_last_settings.c +++ b/applications/main/subghz/subghz_last_settings.c @@ -149,7 +149,7 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count instance->frequency = SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY; } - if(instance->preset_index > 3) { + if(instance->preset_index > 4) { instance->preset_index = SUBGHZ_LAST_SETTING_DEFAULT_PRESET; } } diff --git a/applications/main/subghz/subghz_last_settings.h b/applications/main/subghz/subghz_last_settings.h index c0559e4ec..78de5e51c 100644 --- a/applications/main/subghz/subghz_last_settings.h +++ b/applications/main/subghz/subghz_last_settings.h @@ -8,7 +8,7 @@ #define SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_TRIGGER (-93.0f) // 1 = "AM650" -// "AM270", "AM650", "FM238", "FM476", +// "AM270", "AM650", "FM238", "FM12K", "FM476", #define SUBGHZ_LAST_SETTING_DEFAULT_PRESET 1 #define SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY 433920000 #define SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_FEEDBACK_LEVEL 2 diff --git a/applications/system/js_app/modules/js_subghz/js_subghz.c b/applications/system/js_app/modules/js_subghz/js_subghz.c index f7065d38c..ae3e1f60d 100644 --- a/applications/system/js_app/modules/js_subghz/js_subghz.c +++ b/applications/system/js_app/modules/js_subghz/js_subghz.c @@ -30,6 +30,8 @@ static FuriHalSubGhzPreset js_subghz_get_preset_name(const char* preset_name) { preset = FuriHalSubGhzPresetOok650Async; } else if(!strcmp(preset_name, "FuriHalSubGhzPreset2FSKDev238Async")) { preset = FuriHalSubGhzPreset2FSKDev238Async; + } else if(!strcmp(preset_name, "FuriHalSubGhzPreset2FSKDev12KAsync")) { + preset = FuriHalSubGhzPreset2FSKDev12KAsync; } else if(!strcmp(preset_name, "FuriHalSubGhzPreset2FSKDev476Async")) { preset = FuriHalSubGhzPreset2FSKDev476Async; } else if(!strcmp(preset_name, "FuriHalSubGhzPresetCustom")) { diff --git a/documentation/file_formats/SubGhzFileFormats.md b/documentation/file_formats/SubGhzFileFormats.md index 80047faf7..1ff1f830d 100644 --- a/documentation/file_formats/SubGhzFileFormats.md +++ b/documentation/file_formats/SubGhzFileFormats.md @@ -39,6 +39,7 @@ Built-in presets: - `FuriHalSubGhzPresetOok270Async` — On/Off Keying, 270kHz bandwidth, async(IO throw GP0) - `FuriHalSubGhzPresetOok650Async` — On/Off Keying, 650kHz bandwidth, async(IO throw GP0) - `FuriHalSubGhzPreset2FSKDev238Async` — 2 Frequency Shift Keying, deviation 2kHz, 270kHz bandwidth, async(IO throw GP0) +- `FuriHalSubGhzPreset2FSKDev12KAsync` — 2 Frequency Shift Keying, deviation 12kHz, 270kHz bandwidth, async(IO throw GP0) - `FuriHalSubGhzPreset2FSKDev476Async` — 2 Frequency Shift Keying, deviation 47kHz, 270kHz bandwidth, async(IO throw GP0) ### Transceiver Configuration Data {#transceiver-configuration-data} diff --git a/lib/subghz/blocks/generic.c b/lib/subghz/blocks/generic.c index b659e7947..57fbb580f 100644 --- a/lib/subghz/blocks/generic.c +++ b/lib/subghz/blocks/generic.c @@ -12,6 +12,8 @@ void subghz_block_generic_get_preset_name(const char* preset_name, FuriString* p preset_name_temp = "FuriHalSubGhzPresetOok650Async"; } else if(!strcmp(preset_name, "FM238")) { preset_name_temp = "FuriHalSubGhzPreset2FSKDev238Async"; + } else if(!strcmp(preset_name, "FM12K")) { + preset_name_temp = "FuriHalSubGhzPreset2FSKDev12KAsync"; } else if(!strcmp(preset_name, "FM476")) { preset_name_temp = "FuriHalSubGhzPreset2FSKDev476Async"; } else { diff --git a/lib/subghz/devices/cc1101_configs.c b/lib/subghz/devices/cc1101_configs.c index a75842589..971c3cb28 100644 --- a/lib/subghz/devices/cc1101_configs.c +++ b/lib/subghz/devices/cc1101_configs.c @@ -220,6 +220,77 @@ const uint8_t subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs[] = { 0x00, }; +const uint8_t subghz_device_cc1101_preset_2fsk_dev12khz_async_regs[] = { + + /* GPIO GD0 */ + CC1101_IOCFG0, + 0x0D, // GD0 as async serial data output/input + + /* Frequency Synthesizer Control */ + CC1101_FSCTRL1, + 0x06, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz + + /* Packet engine */ + CC1101_PKTCTRL0, + 0x32, // Async, continious, no whitening + CC1101_PKTCTRL1, + 0x04, + + // // Modem Configuration + CC1101_MDMCFG0, + 0x00, + CC1101_MDMCFG1, + 0x02, + CC1101_MDMCFG2, + 0x04, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized) + CC1101_MDMCFG3, + 0x83, // Data rate is 4.79794 kBaud + CC1101_MDMCFG4, + 0x67, //Rx BW filter is 270.833333 kHz + CC1101_DEVIATN, + 0x30, //Deviation ~12 kHz + + /* Main Radio Control State Machine */ + CC1101_MCSM0, + 0x18, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) + + /* Frequency Offset Compensation Configuration */ + CC1101_FOCCFG, + 0x16, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off + + /* Automatic Gain Control */ + CC1101_AGCCTRL0, + 0x91, //10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary + CC1101_AGCCTRL1, + 0x00, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET + CC1101_AGCCTRL2, + 0x07, // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAIN_TARGET 42 dB + + /* Wake on radio and timeouts control */ + CC1101_WORCTRL, + 0xFB, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours + + /* Frontend configuration */ + CC1101_FREND0, + 0x10, // Adjusts current TX LO buffer + CC1101_FREND1, + 0x56, + + /* End load reg */ + 0, + 0, + + // 2fsk_async_patable[8] + 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; + const uint8_t subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs[] = { /* GPIO GD0 */ diff --git a/lib/subghz/devices/cc1101_configs.h b/lib/subghz/devices/cc1101_configs.h index 5b96b4a1a..86321edab 100644 --- a/lib/subghz/devices/cc1101_configs.h +++ b/lib/subghz/devices/cc1101_configs.h @@ -8,6 +8,7 @@ extern "C" { extern const uint8_t subghz_device_cc1101_preset_ook_270khz_async_regs[]; extern const uint8_t subghz_device_cc1101_preset_ook_650khz_async_regs[]; extern const uint8_t subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs[]; +extern const uint8_t subghz_device_cc1101_preset_2fsk_dev12khz_async_regs[]; extern const uint8_t subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs[]; extern const uint8_t subghz_device_cc1101_preset_msk_99_97kb_async_regs[]; extern const uint8_t subghz_device_cc1101_preset_gfsk_9_99kb_async_regs[]; diff --git a/lib/subghz/devices/cc1101_int/cc1101_int_interconnect.c b/lib/subghz/devices/cc1101_int/cc1101_int_interconnect.c index 284c717fd..be33b8778 100644 --- a/lib/subghz/devices/cc1101_int/cc1101_int_interconnect.c +++ b/lib/subghz/devices/cc1101_int/cc1101_int_interconnect.c @@ -38,6 +38,9 @@ static void subghz_device_cc1101_int_interconnect_load_preset( case FuriHalSubGhzPreset2FSKDev238Async: furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs); break; + case FuriHalSubGhzPreset2FSKDev12KAsync: + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_2fsk_dev12khz_async_regs); + break; case FuriHalSubGhzPreset2FSKDev476Async: furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs); break; diff --git a/lib/subghz/devices/preset.h b/lib/subghz/devices/preset.h index 8716f2e23..6f67594af 100644 --- a/lib/subghz/devices/preset.h +++ b/lib/subghz/devices/preset.h @@ -6,6 +6,7 @@ typedef enum { FuriHalSubGhzPresetOok270Async, /**< OOK, bandwidth 270kHz, asynchronous */ FuriHalSubGhzPresetOok650Async, /**< OOK, bandwidth 650kHz, asynchronous */ FuriHalSubGhzPreset2FSKDev238Async, /**< FM, deviation 2.380371 kHz, asynchronous */ + FuriHalSubGhzPreset2FSKDev12KAsync, /**< FM, deviation ~12 kHz, asynchronous */ FuriHalSubGhzPreset2FSKDev476Async, /**< FM, deviation 47.60742 kHz, asynchronous */ FuriHalSubGhzPresetMSK99_97KbAsync, /**< MSK, deviation 47.60742 kHz, 99.97Kb/s, asynchronous */ FuriHalSubGhzPresetGFSK9_99KbAsync, /**< GFSK, deviation 19.042969 kHz, 9.996Kb/s, asynchronous */ diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 70de346ad..6d40a11ea 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -299,11 +299,13 @@ static bool subghz_protocol_keeloq_gen_data( (strcmp(instance->manufacture_name, "Rosh") == 0) || (strcmp(instance->manufacture_name, "Rossi") == 0) || (strcmp(instance->manufacture_name, "Pecinin") == 0) || - (strcmp(instance->manufacture_name, "Steelmate") == 0)) { + (strcmp(instance->manufacture_name, "Steelmate") == 0) || + (strcmp(instance->manufacture_name, "Cardin_S449") == 0)) { // DTM Neo, Came_Space uses 12bit serial -> simple learning // FAAC_RC,XT , Mutanco_Mutancode, Genius_Bravo, GSN 12bit serial -> normal learning // Rosh, Rossi, Pecinin -> 12bit serial - simple learning // Steelmate -> 12bit serial - normal learning + // Cardin_S449 -> 12bit serial - normal learning decrypt = btn << 28 | (instance->generic.serial & 0xFFF) << 16 | instance->generic.cnt; } else if( @@ -511,6 +513,8 @@ static bool klq_last_custom_btn = 0x6; } else if((strcmp(instance->manufacture_name, "AN-Motors") == 0)) { klq_last_custom_btn = 0xC; + } else if((strcmp(instance->manufacture_name, "Cardin_S449") == 0)) { + klq_last_custom_btn = 0xD; } btn = subghz_protocol_keeloq_get_btn_code(klq_last_custom_btn); diff --git a/lib/subghz/subghz_setting.c b/lib/subghz/subghz_setting.c index fcb426c8c..037bd6df8 100644 --- a/lib/subghz/subghz_setting.c +++ b/lib/subghz/subghz_setting.c @@ -201,6 +201,8 @@ static void subghz_setting_load_default_region( instance, "FM238", subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs); subghz_setting_load_default_preset( instance, "FM476", subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs); + subghz_setting_load_default_preset( + instance, "FM12K", subghz_device_cc1101_preset_2fsk_dev12khz_async_regs); } // Region check removed diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 1213d09e7..74c45e91a 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,87.1,, +Version,+,87.2,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -4274,6 +4274,7 @@ Variable,+,sequence_solid_yellow,const NotificationSequence, Variable,+,sequence_success,const NotificationSequence, Variable,+,simple_array_config_uint8_t,const SimpleArrayConfig, Variable,-,subghz_device_cc1101_int,const SubGhzDevice, +Variable,+,subghz_device_cc1101_preset_2fsk_dev12khz_async_regs,const uint8_t[], Variable,+,subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs,const uint8_t[], Variable,+,subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs,const uint8_t[], Variable,+,subghz_device_cc1101_preset_gfsk_9_99kb_async_regs,const uint8_t[], From 8d23b84ed1b33f33f728f33dbf94a4ec513fe300 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 5 Jan 2026 21:14:33 +0300 Subject: [PATCH 007/160] fix typos in signal settings --- .../scenes/subghz_scene_signal_settings.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_signal_settings.c b/applications/main/subghz/scenes/subghz_scene_signal_settings.c index f5dbfea58..d7d393d52 100644 --- a/applications/main/subghz/scenes/subghz_scene_signal_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_signal_settings.c @@ -197,14 +197,13 @@ void subghz_scene_signal_settings_on_enter(void* context) { } // In protocols output we allways have HEX format for "Cnt:" output (text formating like ...Cnt:%05lX\r\n") - // we take 8 simbols starting from "Cnt:........" - // at first we search "Cnt:????" that mean for this protocol counter cannot be decoded + // we take 8 symbols starting from "Cnt:........" + // at first we search "Cnt:????" that means for this protocol counter cannot be decoded int8_t place = furi_string_search_str(tmp_text, "Cnt:??", 0); if(place > 0) { counter_mode = 0xff; - FURI_LOG_D( - TAG, "Founded Cnt:???? - Counter mode and edit not available for this protocol"); + FURI_LOG_D(TAG, "Found Cnt:???? - Counter mode and edit not available for this protocol"); } else { place = furi_string_search_str(tmp_text, "Cnt:", 0); if(place > 0) { @@ -219,7 +218,7 @@ void subghz_scene_signal_settings_on_enter(void* context) { furi_string_trim(textCnt); FURI_LOG_D( TAG, - "Taked 8 bytes hex value starting after 'Cnt:' - %s", + "Took 8 bytes hex value starting after 'Cnt:' - %s", furi_string_get_cstr(textCnt)); // trim and convert 8 simbols string to uint32 by base 16 (hex); @@ -230,13 +229,13 @@ void subghz_scene_signal_settings_on_enter(void* context) { StrintParseNoError) { counter_not_available = false; - // calculate and roundup number of hex bytes do display counter in byte_input (every 2 hex simbols = 1 byte for view) + // calculate and roundup number of hex bytes to display counter in byte_input (every 2 hex symbols = 1 byte for view) // later must be used in byte_input to restrict number of available byte to edit // cnt_byte_count = (hex_char_lenght + 1) / 2; FURI_LOG_D( TAG, - "Result of conversion from String to uint_32 DEC %li, HEX %lX, HEX lenght %i symbols", + "Result of conversion from String to uint_32 DEC %li, HEX %lX, HEX length %i symbols", loaded_counter32, loaded_counter32, hex_char_lenght); @@ -268,7 +267,7 @@ void subghz_scene_signal_settings_on_enter(void* context) { furi_assert(byte_ptr); furi_assert(byte_count > 0); - //Create and Enable/Disable variable_item_list depent from current values + //Create and Enable/Disable variable_item_list depending on current values VariableItemList* variable_item_list = subghz->variable_item_list; int32_t value_index; VariableItem* item; @@ -315,7 +314,7 @@ bool subghz_scene_signal_settings_on_event(void* context, SceneManagerEvent even // when signal has Cnt:00 we can step only to 0000+FFFF = FFFF, but we need 0000 for next step // for this case we must use +1 additional step to increace Cnt from FFFF to 0000. - // save current user definded counter increase value (mult) + // save current user defined counter increase value (mult) tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); // increase signal counter to max value - at result it must be 0000 in most cases @@ -411,7 +410,7 @@ void subghz_scene_signal_settings_on_exit(void* context) { flipper_format_free(fff_data_file); furi_record_close(RECORD_STORAGE); - // we need reload file after editing when we exit from Signal Settings menu. + // we need to reload file after editing when we exit from Signal Settings menu. if(subghz_key_load(subghz, file_path, false)) { FURI_LOG_D(TAG, "Subghz file was successfully reloaded"); } else { From 529d72f7ddab8cad06acccc13c21407e9d58613f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 5 Jan 2026 21:10:31 +0300 Subject: [PATCH 008/160] kinggates stylo 4k add manually and button switch --- .../main/subghz/helpers/subghz_custom_event.h | 1 + .../main/subghz/helpers/subghz_gen_info.c | 9 + .../main/subghz/helpers/subghz_gen_info.h | 6 + .../helpers/subghz_txrx_create_protocol_key.c | 30 +++ .../helpers/subghz_txrx_create_protocol_key.h | 8 + .../subghz/scenes/subghz_scene_set_button.c | 5 + .../subghz/scenes/subghz_scene_set_counter.c | 17 ++ .../subghz/scenes/subghz_scene_set_seed.c | 2 + .../subghz/scenes/subghz_scene_set_serial.c | 9 + .../subghz/scenes/subghz_scene_set_type.c | 11 + lib/subghz/protocols/kinggates_stylo_4k.c | 190 +++++++++++++++--- lib/subghz/protocols/public_api.h | 18 ++ targets/f7/api_symbols.csv | 1 + 13 files changed, 282 insertions(+), 25 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index 33a70fd57..e21ba128c 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -70,6 +70,7 @@ typedef enum { SetTypeFaacSLH_433, SetTypeBFTMitto, SetTypeSomfyTelis, + SetTypeKingGatesStylo4k, SetTypeANMotorsAT4, SetTypeAlutechAT4N, SetTypePhoenix_V2_433, diff --git a/applications/main/subghz/helpers/subghz_gen_info.c b/applications/main/subghz/helpers/subghz_gen_info.c index 5f1021ddd..82c114268 100644 --- a/applications/main/subghz/helpers/subghz_gen_info.c +++ b/applications/main/subghz/helpers/subghz_gen_info.c @@ -523,6 +523,15 @@ void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType ty .somfy_telis.btn = 0x02, .somfy_telis.cnt = 0x03}; break; + case SetTypeKingGatesStylo4k: + gen_info = (GenInfo){ + .type = GenKingGatesStylo4k, + .mod = "AM650", + .freq = 433920000, + .kinggates_stylo_4k.serial = key & 0xFFFFFFFF, + .kinggates_stylo_4k.btn = 0x0E, + .kinggates_stylo_4k.cnt = 0x03}; + break; case SetTypeMotorline433: gen_info = (GenInfo){ .type = GenKeeloq, diff --git a/applications/main/subghz/helpers/subghz_gen_info.h b/applications/main/subghz/helpers/subghz_gen_info.h index 88ccdec75..f54992738 100644 --- a/applications/main/subghz/helpers/subghz_gen_info.h +++ b/applications/main/subghz/helpers/subghz_gen_info.h @@ -10,6 +10,7 @@ typedef enum { GenKeeloqBFT, GenAlutechAt4n, GenSomfyTelis, + GenKingGatesStylo4k, GenNiceFlorS, GenSecPlus1, GenSecPlus2, @@ -61,6 +62,11 @@ typedef struct { uint8_t btn; uint16_t cnt; } somfy_telis; + struct { + uint32_t serial; + uint8_t btn; + uint16_t cnt; + } kinggates_stylo_4k; struct { uint32_t serial; uint8_t btn; diff --git a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c index 783273e6b..1c0add497 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c +++ b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c @@ -335,6 +335,36 @@ bool subghz_txrx_gen_somfy_telis_protocol( return res; } +bool subghz_txrx_gen_kinggates_stylo_4k_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt) { + SubGhzTxRx* txrx = context; + + bool res = false; + + txrx->transmitter = + subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_KINGGATES_STYLO_4K_NAME); + subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); + + if(txrx->transmitter && subghz_protocol_kinggates_stylo_4k_create_data( + subghz_transmitter_get_protocol_instance(txrx->transmitter), + txrx->fff_data, + serial, + btn, + cnt, + txrx->preset)) { + res = true; + } + + subghz_transmitter_free(txrx->transmitter); + + return res; +} + bool subghz_txrx_gen_secplus_v2_protocol( SubGhzTxRx* instance, const char* name_preset, diff --git a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h index 7daa61b31..590f9fa5b 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h +++ b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h @@ -108,6 +108,14 @@ bool subghz_txrx_gen_somfy_telis_protocol( uint8_t btn, uint16_t cnt); +bool subghz_txrx_gen_kinggates_stylo_4k_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt); + bool subghz_txrx_gen_came_atomo_protocol( void* context, const char* preset_name, diff --git a/applications/main/subghz/scenes/subghz_scene_set_button.c b/applications/main/subghz/scenes/subghz_scene_set_button.c index c07b793e4..baab8f095 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_button.c +++ b/applications/main/subghz/scenes/subghz_scene_set_button.c @@ -36,6 +36,10 @@ void subghz_scene_set_button_on_enter(void* context) { byte_ptr = &subghz->gen_info->somfy_telis.btn; byte_count = sizeof(subghz->gen_info->somfy_telis.btn); break; + case GenKingGatesStylo4k: + byte_ptr = &subghz->gen_info->kinggates_stylo_4k.btn; + byte_count = sizeof(subghz->gen_info->kinggates_stylo_4k.btn); + break; case GenNiceFlorS: byte_ptr = &subghz->gen_info->nice_flor_s.btn; byte_count = sizeof(subghz->gen_info->nice_flor_s.btn); @@ -82,6 +86,7 @@ bool subghz_scene_set_button_on_event(void* context, SceneManagerEvent event) { case GenKeeloqBFT: case GenAlutechAt4n: case GenSomfyTelis: + case GenKingGatesStylo4k: case GenNiceFlorS: case GenSecPlus2: scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCounter); diff --git a/applications/main/subghz/scenes/subghz_scene_set_counter.c b/applications/main/subghz/scenes/subghz_scene_set_counter.c index 9afa3408c..42437fcbf 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_counter.c +++ b/applications/main/subghz/scenes/subghz_scene_set_counter.c @@ -42,6 +42,10 @@ void subghz_scene_set_counter_on_enter(void* context) { byte_ptr = (uint8_t*)&subghz->gen_info->somfy_telis.cnt; byte_count = sizeof(subghz->gen_info->somfy_telis.cnt); break; + case GenKingGatesStylo4k: + byte_ptr = (uint8_t*)&subghz->gen_info->kinggates_stylo_4k.cnt; + byte_count = sizeof(subghz->gen_info->kinggates_stylo_4k.cnt); + break; case GenNiceFlorS: byte_ptr = (uint8_t*)&subghz->gen_info->nice_flor_s.cnt; byte_count = sizeof(subghz->gen_info->nice_flor_s.cnt); @@ -113,6 +117,10 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { case GenSomfyTelis: subghz->gen_info->somfy_telis.cnt = __bswap16(subghz->gen_info->somfy_telis.cnt); break; + case GenKingGatesStylo4k: + subghz->gen_info->kinggates_stylo_4k.cnt = + __bswap16(subghz->gen_info->kinggates_stylo_4k.cnt); + break; case GenNiceFlorS: subghz->gen_info->nice_flor_s.cnt = __bswap16(subghz->gen_info->nice_flor_s.cnt); break; @@ -171,6 +179,15 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { subghz->gen_info->somfy_telis.btn, subghz->gen_info->somfy_telis.cnt); break; + case GenKingGatesStylo4k: + generated_protocol = subghz_txrx_gen_kinggates_stylo_4k_protocol( + subghz->txrx, + subghz->gen_info->mod, + subghz->gen_info->freq, + subghz->gen_info->kinggates_stylo_4k.serial, + subghz->gen_info->kinggates_stylo_4k.btn, + subghz->gen_info->kinggates_stylo_4k.cnt); + break; case GenNiceFlorS: generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( subghz->txrx, diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed.c b/applications/main/subghz/scenes/subghz_scene_set_seed.c index c858b2a17..b93203a17 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed.c @@ -30,6 +30,7 @@ void subghz_scene_set_seed_on_enter(void* context) { case GenKeeloq: case GenAlutechAt4n: case GenSomfyTelis: + case GenKingGatesStylo4k: case GenNiceFlorS: case GenSecPlus2: case GenPhoenixV2: @@ -89,6 +90,7 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { case GenKeeloq: case GenAlutechAt4n: case GenSomfyTelis: + case GenKingGatesStylo4k: case GenNiceFlorS: case GenSecPlus2: case GenPhoenixV2: diff --git a/applications/main/subghz/scenes/subghz_scene_set_serial.c b/applications/main/subghz/scenes/subghz_scene_set_serial.c index 5c3b76733..b11559b44 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_serial.c +++ b/applications/main/subghz/scenes/subghz_scene_set_serial.c @@ -42,6 +42,10 @@ void subghz_scene_set_serial_on_enter(void* context) { byte_ptr = (uint8_t*)&subghz->gen_info->somfy_telis.serial; byte_count = sizeof(subghz->gen_info->somfy_telis.serial); break; + case GenKingGatesStylo4k: + byte_ptr = (uint8_t*)&subghz->gen_info->kinggates_stylo_4k.serial; + byte_count = sizeof(subghz->gen_info->kinggates_stylo_4k.serial); + break; case GenNiceFlorS: byte_ptr = (uint8_t*)&subghz->gen_info->nice_flor_s.serial; byte_count = sizeof(subghz->gen_info->nice_flor_s.serial); @@ -110,6 +114,10 @@ bool subghz_scene_set_serial_on_event(void* context, SceneManagerEvent event) { subghz->gen_info->somfy_telis.serial = __bswap32(subghz->gen_info->somfy_telis.serial); break; + case GenKingGatesStylo4k: + subghz->gen_info->kinggates_stylo_4k.serial = + __bswap32(subghz->gen_info->kinggates_stylo_4k.serial); + break; case GenNiceFlorS: subghz->gen_info->nice_flor_s.serial = __bswap32(subghz->gen_info->nice_flor_s.serial); @@ -136,6 +144,7 @@ bool subghz_scene_set_serial_on_event(void* context, SceneManagerEvent event) { case GenKeeloqBFT: case GenAlutechAt4n: case GenSomfyTelis: + case GenKingGatesStylo4k: case GenNiceFlorS: case GenSecPlus2: scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetButton); diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 731da6f3f..846dda5d0 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -20,6 +20,7 @@ static const char* submenu_names[SetTypeMAX] = { [SetTypeAlutechAT4N] = "Alutech AT4N 433MHz", [SetTypeRoger_433] = "Roger 433MHz", [SetTypePhoenix_V2_433] = "V2 Phoenix 433MHz", + [SetTypeKingGatesStylo4k] = "KingGates Stylo4 433MHz", [SetTypeHCS101_433_92] = "KL: HCS101 433MHz", [SetTypeDoorHan_315_00] = "KL: DoorHan 315MHz", [SetTypeDoorHan_433_92] = "KL: DoorHan 433MHz", @@ -187,6 +188,15 @@ bool subghz_scene_set_type_generate_protocol_from_infos(SubGhz* subghz) { gen_info.somfy_telis.btn, gen_info.somfy_telis.cnt); break; + case GenKingGatesStylo4k: + generated_protocol = subghz_txrx_gen_kinggates_stylo_4k_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.kinggates_stylo_4k.serial, + gen_info.kinggates_stylo_4k.btn, + gen_info.kinggates_stylo_4k.cnt); + break; case GenNiceFlorS: generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( subghz->txrx, @@ -266,6 +276,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { case GenKeeloqBFT: // Serial (u32), Button (u8), Counter (u16), Seed (u32) case GenAlutechAt4n: // Serial (u32), Button (u8), Counter (u16) case GenSomfyTelis: // Serial (u32), Button (u8), Counter (u16) + case GenKingGatesStylo4k: // Serial (u32), Button (u8), Counter (u16) case GenNiceFlorS: // Serial (u32), Button (u8), Counter (u16) case GenSecPlus2: // Serial (u32), Button (u8), Counter (u32) case GenPhoenixV2: // Serial (u32), Counter (u16) diff --git a/lib/subghz/protocols/kinggates_stylo_4k.c b/lib/subghz/protocols/kinggates_stylo_4k.c index 2a34cc522..e41dc19e2 100644 --- a/lib/subghz/protocols/kinggates_stylo_4k.c +++ b/lib/subghz/protocols/kinggates_stylo_4k.c @@ -8,6 +8,8 @@ #include "../blocks/generic.h" #include "../blocks/math.h" +#include "../blocks/custom_btn_i.h" + #define TAG "SubGhzProtocoKingGatesStylo4k" static const SubGhzBlockConst subghz_protocol_kinggates_stylo_4k_const = { @@ -84,6 +86,13 @@ static void subghz_protocol_kinggates_stylo_4k_remote_controller( SubGhzBlockGeneric* instance, SubGhzKeystore* keystore); +/** + * Defines the button value for the current btn_id + * Basic set | 0xE | 0xD | 0xB | 0x7 | + * @return Button code + */ +static uint8_t subghz_protocol_kinggates_stylo_4k_get_btn_code(void); + void* subghz_protocol_encoder_kinggates_stylo_4k_alloc(SubGhzEnvironment* environment) { SubGhzProtocolEncoderKingGates_stylo_4k* instance = malloc(sizeof(SubGhzProtocolEncoderKingGates_stylo_4k)); @@ -138,22 +147,12 @@ LevelDuration subghz_protocol_encoder_kinggates_stylo_4k_yield(void* context) { static bool subghz_protocol_kinggates_stylo_4k_gen_data( SubGhzProtocolEncoderKingGates_stylo_4k* instance, uint8_t btn) { - UNUSED(btn); - uint32_t hop = subghz_protocol_blocks_reverse_key(instance->generic.data_2 >> 4, 32); - uint64_t fix = subghz_protocol_blocks_reverse_key(instance->generic.data, 53); - int res = 0; - uint32_t decrypt = 0; + // Save original button for later use + if(subghz_custom_btn_get_original() == 0) { + subghz_custom_btn_set_original(btn); + } - for - M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { - res = strcmp(furi_string_get_cstr(manufacture_code->name), "Kingates_Stylo4k"); - if(res == 0) { - //Simple Learning - decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); - break; - } - } - instance->generic.cnt = decrypt & 0xFFFF; + btn = subghz_protocol_kinggates_stylo_4k_get_btn_code(); // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { @@ -172,18 +171,21 @@ static bool subghz_protocol_kinggates_stylo_4k_gen_data( } } - instance->generic.btn = (fix >> 17) & 0x0F; - instance->generic.serial = ((fix >> 5) & 0xFFFF0000) | (fix & 0xFFFF); + // hop is encrypted part + uint32_t hop = (uint64_t)btn << 28 | (((uint32_t)0x0C) << 24) | + ((instance->generic.serial & 0xFF) << 16) | (instance->generic.cnt & 0xFFFF); - uint32_t data = (decrypt & 0xFFFF0000) | instance->generic.cnt; + uint64_t fix = ((uint64_t)((instance->generic.serial >> 16) & 0xFFFF) << 21) | + (uint64_t)btn << 17 | 0b1 << 16 | (instance->generic.serial & 0xFFFF); + + instance->generic.data = subghz_protocol_blocks_reverse_key(fix, 53); uint64_t encrypt = 0; for M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { - res = strcmp(furi_string_get_cstr(manufacture_code->name), "Kingates_Stylo4k"); - if(res == 0) { - //Simple Learning - encrypt = subghz_protocol_keeloq_common_encrypt(data, manufacture_code->key); + if(strcmp(furi_string_get_cstr(manufacture_code->name), "Kingates_Stylo4k") == 0) { + // Simple Learning + encrypt = subghz_protocol_keeloq_common_encrypt(hop, manufacture_code->key); encrypt = subghz_protocol_blocks_reverse_key(encrypt, 32); instance->generic.data_2 = encrypt << 4; return true; @@ -193,6 +195,63 @@ static bool subghz_protocol_kinggates_stylo_4k_gen_data( return false; } +bool subghz_protocol_kinggates_stylo_4k_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolEncoderKingGates_stylo_4k* instance = context; + instance->generic.serial = serial; + instance->generic.cnt = cnt; + instance->generic.btn = btn; + instance->generic.data_count_bit = 89; + + uint32_t decrypt = instance->generic.btn << 28 | (((uint32_t)0x0C) << 24) | + ((instance->generic.serial & 0xFF) << 16) | + (instance->generic.cnt & 0xFFFF); + + uint64_t encrypt = 0; + for + M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { + if(strcmp(furi_string_get_cstr(manufacture_code->name), "Kingates_Stylo4k") == 0) { + // Simple Learning + encrypt = subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key); + encrypt = subghz_protocol_blocks_reverse_key(encrypt, 32); + instance->generic.data_2 = encrypt << 4; + break; + } + } + + uint64_t fix = ((uint64_t)((instance->generic.serial >> 16) & 0xFFFF) << 21) | + instance->generic.btn << 17 | 0b1 << 16 | (instance->generic.serial & 0xFFFF); + + instance->generic.data = subghz_protocol_blocks_reverse_key(fix, 53); + + SubGhzProtocolStatus res = + subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data_2 >> (i * 8)) & 0xFF; + } + + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + res = SubGhzProtocolStatusErrorParserOthers; + } + + if((res == SubGhzProtocolStatusOk) && + !flipper_format_insert_or_update_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to add Data2"); + res = SubGhzProtocolStatusErrorParserOthers; + } + + return res == SubGhzProtocolStatusOk; +} + /** * Generating an upload from data. * @param instance Pointer to a SubGhzProtocolEncoderKingGates_stylo_4k instance @@ -281,9 +340,6 @@ SubGhzProtocolStatus subghz_protocol_encoder_kinggates_stylo_4k_deserialize( break; } - subghz_protocol_kinggates_stylo_4k_remote_controller( - &instance->generic, instance->keystore); - //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); @@ -303,6 +359,9 @@ SubGhzProtocolStatus subghz_protocol_encoder_kinggates_stylo_4k_deserialize( instance->generic.data_2 = instance->generic.data_2 << 8 | key_data[i]; } + subghz_protocol_kinggates_stylo_4k_remote_controller( + &instance->generic, instance->keystore); + subghz_protocol_encoder_kinggates_stylo_4k_get_upload(instance, instance->generic.btn); if(!flipper_format_rewind(flipper_format)) { @@ -310,6 +369,14 @@ SubGhzProtocolStatus subghz_protocol_encoder_kinggates_stylo_4k_deserialize( break; } + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data >> i * 8) & 0xFF; + } + if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to update Key"); + break; + } + for(size_t i = 0; i < sizeof(uint64_t); i++) { key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data_2 >> i * 8) & 0xFF; } @@ -501,6 +568,11 @@ static void subghz_protocol_kinggates_stylo_4k_remote_controller( } if(ret) { instance->cnt = decrypt & 0xFFFF; + // Save original button for later use + if(subghz_custom_btn_get_original() == 0) { + subghz_custom_btn_set_original(instance->btn); + } + subghz_custom_btn_set_max(3); } else { instance->btn = 0; instance->serial = 0; @@ -575,6 +647,74 @@ SubGhzProtocolStatus subghz_protocol_decoder_kinggates_stylo_4k_deserialize( return ret; } +static uint8_t subghz_protocol_kinggates_stylo_4k_get_btn_code(void) { + uint8_t custom_btn_id = subghz_custom_btn_get(); + uint8_t original_btn_code = subghz_custom_btn_get_original(); + uint8_t btn = original_btn_code; + + // Set custom button + if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) { + // Restore original button code + btn = original_btn_code; + } else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) { + switch(original_btn_code) { + case 0xE: + btn = 0xD; + break; + case 0xD: + btn = 0xE; + break; + case 0xB: + btn = 0xE; + break; + case 0x7: + btn = 0xE; + break; + + default: + break; + } + } else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) { + switch(original_btn_code) { + case 0xE: + btn = 0xB; + break; + case 0xD: + btn = 0xB; + break; + case 0xB: + btn = 0xD; + break; + case 0x7: + btn = 0xD; + break; + + default: + break; + } + } else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_LEFT) { + switch(original_btn_code) { + case 0xE: + btn = 0x7; + break; + case 0xD: + btn = 0x7; + break; + case 0xB: + btn = 0x7; + break; + case 0x7: + btn = 0xB; + break; + + default: + break; + } + } + + return btn; +} + void subghz_protocol_decoder_kinggates_stylo_4k_get_string(void* context, FuriString* output) { furi_assert(context); SubGhzProtocolDecoderKingGates_stylo_4k* instance = context; diff --git a/lib/subghz/protocols/public_api.h b/lib/subghz/protocols/public_api.h index 39c08e6aa..76cdb2525 100644 --- a/lib/subghz/protocols/public_api.h +++ b/lib/subghz/protocols/public_api.h @@ -215,6 +215,24 @@ bool subghz_protocol_somfy_keytis_create_data( uint16_t cnt, SubGhzRadioPreset* preset); +/** + * Key generation from simple data. + * @param context Pointer to a SubGhzProtocolEncoderKingGates_stylo_4k instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param serial Serial number, 24 bit + * @param btn Button number, 8 bit + * @param cnt Counter value, 16 bit + * @param preset Modulation, SubGhzRadioPreset + * @return true On success + */ +bool subghz_protocol_kinggates_stylo_4k_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + SubGhzRadioPreset* preset); + typedef struct SubGhzProtocolDecoderBinRAW SubGhzProtocolDecoderBinRAW; void subghz_protocol_decoder_bin_raw_data_input_rssi( diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 74c45e91a..3889ce342 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -3674,6 +3674,7 @@ Function,+,subghz_protocol_encoder_raw_yield,LevelDuration,void* Function,+,subghz_protocol_faac_slh_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint32_t, uint32_t, const char*, SubGhzRadioPreset*" Function,+,subghz_protocol_keeloq_bft_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, uint32_t, const char*, SubGhzRadioPreset*" Function,+,subghz_protocol_keeloq_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, const char*, SubGhzRadioPreset*" +Function,+,subghz_protocol_kinggates_stylo_4k_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*" Function,+,subghz_protocol_nice_flor_s_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*, _Bool" Function,+,subghz_protocol_phoenix_v2_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint16_t, SubGhzRadioPreset*" Function,+,subghz_protocol_raw_file_encoder_worker_set_callback_end,void,"SubGhzProtocolEncoderRAW*, SubGhzProtocolEncoderRAWCallbackEnd, void*" From b078213604fe5c020c1e1c067e8c59eab8927b85 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 5 Jan 2026 21:15:41 +0300 Subject: [PATCH 009/160] bump subremote --- applications/main/subghz_remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/subghz_remote b/applications/main/subghz_remote index 885187e22..a8abfcd60 160000 --- a/applications/main/subghz_remote +++ b/applications/main/subghz_remote @@ -1 +1 @@ -Subproject commit 885187e22ccd934093719aac0309b5e1b829f83a +Subproject commit a8abfcd6026190b7492bc42827c6c465691ccb9a From bd87186f413bff51c1336b3122a7793dd1de3465 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 5 Jan 2026 21:21:27 +0300 Subject: [PATCH 010/160] Stilmatic button 9 support --- lib/subghz/protocols/keeloq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 6d40a11ea..ba2df2cde 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -507,7 +507,9 @@ static bool (strcmp(instance->manufacture_name, "Monarch") == 0) || (strcmp(instance->manufacture_name, "NICE_Smilo") == 0)) { klq_last_custom_btn = 0xB; - } else if((strcmp(instance->manufacture_name, "Novoferm") == 0)) { + } else if( + (strcmp(instance->manufacture_name, "Novoferm") == 0) || + (strcmp(instance->manufacture_name, "Stilmatic") == 0)) { klq_last_custom_btn = 0x9; } else if((strcmp(instance->manufacture_name, "EcoStar") == 0)) { klq_last_custom_btn = 0x6; From ef9cd22dfe73a9b3ce9f2b89d657467ce58d11e0 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 5 Jan 2026 21:40:10 +0300 Subject: [PATCH 011/160] NFC: Fix some typos in Type4Tag protocol [ci skip] by WillyJL --- .../nfc/helpers/protocol_support/type_4_tag/type_4_tag.c | 2 +- lib/nfc/protocols/type_4_tag/type_4_tag_poller.c | 6 +++--- lib/nfc/protocols/type_4_tag/type_4_tag_poller.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/type_4_tag/type_4_tag.c b/applications/main/nfc/helpers/protocol_support/type_4_tag/type_4_tag.c index 3b1fc91f6..3fa6b2593 100644 --- a/applications/main/nfc/helpers/protocol_support/type_4_tag/type_4_tag.c +++ b/applications/main/nfc/helpers/protocol_support/type_4_tag/type_4_tag.c @@ -184,7 +184,7 @@ static NfcCommand nfc_device_get_data(instance->nfc_device, NfcProtocolType4Tag); furi_string_reset(instance->text_box_store); view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventCardDetected); - } else if(type_4_tag_event->type == Type4TagPollerEventTypeWriteFail) { + } else if(type_4_tag_event->type == Type4TagPollerEventTypeWriteFailed) { const char* error_str = type_4_tag_event->data->error == Type4TagErrorCardLocked ? "Card does not\nallow writing\nnew data" : "Failed to\nwrite new data"; diff --git a/lib/nfc/protocols/type_4_tag/type_4_tag_poller.c b/lib/nfc/protocols/type_4_tag/type_4_tag_poller.c index 0291d2df9..639f3f1db 100644 --- a/lib/nfc/protocols/type_4_tag/type_4_tag_poller.c +++ b/lib/nfc/protocols/type_4_tag/type_4_tag_poller.c @@ -4,7 +4,7 @@ #define TAG "Type4TagPoller" -typedef NfcCommand (*Type4TagPollerReadHandler)(Type4TagPoller* instance); +typedef NfcCommand (*Type4TagPollerStateHandler)(Type4TagPoller* instance); static const Type4TagData* type_4_tag_poller_get_data(Type4TagPoller* instance) { furi_assert(instance); @@ -191,7 +191,7 @@ static NfcCommand type_4_tag_poller_handler_failed(Type4TagPoller* instance) { iso14443_4a_poller_halt(instance->iso14443_4a_poller); instance->type_4_tag_event.type = instance->mode == Type4TagPollerModeRead ? Type4TagPollerEventTypeReadFailed : - Type4TagPollerEventTypeWriteFail; + Type4TagPollerEventTypeWriteFailed; instance->type_4_tag_event.data->error = instance->error; NfcCommand command = instance->callback(instance->general_event, instance->context); instance->state = Type4TagPollerStateIdle; @@ -208,7 +208,7 @@ static NfcCommand type_4_tag_poller_handler_success(Type4TagPoller* instance) { return command; } -static const Type4TagPollerReadHandler type_4_tag_poller_read_handler[Type4TagPollerStateNum] = { +static const Type4TagPollerStateHandler type_4_tag_poller_read_handler[Type4TagPollerStateNum] = { [Type4TagPollerStateIdle] = type_4_tag_poller_handler_idle, [Type4TagPollerStateRequestMode] = type_4_tag_poller_handler_request_mode, [Type4TagPollerStateDetectPlatform] = type_4_tag_poller_handler_detect_platform, diff --git a/lib/nfc/protocols/type_4_tag/type_4_tag_poller.h b/lib/nfc/protocols/type_4_tag/type_4_tag_poller.h index 5ac4fd0f2..8263e3790 100644 --- a/lib/nfc/protocols/type_4_tag/type_4_tag_poller.h +++ b/lib/nfc/protocols/type_4_tag/type_4_tag_poller.h @@ -19,7 +19,7 @@ typedef enum { Type4TagPollerEventTypeReadSuccess, /**< Card was read successfully. */ Type4TagPollerEventTypeReadFailed, /**< Poller failed to read card. */ Type4TagPollerEventTypeWriteSuccess, /**< Poller wrote card successfully. */ - Type4TagPollerEventTypeWriteFail, /**< Poller failed to write card. */ + Type4TagPollerEventTypeWriteFailed, /**< Poller failed to write card. */ } Type4TagPollerEventType; /** From 02796c391ea8a8aafc6f5e169d3eec6e9a5b2528 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 5 Jan 2026 22:26:28 +0300 Subject: [PATCH 012/160] fix length typos --- .../examples/example_event_loop/example_event_loop_mutex.c | 2 +- .../main/subghz/scenes/subghz_scene_signal_settings.c | 4 ++-- lib/mjs/mjs_exec.c | 2 +- lib/subghz/blocks/generic.c | 4 ++-- lib/subghz/blocks/generic.h | 2 +- lib/subghz/protocols/alutech_at_4n.c | 2 +- lib/subghz/protocols/came_atomo.c | 2 +- lib/subghz/protocols/faac_slh.c | 2 +- lib/subghz/protocols/hay21.c | 2 +- lib/subghz/protocols/keeloq.c | 4 ++-- lib/subghz/protocols/kia.c | 2 +- lib/subghz/protocols/kinggates_stylo_4k.c | 2 +- lib/subghz/protocols/nice_flor_s.c | 2 +- lib/subghz/protocols/phoenix_v2.c | 2 +- lib/subghz/protocols/scher_khan.c | 2 +- lib/subghz/protocols/secplus_v1.c | 2 +- lib/subghz/protocols/secplus_v2.c | 2 +- lib/subghz/protocols/somfy_keytis.c | 2 +- lib/subghz/protocols/somfy_telis.c | 2 +- lib/subghz/protocols/star_line.c | 2 +- 20 files changed, 23 insertions(+), 23 deletions(-) diff --git a/applications/examples/example_event_loop/example_event_loop_mutex.c b/applications/examples/example_event_loop/example_event_loop_mutex.c index 20bf7af4b..cbbd86298 100644 --- a/applications/examples/example_event_loop/example_event_loop_mutex.c +++ b/applications/examples/example_event_loop/example_event_loop_mutex.c @@ -26,7 +26,7 @@ typedef struct { uint8_t worker_result; } EventLoopMutexApp; -// This funciton is being run in a separate thread to simulate lenghty blocking operations +// This funciton is being run in a separate thread to simulate lengthy blocking operations static int32_t event_loop_mutex_app_worker_thread(void* context) { furi_assert(context); EventLoopMutexApp* app = context; diff --git a/applications/main/subghz/scenes/subghz_scene_signal_settings.c b/applications/main/subghz/scenes/subghz_scene_signal_settings.c index 30372d0de..e74219a28 100644 --- a/applications/main/subghz/scenes/subghz_scene_signal_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_signal_settings.c @@ -67,7 +67,7 @@ void subghz_scene_signal_settings_variable_item_list_enter_callback(void* contex // when we click OK on "Edit counter" item if(index == 1) { - furi_string_cat_printf(byte_input_text, "%i", subghz_block_generic_global.cnt_lenght_bit); + furi_string_cat_printf(byte_input_text, "%i", subghz_block_generic_global.cnt_length_bit); furi_string_cat_str(byte_input_text, "-bits counter in HEX"); // Setup byte_input view @@ -151,7 +151,7 @@ void subghz_scene_signal_settings_on_enter(void* context) { // Check is there byte_count more than 2 hex bytes long or not // To show hex value we must correct revert bytes for ByteInput view with __bswapХХ - if(subghz_block_generic_global.cnt_lenght_bit > 16) { + if(subghz_block_generic_global.cnt_length_bit > 16) { counter32 = subghz_block_generic_global.current_cnt; furi_string_printf(tmp_text, "%lX", counter32); counter32 = __bswap32(counter32); diff --git a/lib/mjs/mjs_exec.c b/lib/mjs/mjs_exec.c index 273c38a34..2def08160 100644 --- a/lib/mjs/mjs_exec.c +++ b/lib/mjs/mjs_exec.c @@ -1063,7 +1063,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs* mjs, size_t off, mjs_val_t* res) { mjs_gen_stack_trace(mjs, bp.start_idx + i - 1 /* undo the i++ */); - /* restore stack lenghts */ + /* restore stack lengths */ mjs->stack.len = stack_len; mjs->call_stack.len = call_stack_len; mjs->arg_stack.len = arg_stack_len; diff --git a/lib/subghz/blocks/generic.c b/lib/subghz/blocks/generic.c index adefebadd..f5974ffaa 100644 --- a/lib/subghz/blocks/generic.c +++ b/lib/subghz/blocks/generic.c @@ -17,10 +17,10 @@ void subghz_block_generic_global_counter_override_set(uint32_t counter) { bool subghz_block_generic_global_counter_override_get(uint32_t* counter) { // if override flag was enabled then return succes TRUE and return overrided counter, else return success = FALSE - // we cut counter bit lenght to available protocol bits lenght by the logical AND function + // we cut counter bit length to available protocol bits length by the logical AND function if(subghz_block_generic_global.cnt_need_override) { *counter = subghz_block_generic_global.new_cnt & - ((0xFFFFFFFF >> (32 - subghz_block_generic_global.cnt_lenght_bit))); + ((0xFFFFFFFF >> (32 - subghz_block_generic_global.cnt_length_bit))); subghz_block_generic_global.cnt_need_override = false; return true; } else { diff --git a/lib/subghz/blocks/generic.h b/lib/subghz/blocks/generic.h index 081f05fd3..1e72c5a5e 100644 --- a/lib/subghz/blocks/generic.h +++ b/lib/subghz/blocks/generic.h @@ -33,7 +33,7 @@ struct SubGhzBlockGenericGlobal { uint32_t current_cnt; // global counter value; uint32_t new_cnt; // global counter value; bool cnt_need_override; // flag for protocols to override signals counter inside of protocols - uint8_t cnt_lenght_bit; // counter lenght in bytes (used in counter editor giu) + uint8_t cnt_length_bit; // counter length in bytes (used in counter editor giu) bool cnt_is_available; // is there counter available for protocol (used in counter editor giu) }; diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 7fc8c4aa7..ccbe2ccf9 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -877,7 +877,7 @@ void subghz_protocol_decoder_alutech_at_4n_get_string(void* context, FuriString* // push protocol data to global variable subghz_block_generic_global.cnt_is_available = true; - subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; // diff --git a/lib/subghz/protocols/came_atomo.c b/lib/subghz/protocols/came_atomo.c index 077195f28..043736a34 100644 --- a/lib/subghz/protocols/came_atomo.c +++ b/lib/subghz/protocols/came_atomo.c @@ -827,7 +827,7 @@ void subghz_protocol_decoder_came_atomo_get_string(void* context, FuriString* ou // push protocol data to global variable subghz_block_generic_global.cnt_is_available = true; - subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; // diff --git a/lib/subghz/protocols/faac_slh.c b/lib/subghz/protocols/faac_slh.c index 62005d276..7297a179d 100644 --- a/lib/subghz/protocols/faac_slh.c +++ b/lib/subghz/protocols/faac_slh.c @@ -754,7 +754,7 @@ void subghz_protocol_decoder_faac_slh_get_string(void* context, FuriString* outp } else { // push protocol data to global variable subghz_block_generic_global.cnt_is_available = true; - subghz_block_generic_global.cnt_lenght_bit = 20; + subghz_block_generic_global.cnt_length_bit = 20; subghz_block_generic_global.current_cnt = instance->generic.cnt; // diff --git a/lib/subghz/protocols/hay21.c b/lib/subghz/protocols/hay21.c index 895a709e1..382124ab6 100644 --- a/lib/subghz/protocols/hay21.c +++ b/lib/subghz/protocols/hay21.c @@ -465,7 +465,7 @@ void subghz_protocol_decoder_hay21_get_string(void* context, FuriString* output) // push protocol data to global variable subghz_block_generic_global.cnt_is_available = true; - subghz_block_generic_global.cnt_lenght_bit = 8; + subghz_block_generic_global.cnt_length_bit = 8; subghz_block_generic_global.current_cnt = instance->generic.cnt; furi_string_cat_printf( diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 0d8c26701..4e53989e4 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -1436,7 +1436,7 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output if(strcmp(instance->manufacture_name, "BFT") == 0) { subghz_block_generic_global.cnt_is_available = true; - subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; furi_string_cat_printf( output, @@ -1474,7 +1474,7 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output instance->manufacture_name); } else { subghz_block_generic_global.cnt_is_available = true; - subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; furi_string_cat_printf( output, diff --git a/lib/subghz/protocols/kia.c b/lib/subghz/protocols/kia.c index d273e91f1..093bf966d 100644 --- a/lib/subghz/protocols/kia.c +++ b/lib/subghz/protocols/kia.c @@ -257,7 +257,7 @@ void subghz_protocol_decoder_kia_get_string(void* context, FuriString* output) { uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; // use 'Cntr:' instead of 'Cnt:' to exclude this protocol counter from Counter edit - subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; furi_string_cat_printf( diff --git a/lib/subghz/protocols/kinggates_stylo_4k.c b/lib/subghz/protocols/kinggates_stylo_4k.c index 6b13b55a5..f46d07ccd 100644 --- a/lib/subghz/protocols/kinggates_stylo_4k.c +++ b/lib/subghz/protocols/kinggates_stylo_4k.c @@ -726,7 +726,7 @@ void subghz_protocol_decoder_kinggates_stylo_4k_get_string(void* context, FuriSt // push protocol data to global variable subghz_block_generic_global.cnt_is_available = true; - subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; furi_string_cat_printf( diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index 36099c0cf..b46f5e747 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -916,7 +916,7 @@ void subghz_protocol_decoder_nice_flor_s_get_string(void* context, FuriString* o // push protocol data to global variable subghz_block_generic_global.cnt_is_available = true; - subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; if(instance->generic.data_count_bit == NICE_ONE_COUNT_BIT) { diff --git a/lib/subghz/protocols/phoenix_v2.c b/lib/subghz/protocols/phoenix_v2.c index a36e0ad0e..b32c7fb60 100644 --- a/lib/subghz/protocols/phoenix_v2.c +++ b/lib/subghz/protocols/phoenix_v2.c @@ -595,7 +595,7 @@ void subghz_protocol_decoder_phoenix_v2_get_string(void* context, FuriString* ou // push protocol data to global variable subghz_block_generic_global.cnt_is_available = true; - subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; furi_string_cat_printf( diff --git a/lib/subghz/protocols/scher_khan.c b/lib/subghz/protocols/scher_khan.c index 98c064c22..4ce050f6d 100644 --- a/lib/subghz/protocols/scher_khan.c +++ b/lib/subghz/protocols/scher_khan.c @@ -299,7 +299,7 @@ void subghz_protocol_decoder_scher_khan_get_string(void* context, FuriString* ou // use 'Cntr:' instead of 'Cnt:' to exclude this protocol counter from Counter edit // push protocol data to global variable - subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; furi_string_cat_printf( diff --git a/lib/subghz/protocols/secplus_v1.c b/lib/subghz/protocols/secplus_v1.c index 99bf61fec..c5690b910 100644 --- a/lib/subghz/protocols/secplus_v1.c +++ b/lib/subghz/protocols/secplus_v1.c @@ -583,7 +583,7 @@ void subghz_protocol_decoder_secplus_v1_get_string(void* context, FuriString* ou // push protocol data to global variable subghz_block_generic_global.cnt_is_available = true; - subghz_block_generic_global.cnt_lenght_bit = 32; + subghz_block_generic_global.cnt_length_bit = 32; subghz_block_generic_global.current_cnt = instance->generic.cnt; furi_string_cat_printf( diff --git a/lib/subghz/protocols/secplus_v2.c b/lib/subghz/protocols/secplus_v2.c index 4fc6cfcf9..9d24c1ae8 100644 --- a/lib/subghz/protocols/secplus_v2.c +++ b/lib/subghz/protocols/secplus_v2.c @@ -963,7 +963,7 @@ void subghz_protocol_decoder_secplus_v2_get_string(void* context, FuriString* ou // need to research or practice check how much bits in counter // push protocol data to global variable subghz_block_generic_global.cnt_is_available = true; - subghz_block_generic_global.cnt_lenght_bit = 28; + subghz_block_generic_global.cnt_length_bit = 28; subghz_block_generic_global.current_cnt = instance->generic.cnt; furi_string_cat_printf( diff --git a/lib/subghz/protocols/somfy_keytis.c b/lib/subghz/protocols/somfy_keytis.c index 5f4c8aa9b..cb9af5bb6 100644 --- a/lib/subghz/protocols/somfy_keytis.c +++ b/lib/subghz/protocols/somfy_keytis.c @@ -798,7 +798,7 @@ void subghz_protocol_decoder_somfy_keytis_get_string(void* context, FuriString* // push protocol data to global variable subghz_block_generic_global.cnt_is_available = true; - subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; furi_string_cat_printf( diff --git a/lib/subghz/protocols/somfy_telis.c b/lib/subghz/protocols/somfy_telis.c index d2b35b3fd..116e5e224 100644 --- a/lib/subghz/protocols/somfy_telis.c +++ b/lib/subghz/protocols/somfy_telis.c @@ -755,7 +755,7 @@ void subghz_protocol_decoder_somfy_telis_get_string(void* context, FuriString* o // push protocol data to global variable subghz_block_generic_global.cnt_is_available = true; - subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; furi_string_cat_printf( diff --git a/lib/subghz/protocols/star_line.c b/lib/subghz/protocols/star_line.c index e5009b9af..3fd236202 100644 --- a/lib/subghz/protocols/star_line.c +++ b/lib/subghz/protocols/star_line.c @@ -725,7 +725,7 @@ void subghz_protocol_decoder_star_line_get_string(void* context, FuriString* out // push protocol data to global variable subghz_block_generic_global.cnt_is_available = true; - subghz_block_generic_global.cnt_lenght_bit = 16; + subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; furi_string_cat_printf( From 9b926f275c08a34eec67f185174ae06723ed370f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 5 Jan 2026 23:37:36 +0300 Subject: [PATCH 013/160] upd changelog --- CHANGELOG.md | 8 +++++++- ReadMe.md | 6 +++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25c1e5036..8089f3d15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,14 @@ ## Main changes -- Current API: 87.1 +- Current API: 87.2 +* SubGHz: **Cardin S449 full support** (with Add manually, and all button codes) (**use FSK12K modulation to read the remote**) (closes issues #735 #908) (by @xMasterX and @zero-mega (thanks!)) +* SubGHz: Added **new modulation FSK with 12KHz deviation** +* SubGHz: **KingGates Stylo 4k - Add manually and button switch support** + refactoring of encoder +* SubGHz: **Stilmatic - button 9 support** (two buttons hold simulation) +* SubGHz: **Counter editor refactoring** (PR #939 | by @Dmitry422) * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes +* NFC: Fix some typos in Type4Tag protocol (by @WillyJL) * Clangd: Add clangd parameters in IDE agnostic config file (by @WillyJL)

#### Known NFC post-refactor regressions list: diff --git a/ReadMe.md b/ReadMe.md index d7005a097..25b59a7d9 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -160,7 +160,7 @@ Thanks to Official team (to their SubGHz Developer, Skorp) for implementing supp > | Cenmax_St-7 | Genius_Bravo | Magic_1 | Partisan_RX | IL-100(Smart) | > | Centurion | Gibidi | Magic_2 | Reff | Merlin | > | Monarch | Jolly Motors | Magic_3 | Sheriff | Steelmate | -> | Motorline | Rosh | Pecinin | Rossi | | +> | Motorline | Rosh | Pecinin | Rossi | Cardin S449 | >
@@ -180,7 +180,7 @@ Thanks to Official team (to their SubGHz Developer, Skorp) for implementing supp - Hay21 (dynamic 21 bit) with button parsing - Nero Radio 57bit (+ 56bit support) - CAME 12bit/24bit encoder fixes (Fixes are now merged in OFW) -- Keeloq: Dea Mio, Genius Bravo, GSN, HCS101, AN-Motors, JCM Tech, MHouse, Nice Smilo, DTM Neo, FAAC RC,XT, Mutancode, Normstahl, Beninca + Allmatic, Stilmatic, CAME Space, Aprimatic (model TR and similar), Centurion Nova (thanks Carlos !), Hormann EcoStar, Novoferm, Sommer, Monarch (thanks @ashphx !), Jolly Motors (thanks @pkooiman !), IL-100(Smart) (thx Vitaly for RAWs), Motorline (with add manually support), Rosh, Pecinin, Rossi, Merlin, Steelmate (thanks @RocketGod-git) +- Keeloq: Dea Mio, Genius Bravo, GSN, HCS101, AN-Motors, JCM Tech, MHouse, Nice Smilo, DTM Neo, FAAC RC,XT, Mutancode, Normstahl, Beninca + Allmatic, Stilmatic, CAME Space, Aprimatic (model TR and similar), Centurion Nova (thanks Carlos !), Hormann EcoStar, Novoferm, Sommer, Monarch (thanks @ashphx !), Jolly Motors (thanks @pkooiman !), IL-100(Smart) (thx Vitaly for RAWs), Motorline (with add manually support), Rosh, Pecinin, Rossi, Merlin, Steelmate (thanks @RocketGod-git), Cardin S449 (thanks @zero-mega)
@@ -201,7 +201,7 @@ Thanks to Official team (to their SubGHz Developer, Skorp) for implementing supp - Somfy Telis → How to create new remote - [instructions](/documentation/SubGHzRemoteProg.md) - Somfy Keytis -- KingGates Stylo 4k +- KingGates Stylo 4k (UPD: Add manually and all buttons support) - Alutech AT-4N → How to create new remote - [instructions](/documentation/SubGHzRemoteProg.md) - Nice ON2E (Nice One) → How to create new remote - [instructions](/documentation/SubGHzRemoteProg.md)
From ee59533631d58f2674af8f52bdb4f4e5efb646c4 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 6 Jan 2026 18:16:34 +0300 Subject: [PATCH 014/160] archive allow folders to be pinned by WillyJL --- .../main/archive/helpers/archive_browser.h | 2 +- .../main/archive/helpers/archive_favorites.c | 2 +- .../archive/scenes/archive_scene_browser.c | 8 +++++++- .../main/archive/views/archive_browser_view.c | 18 ++++++++++++------ 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/applications/main/archive/helpers/archive_browser.h b/applications/main/archive/helpers/archive_browser.h index a2330b494..999f088b3 100644 --- a/applications/main/archive/helpers/archive_browser.h +++ b/applications/main/archive/helpers/archive_browser.h @@ -68,7 +68,7 @@ static inline const char* archive_get_default_path(ArchiveTabEnum tab) { } inline bool archive_is_known_app(ArchiveFileTypeEnum type) { - return type != ArchiveFileTypeFolder && type != ArchiveFileTypeUnknown; + return (type != ArchiveFileTypeUnknown); } bool archive_is_item_in_array(ArchiveBrowserViewModel* model, uint32_t idx); diff --git a/applications/main/archive/helpers/archive_favorites.c b/applications/main/archive/helpers/archive_favorites.c index 5ed3adfe3..00e65df1e 100644 --- a/applications/main/archive/helpers/archive_favorites.c +++ b/applications/main/archive/helpers/archive_favorites.c @@ -158,7 +158,7 @@ bool archive_favorites_read(void* context) { need_refresh = true; } } else { - if(storage_file_exists(storage, furi_string_get_cstr(buffer))) { + if(storage_common_exists(storage, furi_string_get_cstr(buffer))) { storage_common_stat(storage, furi_string_get_cstr(buffer), &file_info); archive_add_file_item( browser, file_info_is_dir(&file_info), furi_string_get_cstr(buffer)); diff --git a/applications/main/archive/scenes/archive_scene_browser.c b/applications/main/archive/scenes/archive_scene_browser.c index bd24b51ad..90c19d859 100644 --- a/applications/main/archive/scenes/archive_scene_browser.c +++ b/applications/main/archive/scenes/archive_scene_browser.c @@ -33,6 +33,8 @@ static const char* archive_get_flipper_app_name(ArchiveFileTypeEnum file_type) { return "UpdaterApp"; case ArchiveFileTypeJS: return "JS Runner"; + case ArchiveFileTypeFolder: + return "Archive"; default: return NULL; } @@ -137,7 +139,11 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { consumed = true; break; case ArchiveBrowserEventFileMenuRun: - if(archive_is_known_app(selected->type)) { + if(selected->type == ArchiveFileTypeFolder) { + archive_switch_tab(browser, TAB_LEFT); + archive_show_file_menu(browser, false); + archive_enter_dir(browser, selected->path); + } else if(archive_is_known_app(selected->type)) { archive_run_in_app(browser, selected); archive_show_file_menu(browser, false); } diff --git a/applications/main/archive/views/archive_browser_view.c b/applications/main/archive/views/archive_browser_view.c index aa992264e..2b6d366db 100644 --- a/applications/main/archive/views/archive_browser_view.c +++ b/applications/main/archive/views/archive_browser_view.c @@ -111,11 +111,18 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { // Folder //FURI_LOG_D(TAG, "Directory type"); - // { Copy/Cut, Paste } NewDir, Rename, Delete - model->menu_file_manage = true; - model->menu_can_switch = false; + //model->menu_file_manage = true; + model->menu_can_switch = true; - contex_menu_filemanager_init(model); + if(model->menu_file_manage) { + // { Copy/Cut, Paste } NewDir, Rename, Delete + contex_menu_filemanager_init(model); + } else { + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_pin, + ArchiveBrowserEventFileMenuPin); + } } else if(!archive_is_known_app(selected->type)) { // UnKnown app type //FURI_LOG_D(TAG, "Unknown type"); @@ -489,8 +496,7 @@ static inline void ArchiveFile_t* selected = files_array_get(model->files, model->item_idx - model->array_offset); - if(selected->type != ArchiveFileTypeFolder && - model->tab_idx != ArchiveTabFavorites) { + if(model->tab_idx != ArchiveTabFavorites) { model->menu_file_manage = !model->menu_file_manage; model->menu_idx = 0; menu_array_reset(model->context_menu); From 224777f48e7896f4467eed10803c45cbe40c5150 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 6 Jan 2026 18:34:25 +0300 Subject: [PATCH 015/160] upd changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8089f3d15..5a1ddd3c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * SubGHz: **Stilmatic - button 9 support** (two buttons hold simulation) * SubGHz: **Counter editor refactoring** (PR #939 | by @Dmitry422) * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) +* Archive: Allow folders to be pinned (by @WillyJL) * Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes * NFC: Fix some typos in Type4Tag protocol (by @WillyJL) From 1412a45977fea92808a0a8306f575b86951e6b4f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 6 Jan 2026 19:16:02 +0300 Subject: [PATCH 016/160] move folders too --- applications/main/archive/views/archive_browser_view.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/applications/main/archive/views/archive_browser_view.c b/applications/main/archive/views/archive_browser_view.c index 2b6d366db..b61d0c627 100644 --- a/applications/main/archive/views/archive_browser_view.c +++ b/applications/main/archive/views/archive_browser_view.c @@ -122,6 +122,12 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { menu_array_push_raw(model->context_menu), item_pin, ArchiveBrowserEventFileMenuPin); + if(model->tab_idx == ArchiveTabFavorites) { + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + "Move", + ArchiveBrowserEventEnterFavMove); + } } } else if(!archive_is_known_app(selected->type)) { // UnKnown app type From 015ee6e7e48118b74b78c32c769b78350f20edb0 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Fri, 9 Jan 2026 00:39:44 +0700 Subject: [PATCH 017/160] 1. Add debug status to Desktop clock like "D hh:mm" 2. Alutech_at_4n protocol acceleration --- applications/services/desktop/desktop.c | 16 +++--- lib/subghz/protocols/alutech_at_4n.c | 67 ++++++++++++++++--------- 2 files changed, 52 insertions(+), 31 deletions(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index eed5537c6..41cf3f7d8 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -105,14 +105,18 @@ static void desktop_clock_draw_callback(Canvas* canvas, void* context) { } char buffer[20]; - snprintf(buffer, sizeof(buffer), "%02u:%02u", hour, desktop->clock.minute); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + snprintf(buffer, sizeof(buffer), "D %02u:%02u", hour, desktop->clock.minute); + } else { + snprintf(buffer, sizeof(buffer), "%02u:%02u", hour, desktop->clock.minute); + } - view_port_set_width( - desktop->clock_viewport, - canvas_string_width(canvas, buffer) - 1 + (desktop->clock.minute % 10 == 1)); + view_port_set_width( + desktop->clock_viewport, + canvas_string_width(canvas, buffer) - 1 + (desktop->clock.minute % 10 == 1)); - canvas_draw_str_aligned(canvas, 0, 8, AlignLeft, AlignBottom, buffer); -} + canvas_draw_str_aligned(canvas, 0, 8, AlignLeft, AlignBottom, buffer); + } static void desktop_stealth_mode_icon_draw_callback(Canvas* canvas, void* context) { UNUSED(context); diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index ccbe2ccf9..6175cc47b 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -9,7 +9,8 @@ #define TAG "SubGhzProtocoAlutech_at_4n" -#define SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE 0xFFFFFFFF +#define SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE 0xFFFFFFFFFFFFFFFF +#define SUBGHZ_ALUTECH_AT_4N_RAINBOW_TABLE_SIZE_BYTES 32 static const SubGhzBlockConst subghz_protocol_alutech_at_4n_const = { .te_short = 400, @@ -141,26 +142,20 @@ LevelDuration subghz_protocol_encoder_alutech_at_4n_yield(void* context) { /** * Read bytes from rainbow table - * @param file_name Full path to rainbow table the file + * @param buffer Pointer to decrypted magic data buffer * @param number_alutech_at_4n_magic_data number in the array * @return alutech_at_4n_magic_data */ -static uint32_t subghz_protocol_alutech_at_4n_get_magic_data_in_file( - const char* file_name, +static uint32_t subghz_protocol_alutech_at_4n_get_magic_data_from_buffer( + uint8_t* buffer, uint8_t number_alutech_at_4n_magic_data) { - if(!strcmp(file_name, "")) return SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE; - - uint8_t buffer[sizeof(uint32_t)] = {0}; uint32_t address = number_alutech_at_4n_magic_data * sizeof(uint32_t); uint32_t alutech_at_4n_magic_data = 0; - if(subghz_keystore_raw_get_data(file_name, address, buffer, sizeof(uint32_t))) { - for(size_t i = 0; i < sizeof(uint32_t); i++) { - alutech_at_4n_magic_data = (alutech_at_4n_magic_data << 8) | buffer[i]; - } - } else { - alutech_at_4n_magic_data = SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE; + for(size_t i = address; i < (address + sizeof(uint32_t)); i++) { + alutech_at_4n_magic_data = (alutech_at_4n_magic_data << 8) | buffer[i]; } + return alutech_at_4n_magic_data; } @@ -195,17 +190,28 @@ static uint8_t subghz_protocol_alutech_at_4n_decrypt_data_crc(uint8_t data) { } static uint64_t subghz_protocol_alutech_at_4n_decrypt(uint64_t data, const char* file_name) { + if(!strcmp(file_name, "")) return SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE; + + uint8_t buffer[SUBGHZ_ALUTECH_AT_4N_RAINBOW_TABLE_SIZE_BYTES] = {0}; + uint8_t* buffer_ptr = (uint8_t*)&buffer; + + if(subghz_keystore_raw_get_data( + file_name, 0, buffer, SUBGHZ_ALUTECH_AT_4N_RAINBOW_TABLE_SIZE_BYTES)) { + } else { + return SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE; + } + uint8_t* p = (uint8_t*)&data; uint32_t data1 = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; uint32_t data2 = p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7]; uint32_t data3 = 0; uint32_t magic_data[] = { - subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 0), - subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 1), - subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 2), - subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 3), - subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 4), - subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 5)}; + subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 0), + subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 1), + subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 2), + subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 3), + subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 4), + subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 5)}; uint32_t i = magic_data[0]; do { @@ -230,17 +236,28 @@ static uint64_t subghz_protocol_alutech_at_4n_decrypt(uint64_t data, const char* } static uint64_t subghz_protocol_alutech_at_4n_encrypt(uint64_t data, const char* file_name) { + if(!strcmp(file_name, "")) return SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE; + + uint8_t buffer[SUBGHZ_ALUTECH_AT_4N_RAINBOW_TABLE_SIZE_BYTES] = {0}; + uint8_t* buffer_ptr = (uint8_t*)&buffer; + + if(subghz_keystore_raw_get_data( + file_name, 0, buffer, SUBGHZ_ALUTECH_AT_4N_RAINBOW_TABLE_SIZE_BYTES)) { + } else { + return SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE; + } + uint8_t* p = (uint8_t*)&data; uint32_t data1 = 0; uint32_t data2 = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; uint32_t data3 = p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7]; uint32_t magic_data[] = { - subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 6), - subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 4), - subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 5), - subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 1), - subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 2), - subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 0)}; + subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 6), + subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 4), + subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 5), + subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 1), + subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 2), + subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 0)}; do { data1 = data1 + magic_data[0]; From ed7c4fd8af36ba41a403f12b76effa50ec480670 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 9 Jan 2026 01:06:34 +0300 Subject: [PATCH 018/160] fmt --- applications/services/desktop/desktop.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 41cf3f7d8..3a96bf30a 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -111,12 +111,12 @@ static void desktop_clock_draw_callback(Canvas* canvas, void* context) { snprintf(buffer, sizeof(buffer), "%02u:%02u", hour, desktop->clock.minute); } - view_port_set_width( - desktop->clock_viewport, - canvas_string_width(canvas, buffer) - 1 + (desktop->clock.minute % 10 == 1)); + view_port_set_width( + desktop->clock_viewport, + canvas_string_width(canvas, buffer) - 1 + (desktop->clock.minute % 10 == 1)); - canvas_draw_str_aligned(canvas, 0, 8, AlignLeft, AlignBottom, buffer); - } + canvas_draw_str_aligned(canvas, 0, 8, AlignLeft, AlignBottom, buffer); +} static void desktop_stealth_mode_icon_draw_callback(Canvas* canvas, void* context) { UNUSED(context); From ea3b2375306e5ac7b4c147bc8d404f416ae715ad Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Fri, 9 Jan 2026 10:36:32 +0700 Subject: [PATCH 019/160] Nice Flor S protocol acceleration --- lib/subghz/protocols/alutech_at_4n.c | 8 ++-- lib/subghz/protocols/nice_flor_s.c | 55 +++++++++++++++++++--------- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 6175cc47b..9959e7cd2 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -141,7 +141,7 @@ LevelDuration subghz_protocol_encoder_alutech_at_4n_yield(void* context) { } /** - * Read bytes from rainbow table + * Read bytes from buffer array with rainbow table * @param buffer Pointer to decrypted magic data buffer * @param number_alutech_at_4n_magic_data number in the array * @return alutech_at_4n_magic_data @@ -190,7 +190,8 @@ static uint8_t subghz_protocol_alutech_at_4n_decrypt_data_crc(uint8_t data) { } static uint64_t subghz_protocol_alutech_at_4n_decrypt(uint64_t data, const char* file_name) { - if(!strcmp(file_name, "")) return SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE; + // load and decrypt rainbow table from file to buffer array in RAM + if(!file_name) return SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE; uint8_t buffer[SUBGHZ_ALUTECH_AT_4N_RAINBOW_TABLE_SIZE_BYTES] = {0}; uint8_t* buffer_ptr = (uint8_t*)&buffer; @@ -236,7 +237,8 @@ static uint64_t subghz_protocol_alutech_at_4n_decrypt(uint64_t data, const char* } static uint64_t subghz_protocol_alutech_at_4n_encrypt(uint64_t data, const char* file_name) { - if(!strcmp(file_name, "")) return SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE; + // load and decrypt rainbow table from file to buffer array in RAM + if(!file_name) return SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE; uint8_t buffer[SUBGHZ_ALUTECH_AT_4N_RAINBOW_TABLE_SIZE_BYTES] = {0}; uint8_t* buffer_ptr = (uint8_t*)&buffer; diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index b46f5e747..0b5c39311 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -16,8 +16,10 @@ #define TAG "SubGhzProtocolNiceFlorS" -#define NICE_ONE_COUNT_BIT 72 -#define NICE_ONE_NAME "Nice One" +#define NICE_ONE_COUNT_BIT 72 +#define NICE_ONE_NAME "Nice One" +#define SUBGHZ_NICE_FLOR_S_RAINBOW_TABLE_SIZE_BYTES 32 +#define SUBGHZ_NO_NICE_FLOR_S_RAINBOW_TABLE 0 static const SubGhzBlockConst subghz_protocol_nice_flor_s_const = { .te_short = 500, @@ -414,21 +416,13 @@ static void subghz_protocol_nice_one_get_data(uint8_t* p, uint8_t num_parcel, ui } /** - * Read bytes from rainbow table - * @param file_name Full path to rainbow table the file + * Read bytes from buffer array with rainbow table + * @param buffer pointer to decrypted rainbow table * @param address Byte address in file * @return data */ -static uint8_t - subghz_protocol_nice_flor_s_get_byte_in_file(const char* file_name, uint32_t address) { - if(!file_name) return 0; - - uint8_t buffer[1] = {0}; - if(subghz_keystore_raw_get_data(file_name, address, buffer, sizeof(uint8_t))) { - return buffer[0]; - } else { - return 0; - } +static uint8_t subghz_protocol_nice_flor_s_get_byte_from_buffer(uint8_t* buffer, uint8_t address) { + return buffer[address]; } static inline void subghz_protocol_decoder_nice_flor_s_magic_xor(uint8_t* p, uint8_t k) { @@ -438,16 +432,28 @@ static inline void subghz_protocol_decoder_nice_flor_s_magic_xor(uint8_t* p, uin } uint64_t subghz_protocol_nice_flor_s_encrypt(uint64_t data, const char* file_name) { + // load and decrypt rainbow table from file to buffer array in RAM + if(!file_name) return SUBGHZ_NO_NICE_FLOR_S_RAINBOW_TABLE; + + uint8_t buffer[SUBGHZ_NICE_FLOR_S_RAINBOW_TABLE_SIZE_BYTES] = {0}; + uint8_t* buffer_ptr = (uint8_t*)&buffer; + + if(subghz_keystore_raw_get_data( + file_name, 0, buffer, SUBGHZ_NICE_FLOR_S_RAINBOW_TABLE_SIZE_BYTES)) { + } else { + return SUBGHZ_NO_NICE_FLOR_S_RAINBOW_TABLE; + } + uint8_t* p = (uint8_t*)&data; uint8_t k = 0; for(uint8_t y = 0; y < 2; y++) { - k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] & 0x1f); + k = subghz_protocol_nice_flor_s_get_byte_from_buffer(buffer_ptr, p[0] & 0x1f); subghz_protocol_decoder_nice_flor_s_magic_xor(p, k); p[5] &= 0x0f; p[0] ^= k & 0xe0; - k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] >> 3) + 0x25; + k = subghz_protocol_nice_flor_s_get_byte_from_buffer(buffer_ptr, p[0] >> 3) + 0x25; subghz_protocol_decoder_nice_flor_s_magic_xor(p, k); p[5] &= 0x0f; @@ -475,6 +481,19 @@ static uint64_t subghz_protocol_nice_flor_s_decrypt(SubGhzBlockGeneric* instance, const char* file_name) { furi_assert(instance); uint64_t data = instance->data; + + // load and decrypt rainbow table from file to buffer array in RAM + if(!file_name) return SUBGHZ_NO_NICE_FLOR_S_RAINBOW_TABLE; + + uint8_t buffer[SUBGHZ_NICE_FLOR_S_RAINBOW_TABLE_SIZE_BYTES] = {0}; + uint8_t* buffer_ptr = (uint8_t*)&buffer; + + if(subghz_keystore_raw_get_data( + file_name, 0, buffer, SUBGHZ_NICE_FLOR_S_RAINBOW_TABLE_SIZE_BYTES)) { + } else { + return SUBGHZ_NO_NICE_FLOR_S_RAINBOW_TABLE; + } + uint8_t* p = (uint8_t*)&data; uint8_t k = 0; @@ -489,12 +508,12 @@ static uint64_t p[1] = k; for(uint8_t y = 0; y < 2; y++) { - k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] >> 3) + 0x25; + k = subghz_protocol_nice_flor_s_get_byte_from_buffer(buffer_ptr, p[0] >> 3) + 0x25; subghz_protocol_decoder_nice_flor_s_magic_xor(p, k); p[5] &= 0x0f; p[0] ^= k & 0x7; - k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] & 0x1f); + k = subghz_protocol_nice_flor_s_get_byte_from_buffer(buffer_ptr, p[0] & 0x1f); subghz_protocol_decoder_nice_flor_s_magic_xor(p, k); p[5] &= 0x0f; From 7fb11737ccd274d7b4eff99695fe74de24b8d75f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 9 Jan 2026 11:51:57 +0300 Subject: [PATCH 020/160] upd changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a1ddd3c6..02de280ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,12 @@ * SubGHz: **KingGates Stylo 4k - Add manually and button switch support** + refactoring of encoder * SubGHz: **Stilmatic - button 9 support** (two buttons hold simulation) * SubGHz: **Counter editor refactoring** (PR #939 | by @Dmitry422) +* SubGHz: **Alutech AT-4N & Nice Flor S turbo speedup** (PR #942 | by @Dmitry422) * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * Archive: Allow folders to be pinned (by @WillyJL) * Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes +* Desktop: Show debug status (D) if clock is enabled and debug flag is on (PR #942 | by @Dmitry422) * NFC: Fix some typos in Type4Tag protocol (by @WillyJL) * Clangd: Add clangd parameters in IDE agnostic config file (by @WillyJL)

From b77ca005480fbbeb3fc12c3c721e3bb36c36c144 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 9 Jan 2026 15:03:35 +0300 Subject: [PATCH 021/160] add apps build tag to changelog [ci skip] --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02de280ef..cfcfc73c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ * SubGHz: **Alutech AT-4N & Nice Flor S turbo speedup** (PR #942 | by @Dmitry422) * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * Archive: Allow folders to be pinned (by @WillyJL) -* Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) +* Apps: Build tag (**9jan2026p2**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes * Desktop: Show debug status (D) if clock is enabled and debug flag is on (PR #942 | by @Dmitry422) * NFC: Fix some typos in Type4Tag protocol (by @WillyJL) From e97f90529d5735e38971d54b3879fdc515516852 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 9 Jan 2026 19:35:14 +0300 Subject: [PATCH 022/160] sommer fm2 will be fsk12k now in add manually list --- applications/main/subghz/helpers/subghz_custom_event.h | 4 ++-- applications/main/subghz/helpers/subghz_gen_info.c | 8 ++++---- applications/main/subghz/scenes/subghz_scene_set_type.c | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index e21ba128c..e52cf1897 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -89,8 +89,8 @@ typedef enum { SetTypeMotorline433, SetTypeSommer_FM_434, SetTypeSommer_FM_868, - SetTypeSommer_FM238_434, - SetTypeSommer_FM238_868, + SetTypeSommer_FM12K_434, + SetTypeSommer_FM12K_868, SetTypeStilmatic, SetTypeIronLogic, SetTypeIronLogicSmart, diff --git a/applications/main/subghz/helpers/subghz_gen_info.c b/applications/main/subghz/helpers/subghz_gen_info.c index 82c114268..1f4bc92c6 100644 --- a/applications/main/subghz/helpers/subghz_gen_info.c +++ b/applications/main/subghz/helpers/subghz_gen_info.c @@ -438,20 +438,20 @@ void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType ty .keeloq.cnt = 0x03, .keeloq.manuf = "Sommer(fsk476)"}; break; - case SetTypeSommer_FM238_434: + case SetTypeSommer_FM12K_434: gen_info = (GenInfo){ .type = GenKeeloq, - .mod = "FM238", + .mod = "FM12K", .freq = 434420000, .keeloq.serial = key & 0x0000FFFF, .keeloq.btn = 0x02, .keeloq.cnt = 0x03, .keeloq.manuf = "Sommer(fsk476)"}; break; - case SetTypeSommer_FM238_868: + case SetTypeSommer_FM12K_868: gen_info = (GenInfo){ .type = GenKeeloq, - .mod = "FM238", + .mod = "FM12K", .freq = 868800000, .keeloq.serial = key & 0x0000FFFF, .keeloq.btn = 0x02, diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 846dda5d0..f21f73f38 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -36,8 +36,8 @@ static const char* submenu_names[SetTypeMAX] = { [SetTypeJollyMotors433] = "KL: Jolly Mot. 433MHz", [SetTypeSommer_FM_434] = "KL: Sommer 434MHz", [SetTypeSommer_FM_868] = "KL: Sommer 868MHz", - [SetTypeSommer_FM238_434] = "KL: Sommer fm2 434Mhz", - [SetTypeSommer_FM238_868] = "KL: Sommer fm2 868Mhz", + [SetTypeSommer_FM12K_434] = "KL: Sommer fm2 434Mhz", + [SetTypeSommer_FM12K_868] = "KL: Sommer fm2 868Mhz", [SetTypeStilmatic] = "KL: Stilmatic 433MHz", [SetTypeIronLogic] = "KL: IronLogic 433MHz", [SetTypeIronLogicSmart] = "KL: IronLogic SM 433MHz", From c6ebfb2c4e9902a31bbfb88f9fcfa4b30d76d487 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 9 Jan 2026 19:39:30 +0300 Subject: [PATCH 023/160] add new docs --- ReadMe.md | 1 + documentation/SubGHzSupportedSystems.md | 180 ++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 documentation/SubGHzSupportedSystems.md diff --git a/ReadMe.md b/ReadMe.md index 25b59a7d9..da03afdc0 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -273,6 +273,7 @@ Enhance your Flipper Zero with apps and plugins created by the community: ### ![SubGhz Icon Badge] Sub-GHz +- [Full list of supported protocols and their frequencies/modulations (to use in Read mode)](/documentation/SubGHzSupportedSystems.md) - [How to use Flipper as rolling code remote (Doorhan, Nice FlorS, BFT Mitto, Somfy Telis, Aprimatic, AN-Motors, etc..)](/documentation/SubGHzRemoteProg.md) - [Experimental rolling code counter modes (avoid desync)](/documentation/SubGHzCounterMode.md) - External Radio: [How to connect CC1101 module](https://github.com/quen0n/flipperzero-ext-cc1101) diff --git a/documentation/SubGHzSupportedSystems.md b/documentation/SubGHzSupportedSystems.md new file mode 100644 index 000000000..887c69ad2 --- /dev/null +++ b/documentation/SubGHzSupportedSystems.md @@ -0,0 +1,180 @@ +# Sub-GHz Supported Protocols + +This file lists all supported Sub-GHz protocols available in Unleashed Firmware, both tested and untested. + +That list is only for default SubGHz app, apps like *Weather Station* have their own protocols list + + +## Static & Dynamic protocols list + +*433 MHz usually means `433.92MHz` and 868 MHz = `868.35MHz`* + +*If you see no frequency after protocol name, that means we don't know it, let us know in issues tab!* + +*`AM650`, `FM`, `FSK476` - means modulation to use when reading the remote* + +*`FM` means you should try any existing FM modulations, `FSK???` means `FM???` in SubGHz - Read - Config* + +### Garage Door Openers & Gate Openers (Boom barriers, roller shutters, etc.) +- Alutech AT-4N `433.92MHz` `AM650` (72 bits, Dynamic) +- AN-Motors (Alutech) AT4 `433.92MHz` `AM650` (64 bits, Pseudo-Dynamic, KeeLoq based) +- Ansonic `433MHz` `FM` (12 bits, Static) +- BETT `433.92MHz` `AM650` (18 bits, Static) +- BFT Mitto `433.92MHz` `AM650` (64 bits, Dynamic, KeeLoq based with Seed) +- CAME Atomo `433.92MHz, 868MHz` `AM650` (62 bits, Dynamic) +- CAME TWEE `433.92MHz` `AM650` (54 bits, Static) +- CAME `433.92MHz, 868MHz` `AM650` (12, 24 bits, Static) +- Prastel `433.92MHz, 868MHz` `AM650` (25, 42 bits, Static) +- Airforce `433.92MHz, 868MHz` `AM650` (18 bits, Static) +- Chamberlain Code `AM650` (10 bits, Static) +- Clemsa `AM650` (18 bits, Static) +- Dickert MAHS `AM650` (36 bits, Static) +- Doitrand `AM650` (37 bits, Dynamic) +- Elplast/P-11B/3BK/E.C.A `433MHz` `AM650` (18 bits, Static) +- FAAC SLH `433.92MHz, 868MHz` `AM650` (64 bits, Dynamic) +- Gate TX `433.92MHz` `AM650` (64 bits, Static) +- Hormann `868MHz` `AM650` (44 bits, Static) +- HCS101 `AM650` (64 bits, Simple Dynamic, KeeLoq-like) +- IDO `433MHz` `AM650` (48 bits, Dynamic) +- KingGates Stylo 4k `433.92MHz` `AM650` (89 bits, Dynamic, KeeLoq based) +- Mastercode `AM650` (36 bits, Static) +- Megacode `AM650` (24 bits, Static) +- Nero Sketch `AM650` (40 bits, Static) +- Nice Flo `433.92MHz` `AM650` (12, 24 bits, Static) +- Nice FloR-S `433.92MHz` `AM650` (52 bits, Dynamic) +- Nice One `433.92MHz` `AM650` (72 bits, Dynamic) +- Revers RB2 (Реверс РБ-2 (М)) `433.92MHz` `AM650` (64 bits, Static) +- Roger `433.92MHz` `AM650` (28 bits, Static) +- V2 Phoenix (Phox) `433.92MHz` `AM650` (52 bits, Dynamic) +- Marantec `433.92MHz, 868MHz` `AM650` (49 bits, Static) +- Marantec24 `868MHz` `AM650` (24 bits, Static) +- Somfy Keytis `433.92MHz, 868MHz` `AM650` (80 bits, Dynamic) +- ZKTeco `430.5MHz` `AM650` (24 bits, Static - Princeton based) - (Button codes (already mapped to arrow keys): `0x30 (UP)`, `0x03 (STOP)`, `0x0C (DOWN)`) +- Linear `300MHz` `AM650` (10 bits, Static) +- Linear Delta3 `AM650` (8 bits, Static) +- Nero Radio `434MHz` `AM650` (56 bits, Static mode only, Dynamic is unsupported) +- Security+1.0 `315MHz, 433.92MHz, 390MHz` `AM650` (42 bits, Dynamic) +- Security+2.0 `310MHz, 390MHz, 868MHz` `AM650` (62 bits, Dynamic) + +### Sensors & Smart home +- Intertechno V3 `AM650` (32 bits, Static) - Lights, sockets, other. +- Dooya `AM650` (40 bits, Static) - Electric blinds +- Power Smart `AM650` (64 bits, Static) - Blinds, shutters +- Legrand `AM650` (18 bits, Static) - Doorbells +- Somfy Telis `433.92MHz` `AM650` (56 bits, Dynamic) +- Feron `433.92MHz` `AM650` (32 bits, Static) - RGB LED remotes, other. +- Honeywell `AM650` (64 bits, Dynamic) - Alarm, Sensor +- Honeywell WDB `AM650` (48 bits, Dynamic) - Doorbell +- Magellan `433.92MHz` `AM650` (32 bits, Static) - Sensor, alarm + +### Alarms +- Hollarm `433.92MHz` `AM650` (42 bits, Static) - Bike alarms +- Scher Khan `433.92MHz` `AM650` (35-82 bits, Dynamic) - Russian external car alarm system (Decode and display only), 200x year +- Kia `433/434MHz` `FSK476` (61 bits, Dynamic) - Car alarm system (Decode and display only) +- Star Line `433.92MHz` `AM650` (KeeLoq based, 64 bits) - Russian external car alarm system, 200x year +- GangQi `433.92MHz` `AM650` (34 bits, Static) - Bike alarms + + +### Generic any branded remotes +- Holtek `AM650` (40 bits, Static) +- Holtek HT12X `AM650` (12 bits, Static) +- Princeton (PT2262, PT****) `315MHz, 433.92MHz, Any other frequency` `AM650` (24 bits, Static) +- SMC5326 `315MHz, 433.92MHz, Any other frequency` `AM650` (25 bits, Static) +- Hay21 `433.92MHz` `AM650` (21 bits, Dynamic) + +--- + +## KeeLoq Rolling Code Supported Manufacturers list + +KeeLoq is a rolling code encryption system used by many garage door openers and gate systems. +The following manufacturers have KeeLoq support in Unleashed firmware: + +*Default value for encryption type "learning" is `simple` and `10bits` for serial part in Hop* + +*In case if remote uses other serial bits or different encryption type and it was verified - it will be stated in the end* + +### Garage Door Openers & Gate Openers (Boom barriers, roller shutters, etc.) +- Allmatic - `868MHz` `AM650` (KeeLoq, 64 bits) (no serial part in Hop - magic XOR) +- Aprimatic - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial number art in Hop + 2bit "parity" in front of it replacing first 2 bits of serial) +- Beninca - `433.92MHz, 868MHz` `AM650` (KeeLoq, 64 bits) (no serial part in Hop - magic XOR) +- CAME Space - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - simple learning) +- Cardin S449 - `433.92MHz` `FSK12K` (KeeLoq, 64 bits) (12bit (original remotes) or 10bit (chinese remotes) serial part in Hop - normal learning) +- Centurion - `433.92MHz` `AM650` (KeeLoq, 64 bits) (no serial in Hop, uses fixed value 0x1CE - normal learning) +- Comunello - `433.92MHz, 868MHz` `AM650` (KeeLoq, 64 bits) (normal learning) +- DEA Mio - `433.92MHz` `AM650` (KeeLoq, 64 bits) (modified serial in Hop, uses last 3 digits modifying first one (example - 419 -> C19) - simple learning) +- DoorHan - 315MHz, `433.92MHz` `AM650` (KeeLoq, 64 bits) +- DTM Neo - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - simple learning) +- Elmes Poland - `433.92MHz` `AM650` (KeeLoq, 64 bits) (normal learning) +- FAAC RC,XT - `433.92MHz, 868MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) +- Genius Bravo - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) +- Gibidi - `433.92MHz` `AM650` (KeeLoq, 64 bits) +- GSN - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) +- Hormann EcoStar - `433.92MHz` `AM650` (KeeLoq, 64 bits) (normal learning) +- IronLogic IL-100 - `433.92MHz` `AM650` (KeeLoq, 64 bits) +- IronLogic IL-100 Smart PPult - `433.92MHz` `AM650` (KeeLoq, 64 bits) +- JCM Tech - `433.92MHz` `AM650` (KeeLoq, 64 bits) (8bit serial part in Hop - simple learning) +- Jolly Motors - `433.92MHz` `AM650` (KeeLoq, 64 bits) +- KEY (KeeLoq, 64 bits) +- Monarch - `433.92MHz` `AM650` (KeeLoq, 64 bits) (no serial in Hop, uses fixed value 0x100 - normal learning) +- Motorline - `433.92MHz` `AM650` (KeeLoq, 64 bits) (normal learning) +- Mutanco/Mutancode (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) +- Mhouse - `433.92MHz` `AM650` (KeeLoq, 64 bits) (8bit serial part in Hop - simple learning) +- Nice Smilo - `433.92MHz` `AM650` (KeeLoq, 64 bits) (8bit serial part in Hop - simple learning) +- Normstahl - `433.92MHz` `AM650` (KeeLoq, 64 bits) +- Novoferm - `433.92MHz` `AM650` (KeeLoq, 64 bits) +- Sommer `434.42MHz, 868.80MHz` `FSK12K (or FSK476)` (KeeLoq, 64 bits) (normal learning) +- Steelmate - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) +- Stilmatic - `433.92MHz` `AM650` (KeeLoq, 64 bits) (normal learning) + +### Alarms, unknown origin, etc. +- APS-1100/APS-2550 (KeeLoq, 64 bits) +- Alligator (KeeLoq, 64 bits) +- Alligator S-275 (KeeLoq, 64 bits) +- Cenmax (KeeLoq, 64 bits) +- Cenmax St-5 (KeeLoq, 64 bits) +- Cenmax St-7 (KeeLoq, 64 bits) +- Faraon (KeeLoq, 64 bits) +- Guard RF-311A (KeeLoq, 64 bits) (normal learning) +- Harpoon (KeeLoq, 64 bits) +- KGB/Subaru (KeeLoq, 64 bits) (magic serial type 1) +- Leopard (KeeLoq, 64 bits) +- Magic 1 (KeeLoq, 64 bits) (magic serial type 2) +- Magic 2 (KeeLoq, 64 bits) (magic serial type 2) +- Magic 3 (KeeLoq, 64 bits) (magic serial type 3) +- Magic 4 (KeeLoq, 64 bits) (magic serial type 3) +- Merlin (KeeLoq, 64 bits) (no serial part in Hop - simple XOR) +- Mongoose (KeeLoq, 64 bits) (normal learning) +- Pantera (KeeLoq, 64 bits) +- Pantera CLK (KeeLoq, 64 bits) +- Pantera XS/Jaguar (KeeLoq, 64 bits) +- Partisan RX (KeeLoq, 64 bits) +- Pecinin (KeeLoq, 64 bits) (12bit serial part in Hop - simple learning) +- Reff (KeeLoq, 64 bits) +- Rossi (KeeLoq, 64 bits) (12bit serial part in Hop - simple learning) +- Rosh (KeeLoq, 64 bits) (12bit serial part in Hop - simple learning) +- Sheriff (KeeLoq, 64 bits) +- SL A2-A4 (KeeLoq, 64 bits) +- SL A6-A9/Tomahawk 9010 (KeeLoq, 64 bits) +- SL B6,B9 dop (KeeLoq, 64 bits) +- Teco (KeeLoq, 64 bits) +- Tomahawk TZ-9030 (KeeLoq, 64 bits) +- Tomahawk Z,X 3-5 (KeeLoq, 64 bits) +- ZX-730-750-1055 (KeeLoq, 64 bits) + +*Note: Most KeeLoq manufacturers operate in the 433 MHz and 868 MHz frequency bands with AM650 modulation. Some operate at other frequencies or modulations. Not all KeeLoq systems are supported for full decoding or emulation.* + +--- + +## Protocol Type Reference + +Unleashed firmware supports various protocol types: + +- **Static Code**: Fixed transmission codes (e.g., Roger, Princeton, Marantec, Revers RB2) +- **Rolling Code (Dynamic) (KeeLoq)**: Dynamic codes with rolling counter using KeeLoq encryption (60+ manufacturer systems supported) +- **Rolling Code (Dynamic)**: Other dynamic systems with custom encoding (e.g., CAME Atomo, Nice Flor S, Somfy Telis, FAAC SLH, Alutech AT-4N, Security+) + +For more information on how to use some of these protocols, see also [SubGHzRemoteProg.md](/documentation/SubGHzRemoteProg.md) and the main [ReadMe.md](/ReadMe.md). + +--- + +*Docs made for Unleashed FW, please mention source when copying* \ No newline at end of file From 9bf98b8ec047836abad2d5ec11d4f55e6d007ca4 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 9 Jan 2026 19:43:23 +0300 Subject: [PATCH 024/160] upd changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfcfc73c7..a9023c5e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,12 @@ * SubGHz: **Stilmatic - button 9 support** (two buttons hold simulation) * SubGHz: **Counter editor refactoring** (PR #939 | by @Dmitry422) * SubGHz: **Alutech AT-4N & Nice Flor S turbo speedup** (PR #942 | by @Dmitry422) +* SubGHz: **Sommer fm2 in Add manually now uses FM12K modulation** (Sommer without fm2 tag uses FM476) (try this if regular option doesn't work for you) * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * Archive: Allow folders to be pinned (by @WillyJL) * Apps: Build tag (**9jan2026p2**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes +* Docs: Add full list of supported SubGHz protocols and their frequencies/modulations that can be used for reading remotes - [Docs Link](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSupportedSystems.md) * Desktop: Show debug status (D) if clock is enabled and debug flag is on (PR #942 | by @Dmitry422) * NFC: Fix some typos in Type4Tag protocol (by @WillyJL) * Clangd: Add clangd parameters in IDE agnostic config file (by @WillyJL) From 1bfd931f0c26f73c43526718752fe59a8126a10f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 9 Jan 2026 21:01:27 +0300 Subject: [PATCH 025/160] upd docs [ci skip] --- CHANGELOG.md | 2 +- ReadMe.md | 9 +++++++-- documentation/HowToInstall.md | 28 ++++++++++++++++++++++------ 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9023c5e3..3d17cebbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,7 @@ [-> How to install firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md) -[-> Download qFlipper (official link)](https://flipperzero.one/update) +[-> Unleashed FW Web Installer](https://web.unleashedflip.com) ## Please support development of the project diff --git a/ReadMe.md b/ReadMe.md index da03afdc0..9cb6dbda0 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -33,6 +33,9 @@ Before getting started: - **FAQ:** Find answers to common questions in the [FAQ](/documentation/FAQ.md) +- **Web Installer:** + -> [Unleashed FW Web Installer](https://web.unleashedflip.com) + ## 📦 Releases @@ -328,11 +331,13 @@ Also, pay attention to the `ReadMe.md` files inside those directories. ## 🔗 Links - **Unleashed web page:** [flipperunleashed.com](https://flipperunleashed.com) -- **Unleashed update server, direct .tgz update links for web updater or direct download:** [unleashedflip.com](https://unleashedflip.com) +- **Unleashed FW Web Installer:** [web.unleashedflip.com](https://web.unleashedflip.com) +- **Unleashed domain used for direct .tgz update links for web updater or direct download:** [unleashedflip.com](https://unleashedflip.com) +- **Unleashed directory json for ufbt builds:** [up.unleashedflip.com/directory.json](https://up.unleashedflip.com/directory.json) - Official Docs: [docs.flipper.net](https://docs.flipper.net) - Official Forum: [forum.flipperzero.one](https://forum.flipperzero.one) -- Update! Developer Documentation [developer.flipper.net](https://developer.flipper.net/flipperzero/doxygen) +- Update! Official Developer Documentation [developer.flipper.net](https://developer.flipper.net/flipperzero/doxygen) [RFID Icon Badge]: https://custom-icon-badges.demolab.com/badge/-rgb(255,244,147)?style=flat&logo=fz-rfid&logoColor=black diff --git a/documentation/HowToInstall.md b/documentation/HowToInstall.md index 656d4cc4b..a52bd3900 100644 --- a/documentation/HowToInstall.md +++ b/documentation/HowToInstall.md @@ -12,11 +12,27 @@

-## With Web Updater +## With Unleashed FW Web Installer -- Be sure you updated to latest official release before(if installing for the first time), and verify that microSD card is installed +- Be sure you updated to latest official release before(only if installing for the first time), and verify that microSD card is installed +- Open [-> Unleashed FW Web Installer](https://web.unleashedflip.com) +- Connect your device and press `Connect` button - Select your device in popup window (be sure to use Chromium based browser) +- Select Release or Dev branch +- Press `Install` button + +- And wait, if all flashed + successfully - you will have all needed assets pre installed +- Done + + +
+
+ +## With Flipper Lab - Web Updater + +- Be sure you updated to latest official release before(only if installing for the first time), and verify that microSD card is installed - Open latest release page - [Releases](https://github.com/DarkFlippers/unleashed-firmware/releases/latest) -- Connect your device and select `Install via Web Updater` +- Connect your device and follow link - `Install via Web Updater` after that on web updater page - press `Connect` button - Press `Install` button @@ -31,7 +47,7 @@ after that on web updater page - press `Connect` button ## With iOS mobile app -- Be sure you updated to latest official release before(if installing for the first time), and verify that microSD card is installed +- Be sure you updated to latest official release before(only if installing for the first time), and verify that microSD card is installed - Open latest release page - [Releases](https://github.com/DarkFlippers/unleashed-firmware/releases/latest) - Download `flipper-z-f7-update-(version).tgz` - Open downloads in ios Files app, select downloaded `.tgz` file, click Share, select Flipper App @@ -47,7 +63,7 @@ after that on web updater page - press `Connect` button ## With Android mobile app (with .tgz download) -- Be sure you updated to latest official release before(if installing for the first time), and verify that microSD card is installed +- Be sure you updated to latest official release before(only if installing for the first time), and verify that microSD card is installed - Open latest release page - [Releases](https://github.com/DarkFlippers/unleashed-firmware/releases/latest) - Download `flipper-z-f7-update-(version).tgz` - In flipper app click `Update channel` button, select `Custom` @@ -64,7 +80,7 @@ after that on web updater page - press `Connect` button ## With Android mobile app (via web updater link) -- Be sure you updated to latest official release before(if installing for the first time), and verify that microSD card is installed +- Be sure you updated to latest official release before(only if installing for the first time), and verify that microSD card is installed - Open latest release page - [Releases](https://github.com/DarkFlippers/unleashed-firmware/releases/latest) - Click `Install via Web Updater` - It will ask to open with browser or Flipper app, select Flipper App From c5520b7d3325fd8d8b17d66f668a3a321d3a54a4 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 9 Jan 2026 21:54:29 +0300 Subject: [PATCH 026/160] subghz: sommer last button 0x6 support --- CHANGELOG.md | 3 ++- lib/subghz/protocols/keeloq.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d17cebbd..258cd7915 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,11 @@ * SubGHz: **Cardin S449 full support** (with Add manually, and all button codes) (**use FSK12K modulation to read the remote**) (closes issues #735 #908) (by @xMasterX and @zero-mega (thanks!)) * SubGHz: Added **new modulation FSK with 12KHz deviation** * SubGHz: **KingGates Stylo 4k - Add manually and button switch support** + refactoring of encoder -* SubGHz: **Stilmatic - button 9 support** (two buttons hold simulation) +* SubGHz: **Stilmatic - button 9 support** (two buttons hold simulation) (mapped on arrow keys) * SubGHz: **Counter editor refactoring** (PR #939 | by @Dmitry422) * SubGHz: **Alutech AT-4N & Nice Flor S turbo speedup** (PR #942 | by @Dmitry422) * SubGHz: **Sommer fm2 in Add manually now uses FM12K modulation** (Sommer without fm2 tag uses FM476) (try this if regular option doesn't work for you) +* SubGHz: **Sommer - last button code 0x6 support** (mapped on arrow keys) * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * Archive: Allow folders to be pinned (by @WillyJL) * Apps: Build tag (**9jan2026p2**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 4e53989e4..8a3a81c75 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -516,7 +516,9 @@ static bool (strcmp(instance->manufacture_name, "Novoferm") == 0) || (strcmp(instance->manufacture_name, "Stilmatic") == 0)) { klq_last_custom_btn = 0x9; - } else if((strcmp(instance->manufacture_name, "EcoStar") == 0)) { + } else if( + (strcmp(instance->manufacture_name, "EcoStar") == 0) || + (strcmp(instance->manufacture_name, "Sommer(fsk476)") == 0)) { klq_last_custom_btn = 0x6; } else if((strcmp(instance->manufacture_name, "AN-Motors") == 0)) { klq_last_custom_btn = 0xC; From 0e44e56659c3208fc8a2718436b8adb3af710e2e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 9 Jan 2026 22:27:36 +0300 Subject: [PATCH 027/160] subghz: add 2 freqs to default hopper list --- CHANGELOG.md | 1 + documentation/SubGHzSettings.md | 2 ++ lib/subghz/subghz_setting.c | 2 ++ 3 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 258cd7915..a126b7e50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ * SubGHz: **Alutech AT-4N & Nice Flor S turbo speedup** (PR #942 | by @Dmitry422) * SubGHz: **Sommer fm2 in Add manually now uses FM12K modulation** (Sommer without fm2 tag uses FM476) (try this if regular option doesn't work for you) * SubGHz: **Sommer - last button code 0x6 support** (mapped on arrow keys) +* SubGHz: Add 390MHz, 430.5MHz to default hopper list (6 elements like in OFW) (works well with Hopper RSSI level set for your enviroment) * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * Archive: Allow folders to be pinned (by @WillyJL) * Apps: Build tag (**9jan2026p2**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) diff --git a/documentation/SubGHzSettings.md b/documentation/SubGHzSettings.md index 682111bcd..c658cbef3 100644 --- a/documentation/SubGHzSettings.md +++ b/documentation/SubGHzSettings.md @@ -102,6 +102,8 @@ Your frequencies will be added after default ones ### Default hopper list ``` 315000000, + 390000000, + 430500000, 433920000, 434420000, 868350000, diff --git a/lib/subghz/subghz_setting.c b/lib/subghz/subghz_setting.c index 037bd6df8..3d062e413 100644 --- a/lib/subghz/subghz_setting.c +++ b/lib/subghz/subghz_setting.c @@ -87,6 +87,8 @@ static const uint32_t subghz_frequency_list[] = { static const uint32_t subghz_hopper_frequency_list[] = { 315000000, + 390000000, + 430500000, 433920000, 434420000, 868350000, From 942c3f9346b2f309bb250d67985550c54f258c5e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 9 Jan 2026 22:30:43 +0300 Subject: [PATCH 028/160] add full nero radio freq in docs --- documentation/SubGHzSupportedSystems.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/SubGHzSupportedSystems.md b/documentation/SubGHzSupportedSystems.md index 887c69ad2..6ad6ec09d 100644 --- a/documentation/SubGHzSupportedSystems.md +++ b/documentation/SubGHzSupportedSystems.md @@ -52,7 +52,7 @@ That list is only for default SubGHz app, apps like *Weather Station* have their - ZKTeco `430.5MHz` `AM650` (24 bits, Static - Princeton based) - (Button codes (already mapped to arrow keys): `0x30 (UP)`, `0x03 (STOP)`, `0x0C (DOWN)`) - Linear `300MHz` `AM650` (10 bits, Static) - Linear Delta3 `AM650` (8 bits, Static) -- Nero Radio `434MHz` `AM650` (56 bits, Static mode only, Dynamic is unsupported) +- Nero Radio `434.42MHz` `AM650` (56 bits, Static mode only, Dynamic is unsupported) - Security+1.0 `315MHz, 433.92MHz, 390MHz` `AM650` (42 bits, Dynamic) - Security+2.0 `310MHz, 390MHz, 868MHz` `AM650` (62 bits, Dynamic) From 4df12a5d12ba7c15af21d95f2501a76ebd5cd56a Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 10 Jan 2026 04:55:47 +0300 Subject: [PATCH 029/160] rename sommer klq --- CHANGELOG.md | 1 + ReadMe.md | 5 +- .../main/subghz/helpers/subghz_gen_info.c | 8 +- .../resources/subghz/assets/keeloq_mfcodes | 134 +++++++++--------- lib/subghz/protocols/keeloq.c | 2 +- 5 files changed, 77 insertions(+), 73 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a126b7e50..d15e2edef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * Archive: Allow folders to be pinned (by @WillyJL) * Apps: Build tag (**9jan2026p2**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes +* SubGHz: Rename Sommer(fsk476) to Sommer (Sommer keeloq works better with FM12K) * Docs: Add full list of supported SubGHz protocols and their frequencies/modulations that can be used for reading remotes - [Docs Link](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSupportedSystems.md) * Desktop: Show debug status (D) if clock is enabled and debug flag is on (PR #942 | by @Dmitry422) * NFC: Fix some typos in Type4Tag protocol (by @WillyJL) diff --git a/ReadMe.md b/ReadMe.md index 9cb6dbda0..7c353fd27 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -143,6 +143,8 @@ Also check the [changelog in releases](https://github.com/DarkFlippers/unleashed ### Current modified and new Sub-GHz protocols list: Thanks to Official team (to their SubGHz Developer, Skorp) for implementing support (decoder + encoder / or decode only) for these protocols in OFW. +[Full list of supported protocols and their frequencies/modulations (to use in Read mode)](/documentation/SubGHzSupportedSystems.md) + > [!NOTE] > Not all Keeloq systems are supported for decoding or emulation! >
@@ -154,7 +156,7 @@ Thanks to Official team (to their SubGHz Developer, Skorp) for implementing supp > | Alligator | Comunello | GSN | Magic_4 | SL_A2-A4 | > | Alligator_S-275 | Dea_Mio | Guard_RF-311A | Mongoose | SL_A6-A9/Tomahawk_9010 | > | APS-1100_APS-2550 | DTM_Neo | Harpoon | Mutanco_Mutancode | SL_B6,B9_dop | -> | Aprimatic | DoorHan | IronLogic | NICE_MHOUSE | Sommer(fsk476) | +> | Aprimatic | DoorHan | IronLogic | NICE_MHOUSE | Sommer | > | Beninca | EcoStar | JCM_Tech | NICE_Smilo | Stilmatic | > | BFT | Elmes_Poland | KEY | Normstahl | Teco | > | Came_Space | FAAC_RC,XT | Kingates_Stylo4k | Pantera | Tomahawk_TZ-9030 | @@ -264,6 +266,7 @@ Enhance your Flipper Zero with apps and plugins created by the community: ## 📁 Where I can find IR, Sub-GHz, ... files, DBs, and other stuff? - [UberGuidoZ Playground - Large collection of files - Github](https://github.com/UberGuidoZ/Flipper) - [Awesome Flipper Zero - Github](https://github.com/djsime1/awesome-flipperzero) +- [IRDB - Infrared remotes database - Github](https://github.com/Lucaslhm/Flipper-IRDB) ## 📘 Instructions diff --git a/applications/main/subghz/helpers/subghz_gen_info.c b/applications/main/subghz/helpers/subghz_gen_info.c index 1f4bc92c6..388327da2 100644 --- a/applications/main/subghz/helpers/subghz_gen_info.c +++ b/applications/main/subghz/helpers/subghz_gen_info.c @@ -426,7 +426,7 @@ void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType ty .keeloq.serial = (key & 0x0000FFFF) | 0x01700000, .keeloq.btn = 0x02, .keeloq.cnt = 0x03, - .keeloq.manuf = "Sommer(fsk476)"}; + .keeloq.manuf = "Sommer"}; break; case SetTypeSommer_FM_868: gen_info = (GenInfo){ @@ -436,7 +436,7 @@ void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType ty .keeloq.serial = (key & 0x0000FFFF) | 0x01700000, .keeloq.btn = 0x02, .keeloq.cnt = 0x03, - .keeloq.manuf = "Sommer(fsk476)"}; + .keeloq.manuf = "Sommer"}; break; case SetTypeSommer_FM12K_434: gen_info = (GenInfo){ @@ -446,7 +446,7 @@ void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType ty .keeloq.serial = key & 0x0000FFFF, .keeloq.btn = 0x02, .keeloq.cnt = 0x03, - .keeloq.manuf = "Sommer(fsk476)"}; + .keeloq.manuf = "Sommer"}; break; case SetTypeSommer_FM12K_868: gen_info = (GenInfo){ @@ -456,7 +456,7 @@ void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType ty .keeloq.serial = key & 0x0000FFFF, .keeloq.btn = 0x02, .keeloq.cnt = 0x03, - .keeloq.manuf = "Sommer(fsk476)"}; + .keeloq.manuf = "Sommer"}; break; case SetTypeDTMNeo433: gen_info = (GenInfo){ diff --git a/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes b/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes index b146d0ded..fddea5abd 100644 --- a/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes +++ b/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes @@ -1,70 +1,70 @@ Filetype: Flipper SubGhz Keystore File Version: 0 Encryption: 1 -IV: 41 20 46 75 72 72 79 20 48 41 4C 21 4F 77 4F 21 -2CAD19E0C7E482D138AD8EC452C5D9175534F5FD5B8DAB0FF2082A75A9410C60 -87341133DBC22CC39E1952466C1FA6F7DA4215FB3B9D6975CDA16CD0211AEC7E -8D60AA06878EA9EE24D3F2CDC0166373E3CD131CAD016976758B4F5F0DCC4A36 -E455A4EF9016D5682815F4714A678833CD09D6CED6D9D3D796CC700B0FFB79CC -FD5A46DF885486EE89F867BF629B63940AE8A1D0695BE93FCE4385AF523F8809145A3381F2F3F578A38FD40B2546A423 -84F8D5D63DC863490A0B36BC6102FFAA4D0852DE5E92B567B39F0C6F90454029 -8D1A3A7BE24A6F96B3401944435FF5441628B3E60C1CA29F54650BF5912C7E00 -4F2A1A51AC845F91CC8F0AC693CC8D95C4FCF2524317F2576BF1B426332257F2 -6482B6BC4C59F14FC414C4A1E8DEE687E3263FC575646287CF07CE21D5356CB9 -B98C8FE2030F448F80F075EC844311F503B8B4A1048F3EF761AFC695BED8767D -426044078972749851904C762094DC45D8E6DEEEB36232A1489BFBEDC15F6EA0308756673C7494241BCA9BF6216B0C63 -7446FBF891E79C130550E5AEC07BCD6605AB16A16123C7F58B34BA8243567CD29EFBFF44730F36E86A17B97B4CA86BCD -3F76A9C0273C7A344244703F24F625091B1F599A2DDFBD698F33CF7BF7765BD4 -AC491FF039EE8D1548F127AA11863B8CD6B67C37F5DE55D810C04AA1A0207D7D -E14027E544A3B867402F1FD496AD8E173CB6FC55053C3846142882D746C8A3BA -182599DE46C923C4A2A8B1CB07165A8FD5F571BE95A32DA4D517B99378AF618C -5AE341DCF8BFDBA55301555D3300946352CA174F5B0DF6EB239EE997C0E093D1930F6A75996B149199DFFE78B25F5BD5 -A495E957DBE11937C967CEBF99BCFE85CE2E2FFBBD6952352EC7E59FD9ABDC2D -F1F924BD569DD0E6AB7EEC7C880EDE0CE53757A2A183EED3674C10FDE4ADFF17 -B6E32951F4C886371968E5BED5711C05648E87F36FC397E2455B8DD5AFF3865D3BADADF7626D071F792712F6B0FD115B -BC88789A8C037EBCA6F9F6A0FC616D3512474AED1C96270845171CF76F7CDA6D4D2CD42CB8463CE706398B0A9DBEA87A -4A8686B20E1339C81AAE8BBF1C9EABA5BEB61D0A394F314958546FA14A67DEE7 -CA71F413EC992ACFEB03EE1760BE683050FF4D1E1B65ACF9E3A4964F2B3C2B01 -0E05B3BD4854604B6FB82900A13051C0377E85C49A293A39C2A8C75B904D8102 -C9EDE274DD3C5B6DF276565FEE81ED060F0C3BD0CB72EA3E49E9595FAFE77F5C -A33A4B9AD451ACDB5EC4830EFE421AE8929E024108C34343D3D55F098CDE5B0B -9C5C17D4FB32DDD18D88A2B358786E9A941931BE9D645B379412F2E187020C14 -2626DD2FCE983EA3DEAB2FE2A5F378250F1644BE24BDCC2C5FAFDBA68D4F1872 -9F1E27964102BFCEFBF6F5FE7DA8C3B102E97ED0CEE074625175FB02674D5EF2 -7E1745495E213781ABCA814552046470EA41F0EBE8BDD64592DDFA7319AFCD69 -EB6C3B1F4265C71A0DD74847588A89CCF57539CF20711233A221C9BE1F9EB6C9 -4C1A2768E44F9DD2E4AEE9C18DE5449B92CD4DFE5BDA7F65F5A654C86544B2E1 -4F1835CDBDA4128324F4B92E709201502852892699EC0C84B1E4A4B841542C3C -E0EBE4B259B61F05475FFE07EAC8E2A9D013D4471DC7CF3481E1334006F7FB02 -20342B2D84CD3936DEA5058CE07F3F3DB6178C6BF0AC72CF8F807503B3AC8F88 -DC775129215670CD8B81A5335190F6544687D38A70E758348578B0B3A1389300 -208F0D588404D9BDD6E310F16B7460BDB2A8B284CA6E59E24F5FACFD55D48AACC5D86C886A9EF5F06DC2AADE76EFF35F -5CD70EFEAB4B5345531102A0DA1453F857AC93F3456E81C305111626CE084627 -341E61A3AB6BA3F71F5215905149E2D3E84260CC77C068C92D71C6DD9067F633 -0342C01D966663D7542F2D5D7635758EC65CDDE5E7FD5884846D675D06C59363 -2E9F77AD044F9C8C23CA239E71303D6682A2A86C3B4D44831DB4B1BC377043CD -3A11CBA6703808A36911F036E9042198950C2C82269D892F5C87DFD32C101BCA -6E75A69923DFC22957705A624368CFB657B77C11D7F831704BCC76A87377AB26 -21F70436CF950862D306829B542E307EF327F23870D4FBF42869A3BF0891F9DB -4A00DFB119C12D86B953BEC9F41DFB3D4AE3A9BE984CD8C3606CC1ED4B9020ED82922BCED5AE8A2A88DD2995A0D28EFE -12E2B40E49B0FC157203286B39ED852EDC2B444527472A8C07E78A70722DB825 -91A106AF60685D56D19D2E58C9F902F2B3B80A1CFCBC1B84316FBAF69DB47730 -58B5AF1BB0EF318CC3026041A3403B025980FB4DE06C3F2B804800B8578295B7 -FA7C4461C2F0BECADB414694B04E7A89BC99433A635E2905DC3A40A947EC9846 -DF356AFF3212088F223EC32E5FE9D5D73701F25B2075BC50E0F0B45195F28365 -2D099AE3FB0AE7B92976E02E2F01A9D6821D7C15CC04DCA881E05D50BC46EB11 -1FE9F8D29A77CD399B068A8AD890ECB85A957438855F85223B16E3B83A655213 -07DFA64C22CF6DB1E36D16F763BDD822AF3991BDE07C30B4F4084BD13CDEF012 -3BA563F522243D807151BC2EF1B524C174058888D9DE852AA0E9C15F1EA22950 -475979BC2EA05EE2443F65F2372E36D780A34EC8AC1D70BB2480FF519C6C84C1 -7275E88766DCA0EB3725641E950EEC094129361D280AE963D89A9B5403136B06 -65202C209229A36A2B80ED69DEEA285A7273BAA007365AC2E7F438C7AE428BBA -C83ABA33828918FB80D92D8217BB8AE6B5AA4017D0CD7F37C39925F7F96B9BD2 -AAEF1B708581570F87D1FB016FE23FF2804CB6942E576C40165D9F81A4E7AB04 -F7434FBA076E677D71A584341A77D54BFEF4DEBDCADA67D23DB50AA5902DA4EE -5480CB40AB7CA50ABA5EED094281282D5302C38E5EF0B8AF7AE51B5C702574F2 -1C90B716E8AF97DEADB0199C4BBDE7E3669FB4D6794A27F716D523DDFC74905ECEB64509C073405B38A271B7FBFEA3DD -36036999661471644E50D56532DA3D82F2713035BDBDA399E6B121B15E2FDCD5 -DCD61BB556CD42849B99C7A1916005305E57723555CD24F6F1D67D30224A275F -4E3662D52FB2396DCC0D76E7ECFFECF5E581492FA520D8427F772C61435FF925 -7F33462CB81E81DDF8284A6EA121401EEA6301277ABDF2D5C39EDB818AE973F0D51527BA6146C3178624F61E38F220D2 +IV: 46 75 72 72 79 20 49 56 20 4F 77 4F 20 55 77 55 +30A13FCF86676F7027AF9D7BECBAA6A08C83B0DB00E4FFFB6F53249D0EA057AD +2D3AA216E454121B2C4DAC9EEE2502ECADCDC0B29C383102CDD7A078ED813A6C +B08365492BC7FBAE96B0A38FFAE7DF72E86BA1979860585582D69FF740E85C1A +7FA151F83A3550AB4EF7710325E54525A59DC499F2CE53885F886C1E848C6A18 +CFAB501321D7EF01946308915B43EBB7FDACBDBFC7BDD797437B6F2797225609E13738CD0D90A2C4A1432FA9E34618C3 +322A0030702A3930977D1AD1C762356161F3402BFA6435F184F14BFBDAEC3F4A +BAB2E4702DA0FC7D0BA9581A04A1728D2FD9B986E4B180550BBC59DF1B04BC0A +CD87059AE7E0CA962065FBDF55EDBBD45253D5A01B714EDF28F7744F11A35C65 +6226EDFC8F7C7C51A06FADAF98241EE92CA2E827217AEB7A2C917DE431BC91A4 +057FEF7D36FF24D3C5F6C59FBA9C09197575E1A6E674A73692CCF8118C6B3C6E +5BA3EB99D621A7DD9D2EBBC4A24CE935D29A78EB200D82ED295B4ABBB6425525F82A502A09ECC9C310401BEF7E354CDD +8303490AC2E6576FF1E159342754AC45B38323836D1164AFDEE2578F5B70C70229A7DB64FB5283DA4F83A616AB11E394 +79208032CC01AA421851310727CCF2E81448671AFA07D7156C2C40707787C856 +9846F3ACF236D210A0AD138B3949A3CDA9A2E841F11BF9F531F299B33FD97B40 +6BD0CCA70D86E2D71645D2E6C223B2AF501ED9A5EDA24643FC90AAC7C3840E4E +69D9A4E90065AA5A1D7A6E40FBB2FC6BF4A72CF591E1FD51822A8B59CB6DBB22 +9032CDF1F5AF42EEE6121DFFA12F578F2088D25B9F260357E02590B19560462980D11A81462AD23D61A7927D2ECCF49B +1528C0F81E0F0510AA65D07C61EB29149C7238F474B3512F4BEDB0C4BA4966BB +80ADFA97303DA2907FC982E705DB45902BB251E08EC322B5429F70EDC6D7E2C9 +561F49B1A85F2FD839FC022ABD22A11E036891FC8B52220BFDE7194192C43F173637F76FFA1AEE4A4344647886EE3E3B +0AAFA120E57966064AFCD0B3F3571CE92118379160131C646B0E46262E4844883111DF28B2B17A46750D481216375055 +45E76A7B85593DCA6E0A9A71067AA0031590CA4C60161887D8E6BE54F254128A +537091AC4E7FD1841E03B352B1E62855AD26233DE167087A7F818804EA9DA56D +84DE10BB68269D0BF1723F29A683569F0D17FE247898C76523E6155AD4931195 +CF16625381ADFBEA6D89142A13CDA19FEA8345511692A0FBBA66E178BAF8126E +D25962A77350E7B7222983150A1C92053364F9954142A85AEA4FEC1D3B524C71 +A76F292F18E464511FD3232B604893985F9A823BBD9D73B2D84E43D4BDF7C5A8 +F92496E57B1B0F57C155ED15A6CBDDBF6A9C309A3A3B2B2D3118E51F8B8B718B +E59C00F03AA3DA0B961E04ACE90E85005DB3C4E402BF9A280775BCE9FC7EDE05 +494CB3B66A924E90DD180A96F77182F708C7CCC3E379D302D436FED839EBEEDB +D93838B8AC08491FE0F29EC5077F5BAB6F75DAE77C6F305A963F0555346B9EE1 +569E5F5EA968A636C657D009525BB3C416546D19ADDC05B9D005B023B0957DFA +A16CE196104A013E064663AE9DD0393BBF87E4FAFA1489C6ABA367928A2905F7 +4FF57FB9C064CCC452473D0713E0EE17EA85726CD00203F359252ABE613BF054 +C489D64C0CF7535117D21461EDC3FEBEDAFD2D2E55C0DC87943E9E8D0461EB60 +F9BB5CBF9E514F5B2918880D8336C2552D67346C5365DFAB816517F1793D26E3 +7258ACEBE2090849F6756E6033A7F92AD3D75D753C0438F266B22F270FA5535A +0B4CF3F92742FF775A14B66540FBC214F455CD992DFCEEF925EB0E38B21745A3 +5B17E197557BACB4C355F23D28C22280F9860A756CE2FC0959F1B07B9A6572A9 +0067A9EB86AEE637DA8E9E03512D1129252F5C530602B03D5C3383E0744F23BD +658FEA8B449D1EC5530FACBCDE3E3DF6CB0644B49D96C3FE1231FCDACE266BC1 +11325D0A765463419D6623C69961A0071EDA461E14C940326F1CA36339C946CD +007D6143BABAFFF19D77CC57E15AB4351C1D102856CB182F3F512EEFCD6FDF4F +CB97161DDE414D6D4D96FF726F73FF3AD0D71F9768EA6BBBFF08ABABB33A15B2 +A558FB601E42FAC986D0421446C7C898A9BDB0711FFB872B333CBEE9FC560DB9D7C790C502E59A29F493A2EC1EBA3FA5 +65E772E08F92E50C8151AA99FCA8D27F35D5F90C1CD45D098C5654C8046649F0 +DCB929C33CB3E4D28029D0E50C146074714CEFC765BE475B324F4D8DCBCDA931 +0ACC1EC04B63A689270904860E1EC3BF8E7F1DB1B18FBDD460AAE6148641894F +CE96406CECA957184499060DEF5FA7F0E956BC6B120B60DB1DCCB0F665F455E4 +D8C0B7CFDD3D20F58112660C08B236040242BCB1CF1FA5CFC66A6382282D2340 +D5E0F33DDD03D11AC90D33A230AA77A9ACB7C239520EE5A95587700CD87AF5C7 +D095F39B66EFAEECAAA2B9D4EC0AAEE6EA0749B2F12C17B38D96DC0197DECAD9 +E52D638ADD750B0231738F751EB97C2724877E184C365F9761F5995BCFD6F812 +EFA069F75B0A4B3FD6E6B8845E4A466BE092C746F6F574118AE435A32550464E +6FBFBD47F3EC4846E946121A54042E418C4A98E5EEF4F8D8C667EC2A774EBEA2 +0A73F468C6F8C4E8CF4934A28DF83972CCF41905562A2AEE79BCADD9CFC11F00 +73AD62A6660287252396902D6F80557772B64E4D6B16E1635489F985E54CFBED +942F89D0520D08B20973D8560F89C8DA8111842DB867EBC51B9F5451AC942EE7 +4FFA3EC48275D44C1A3FE528546FCA0D6E44262BADDA765B71E19863F0337C59 +484C420725B919EF3F2D3D9887175C3EE58CA17E8AD9588AC4EC241A7B91FB96 +39C3E86438AC72575B8BC7F9C2108D1C40AD56D920C0F820D6D92416AFB6244B +D0B3CD5D299820AF61BB4782746750056A7D212B9595424D6E50BFAEBCB089951090BD09D4C0B1F4D357C3FAFE6E73A9 +BB441902B1078F7F3D5E1F2BC5546E242C4E27B49149D3E1A54C20B6FD9EC56A +78C4CF85F6DB0CD63CB72A9B118C5DCE8EE7E6CC15A4312ACEC0B6503738325C +DE92516887651C73E89E2CE0D64DEE236E235C7CCBF0D14FE291D8793782616D +74F855306E36A0DA5B0FFF097CB69AAB34DEF3CF3D2DFFCF1A80447D6CC057A438AA4FBCB631F476FE568E9BA941ED2B diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 8a3a81c75..599b542e5 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -518,7 +518,7 @@ static bool klq_last_custom_btn = 0x9; } else if( (strcmp(instance->manufacture_name, "EcoStar") == 0) || - (strcmp(instance->manufacture_name, "Sommer(fsk476)") == 0)) { + (strcmp(instance->manufacture_name, "Sommer") == 0)) { klq_last_custom_btn = 0x6; } else if((strcmp(instance->manufacture_name, "AN-Motors") == 0)) { klq_last_custom_btn = 0xC; From c407fd2d1a9e0569c8542e84c51cc9d0dea47158 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 11 Jan 2026 06:25:22 +0300 Subject: [PATCH 030/160] subghz: sommer add backwards comp. fix for older files --- CHANGELOG.md | 2 +- lib/subghz/protocols/keeloq.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d15e2edef..7a0ad81f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ * Archive: Allow folders to be pinned (by @WillyJL) * Apps: Build tag (**9jan2026p2**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes -* SubGHz: Rename Sommer(fsk476) to Sommer (Sommer keeloq works better with FM12K) +* SubGHz: Rename Sommer(fsk476) to Sommer (Sommer keeloq works better with FM12K) + added backwards compatibility with older saved files * Docs: Add full list of supported SubGHz protocols and their frequencies/modulations that can be used for reading remotes - [Docs Link](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSupportedSystems.md) * Desktop: Show debug status (D) if clock is enabled and debug flag is on (PR #942 | by @Dmitry422) * NFC: Fix some typos in Type4Tag protocol (by @WillyJL) diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 599b542e5..6b03badb9 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -624,6 +624,21 @@ SubGhzProtocolStatus flipper_format, "Manufacture", instance->manufacture_from_file)) { instance->manufacture_name = furi_string_get_cstr(instance->manufacture_from_file); instance->keystore->mfname = instance->manufacture_name; + // Compatibility fixes for old names in user files + if(strcmp(instance->manufacture_name, "Sommer(fsk476)") == 0) { + instance->manufacture_name = "Sommer"; + instance->keystore->mfname = instance->manufacture_name; + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + if(!flipper_format_update_string_cstr( + flipper_format, "Manufacture", instance->manufacture_name)) { + FURI_LOG_E(TAG, "DECODER: Unable to fix Sommer manufacture name"); + ret = SubGhzProtocolStatusError; + break; + } + } } else { FURI_LOG_D(TAG, "ENCODER: Missing Manufacture"); } @@ -1275,6 +1290,21 @@ SubGhzProtocolStatus flipper_format, "Manufacture", instance->manufacture_from_file)) { instance->manufacture_name = furi_string_get_cstr(instance->manufacture_from_file); instance->keystore->mfname = instance->manufacture_name; + // Compatibility fixes for old names in user files + if(strcmp(instance->manufacture_name, "Sommer(fsk476)") == 0) { + instance->manufacture_name = "Sommer"; + instance->keystore->mfname = instance->manufacture_name; + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + if(!flipper_format_update_string_cstr( + flipper_format, "Manufacture", instance->manufacture_name)) { + FURI_LOG_E(TAG, "DECODER: Unable to fix Sommer manufacture name"); + res = SubGhzProtocolStatusError; + break; + } + } } else { FURI_LOG_D(TAG, "DECODER: Missing Manufacture"); } From 2db115783c81478195bfa9ecc839475d4e0c9a85 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 11 Jan 2026 09:30:28 +0300 Subject: [PATCH 031/160] moving non critical settings to sd based on WillyJL's work TODO: fix loader_menu --- applications/services/applications.h | 6 + applications/services/bt/application.fam | 7 +- .../bt/bt_service/bt_settings_api_i.h | 8 + applications/services/desktop/application.fam | 1 + applications/services/desktop/desktop.h | 8 + .../services/desktop/desktop_settings.h | 8 + applications/services/dolphin/dolphin.h | 2 +- .../services/dolphin/helpers/dolphin_state.h | 8 + .../services/expansion/application.fam | 1 + applications/services/loader/loader.c | 6 + applications/services/loader/loader_cli.c | 6 +- applications/services/loader/loader_menu.c | 16 +- .../services/notification/application.fam | 2 +- .../services/notification/notification_app.h | 8 + applications/settings/about/application.fam | 4 +- .../settings/bt_settings_app/application.fam | 4 +- .../settings/clock_settings/application.fam | 4 +- .../settings/desktop_settings/application.fam | 4 +- .../desktop_settings/helpers/pin_code.c | 1 + .../scenes/desktop_settings_scene_favorite.c | 2 +- .../views/desktop_view_pin_input.c | 1 + .../settings/dolphin_passport/application.fam | 4 +- .../expansion_settings_app/application.fam | 4 +- .../input_settings_app/application.fam | 4 +- .../notification_settings/application.fam | 4 +- lib/SConscript | 3 + lib/u8g2/SConscript | 3 + lib/u8g2/u8g2_glue.h | 8 + scripts/fbt/appmanifest.py | 2 + scripts/fbt_tools/fbt_apps.py | 29 +- scripts/fbt_tools/fbt_extapps.py | 1 + scripts/ufbt/SConstruct | 1 + targets/f7/api_symbols.csv | 2967 ++++++++++++++++- 33 files changed, 3103 insertions(+), 34 deletions(-) create mode 100644 applications/settings/desktop_settings/helpers/pin_code.c create mode 100644 applications/settings/desktop_settings/views/desktop_view_pin_input.c diff --git a/applications/services/applications.h b/applications/services/applications.h index 7dbb7063f..c9408dc50 100644 --- a/applications/services/applications.h +++ b/applications/services/applications.h @@ -65,6 +65,12 @@ extern const FlipperInternalApplication FLIPPER_ARCHIVE; extern const FlipperInternalApplication FLIPPER_SETTINGS_APPS[]; extern const size_t FLIPPER_SETTINGS_APPS_COUNT; +/* External Settings list + * Spawned by loader + */ +extern const FlipperExternalApplication FLIPPER_EXTSETTINGS_APPS[]; +extern const size_t FLIPPER_EXTSETTINGS_APPS_COUNT; + /* External Menu Apps list * Spawned by loader */ diff --git a/applications/services/bt/application.fam b/applications/services/bt/application.fam index 0e4cc918f..70a3d3857 100644 --- a/applications/services/bt/application.fam +++ b/applications/services/bt/application.fam @@ -14,7 +14,12 @@ App( ], stack_size=1 * 1024, order=20, - sdk_headers=["bt_service/bt.h", "bt_service/bt_keys_storage.h"], + sdk_headers=[ + "bt_service/bt.h", + "bt_service/bt_keys_storage.h", + "bt_settings.h", + "bt_service/bt_settings_api_i.h", + ], ) App( diff --git a/applications/services/bt/bt_service/bt_settings_api_i.h b/applications/services/bt/bt_service/bt_settings_api_i.h index 441295893..9dcd2baf1 100644 --- a/applications/services/bt/bt_service/bt_settings_api_i.h +++ b/applications/services/bt/bt_service/bt_settings_api_i.h @@ -3,6 +3,14 @@ #include "bt.h" #include "../bt_settings.h" +#ifdef __cplusplus +extern "C" { +#endif + void bt_get_settings(Bt* bt, BtSettings* settings); void bt_set_settings(Bt* bt, const BtSettings* settings); + +#ifdef __cplusplus +} +#endif diff --git a/applications/services/desktop/application.fam b/applications/services/desktop/application.fam index da6e2b802..a0a533c3b 100644 --- a/applications/services/desktop/application.fam +++ b/applications/services/desktop/application.fam @@ -14,4 +14,5 @@ App( conflicts=["updater"], stack_size=2 * 1024, order=60, + sdk_headers=["desktop_settings.h", "desktop.h"], ) diff --git a/applications/services/desktop/desktop.h b/applications/services/desktop/desktop.h index e83bc3ee4..1f332cd76 100644 --- a/applications/services/desktop/desktop.h +++ b/applications/services/desktop/desktop.h @@ -6,6 +6,10 @@ #define RECORD_DESKTOP "desktop" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct Desktop Desktop; typedef struct { @@ -21,3 +25,7 @@ FuriPubSub* desktop_api_get_status_pubsub(Desktop* instance); void desktop_api_get_settings(Desktop* instance, DesktopSettings* settings); void desktop_api_set_settings(Desktop* instance, const DesktopSettings* settings); + +#ifdef __cplusplus +} +#endif diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index 6f81d99cb..b5db60ee6 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -9,6 +9,10 @@ #define DISPLAY_BATTERY_RETRO_5 4 #define DISPLAY_BATTERY_BAR_PERCENT 5 +#ifdef __cplusplus +extern "C" { +#endif + typedef enum { FavoriteAppLeftShort, FavoriteAppLeftLong, @@ -49,3 +53,7 @@ typedef struct { void desktop_settings_load(DesktopSettings* settings); void desktop_settings_save(const DesktopSettings* settings); + +#ifdef __cplusplus +} +#endif diff --git a/applications/services/dolphin/dolphin.h b/applications/services/dolphin/dolphin.h index 95f851a51..82bab66e4 100644 --- a/applications/services/dolphin/dolphin.h +++ b/applications/services/dolphin/dolphin.h @@ -3,7 +3,7 @@ #include #include -#include "helpers/dolphin_deed.h" +#include "helpers/dolphin_state.h" #ifdef __cplusplus extern "C" { diff --git a/applications/services/dolphin/helpers/dolphin_state.h b/applications/services/dolphin/helpers/dolphin_state.h index 23a7d7b5f..21253e762 100644 --- a/applications/services/dolphin/helpers/dolphin_state.h +++ b/applications/services/dolphin/helpers/dolphin_state.h @@ -5,6 +5,10 @@ #include "dolphin_deed.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef enum { DolphinFlagHappyMode = 1, } DolphinFlags; @@ -50,3 +54,7 @@ bool dolphin_state_is_levelup(uint32_t icounter); void dolphin_state_increase_level(DolphinState* dolphin_state); uint8_t dolphin_get_level(uint32_t icounter); + +#ifdef __cplusplus +} +#endif diff --git a/applications/services/expansion/application.fam b/applications/services/expansion/application.fam index f85450e40..29e5dd369 100644 --- a/applications/services/expansion/application.fam +++ b/applications/services/expansion/application.fam @@ -5,6 +5,7 @@ App( cdefines=["SRV_EXPANSION"], sdk_headers=[ "expansion.h", + "expansion_settings.h", ], requires=["rpc_start"], provides=["expansion_settings"], diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index 60a21395c..afb8c209f 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -23,6 +23,12 @@ static const char* loader_find_external_application_by_name(const char* app_name } } + for(size_t i = 0; i < FLIPPER_EXTSETTINGS_APPS_COUNT; i++) { + if(strcmp(FLIPPER_EXTSETTINGS_APPS[i].name, app_name) == 0) { + return FLIPPER_EXTSETTINGS_APPS[i].path; + } + } + return NULL; } diff --git a/applications/services/loader/loader_cli.c b/applications/services/loader/loader_cli.c index 265779e8f..6632163d6 100644 --- a/applications/services/loader/loader_cli.c +++ b/applications/services/loader/loader_cli.c @@ -25,10 +25,14 @@ static void loader_cli_list(void) { for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { printf("\t%s\r\n", FLIPPER_APPS[i].name); } - printf("Settings:\r\n"); + printf("Int Settings:\r\n"); for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { printf("\t%s\r\n", FLIPPER_SETTINGS_APPS[i].name); } + printf("Ext Settings:\r\n"); + for(size_t i = 0; i < FLIPPER_EXTSETTINGS_APPS_COUNT; i++) { + printf("\t%s\r\n", FLIPPER_EXTSETTINGS_APPS[i].name); + } } static void loader_cli_info(Loader* loader) { diff --git a/applications/services/loader/loader_menu.c b/applications/services/loader/loader_menu.c index 525861f55..4fec926fe 100644 --- a/applications/services/loader/loader_menu.c +++ b/applications/services/loader/loader_menu.c @@ -76,11 +76,9 @@ static void loader_menu_settings_menu_callback(void* context, InputType input_type, uint32_t index) { UNUSED(context); if(input_type == InputTypeShort) { - const char* name = FLIPPER_SETTINGS_APPS[index].name; - loader_menu_start(name); + loader_menu_start((const char*)index); } else if(input_type == InputTypeLong) { - const char* name = FLIPPER_SETTINGS_APPS[index].name; - archive_favorites_handle_setting_pin_unpin(name, NULL); + archive_favorites_handle_setting_pin_unpin((const char*)index, NULL); } } @@ -140,7 +138,15 @@ static void loader_menu_build_submenu(LoaderMenuApp* app, LoaderMenu* loader_men submenu_add_item_ex( app->settings_menu, FLIPPER_SETTINGS_APPS[i].name, - i, + (uint32_t)FLIPPER_SETTINGS_APPS[i].name, + loader_menu_settings_menu_callback, + loader_menu); + } + for(size_t i = 0; i < FLIPPER_EXTSETTINGS_APPS_COUNT; i++) { + submenu_add_item_ex( + app->settings_menu, + FLIPPER_EXTSETTINGS_APPS[i].name, + (uint32_t)FLIPPER_EXTSETTINGS_APPS[i].name, loader_menu_settings_menu_callback, loader_menu); } diff --git a/applications/services/notification/application.fam b/applications/services/notification/application.fam index 82f94085a..c93dc4d6c 100644 --- a/applications/services/notification/application.fam +++ b/applications/services/notification/application.fam @@ -8,5 +8,5 @@ App( provides=["notification_settings"], stack_size=int(1.5 * 1024), order=100, - sdk_headers=["notification.h", "notification_messages.h"], + sdk_headers=["notification.h", "notification_messages.h", "notification_app.h"], ) diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 754c8d4c3..abf3cc15e 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -9,6 +9,10 @@ #define NOTIFICATION_LED_COUNT 3 #define NOTIFICATION_EVENT_COMPLETE 0x00000001U +#ifdef __cplusplus +extern "C" { +#endif + typedef enum { NotificationLayerMessage, InternalLayerMessage, @@ -102,3 +106,7 @@ void rainbow_timer_starter(NotificationApp* app); const char* rgb_backlight_get_color_text(uint8_t index); uint8_t rgb_backlight_get_color_count(void); void set_rgb_backlight_installed_variable(uint8_t var); + +#ifdef __cplusplus +} +#endif diff --git a/applications/settings/about/application.fam b/applications/settings/about/application.fam index d97817b43..0534c5a28 100644 --- a/applications/settings/about/application.fam +++ b/applications/settings/about/application.fam @@ -1,7 +1,7 @@ App( appid="about", name="About", - apptype=FlipperAppType.SETTINGS, + apptype=FlipperAppType.EXTSETTINGS, entry_point="about_settings_app", cdefines=["APP_ABOUT"], requires=[ @@ -10,4 +10,6 @@ App( ], stack_size=1 * 1024, order=1000, + fap_libs=["assets"], + fap_category="assets", ) diff --git a/applications/settings/bt_settings_app/application.fam b/applications/settings/bt_settings_app/application.fam index 7a985046b..451c837df 100644 --- a/applications/settings/bt_settings_app/application.fam +++ b/applications/settings/bt_settings_app/application.fam @@ -1,7 +1,7 @@ App( appid="bt_settings", name="Bluetooth", - apptype=FlipperAppType.SETTINGS, + apptype=FlipperAppType.EXTSETTINGS, entry_point="bt_settings_app", stack_size=1 * 1024, requires=[ @@ -9,4 +9,6 @@ App( "gui", ], order=10, + fap_libs=["assets"], + fap_category="assets", ) diff --git a/applications/settings/clock_settings/application.fam b/applications/settings/clock_settings/application.fam index 206848aa3..d6a96d2e5 100644 --- a/applications/settings/clock_settings/application.fam +++ b/applications/settings/clock_settings/application.fam @@ -1,12 +1,14 @@ App( appid="clock_settings", name="Clock & Alarm", - apptype=FlipperAppType.SETTINGS, + apptype=FlipperAppType.EXTSETTINGS, entry_point="clock_settings", requires=["gui"], provides=["clock_settings_start"], stack_size=1 * 1024, order=90, + fap_libs=["assets"], + fap_category="assets", ) App( diff --git a/applications/settings/desktop_settings/application.fam b/applications/settings/desktop_settings/application.fam index d01a28d36..5e6da74de 100644 --- a/applications/settings/desktop_settings/application.fam +++ b/applications/settings/desktop_settings/application.fam @@ -1,7 +1,7 @@ App( appid="desktop_settings", name="Desktop", - apptype=FlipperAppType.SETTINGS, + apptype=FlipperAppType.EXTSETTINGS, entry_point="desktop_settings_app", requires=[ "desktop", @@ -9,4 +9,6 @@ App( ], stack_size=1 * 1024, order=50, + fap_libs=["assets"], + fap_category="assets", ) diff --git a/applications/settings/desktop_settings/helpers/pin_code.c b/applications/settings/desktop_settings/helpers/pin_code.c new file mode 100644 index 000000000..f4a39da6f --- /dev/null +++ b/applications/settings/desktop_settings/helpers/pin_code.c @@ -0,0 +1 @@ +#include \ No newline at end of file diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c index 08bb76516..e90337634 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c @@ -1,5 +1,5 @@ #include "../desktop_settings_app.h" -#include "applications.h" +#include #include "desktop_settings_scene.h" #include "desktop_settings_scene_i.h" #include diff --git a/applications/settings/desktop_settings/views/desktop_view_pin_input.c b/applications/settings/desktop_settings/views/desktop_view_pin_input.c new file mode 100644 index 000000000..4d3dbb156 --- /dev/null +++ b/applications/settings/desktop_settings/views/desktop_view_pin_input.c @@ -0,0 +1 @@ +#include \ No newline at end of file diff --git a/applications/settings/dolphin_passport/application.fam b/applications/settings/dolphin_passport/application.fam index 4167e9dcd..142840ece 100644 --- a/applications/settings/dolphin_passport/application.fam +++ b/applications/settings/dolphin_passport/application.fam @@ -1,7 +1,7 @@ App( appid="passport", name="Passport", - apptype=FlipperAppType.SETTINGS, + apptype=FlipperAppType.EXTSETTINGS, entry_point="passport_app", cdefines=["APP_PASSPORT"], requires=[ @@ -10,4 +10,6 @@ App( ], stack_size=1 * 1024, order=60, + fap_libs=["assets"], + fap_category="assets", ) diff --git a/applications/settings/expansion_settings_app/application.fam b/applications/settings/expansion_settings_app/application.fam index b253ad174..e3c1881bf 100644 --- a/applications/settings/expansion_settings_app/application.fam +++ b/applications/settings/expansion_settings_app/application.fam @@ -1,9 +1,11 @@ App( appid="expansion_settings", name="Expansion Modules", - apptype=FlipperAppType.SETTINGS, + apptype=FlipperAppType.EXTSETTINGS, entry_point="expansion_settings_app", requires=["gui"], stack_size=1 * 1024, order=80, + fap_libs=["assets"], + fap_category="assets", ) diff --git a/applications/settings/input_settings_app/application.fam b/applications/settings/input_settings_app/application.fam index 14be52fc4..b15c0956a 100644 --- a/applications/settings/input_settings_app/application.fam +++ b/applications/settings/input_settings_app/application.fam @@ -1,9 +1,11 @@ App( appid="input_settings", name="Input", - apptype=FlipperAppType.SETTINGS, + apptype=FlipperAppType.EXTSETTINGS, entry_point="input_settings_app", requires=["input"], stack_size=1 * 1024, order=100, + fap_libs=["assets"], + fap_category="assets", ) diff --git a/applications/settings/notification_settings/application.fam b/applications/settings/notification_settings/application.fam index 117a83870..ae242c966 100644 --- a/applications/settings/notification_settings/application.fam +++ b/applications/settings/notification_settings/application.fam @@ -1,9 +1,11 @@ App( appid="notification_settings", name="LCD and Notifications", - apptype=FlipperAppType.SETTINGS, + apptype=FlipperAppType.EXTSETTINGS, entry_point="notification_settings_app", requires=["notification"], stack_size=1 * 1024, order=20, + fap_libs=["assets"], + fap_category="assets", ) diff --git a/lib/SConscript b/lib/SConscript index 4e6171aba..e3e3a865b 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -8,6 +8,9 @@ env.Append( # Ugly hack Dir("../assets/compiled"), ], + SDK_HEADERS=[ + File("../applications/services/applications.h"), + ], ) diff --git a/lib/u8g2/SConscript b/lib/u8g2/SConscript index dacdfbacb..449f60616 100644 --- a/lib/u8g2/SConscript +++ b/lib/u8g2/SConscript @@ -7,6 +7,9 @@ env.Append( LINT_SOURCES=[ Dir("."), ], + SDK_HEADERS=[ + File("u8g2_glue.h"), + ], ) diff --git a/lib/u8g2/u8g2_glue.h b/lib/u8g2/u8g2_glue.h index 858e8ec7f..b2d16b139 100644 --- a/lib/u8g2/u8g2_glue.h +++ b/lib/u8g2/u8g2_glue.h @@ -3,6 +3,10 @@ #include "u8g2.h" #include +#ifdef __cplusplus +extern "C" { +#endif + uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr); uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr); @@ -18,3 +22,7 @@ void u8x8_d_st756x_init(u8x8_t* u8x8, uint8_t contrast, uint8_t regulation_ratio void u8x8_d_st756x_set_contrast(u8x8_t* u8x8, int8_t contrast_offset); void u8x8_d_st756x_set_inversion(u8x8_t* u8x8, bool arg); + +#ifdef __cplusplus +} +#endif diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index c46dffdbe..6bb47110b 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -26,6 +26,7 @@ class FlipperAppType(Enum): STARTUP = "StartupHook" EXTERNAL = "External" MENUEXTERNAL = "MenuExternal" + EXTSETTINGS = "ExtSettings" METAPACKAGE = "Package" PLUGIN = "Plugin" @@ -260,6 +261,7 @@ class AppBuildset: FlipperAppType.PLUGIN: True, FlipperAppType.DEBUG: True, FlipperAppType.MENUEXTERNAL: False, + FlipperAppType.EXTSETTINGS: False, } DIST_APP_TYPES = list( # Applications that are installed on SD card diff --git a/scripts/fbt_tools/fbt_apps.py b/scripts/fbt_tools/fbt_apps.py index c48e4ba80..6a8820dc6 100644 --- a/scripts/fbt_tools/fbt_apps.py +++ b/scripts/fbt_tools/fbt_apps.py @@ -33,10 +33,16 @@ class ApplicationsCGenerator: ), } - APP_EXTERNAL_TYPE = ( - "FlipperExternalApplication", - "FLIPPER_EXTERNAL_APPS", - ) + EXTERNAL_TYPE_MAP = { + FlipperAppType.MENUEXTERNAL: ( + "FlipperExternalApplication", + "FLIPPER_EXTERNAL_APPS", + ), + FlipperAppType.EXTSETTINGS: ( + "FlipperExternalApplication", + "FLIPPER_EXTSETTINGS_APPS", + ), + } def __init__(self, buildset: AppBuildset, autorun_app: str = ""): self.buildset = buildset @@ -100,12 +106,15 @@ class ApplicationsCGenerator: ] ) - entry_type, entry_block = self.APP_EXTERNAL_TYPE - external_apps = self.buildset.get_apps_of_type(FlipperAppType.MENUEXTERNAL) - contents.append(f"const {entry_type} {entry_block}[] = {{") - contents.append(",\n".join(map(self.get_external_app_descr, external_apps))) - contents.append("};") - contents.append(f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});") + for apptype in self.EXTERNAL_TYPE_MAP: + entry_type, entry_block = self.EXTERNAL_TYPE_MAP[apptype] + external_apps = self.buildset.get_apps_of_type(apptype) + contents.append(f"const {entry_type} {entry_block}[] = {{") + contents.append(",\n".join(map(self.get_external_app_descr, external_apps))) + contents.append("};") + contents.append( + f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});" + ) return "\n".join(contents) diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index 540510b0d..e00edabec 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -456,6 +456,7 @@ def _gather_app_components(env, appname) -> AppDeploymentComponents: if host_app.apptype in [ FlipperAppType.EXTERNAL, FlipperAppType.MENUEXTERNAL, + FlipperAppType.EXTSETTINGS, ]: components.add_app(host_app) else: diff --git a/scripts/ufbt/SConstruct b/scripts/ufbt/SConstruct index 18c4d1cac..c79cd06da 100644 --- a/scripts/ufbt/SConstruct +++ b/scripts/ufbt/SConstruct @@ -232,6 +232,7 @@ apps_to_build_as_faps = [ FlipperAppType.PLUGIN, FlipperAppType.EXTERNAL, FlipperAppType.MENUEXTERNAL, + FlipperAppType.EXTSETTINGS, ] known_extapps = [ diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 104149b6e..a293d7430 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,13 +1,19 @@ entry,status,name,type,params -Version,+,87.2,, +Version,+,87.3,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, +Header,+,applications/services/applications.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, +Header,+,applications/services/bt/bt_service/bt_settings_api_i.h,, +Header,+,applications/services/bt/bt_settings.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, +Header,+,applications/services/desktop/desktop.h,, +Header,+,applications/services/desktop/desktop_settings.h,, Header,+,applications/services/dialogs/dialogs.h,, Header,+,applications/services/dolphin/dolphin.h,, Header,+,applications/services/expansion/expansion.h,, +Header,+,applications/services/expansion/expansion_settings.h,, Header,+,applications/services/gui/elements.h,, Header,+,applications/services/gui/gui.h,, Header,+,applications/services/gui/icon_i.h,, @@ -38,6 +44,7 @@ Header,+,applications/services/loader/firmware_api/firmware_api.h,, Header,+,applications/services/loader/loader.h,, Header,+,applications/services/locale/locale.h,, Header,+,applications/services/notification/notification.h,, +Header,+,applications/services/notification/notification_app.h,, Header,+,applications/services/notification/notification_messages.h,, Header,+,applications/services/power/power_service/power.h,, Header,+,applications/services/rpc/rpc_app.h,, @@ -273,6 +280,7 @@ Header,+,lib/toolbox/tar/tar_archive.h,, Header,+,lib/toolbox/value_index.h,, Header,+,lib/toolbox/varint.h,, Header,+,lib/toolbox/version.h,, +Header,+,lib/u8g2/u8g2_glue.h,, Header,+,targets/f7/ble_glue/furi_ble/event_dispatcher.h,, Header,+,targets/f7/ble_glue/furi_ble/gatt.h,, Header,+,targets/f7/ble_glue/furi_ble/profile_interface.h,, @@ -431,6 +439,10 @@ Function,-,LL_mDelay,void,uint32_t Function,-,Osal_MemCmp,int,"const void*, const void*, unsigned int" Function,-,Osal_MemCpy,void*,"void*, const void*, unsigned int" Function,-,Osal_MemSet,void*,"void*, int, unsigned int" +Function,-,SK6805_get_led_count,uint8_t, +Function,-,SK6805_init,void, +Function,-,SK6805_set_led_color,void,"uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,SK6805_update,void, Function,-,SystemCoreClockUpdate,void, Function,-,SystemInit,void, Function,-,_Exit,void,int @@ -799,6 +811,7 @@ Function,+,ble_svc_serial_update_tx,_Bool,"BleServiceSerial*, uint8_t*, uint16_t Function,-,bsearch,void*,"const void*, const void*, size_t, size_t, __compar_fn_t" Function,+,bt_disconnect,void,Bt* Function,+,bt_forget_bonded_devices,void,Bt* +Function,+,bt_get_settings,void,"Bt*, BtSettings*" Function,+,bt_keys_storage_alloc,BtKeysStorage*,const char* Function,+,bt_keys_storage_delete,_Bool,BtKeysStorage* Function,+,bt_keys_storage_free,void,BtKeysStorage* @@ -812,7 +825,10 @@ Function,+,bt_keys_storage_set_storage_path,void,"Bt*, const char*" Function,+,bt_keys_storage_update,_Bool,"BtKeysStorage*, uint8_t*, uint32_t" Function,+,bt_profile_restore_default,_Bool,Bt* Function,+,bt_profile_start,FuriHalBleProfileBase*,"Bt*, const FuriHalBleProfileTemplate*, FuriHalBleProfileParams" +Function,+,bt_set_settings,void,"Bt*, const BtSettings*" Function,+,bt_set_status_changed_callback,void,"Bt*, BtStatusChangedCallback, void*" +Function,+,bt_settings_load,void,BtSettings* +Function,+,bt_settings_save,void,const BtSettings* Function,+,buffered_file_stream_alloc,Stream*,Storage* Function,+,buffered_file_stream_close,_Bool,Stream* Function,+,buffered_file_stream_get_error,FS_Error,Stream* @@ -963,6 +979,13 @@ Function,+,datetime_get_days_per_year,uint16_t,uint16_t Function,+,datetime_is_leap_year,_Bool,uint16_t Function,+,datetime_timestamp_to_datetime,void,"uint32_t, DateTime*" Function,+,datetime_validate_datetime,_Bool,DateTime* +Function,+,desktop_api_get_settings,void,"Desktop*, DesktopSettings*" +Function,-,desktop_api_get_status_pubsub,FuriPubSub*,Desktop* +Function,-,desktop_api_is_locked,_Bool,Desktop* +Function,+,desktop_api_set_settings,void,"Desktop*, const DesktopSettings*" +Function,-,desktop_api_unlock,void,Desktop* +Function,+,desktop_settings_load,void,DesktopSettings* +Function,+,desktop_settings_save,void,const DesktopSettings* Function,+,dialog_ex_alloc,DialogEx*, Function,+,dialog_ex_disable_extended_events,void,DialogEx* Function,+,dialog_ex_enable_extended_events,void,DialogEx* @@ -1015,9 +1038,22 @@ Function,+,dolphin_deed_get_app,DolphinApp,DolphinDeed Function,+,dolphin_deed_get_app_limit,uint8_t,DolphinApp Function,+,dolphin_deed_get_weight,uint8_t,DolphinDeed Function,+,dolphin_flush,void,Dolphin* +Function,-,dolphin_get_level,uint8_t,uint32_t Function,+,dolphin_get_pubsub,FuriPubSub*,Dolphin* Function,+,dolphin_get_settings,void,"Dolphin*, DolphinSettings*" Function,+,dolphin_set_settings,void,"Dolphin*, DolphinSettings*" +Function,-,dolphin_state_alloc,DolphinState*, +Function,-,dolphin_state_butthurted,void,DolphinState* +Function,-,dolphin_state_clear_limits,void,DolphinState* +Function,-,dolphin_state_free,void,DolphinState* +Function,-,dolphin_state_increase_level,void,DolphinState* +Function,-,dolphin_state_is_levelup,_Bool,uint32_t +Function,-,dolphin_state_load,void,DolphinState* +Function,-,dolphin_state_on_deed,void,"DolphinState*, DolphinDeed" +Function,-,dolphin_state_save,void,DolphinState* +Function,-,dolphin_state_timestamp,uint64_t, +Function,+,dolphin_state_xp_above_last_levelup,uint32_t,uint32_t +Function,+,dolphin_state_xp_to_levelup,uint32_t,uint32_t Function,+,dolphin_stats,DolphinStats,Dolphin* Function,+,dolphin_upgrade_level,void,Dolphin* Function,-,dprintf,int,"int, const char*, ..." @@ -1090,6 +1126,8 @@ Function,+,expansion_disable,void,Expansion* Function,+,expansion_enable,void,Expansion* Function,+,expansion_is_connected,_Bool,Expansion* Function,+,expansion_set_listen_serial,void,"Expansion*, FuriHalSerialId" +Function,+,expansion_settings_load,void,ExpansionSettings* +Function,+,expansion_settings_save,void,const ExpansionSettings* Function,-,expf,float,float Function,-,expl,long double,long double Function,-,explicit_bzero,void,"void*, size_t" @@ -1658,7 +1696,7 @@ Function,+,furi_hal_rfid_tim_read_pause,void, Function,+,furi_hal_rfid_tim_read_start,void,"float, float" Function,+,furi_hal_rfid_tim_read_stop,void, Function,-,furi_hal_rtc_deinit_early,void, -Function,-,furi_hal_rtc_get_alarm,_Bool,DateTime* +Function,+,furi_hal_rtc_get_alarm,_Bool,DateTime* Function,+,furi_hal_rtc_get_boot_mode,FuriHalRtcBootMode, Function,+,furi_hal_rtc_get_datetime,void,DateTime* Function,+,furi_hal_rtc_get_fault_data,uint32_t, @@ -1670,7 +1708,7 @@ Function,+,furi_hal_rtc_get_log_baud_rate,FuriHalRtcLogBaudRate, Function,+,furi_hal_rtc_get_log_device,FuriHalRtcLogDevice, Function,+,furi_hal_rtc_get_log_level,uint8_t, Function,+,furi_hal_rtc_get_pin_fails,uint32_t, -Function,-,furi_hal_rtc_get_pin_value,uint32_t, +Function,+,furi_hal_rtc_get_pin_value,uint32_t, Function,+,furi_hal_rtc_get_register,uint32_t,FuriHalRtcRegister Function,+,furi_hal_rtc_get_timestamp,uint32_t, Function,-,furi_hal_rtc_init,void, @@ -1679,7 +1717,7 @@ Function,+,furi_hal_rtc_is_flag_set,_Bool,FuriHalRtcFlag Function,-,furi_hal_rtc_prepare_for_shutdown,void, Function,+,furi_hal_rtc_reset_flag,void,FuriHalRtcFlag Function,+,furi_hal_rtc_reset_registers,void, -Function,-,furi_hal_rtc_set_alarm,void,"const DateTime*, _Bool" +Function,+,furi_hal_rtc_set_alarm,void,"const DateTime*, _Bool" Function,-,furi_hal_rtc_set_alarm_callback,void,"FuriHalRtcAlarmCallback, void*" Function,+,furi_hal_rtc_set_boot_mode,void,FuriHalRtcBootMode Function,+,furi_hal_rtc_set_datetime,void,DateTime* @@ -1693,7 +1731,7 @@ Function,+,furi_hal_rtc_set_log_baud_rate,void,FuriHalRtcLogBaudRate Function,+,furi_hal_rtc_set_log_device,void,FuriHalRtcLogDevice Function,+,furi_hal_rtc_set_log_level,void,uint8_t Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t -Function,-,furi_hal_rtc_set_pin_value,void,uint32_t +Function,+,furi_hal_rtc_set_pin_value,void,uint32_t Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t" Function,+,furi_hal_rtc_sync_shadow,void, Function,+,furi_hal_sd_get_card_state,FuriStatus, @@ -3023,10 +3061,13 @@ Function,+,nfc_util_even_parity32,uint8_t,uint32_t Function,+,nfc_util_even_parity8,uint8_t,uint8_t Function,+,nfc_util_odd_parity,void,"const uint8_t*, uint8_t*, uint8_t" Function,+,nfc_util_odd_parity8,uint8_t,uint8_t +Function,+,night_shift_timer_start,void,NotificationApp* +Function,+,night_shift_timer_stop,void,NotificationApp* Function,+,notification_internal_message,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_internal_message_block,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_message_block,void,"NotificationApp*, const NotificationSequence*" +Function,+,notification_message_save_settings,void,NotificationApp* Function,+,notification_messages_notes_frequency_from_name,float,const char* Function,-,nrand48,long,unsigned short[3] Function,+,ntag4xx_alloc,Ntag4xxData*, @@ -3170,7 +3211,7 @@ Function,+,power_off,void,Power* Function,+,power_reboot,void,"Power*, PowerBootMode" Function,+,power_settings_load,void,PowerSettings* Function,+,power_settings_save,void,const PowerSettings* -Function,-,power_trigger_ui_update,void,Power* +Function,+,power_trigger_ui_update,void,Power* Function,+,powf,float,"float, float" Function,-,powl,long double,"long double, long double" Function,+,pretty_format_bytes_hex_canonical,void,"FuriString*, size_t, const char*, const uint8_t*, size_t" @@ -3221,6 +3262,9 @@ Function,-,putw,int,"int, FILE*" Function,-,qsort,void,"void*, size_t, size_t, __compar_fn_t" Function,-,qsort_r,void,"void*, size_t, size_t, int (*)(const void*, const void*, void*), void*" Function,-,quick_exit,void,int +Function,-,rainbow_timer_start,void,NotificationApp* +Function,+,rainbow_timer_starter,void,NotificationApp* +Function,+,rainbow_timer_stop,void,NotificationApp* Function,+,rand,int, Function,-,rand_r,int,unsigned* Function,+,random,long, @@ -3239,6 +3283,10 @@ Function,-,remquol,long double,"long double, long double, int*" Function,-,rename,int,"const char*, const char*" Function,-,renameat,int,"int, const char*, int, const char*" Function,-,rewind,void,FILE* +Function,+,rgb_backlight_get_color_count,uint8_t, +Function,+,rgb_backlight_get_color_text,const char*,uint8_t +Function,+,rgb_backlight_set_led_static_color,void,"uint8_t, uint8_t" +Function,+,rgb_backlight_update,void,float Function,-,rindex,char*,"const char*, int" Function,-,rint,double,double Function,-,rintf,float,float @@ -3293,6 +3341,7 @@ Function,+,scene_manager_stop,void,SceneManager* Function,+,sd_api_get_fs_type_text,const char*,SDFsType Function,-,secure_getenv,char*,const char* Function,-,seed48,unsigned short*,unsigned short[3] +Function,+,set_rgb_backlight_installed_variable,void,uint8_t Function,-,setbuf,void,"FILE*, char*" Function,-,setbuffer,void,"FILE*, char*, int" Function,-,setenv,int,"const char*, const char*, int" @@ -3803,6 +3852,7 @@ Function,+,text_input_set_header_text,void,"TextInput*, const char*" Function,+,text_input_set_minimum_length,void,"TextInput*, size_t" Function,+,text_input_set_result_callback,void,"TextInput*, TextInputCallback, void*, char*, size_t, _Bool" Function,+,text_input_set_validator,void,"TextInput*, TextInputValidatorCallback, void*" +Function,-,tga_save,void,const char* Function,-,tgamma,double,double Function,-,tgammaf,float,float Function,-,tgammal,long double,long double @@ -3831,10 +3881,1072 @@ Function,+,type_4_tag_reset,void,Type4TagData* Function,+,type_4_tag_save,_Bool,"const Type4TagData*, FlipperFormat*" Function,+,type_4_tag_set_uid,_Bool,"Type4TagData*, const uint8_t*, size_t" Function,+,type_4_tag_verify,_Bool,"Type4TagData*, const FuriString*" +Function,-,u8g2_AddPolygonXY,void,"u8g2_t*, int16_t, int16_t" +Function,-,u8g2_ClearBuffer,void,u8g2_t* +Function,-,u8g2_ClearDisplay,void,u8g2_t* +Function,-,u8g2_ClearPolygonXY,void, +Function,-,u8g2_DrawBitmap,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, const uint8_t*" +Function,-,u8g2_DrawBox,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" +Function,-,u8g2_DrawCircle,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, uint8_t" +Function,-,u8g2_DrawDisc,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, uint8_t" +Function,-,u8g2_DrawEllipse,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, uint8_t" +Function,-,u8g2_DrawExtUTF8,u8g2_uint_t,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, uint8_t, const uint16_t*, const char*" +Function,-,u8g2_DrawExtendedUTF8,u8g2_uint_t,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, uint8_t, u8g2_kerning_t*, const char*" +Function,-,u8g2_DrawFilledEllipse,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, uint8_t" +Function,-,u8g2_DrawFrame,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" +Function,-,u8g2_DrawGlyph,u8g2_uint_t,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, uint16_t" +Function,-,u8g2_DrawHLine,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" +Function,-,u8g2_DrawHVLine,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, uint8_t" +Function,-,u8g2_DrawHorizontalBitmap,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, const uint8_t*" +Function,-,u8g2_DrawLine,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" +Function,-,u8g2_DrawLog,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8log_t*" +Function,-,u8g2_DrawPixel,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t" +Function,-,u8g2_DrawPolygon,void,u8g2_t* +Function,-,u8g2_DrawRBox,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" +Function,-,u8g2_DrawRFrame,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" +Function,-,u8g2_DrawStr,u8g2_uint_t,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, const char*" +Function,-,u8g2_DrawTriangle,void,"u8g2_t*, int16_t, int16_t, int16_t, int16_t, int16_t, int16_t" +Function,-,u8g2_DrawUTF8,u8g2_uint_t,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, const char*" +Function,-,u8g2_DrawUTF8Line,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, const char*, uint8_t, uint8_t" +Function,-,u8g2_DrawUTF8Lines,u8g2_uint_t,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, const char*" +Function,-,u8g2_DrawVLine,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" +Function,-,u8g2_DrawXBM,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, const uint8_t*" +Function,-,u8g2_DrawXBMP,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, const uint8_t*" +Function,-,u8g2_FillBuffer,void,u8g2_t* +Function,-,u8g2_FirstPage,void,u8g2_t* +Function,-,u8g2_GetFontSize,size_t,const uint8_t* +Function,-,u8g2_GetGlyphWidth,int8_t,"u8g2_t*, uint16_t" +Function,-,u8g2_GetKerning,uint8_t,"u8g2_t*, u8g2_kerning_t*, uint16_t, uint16_t" +Function,-,u8g2_GetKerningByTable,uint8_t,"u8g2_t*, const uint16_t*, uint16_t, uint16_t" +Function,-,u8g2_GetStrWidth,u8g2_long_t,"u8g2_t*, const char*" +Function,-,u8g2_GetStrX,int8_t,"u8g2_t*, const char*" +Function,-,u8g2_GetUTF8Width,u8g2_uint_t,"u8g2_t*, const char*" +Function,-,u8g2_IsAllValidUTF8,uint8_t,"u8g2_t*, const char*" +Function,-,u8g2_IsGlyph,uint8_t,"u8g2_t*, uint16_t" +Function,-,u8g2_IsIntersection,uint8_t,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" +Function,-,u8g2_NextPage,uint8_t,u8g2_t* +Function,-,u8g2_SendBuffer,void,u8g2_t* +Function,-,u8g2_SendF,void,"u8g2_t*, const char*, ..." +Function,-,u8g2_SetBitmapMode,void,"u8g2_t*, uint8_t" +Function,-,u8g2_SetBufferCurrTileRow,void,"u8g2_t*, uint8_t" +Function,-,u8g2_SetClipWindow,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" +Function,-,u8g2_SetDisplayRotation,void,"u8g2_t*, const u8g2_cb_t*" +Function,-,u8g2_SetDrawColor,void,"u8g2_t*, uint8_t" +Function,-,u8g2_SetFont,void,"u8g2_t*, const uint8_t*" +Function,-,u8g2_SetFontDirection,void,"u8g2_t*, uint8_t" +Function,-,u8g2_SetFontMode,void,"u8g2_t*, uint8_t" +Function,-,u8g2_SetFontPosBaseline,void,u8g2_t* +Function,-,u8g2_SetFontPosBottom,void,u8g2_t* +Function,-,u8g2_SetFontPosCenter,void,u8g2_t* +Function,-,u8g2_SetFontPosTop,void,u8g2_t* +Function,-,u8g2_SetFontRefHeightAll,void,u8g2_t* +Function,-,u8g2_SetFontRefHeightExtendedText,void,u8g2_t* +Function,-,u8g2_SetFontRefHeightText,void,u8g2_t* +Function,-,u8g2_SetMaxClipWindow,void,u8g2_t* +Function,-,u8g2_SetupBitmap,void,"u8g2_t*, const u8g2_cb_t*, uint16_t, uint16_t" +Function,-,u8g2_SetupBuffer,void,"u8g2_t*, uint8_t*, uint8_t, u8g2_draw_ll_hvline_cb, const u8g2_cb_t*" +Function,-,u8g2_SetupBuffer_SDL_128x64,void,"u8g2_t*, const u8g2_cb_t*" +Function,-,u8g2_SetupBuffer_SDL_128x64_1,void,"u8g2_t*, const u8g2_cb_t*" +Function,-,u8g2_SetupBuffer_SDL_128x64_4,void,"u8g2_t*, const u8g2_cb_t*" +Function,-,u8g2_SetupBuffer_TGA_DESC,void,"u8g2_t*, const u8g2_cb_t*" +Function,-,u8g2_SetupBuffer_TGA_LCD,void,"u8g2_t*, const u8g2_cb_t*" +Function,-,u8g2_SetupBuffer_Utf8,void,"u8g2_t*, const u8g2_cb_t*" +Function,-,u8g2_Setup_a2printer_384x240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_a2printer_384x240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_a2printer_384x240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_hx1230_96x68_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_hx1230_96x68_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_hx1230_96x68_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_il3820_296x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_il3820_296x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_il3820_296x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_il3820_v2_296x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_il3820_v2_296x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_il3820_v2_296x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ist3020_erc19264_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ist3020_erc19264_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ist3020_erc19264_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ist7920_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ist7920_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ist7920_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ks0108_128x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ks0108_128x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ks0108_128x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ks0108_erm19264_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ks0108_erm19264_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ks0108_erm19264_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_lc7981_160x160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_lc7981_160x160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_lc7981_160x160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_lc7981_160x80_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_lc7981_160x80_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_lc7981_160x80_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_lc7981_240x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_lc7981_240x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_lc7981_240x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_lc7981_240x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_lc7981_240x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_lc7981_240x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ld7032_60x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ld7032_60x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ld7032_60x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ld7032_i2c_60x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ld7032_i2c_60x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ld7032_i2c_60x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ls013b7dh03_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ls013b7dh03_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ls013b7dh03_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ls013b7dh05_144x168_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ls013b7dh05_144x168_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ls013b7dh05_144x168_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ls027b7dh01_400x240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ls027b7dh01_400x240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ls027b7dh01_400x240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_max7219_32x8_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_max7219_32x8_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_max7219_32x8_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_max7219_64x8_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_max7219_64x8_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_max7219_64x8_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_max7219_8x8_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_max7219_8x8_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_max7219_8x8_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_nt7534_tg12864r_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_nt7534_tg12864r_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_nt7534_tg12864r_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_null,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_pcd8544_84x48_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_pcd8544_84x48_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_pcd8544_84x48_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_pcf8812_96x65_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_pcf8812_96x65_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_pcf8812_96x65_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ra8835_320x240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ra8835_320x240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ra8835_320x240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ra8835_nhd_240x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ra8835_nhd_240x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ra8835_nhd_240x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sbn1661_122x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sbn1661_122x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sbn1661_122x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sed1330_240x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sed1330_240x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sed1330_240x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sed1520_122x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sed1520_122x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sed1520_122x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_128x64_noname_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_128x64_noname_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_128x64_noname_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_128x64_vcomh0_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_128x64_vcomh0_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_128x64_vcomh0_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_128x64_winstar_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_128x64_winstar_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_128x64_winstar_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_64x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_64x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_64x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_72x40_wise_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_72x40_wise_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_72x40_wise_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_i2c_128x64_noname_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_i2c_128x64_noname_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_i2c_128x64_noname_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_i2c_128x64_vcomh0_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_i2c_128x64_vcomh0_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_i2c_128x64_vcomh0_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_i2c_128x64_winstar_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_i2c_128x64_winstar_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_i2c_128x64_winstar_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_i2c_64x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_i2c_64x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_i2c_64x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_i2c_72x40_wise_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_i2c_72x40_wise_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1106_i2c_72x40_wise_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_64x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_64x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_64x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_i2c_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_i2c_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_i2c_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_i2c_64x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_i2c_64x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_i2c_64x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_i2c_pimoroni_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_i2c_pimoroni_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_i2c_pimoroni_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_i2c_seeed_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_i2c_seeed_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_i2c_seeed_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_i2c_seeed_96x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_i2c_seeed_96x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_i2c_seeed_96x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_pimoroni_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_pimoroni_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_pimoroni_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_seeed_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_seeed_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_seeed_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_seeed_96x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_seeed_96x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1107_seeed_96x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1108_160x160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1108_160x160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1108_160x160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1108_i2c_160x160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1108_i2c_160x160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1108_i2c_160x160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1122_256x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1122_256x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1122_256x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1122_i2c_256x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1122_i2c_256x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_sh1122_i2c_256x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd0323_i2c_os128064_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd0323_i2c_os128064_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd0323_i2c_os128064_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd0323_os128064_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd0323_os128064_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd0323_os128064_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1305_128x32_adafruit_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1305_128x32_adafruit_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1305_128x32_adafruit_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1305_128x32_noname_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1305_128x32_noname_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1305_128x32_noname_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1305_128x64_adafruit_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1305_128x64_adafruit_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1305_128x64_adafruit_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1305_i2c_128x32_adafruit_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1305_i2c_128x32_adafruit_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1305_i2c_128x32_adafruit_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1305_i2c_128x32_noname_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1305_i2c_128x32_noname_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1305_i2c_128x32_noname_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1305_i2c_128x64_adafruit_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1305_i2c_128x64_adafruit_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1305_i2c_128x64_adafruit_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_128x32_univision_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_128x32_univision_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_128x32_univision_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_128x32_winstar_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_128x32_winstar_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_128x32_winstar_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_128x64_alt0_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_128x64_alt0_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_128x64_alt0_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_128x64_noname_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_128x64_noname_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_128x64_noname_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_128x64_vcomh0_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_128x64_vcomh0_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_128x64_vcomh0_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_48x64_winstar_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_48x64_winstar_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_48x64_winstar_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_64x32_1f_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_64x32_1f_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_64x32_1f_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_64x32_noname_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_64x32_noname_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_64x32_noname_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_64x48_er_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_64x48_er_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_64x48_er_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_72x40_er_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_72x40_er_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_72x40_er_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_96x16_er_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_96x16_er_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_96x16_er_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_128x32_univision_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_128x32_univision_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_128x32_univision_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_128x32_winstar_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_128x32_winstar_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_128x32_winstar_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_128x64_alt0_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_128x64_alt0_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_128x64_alt0_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_128x64_noname_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_128x64_noname_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_128x64_noname_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_128x64_vcomh0_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_128x64_vcomh0_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_128x64_vcomh0_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_48x64_winstar_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_48x64_winstar_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_48x64_winstar_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_64x32_1f_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_64x32_1f_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_64x32_1f_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_64x32_noname_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_64x32_noname_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_64x32_noname_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_64x48_er_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_64x48_er_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_64x48_er_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_72x40_er_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_72x40_er_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_72x40_er_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_96x16_er_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_96x16_er_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1306_i2c_96x16_er_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1309_128x64_noname0_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1309_128x64_noname0_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1309_128x64_noname0_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1309_128x64_noname2_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1309_128x64_noname2_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1309_128x64_noname2_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1309_i2c_128x64_noname0_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1309_i2c_128x64_noname0_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1309_i2c_128x64_noname0_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1309_i2c_128x64_noname2_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1309_i2c_128x64_noname2_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1309_i2c_128x64_noname2_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1316_128x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1316_128x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1316_128x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1316_i2c_128x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1316_i2c_128x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1316_i2c_128x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1317_96x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1317_96x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1317_96x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1317_i2c_96x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1317_i2c_96x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1317_i2c_96x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1318_128x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1318_128x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1318_128x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1318_128x96_xcp_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1318_128x96_xcp_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1318_128x96_xcp_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1318_i2c_128x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1318_i2c_128x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1318_i2c_128x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1318_i2c_128x96_xcp_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1318_i2c_128x96_xcp_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1318_i2c_128x96_xcp_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1322_nhd_128x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1322_nhd_128x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1322_nhd_128x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1322_nhd_256x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1322_nhd_256x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1322_nhd_256x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1325_i2c_nhd_128x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1325_i2c_nhd_128x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1325_i2c_nhd_128x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1325_nhd_128x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1325_nhd_128x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1325_nhd_128x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1326_er_256x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1326_er_256x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1326_er_256x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1326_i2c_er_256x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1326_i2c_er_256x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1326_i2c_er_256x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_ea_w128128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_ea_w128128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_ea_w128128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_i2c_ea_w128128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_i2c_ea_w128128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_i2c_ea_w128128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_i2c_midas_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_i2c_midas_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_i2c_midas_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_i2c_seeed_96x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_i2c_seeed_96x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_i2c_seeed_96x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_i2c_visionox_128x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_i2c_visionox_128x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_i2c_visionox_128x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_i2c_ws_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_i2c_ws_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_i2c_ws_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_i2c_ws_96x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_i2c_ws_96x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_i2c_ws_96x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_midas_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_midas_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_midas_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_seeed_96x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_seeed_96x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_seeed_96x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_visionox_128x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_visionox_128x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_visionox_128x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_ws_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_ws_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_ws_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_ws_96x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_ws_96x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1327_ws_96x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1329_128x96_noname_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1329_128x96_noname_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1329_128x96_noname_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1606_172x72_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1606_172x72_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1606_172x72_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1607_200x200_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1607_200x200_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1607_200x200_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1607_gd_200x200_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1607_gd_200x200_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1607_gd_200x200_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1607_ws_200x200_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1607_ws_200x200_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_ssd1607_ws_200x200_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7511_avd_320x240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7511_avd_320x240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7511_avd_320x240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx172104_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx172104_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx172104_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx19296_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx19296_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx19296_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx240160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx240160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx240160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx256128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx256128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx256128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx256160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx256160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx256160_alt_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx256160_alt_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx256160_alt_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx256160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx256160m_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx256160m_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx256160m_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx25664_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx25664_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_jlx25664_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_wo256x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_wo256x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_i2c_wo256x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx172104_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx172104_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx172104_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx19296_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx19296_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx19296_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx240160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx240160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx240160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx256128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx256128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx256128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx256160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx256160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx256160_alt_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx256160_alt_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx256160_alt_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx256160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx256160m_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx256160m_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx256160m_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx25664_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx25664_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_jlx25664_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_wo256x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_wo256x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75256_wo256x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7528_i2c_nhd_c160100_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7528_i2c_nhd_c160100_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7528_i2c_nhd_c160100_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7528_nhd_c160100_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7528_nhd_c160100_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7528_nhd_c160100_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75320_i2c_jlx320240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75320_i2c_jlx320240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75320_i2c_jlx320240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75320_jlx320240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75320_jlx320240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st75320_jlx320240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_64128n_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_64128n_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_64128n_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_ea_dogm128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_ea_dogm128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_ea_dogm128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_ea_dogm132_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_ea_dogm132_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_ea_dogm132_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_erc12864_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_erc12864_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_erc12864_alt_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_erc12864_alt_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_erc12864_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_jlx12864_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_jlx12864_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_jlx12864_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_lm6059_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_lm6059_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_lm6059_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_lm6063_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_lm6063_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_lm6063_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_lx12864_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_lx12864_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_lx12864_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_nhd_c12832_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_nhd_c12832_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_nhd_c12832_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_nhd_c12864_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_nhd_c12864_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_nhd_c12864_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_zolen_128x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_zolen_128x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7565_zolen_128x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_64x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_64x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_64x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_enh_dg128064_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_enh_dg128064_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_enh_dg128064_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_enh_dg128064i_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_enh_dg128064i_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_enh_dg128064i_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_i2c_64x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_i2c_64x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_i2c_64x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_jlx12864_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_jlx12864_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_jlx12864_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_os12864_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_os12864_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_os12864_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_pi_132x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_pi_132x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7567_pi_132x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st756x_flipper,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7586s_erc240160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7586s_erc240160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7586s_erc240160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7586s_s028hn118a_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7586s_s028hn118a_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7586s_s028hn118a_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7588_i2c_jlx12864_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7588_i2c_jlx12864_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7588_i2c_jlx12864_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7588_jlx12864_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7588_jlx12864_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7588_jlx12864_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7920_128x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7920_128x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7920_128x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7920_192x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7920_192x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7920_192x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7920_p_128x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7920_p_128x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7920_p_128x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7920_p_192x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7920_p_192x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7920_p_192x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7920_s_128x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7920_s_128x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7920_s_128x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7920_s_192x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7920_s_192x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_st7920_s_192x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_t6963_128x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_t6963_128x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_t6963_128x64_alt_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_t6963_128x64_alt_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_t6963_128x64_alt_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_t6963_128x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_t6963_160x80_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_t6963_160x80_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_t6963_160x80_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_t6963_240x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_t6963_240x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_t6963_240x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_t6963_240x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_t6963_240x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_t6963_240x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_t6963_256x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_t6963_256x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_t6963_256x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1601_128x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1601_128x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1601_128x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1601_i2c_128x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1601_i2c_128x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1601_i2c_128x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1604_i2c_jlx19264_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1604_i2c_jlx19264_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1604_i2c_jlx19264_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1604_jlx19264_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1604_jlx19264_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1604_jlx19264_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1608_240x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1608_240x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1608_240x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1608_erc240120_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1608_erc240120_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1608_erc240120_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1608_erc24064_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1608_erc24064_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1608_erc24064_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1608_i2c_240x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1608_i2c_240x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1608_i2c_240x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1608_i2c_erc240120_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1608_i2c_erc240120_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1608_i2c_erc240120_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1608_i2c_erc24064_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1608_i2c_erc24064_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1608_i2c_erc24064_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1610_ea_dogxl160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1610_ea_dogxl160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1610_ea_dogxl160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1610_i2c_ea_dogxl160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1610_i2c_ea_dogxl160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1610_i2c_ea_dogxl160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_cg160160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_cg160160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_cg160160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_ea_dogm240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_ea_dogm240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_ea_dogm240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_ea_dogxl240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_ea_dogxl240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_ea_dogxl240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_ew50850_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_ew50850_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_ew50850_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_i2c_cg160160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_i2c_cg160160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_i2c_cg160160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_i2c_ea_dogm240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_i2c_ea_dogm240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_i2c_ea_dogm240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_i2c_ea_dogxl240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_i2c_ea_dogxl240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_i2c_ea_dogxl240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_i2c_ew50850_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_i2c_ew50850_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1611_i2c_ew50850_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1638_160x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1638_160x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1638_160x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1701_ea_dogs102_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1701_ea_dogs102_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1701_ea_dogs102_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1701_mini12864_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1701_mini12864_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_Setup_uc1701_mini12864_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8g2_UpdateDisplay,void,u8g2_t* +Function,-,u8g2_UpdateDisplayArea,void,"u8g2_t*, uint8_t, uint8_t, uint8_t, uint8_t" +Function,-,u8g2_UserInterfaceInputValue,uint8_t,"u8g2_t*, const char*, const char*, uint8_t*, uint8_t, uint8_t, uint8_t, const char*" +Function,-,u8g2_UserInterfaceMessage,uint8_t,"u8g2_t*, const char*, const char*, const char*, const char*" +Function,-,u8g2_UserInterfaceSelectionList,uint8_t,"u8g2_t*, const char*, uint8_t, const char*" +Function,-,u8g2_WriteBufferPBM,void,"u8g2_t*, void (*)(const char*)" +Function,-,u8g2_WriteBufferPBM2,void,"u8g2_t*, void (*)(const char*)" +Function,-,u8g2_WriteBufferXBM,void,"u8g2_t*, void (*)(const char*)" +Function,-,u8g2_WriteBufferXBM2,void,"u8g2_t*, void (*)(const char*)" +Function,-,u8g2_add_vector_x,u8g2_uint_t,"u8g2_uint_t, int8_t, int8_t, uint8_t" +Function,-,u8g2_add_vector_y,u8g2_uint_t,"u8g2_uint_t, int8_t, int8_t, uint8_t" +Function,-,u8g2_draw_l90_r0,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, uint8_t" +Function,-,u8g2_gpio_and_delay_stm32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8g2_ll_hvline_horizontal_right_lsb,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, uint8_t" +Function,-,u8g2_ll_hvline_vertical_top_lsb,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, uint8_t" +Function,-,u8g2_m_11_6_1,uint8_t*,uint8_t* +Function,-,u8g2_m_11_6_2,uint8_t*,uint8_t* +Function,-,u8g2_m_11_6_f,uint8_t*,uint8_t* +Function,-,u8g2_m_12_12_1,uint8_t*,uint8_t* +Function,-,u8g2_m_12_12_2,uint8_t*,uint8_t* +Function,-,u8g2_m_12_12_f,uint8_t*,uint8_t* +Function,-,u8g2_m_12_2_1,uint8_t*,uint8_t* +Function,-,u8g2_m_12_2_2,uint8_t*,uint8_t* +Function,-,u8g2_m_12_2_f,uint8_t*,uint8_t* +Function,-,u8g2_m_12_8_1,uint8_t*,uint8_t* +Function,-,u8g2_m_12_8_2,uint8_t*,uint8_t* +Function,-,u8g2_m_12_8_f,uint8_t*,uint8_t* +Function,-,u8g2_m_12_9_1,uint8_t*,uint8_t* +Function,-,u8g2_m_12_9_2,uint8_t*,uint8_t* +Function,-,u8g2_m_12_9_f,uint8_t*,uint8_t* +Function,-,u8g2_m_13_8_1,uint8_t*,uint8_t* +Function,-,u8g2_m_13_8_2,uint8_t*,uint8_t* +Function,-,u8g2_m_13_8_f,uint8_t*,uint8_t* +Function,-,u8g2_m_16_12_1,uint8_t*,uint8_t* +Function,-,u8g2_m_16_12_2,uint8_t*,uint8_t* +Function,-,u8g2_m_16_12_f,uint8_t*,uint8_t* +Function,-,u8g2_m_16_16_1,uint8_t*,uint8_t* +Function,-,u8g2_m_16_16_2,uint8_t*,uint8_t* +Function,-,u8g2_m_16_16_f,uint8_t*,uint8_t* +Function,-,u8g2_m_16_4_1,uint8_t*,uint8_t* +Function,-,u8g2_m_16_4_2,uint8_t*,uint8_t* +Function,-,u8g2_m_16_4_f,uint8_t*,uint8_t* +Function,-,u8g2_m_16_8_1,uint8_t*,uint8_t* +Function,-,u8g2_m_16_8_2,uint8_t*,uint8_t* +Function,-,u8g2_m_16_8_f,uint8_t*,uint8_t* +Function,-,u8g2_m_17_4_1,uint8_t*,uint8_t* +Function,-,u8g2_m_17_4_2,uint8_t*,uint8_t* +Function,-,u8g2_m_17_4_f,uint8_t*,uint8_t* +Function,-,u8g2_m_17_8_1,uint8_t*,uint8_t* +Function,-,u8g2_m_17_8_2,uint8_t*,uint8_t* +Function,-,u8g2_m_17_8_f,uint8_t*,uint8_t* +Function,-,u8g2_m_18_21_1,uint8_t*,uint8_t* +Function,-,u8g2_m_18_21_2,uint8_t*,uint8_t* +Function,-,u8g2_m_18_21_f,uint8_t*,uint8_t* +Function,-,u8g2_m_1_1_1,uint8_t*,uint8_t* +Function,-,u8g2_m_1_1_2,uint8_t*,uint8_t* +Function,-,u8g2_m_1_1_f,uint8_t*,uint8_t* +Function,-,u8g2_m_20_10_1,uint8_t*,uint8_t* +Function,-,u8g2_m_20_10_2,uint8_t*,uint8_t* +Function,-,u8g2_m_20_10_f,uint8_t*,uint8_t* +Function,-,u8g2_m_20_13_1,uint8_t*,uint8_t* +Function,-,u8g2_m_20_13_2,uint8_t*,uint8_t* +Function,-,u8g2_m_20_13_f,uint8_t*,uint8_t* +Function,-,u8g2_m_20_16_1,uint8_t*,uint8_t* +Function,-,u8g2_m_20_16_2,uint8_t*,uint8_t* +Function,-,u8g2_m_20_16_f,uint8_t*,uint8_t* +Function,-,u8g2_m_20_20_1,uint8_t*,uint8_t* +Function,-,u8g2_m_20_20_2,uint8_t*,uint8_t* +Function,-,u8g2_m_20_20_f,uint8_t*,uint8_t* +Function,-,u8g2_m_22_13_1,uint8_t*,uint8_t* +Function,-,u8g2_m_22_13_2,uint8_t*,uint8_t* +Function,-,u8g2_m_22_13_f,uint8_t*,uint8_t* +Function,-,u8g2_m_22_9_1,uint8_t*,uint8_t* +Function,-,u8g2_m_22_9_2,uint8_t*,uint8_t* +Function,-,u8g2_m_22_9_f,uint8_t*,uint8_t* +Function,-,u8g2_m_24_12_1,uint8_t*,uint8_t* +Function,-,u8g2_m_24_12_2,uint8_t*,uint8_t* +Function,-,u8g2_m_24_12_f,uint8_t*,uint8_t* +Function,-,u8g2_m_24_4_1,uint8_t*,uint8_t* +Function,-,u8g2_m_24_4_2,uint8_t*,uint8_t* +Function,-,u8g2_m_24_4_f,uint8_t*,uint8_t* +Function,-,u8g2_m_24_8_1,uint8_t*,uint8_t* +Function,-,u8g2_m_24_8_2,uint8_t*,uint8_t* +Function,-,u8g2_m_24_8_f,uint8_t*,uint8_t* +Function,-,u8g2_m_25_25_1,uint8_t*,uint8_t* +Function,-,u8g2_m_25_25_2,uint8_t*,uint8_t* +Function,-,u8g2_m_25_25_f,uint8_t*,uint8_t* +Function,-,u8g2_m_30_15_1,uint8_t*,uint8_t* +Function,-,u8g2_m_30_15_2,uint8_t*,uint8_t* +Function,-,u8g2_m_30_15_f,uint8_t*,uint8_t* +Function,-,u8g2_m_30_16_1,uint8_t*,uint8_t* +Function,-,u8g2_m_30_16_2,uint8_t*,uint8_t* +Function,-,u8g2_m_30_16_f,uint8_t*,uint8_t* +Function,-,u8g2_m_30_20_1,uint8_t*,uint8_t* +Function,-,u8g2_m_30_20_2,uint8_t*,uint8_t* +Function,-,u8g2_m_30_20_f,uint8_t*,uint8_t* +Function,-,u8g2_m_30_8_1,uint8_t*,uint8_t* +Function,-,u8g2_m_30_8_2,uint8_t*,uint8_t* +Function,-,u8g2_m_30_8_f,uint8_t*,uint8_t* +Function,-,u8g2_m_32_16_1,uint8_t*,uint8_t* +Function,-,u8g2_m_32_16_2,uint8_t*,uint8_t* +Function,-,u8g2_m_32_16_f,uint8_t*,uint8_t* +Function,-,u8g2_m_32_20_1,uint8_t*,uint8_t* +Function,-,u8g2_m_32_20_2,uint8_t*,uint8_t* +Function,-,u8g2_m_32_20_f,uint8_t*,uint8_t* +Function,-,u8g2_m_32_4_1,uint8_t*,uint8_t* +Function,-,u8g2_m_32_4_2,uint8_t*,uint8_t* +Function,-,u8g2_m_32_4_f,uint8_t*,uint8_t* +Function,-,u8g2_m_32_8_1,uint8_t*,uint8_t* +Function,-,u8g2_m_32_8_2,uint8_t*,uint8_t* +Function,-,u8g2_m_32_8_f,uint8_t*,uint8_t* +Function,-,u8g2_m_37_16_1,uint8_t*,uint8_t* +Function,-,u8g2_m_37_16_2,uint8_t*,uint8_t* +Function,-,u8g2_m_37_16_f,uint8_t*,uint8_t* +Function,-,u8g2_m_40_30_1,uint8_t*,uint8_t* +Function,-,u8g2_m_40_30_2,uint8_t*,uint8_t* +Function,-,u8g2_m_40_30_f,uint8_t*,uint8_t* +Function,-,u8g2_m_48_17_1,uint8_t*,uint8_t* +Function,-,u8g2_m_48_17_2,uint8_t*,uint8_t* +Function,-,u8g2_m_48_17_f,uint8_t*,uint8_t* +Function,-,u8g2_m_48_30_1,uint8_t*,uint8_t* +Function,-,u8g2_m_48_30_2,uint8_t*,uint8_t* +Function,-,u8g2_m_48_30_f,uint8_t*,uint8_t* +Function,-,u8g2_m_4_1_1,uint8_t*,uint8_t* +Function,-,u8g2_m_4_1_2,uint8_t*,uint8_t* +Function,-,u8g2_m_4_1_f,uint8_t*,uint8_t* +Function,-,u8g2_m_50_30_1,uint8_t*,uint8_t* +Function,-,u8g2_m_50_30_2,uint8_t*,uint8_t* +Function,-,u8g2_m_50_30_f,uint8_t*,uint8_t* +Function,-,u8g2_m_6_8_1,uint8_t*,uint8_t* +Function,-,u8g2_m_6_8_2,uint8_t*,uint8_t* +Function,-,u8g2_m_6_8_f,uint8_t*,uint8_t* +Function,-,u8g2_m_8_16_1,uint8_t*,uint8_t* +Function,-,u8g2_m_8_16_2,uint8_t*,uint8_t* +Function,-,u8g2_m_8_16_f,uint8_t*,uint8_t* +Function,-,u8g2_m_8_1_1,uint8_t*,uint8_t* +Function,-,u8g2_m_8_1_2,uint8_t*,uint8_t* +Function,-,u8g2_m_8_1_f,uint8_t*,uint8_t* +Function,-,u8g2_m_8_4_1,uint8_t*,uint8_t* +Function,-,u8g2_m_8_4_2,uint8_t*,uint8_t* +Function,-,u8g2_m_8_4_f,uint8_t*,uint8_t* +Function,-,u8g2_m_8_6_1,uint8_t*,uint8_t* +Function,-,u8g2_m_8_6_2,uint8_t*,uint8_t* +Function,-,u8g2_m_8_6_f,uint8_t*,uint8_t* +Function,-,u8g2_m_9_5_1,uint8_t*,uint8_t* +Function,-,u8g2_m_9_5_2,uint8_t*,uint8_t* +Function,-,u8g2_m_9_5_f,uint8_t*,uint8_t* +Function,-,u8g_sdl_get_key,int, +Function,-,u8log_Init,void,"u8log_t*, uint8_t, uint8_t, uint8_t*" +Function,-,u8log_SetCallback,void,"u8log_t*, u8log_cb, void*" +Function,-,u8log_SetLineHeightOffset,void,"u8log_t*, int8_t" +Function,-,u8log_SetRedrawMode,void,"u8log_t*, uint8_t" +Function,-,u8log_WriteChar,void,"u8log_t*, uint8_t" +Function,-,u8log_WriteDec16,void,"u8log_t*, uint16_t, uint8_t" +Function,-,u8log_WriteDec8,void,"u8log_t*, uint8_t, uint8_t" +Function,-,u8log_WriteHex16,void,"u8log_t*, uint16_t" +Function,-,u8log_WriteHex32,void,"u8log_t*, uint32_t" +Function,-,u8log_WriteHex8,void,"u8log_t*, uint8_t" +Function,-,u8log_WriteString,void,"u8log_t*, const char*" +Function,-,u8log_u8g2_cb,void,u8log_t* +Function,-,u8log_u8x8_cb,void,u8log_t* +Function,-,u8sl_Next,void,u8sl_t* +Function,-,u8sl_Prev,void,u8sl_t* +Function,-,u8x8_ClearDisplay,void,u8x8_t* +Function,-,u8x8_ClearDisplayWithTile,void,"u8x8_t*, const uint8_t*" +Function,-,u8x8_ClearLine,void,"u8x8_t*, uint8_t" +Function,-,u8x8_ConnectBitmapToU8x8,uint8_t,u8x8_t* +Function,-,u8x8_CopyStringLine,void,"char*, uint8_t, const char*" +Function,-,u8x8_Draw1x2Glyph,void,"u8x8_t*, uint8_t, uint8_t, uint8_t" +Function,-,u8x8_Draw1x2String,uint8_t,"u8x8_t*, uint8_t, uint8_t, const char*" +Function,-,u8x8_Draw1x2UTF8,uint8_t,"u8x8_t*, uint8_t, uint8_t, const char*" +Function,-,u8x8_Draw2x2Glyph,void,"u8x8_t*, uint8_t, uint8_t, uint8_t" +Function,-,u8x8_Draw2x2String,uint8_t,"u8x8_t*, uint8_t, uint8_t, const char*" +Function,-,u8x8_Draw2x2UTF8,uint8_t,"u8x8_t*, uint8_t, uint8_t, const char*" +Function,-,u8x8_DrawGlyph,void,"u8x8_t*, uint8_t, uint8_t, uint8_t" +Function,-,u8x8_DrawLog,void,"u8x8_t*, uint8_t, uint8_t, u8log_t*" +Function,-,u8x8_DrawString,uint8_t,"u8x8_t*, uint8_t, uint8_t, const char*" +Function,-,u8x8_DrawTile,uint8_t,"u8x8_t*, uint8_t, uint8_t, uint8_t, uint8_t*" +Function,-,u8x8_DrawUTF8,uint8_t,"u8x8_t*, uint8_t, uint8_t, const char*" +Function,-,u8x8_DrawUTF8Line,uint8_t,"u8x8_t*, uint8_t, uint8_t, uint8_t, const char*" +Function,-,u8x8_DrawUTF8Lines,uint8_t,"u8x8_t*, uint8_t, uint8_t, uint8_t, const char*" +Function,-,u8x8_FillDisplay,void,u8x8_t* +Function,-,u8x8_GetBitmapPixel,uint8_t,"u8x8_t*, uint16_t, uint16_t" +Function,-,u8x8_GetMenuEvent,uint8_t,u8x8_t* +Function,-,u8x8_GetStringLineCnt,uint8_t,const char* +Function,-,u8x8_GetStringLineStart,const char*,"uint8_t, const char*" +Function,-,u8x8_GetUTF8Len,uint8_t,"u8x8_t*, const char*" +Function,-,u8x8_InitDisplay,void,u8x8_t* +Function,-,u8x8_RefreshDisplay,void,u8x8_t* +Function,-,u8x8_SaveBitmapTGA,void,"u8x8_t*, const char*" +Function,-,u8x8_SendF,void,"u8x8_t*, const char*, ..." +Function,-,u8x8_SetContrast,void,"u8x8_t*, uint8_t" +Function,-,u8x8_SetFlipMode,void,"u8x8_t*, uint8_t" +Function,-,u8x8_SetFont,void,"u8x8_t*, const uint8_t*" +Function,-,u8x8_SetPowerSave,void,"u8x8_t*, uint8_t" +Function,-,u8x8_Setup,void,"u8x8_t*, u8x8_msg_cb, u8x8_msg_cb, u8x8_msg_cb, u8x8_msg_cb" +Function,-,u8x8_SetupBitmap,void,"u8x8_t*, uint16_t, uint16_t" +Function,-,u8x8_SetupDefaults,void,u8x8_t* +Function,-,u8x8_SetupMemory,void,u8x8_t* +Function,-,u8x8_SetupStdio,void,u8x8_t* +Function,-,u8x8_Setup_SDL_128x64,void,u8x8_t* +Function,-,u8x8_Setup_SDL_240x160,void,u8x8_t* +Function,-,u8x8_Setup_TGA_DESC,void,u8x8_t* +Function,-,u8x8_Setup_TGA_LCD,void,u8x8_t* +Function,-,u8x8_Setup_Utf8,void,u8x8_t* +Function,-,u8x8_UserInterfaceInputValue,uint8_t,"u8x8_t*, const char*, const char*, uint8_t*, uint8_t, uint8_t, uint8_t, const char*" +Function,-,u8x8_UserInterfaceMessage,uint8_t,"u8x8_t*, const char*, const char*, const char*, const char*" +Function,-,u8x8_UserInterfaceSelectionList,uint8_t,"u8x8_t*, const char*, uint8_t, const char*" +Function,-,u8x8_ascii_next,uint16_t,"u8x8_t*, uint8_t" +Function,-,u8x8_byte_3wire_sw_spi,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_byte_4wire_sw_spi,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_byte_8bit_6800mode,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_byte_8bit_8080mode,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_byte_EndTransfer,uint8_t,u8x8_t* +Function,-,u8x8_byte_SendByte,uint8_t,"u8x8_t*, uint8_t" +Function,-,u8x8_byte_SendBytes,uint8_t,"u8x8_t*, uint8_t, uint8_t*" +Function,-,u8x8_byte_SetDC,uint8_t,"u8x8_t*, uint8_t" +Function,-,u8x8_byte_StartTransfer,uint8_t,u8x8_t* +Function,-,u8x8_byte_empty,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_byte_ks0108,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_byte_sed1520,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_byte_set_ks0108_cs,void,"u8x8_t*, uint8_t" +Function,-,u8x8_byte_ssd13xx_sw_i2c,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_byte_sw_i2c,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_cad_001,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_cad_011,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_cad_100,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_cad_110,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_cad_EndTransfer,uint8_t,u8x8_t* +Function,-,u8x8_cad_SendArg,uint8_t,"u8x8_t*, uint8_t" +Function,-,u8x8_cad_SendCmd,uint8_t,"u8x8_t*, uint8_t" +Function,-,u8x8_cad_SendData,uint8_t,"u8x8_t*, uint8_t, uint8_t*" +Function,-,u8x8_cad_SendMultipleArg,uint8_t,"u8x8_t*, uint8_t, uint8_t" +Function,-,u8x8_cad_SendSequence,void,"u8x8_t*, const uint8_t*" +Function,-,u8x8_cad_StartTransfer,uint8_t,u8x8_t* +Function,-,u8x8_cad_empty,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_cad_ld7032_i2c,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_cad_ssd13xx_fast_i2c,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_cad_ssd13xx_i2c,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_cad_st75256_i2c,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_cad_st7920_spi,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_cad_uc16xx_i2c,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_cad_vsendf,void,"u8x8_t*, const char*, va_list" +Function,-,u8x8_capture_get_pixel_1,uint8_t,"uint16_t, uint16_t, uint8_t*, uint8_t" +Function,-,u8x8_capture_get_pixel_2,uint8_t,"uint16_t, uint16_t, uint8_t*, uint8_t" +Function,-,u8x8_capture_write_pbm_buffer,void,"uint8_t*, uint8_t, uint8_t, uint8_t (*)(uint16_t, uint16_t, uint8_t*, uint8_t), void (*)(const char*)" +Function,-,u8x8_capture_write_pbm_pre,void,"uint8_t, uint8_t, void (*)(const char*)" +Function,-,u8x8_capture_write_xbm_buffer,void,"uint8_t*, uint8_t, uint8_t, uint8_t (*)(uint16_t, uint16_t, uint8_t*, uint8_t), void (*)(const char*)" +Function,-,u8x8_capture_write_xbm_pre,void,"uint8_t, uint8_t, void (*)(const char*)" +Function,-,u8x8_d_a2printer_384x240,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_helper_display_init,void,u8x8_t* +Function,-,u8x8_d_helper_display_setup_memory,void,"u8x8_t*, const u8x8_display_info_t*" +Function,-,u8x8_d_hx1230_96x68,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_il3820_296x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_il3820_v2_296x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ist3020_erc19264,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ist7920_128x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ks0108_128x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ks0108_erm19264,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_lc7981_160x160,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_lc7981_160x80,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_lc7981_240x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_lc7981_240x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ld7032_60x32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ls013b7dh03_128x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ls013b7dh05_144x168,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ls027b7dh01_400x240,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_max7219_16x16,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_max7219_32x8,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_max7219_64x8,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_max7219_8x8,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_nt7534_tg12864r,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_null_cb,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_pcd8544_84x48,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_pcf8812_96x65,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ra8835_320x240,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ra8835_nhd_240x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_sbn1661_122x32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_sed1330_240x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_sed1520_122x32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_sh1106_128x64_noname,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_sh1106_128x64_vcomh0,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_sh1106_128x64_winstar,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_sh1106_64x32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_sh1106_72x40_wise,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_sh1107_128x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_sh1107_64x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_sh1107_pimoroni_128x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_sh1107_seeed_128x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_sh1107_seeed_96x96,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_sh1108_160x160,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_sh1122_256x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd0323_os128064,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1305_128x32_adafruit,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1305_128x32_noname,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1305_128x64_adafruit,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1306_128x32_univision,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1306_128x32_winstar,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1306_128x64_alt0,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1306_128x64_noname,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1306_128x64_vcomh0,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1306_48x64_winstar,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1306_64x32_1f,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1306_64x32_noname,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1306_64x48_er,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1306_72x40_er,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1306_96x16_er,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1309_128x64_noname0,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1309_128x64_noname2,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1316_128x32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1317_96x96,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1318_128x96,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1318_128x96_xcp,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1322_nhd_128x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1322_nhd_256x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1325_nhd_128x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1326_er_256x32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1327_ea_w128128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1327_midas_128x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1327_seeed_96x96,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1327_visionox_128x96,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1327_ws_128x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1327_ws_96x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1329_128x96_noname,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1606_172x72,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1607_200x200,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1607_gd_200x200,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1607_v2_200x200,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_ssd1607_ws_200x200,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7511_avd_320x240,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st75256_jlx172104,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st75256_jlx19296,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st75256_jlx240160,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st75256_jlx256128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st75256_jlx256160,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st75256_jlx256160_alt,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st75256_jlx256160m,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st75256_jlx25664,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st75256_wo256x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7528_nhd_c160100,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st75320_jlx320240,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7565_64128n,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7565_ea_dogm128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7565_ea_dogm132,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7565_erc12864,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7565_erc12864_alt,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7565_jlx12864,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7565_lm6059,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7565_lm6063,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7565_lx12864,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7565_nhd_c12832,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7565_nhd_c12864,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7565_zolen_128x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7567_64x32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7567_enh_dg128064,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7567_enh_dg128064i,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7567_jlx12864,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7567_os12864,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7567_pi_132x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st756x_init,void,"u8x8_t*, uint8_t, uint8_t, _Bool" +Function,-,u8x8_d_st756x_set_contrast,void,"u8x8_t*, int8_t" +Function,+,u8x8_d_st756x_set_inversion,void,"u8x8_t*, _Bool" +Function,-,u8x8_d_st7586s_erc240160,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7586s_s028hn118a,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7588_jlx12864,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7920_128x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_st7920_192x32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_t6963_128x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_t6963_128x64_alt,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_t6963_160x80,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_t6963_240x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_t6963_240x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_t6963_256x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_uc1601_128x32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_uc1604_jlx19264,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_uc1608_240x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_uc1608_erc240120,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_uc1608_erc24064,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_uc1610_ea_dogxl160,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_uc1611_cg160160,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_uc1611_ea_dogm240,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_uc1611_ea_dogxl240,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_uc1611_ew50850,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_uc1617_jlx128128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_uc1638_160x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_uc1701_ea_dogs102,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_d_uc1701_mini12864,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_dummy_cb,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_gpio_call,void,"u8x8_t*, uint8_t, uint8_t" +Function,-,u8x8_hw_spi_stm32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" +Function,-,u8x8_u16toa,const char*,"uint16_t, uint8_t" +Function,-,u8x8_u8toa,const char*,"uint8_t, uint8_t" +Function,-,u8x8_upscale_byte,uint16_t,uint8_t +Function,-,u8x8_utf8_init,void,u8x8_t* +Function,-,u8x8_utf8_next,uint16_t,"u8x8_t*, uint8_t" +Function,-,u8x8_utoa,const char*,uint16_t Function,+,uint8_to_hex_chars,void,"const uint8_t*, uint8_t*, int" Function,-,ungetc,int,"int, FILE*" Function,-,unsetenv,int,const char* Function,-,usbd_poll,void,usbd_device* +Function,-,utf8_show,void, Function,-,utoa,char*,"unsigned, char*, int" Function,+,validator_is_file_alloc_init,ValidatorIsFile*,"const char*, const char*, const char*" Function,+,validator_is_file_callback,_Bool,"const char*, FuriString*, void*" @@ -3983,6 +5095,24 @@ Function,-,yn,double,"int, double" Function,-,ynf,float,"int, float" Variable,-,AHBPrescTable,const uint32_t[16], Variable,-,APBPrescTable,const uint32_t[8], +Variable,+,FLIPPER_APPS,const FlipperInternalApplication[], +Variable,+,FLIPPER_APPS_COUNT,const size_t, +Variable,-,FLIPPER_ARCHIVE,const FlipperInternalApplication, +Variable,-,FLIPPER_AUTORUN_APP_NAME,const char*, +Variable,-,FLIPPER_DEBUG_APPS,const FlipperInternalApplication[], +Variable,-,FLIPPER_DEBUG_APPS_COUNT,const size_t, +Variable,+,FLIPPER_EXTERNAL_APPS,const FlipperExternalApplication[], +Variable,+,FLIPPER_EXTERNAL_APPS_COUNT,const size_t, +Variable,-,FLIPPER_EXTSETTINGS_APPS,const FlipperExternalApplication[], +Variable,-,FLIPPER_EXTSETTINGS_APPS_COUNT,const size_t, +Variable,-,FLIPPER_ON_SYSTEM_START,const FlipperInternalOnStartHook[], +Variable,-,FLIPPER_ON_SYSTEM_START_COUNT,const size_t, +Variable,-,FLIPPER_SERVICES,const FlipperInternalApplication[], +Variable,-,FLIPPER_SERVICES_COUNT,const size_t, +Variable,-,FLIPPER_SETTINGS_APPS,const FlipperInternalApplication[], +Variable,-,FLIPPER_SETTINGS_APPS_COUNT,const size_t, +Variable,-,FLIPPER_SYSTEM_APPS,const FlipperInternalApplication[], +Variable,-,FLIPPER_SYSTEM_APPS_COUNT,const size_t, Variable,-,ITM_RxBuffer,volatile int32_t, Variable,-,MSIRangeTable,const uint32_t[16], Variable,-,SmpsPrescalerTable,const uint32_t[4][6], @@ -4291,6 +5421,1831 @@ Variable,+,subghz_protocol_raw_decoder,const SubGhzProtocolDecoder, Variable,+,subghz_protocol_raw_encoder,const SubGhzProtocolEncoder, Variable,+,subghz_protocol_registry,const SubGhzProtocolRegistry, Variable,-,suboptarg,char*, +Variable,-,u8g2_cb_mirror,const u8g2_cb_t, +Variable,-,u8g2_cb_r0,const u8g2_cb_t, +Variable,-,u8g2_cb_r1,const u8g2_cb_t, +Variable,-,u8g2_cb_r2,const u8g2_cb_t, +Variable,-,u8g2_cb_r3,const u8g2_cb_t, +Variable,-,u8g2_font_10x20_me,const uint8_t[], +Variable,-,u8g2_font_10x20_mf,const uint8_t[], +Variable,-,u8g2_font_10x20_mn,const uint8_t[], +Variable,-,u8g2_font_10x20_mr,const uint8_t[], +Variable,-,u8g2_font_10x20_t_arabic,const uint8_t[], +Variable,-,u8g2_font_10x20_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_10x20_t_greek,const uint8_t[], +Variable,-,u8g2_font_10x20_te,const uint8_t[], +Variable,-,u8g2_font_10x20_tf,const uint8_t[], +Variable,-,u8g2_font_10x20_tn,const uint8_t[], +Variable,-,u8g2_font_10x20_tr,const uint8_t[], +Variable,-,u8g2_font_4x6_mf,const uint8_t[], +Variable,-,u8g2_font_4x6_mn,const uint8_t[], +Variable,-,u8g2_font_4x6_mr,const uint8_t[], +Variable,-,u8g2_font_4x6_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_4x6_tf,const uint8_t[], +Variable,-,u8g2_font_4x6_tn,const uint8_t[], +Variable,-,u8g2_font_4x6_tr,const uint8_t[], +Variable,-,u8g2_font_5x7_mf,const uint8_t[], +Variable,-,u8g2_font_5x7_mn,const uint8_t[], +Variable,-,u8g2_font_5x7_mr,const uint8_t[], +Variable,-,u8g2_font_5x7_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_5x7_tf,const uint8_t[], +Variable,-,u8g2_font_5x7_tn,const uint8_t[], +Variable,-,u8g2_font_5x7_tr,const uint8_t[], +Variable,-,u8g2_font_5x8_mf,const uint8_t[], +Variable,-,u8g2_font_5x8_mn,const uint8_t[], +Variable,-,u8g2_font_5x8_mr,const uint8_t[], +Variable,-,u8g2_font_5x8_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_5x8_tf,const uint8_t[], +Variable,-,u8g2_font_5x8_tn,const uint8_t[], +Variable,-,u8g2_font_5x8_tr,const uint8_t[], +Variable,-,u8g2_font_6x10_mf,const uint8_t[], +Variable,-,u8g2_font_6x10_mn,const uint8_t[], +Variable,-,u8g2_font_6x10_mr,const uint8_t[], +Variable,-,u8g2_font_6x10_tf,const uint8_t[], +Variable,-,u8g2_font_6x10_tn,const uint8_t[], +Variable,-,u8g2_font_6x10_tr,const uint8_t[], +Variable,-,u8g2_font_6x12_m_symbols,const uint8_t[], +Variable,-,u8g2_font_6x12_me,const uint8_t[], +Variable,-,u8g2_font_6x12_mf,const uint8_t[], +Variable,-,u8g2_font_6x12_mn,const uint8_t[], +Variable,-,u8g2_font_6x12_mr,const uint8_t[], +Variable,-,u8g2_font_6x12_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_6x12_t_symbols,const uint8_t[], +Variable,-,u8g2_font_6x12_te,const uint8_t[], +Variable,-,u8g2_font_6x12_tf,const uint8_t[], +Variable,-,u8g2_font_6x12_tn,const uint8_t[], +Variable,-,u8g2_font_6x12_tr,const uint8_t[], +Variable,-,u8g2_font_6x13B_mf,const uint8_t[], +Variable,-,u8g2_font_6x13B_mn,const uint8_t[], +Variable,-,u8g2_font_6x13B_mr,const uint8_t[], +Variable,-,u8g2_font_6x13B_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_6x13B_t_hebrew,const uint8_t[], +Variable,-,u8g2_font_6x13B_tf,const uint8_t[], +Variable,-,u8g2_font_6x13B_tn,const uint8_t[], +Variable,-,u8g2_font_6x13B_tr,const uint8_t[], +Variable,-,u8g2_font_6x13O_mf,const uint8_t[], +Variable,-,u8g2_font_6x13O_mn,const uint8_t[], +Variable,-,u8g2_font_6x13O_mr,const uint8_t[], +Variable,-,u8g2_font_6x13O_tf,const uint8_t[], +Variable,-,u8g2_font_6x13O_tn,const uint8_t[], +Variable,-,u8g2_font_6x13O_tr,const uint8_t[], +Variable,-,u8g2_font_6x13_me,const uint8_t[], +Variable,-,u8g2_font_6x13_mf,const uint8_t[], +Variable,-,u8g2_font_6x13_mn,const uint8_t[], +Variable,-,u8g2_font_6x13_mr,const uint8_t[], +Variable,-,u8g2_font_6x13_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_6x13_t_hebrew,const uint8_t[], +Variable,-,u8g2_font_6x13_te,const uint8_t[], +Variable,-,u8g2_font_6x13_tf,const uint8_t[], +Variable,-,u8g2_font_6x13_tn,const uint8_t[], +Variable,-,u8g2_font_6x13_tr,const uint8_t[], +Variable,-,u8g2_font_7Segments_26x42_mn,const uint8_t[], +Variable,-,u8g2_font_7x13B_mf,const uint8_t[], +Variable,-,u8g2_font_7x13B_mn,const uint8_t[], +Variable,-,u8g2_font_7x13B_mr,const uint8_t[], +Variable,-,u8g2_font_7x13B_tf,const uint8_t[], +Variable,-,u8g2_font_7x13B_tn,const uint8_t[], +Variable,-,u8g2_font_7x13B_tr,const uint8_t[], +Variable,-,u8g2_font_7x13O_mf,const uint8_t[], +Variable,-,u8g2_font_7x13O_mn,const uint8_t[], +Variable,-,u8g2_font_7x13O_mr,const uint8_t[], +Variable,-,u8g2_font_7x13O_tf,const uint8_t[], +Variable,-,u8g2_font_7x13O_tn,const uint8_t[], +Variable,-,u8g2_font_7x13O_tr,const uint8_t[], +Variable,-,u8g2_font_7x13_m_symbols,const uint8_t[], +Variable,-,u8g2_font_7x13_me,const uint8_t[], +Variable,-,u8g2_font_7x13_mf,const uint8_t[], +Variable,-,u8g2_font_7x13_mn,const uint8_t[], +Variable,-,u8g2_font_7x13_mr,const uint8_t[], +Variable,-,u8g2_font_7x13_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_7x13_t_symbols,const uint8_t[], +Variable,-,u8g2_font_7x13_te,const uint8_t[], +Variable,-,u8g2_font_7x13_tf,const uint8_t[], +Variable,-,u8g2_font_7x13_tn,const uint8_t[], +Variable,-,u8g2_font_7x13_tr,const uint8_t[], +Variable,-,u8g2_font_7x14B_mf,const uint8_t[], +Variable,-,u8g2_font_7x14B_mn,const uint8_t[], +Variable,-,u8g2_font_7x14B_mr,const uint8_t[], +Variable,-,u8g2_font_7x14B_tf,const uint8_t[], +Variable,-,u8g2_font_7x14B_tn,const uint8_t[], +Variable,-,u8g2_font_7x14B_tr,const uint8_t[], +Variable,-,u8g2_font_7x14_mf,const uint8_t[], +Variable,-,u8g2_font_7x14_mn,const uint8_t[], +Variable,-,u8g2_font_7x14_mr,const uint8_t[], +Variable,-,u8g2_font_7x14_tf,const uint8_t[], +Variable,-,u8g2_font_7x14_tn,const uint8_t[], +Variable,-,u8g2_font_7x14_tr,const uint8_t[], +Variable,-,u8g2_font_8x13B_mf,const uint8_t[], +Variable,-,u8g2_font_8x13B_mn,const uint8_t[], +Variable,-,u8g2_font_8x13B_mr,const uint8_t[], +Variable,-,u8g2_font_8x13B_tf,const uint8_t[], +Variable,-,u8g2_font_8x13B_tn,const uint8_t[], +Variable,-,u8g2_font_8x13B_tr,const uint8_t[], +Variable,-,u8g2_font_8x13O_mf,const uint8_t[], +Variable,-,u8g2_font_8x13O_mn,const uint8_t[], +Variable,-,u8g2_font_8x13O_mr,const uint8_t[], +Variable,-,u8g2_font_8x13O_tf,const uint8_t[], +Variable,-,u8g2_font_8x13O_tn,const uint8_t[], +Variable,-,u8g2_font_8x13O_tr,const uint8_t[], +Variable,-,u8g2_font_8x13_m_symbols,const uint8_t[], +Variable,-,u8g2_font_8x13_me,const uint8_t[], +Variable,-,u8g2_font_8x13_mf,const uint8_t[], +Variable,-,u8g2_font_8x13_mn,const uint8_t[], +Variable,-,u8g2_font_8x13_mr,const uint8_t[], +Variable,-,u8g2_font_8x13_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_8x13_t_symbols,const uint8_t[], +Variable,-,u8g2_font_8x13_te,const uint8_t[], +Variable,-,u8g2_font_8x13_tf,const uint8_t[], +Variable,-,u8g2_font_8x13_tn,const uint8_t[], +Variable,-,u8g2_font_8x13_tr,const uint8_t[], +Variable,-,u8g2_font_9x15B_mf,const uint8_t[], +Variable,-,u8g2_font_9x15B_mn,const uint8_t[], +Variable,-,u8g2_font_9x15B_mr,const uint8_t[], +Variable,-,u8g2_font_9x15B_tf,const uint8_t[], +Variable,-,u8g2_font_9x15B_tn,const uint8_t[], +Variable,-,u8g2_font_9x15B_tr,const uint8_t[], +Variable,-,u8g2_font_9x15_m_symbols,const uint8_t[], +Variable,-,u8g2_font_9x15_me,const uint8_t[], +Variable,-,u8g2_font_9x15_mf,const uint8_t[], +Variable,-,u8g2_font_9x15_mn,const uint8_t[], +Variable,-,u8g2_font_9x15_mr,const uint8_t[], +Variable,-,u8g2_font_9x15_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_9x15_t_symbols,const uint8_t[], +Variable,-,u8g2_font_9x15_te,const uint8_t[], +Variable,-,u8g2_font_9x15_tf,const uint8_t[], +Variable,-,u8g2_font_9x15_tn,const uint8_t[], +Variable,-,u8g2_font_9x15_tr,const uint8_t[], +Variable,-,u8g2_font_9x18B_mf,const uint8_t[], +Variable,-,u8g2_font_9x18B_mn,const uint8_t[], +Variable,-,u8g2_font_9x18B_mr,const uint8_t[], +Variable,-,u8g2_font_9x18B_tf,const uint8_t[], +Variable,-,u8g2_font_9x18B_tn,const uint8_t[], +Variable,-,u8g2_font_9x18B_tr,const uint8_t[], +Variable,-,u8g2_font_9x18_mf,const uint8_t[], +Variable,-,u8g2_font_9x18_mn,const uint8_t[], +Variable,-,u8g2_font_9x18_mr,const uint8_t[], +Variable,-,u8g2_font_9x18_tf,const uint8_t[], +Variable,-,u8g2_font_9x18_tn,const uint8_t[], +Variable,-,u8g2_font_9x18_tr,const uint8_t[], +Variable,-,u8g2_font_BBSesque_te,const uint8_t[], +Variable,-,u8g2_font_BBSesque_tf,const uint8_t[], +Variable,-,u8g2_font_BBSesque_tr,const uint8_t[], +Variable,-,u8g2_font_BitTypeWriter_te,const uint8_t[], +Variable,-,u8g2_font_BitTypeWriter_tr,const uint8_t[], +Variable,-,u8g2_font_Born2bSportySlab_t_all,const uint8_t[], +Variable,-,u8g2_font_Born2bSportySlab_te,const uint8_t[], +Variable,-,u8g2_font_Born2bSportySlab_tf,const uint8_t[], +Variable,-,u8g2_font_Born2bSportySlab_tr,const uint8_t[], +Variable,-,u8g2_font_Born2bSportyV2_te,const uint8_t[], +Variable,-,u8g2_font_Born2bSportyV2_tf,const uint8_t[], +Variable,-,u8g2_font_Born2bSportyV2_tr,const uint8_t[], +Variable,-,u8g2_font_CursivePixel_tr,const uint8_t[], +Variable,-,u8g2_font_DigitalDiscoThin_te,const uint8_t[], +Variable,-,u8g2_font_DigitalDiscoThin_tf,const uint8_t[], +Variable,-,u8g2_font_DigitalDiscoThin_tn,const uint8_t[], +Variable,-,u8g2_font_DigitalDiscoThin_tr,const uint8_t[], +Variable,-,u8g2_font_DigitalDiscoThin_tu,const uint8_t[], +Variable,-,u8g2_font_DigitalDisco_te,const uint8_t[], +Variable,-,u8g2_font_DigitalDisco_tf,const uint8_t[], +Variable,-,u8g2_font_DigitalDisco_tn,const uint8_t[], +Variable,-,u8g2_font_DigitalDisco_tr,const uint8_t[], +Variable,-,u8g2_font_DigitalDisco_tu,const uint8_t[], +Variable,-,u8g2_font_Engrish_tf,const uint8_t[], +Variable,-,u8g2_font_Engrish_tr,const uint8_t[], +Variable,-,u8g2_font_Georgia7px_te,const uint8_t[], +Variable,-,u8g2_font_Georgia7px_tf,const uint8_t[], +Variable,-,u8g2_font_Georgia7px_tr,const uint8_t[], +Variable,-,u8g2_font_HelvetiPixelOutline_te,const uint8_t[], +Variable,-,u8g2_font_HelvetiPixelOutline_tr,const uint8_t[], +Variable,-,u8g2_font_HelvetiPixel_tr,const uint8_t[], +Variable,-,u8g2_font_IPAandRUSLCD_te,const uint8_t[], +Variable,-,u8g2_font_IPAandRUSLCD_tf,const uint8_t[], +Variable,-,u8g2_font_IPAandRUSLCD_tr,const uint8_t[], +Variable,-,u8g2_font_ImpactBits_tr,const uint8_t[], +Variable,-,u8g2_font_Pixellari_te,const uint8_t[], +Variable,-,u8g2_font_Pixellari_tf,const uint8_t[], +Variable,-,u8g2_font_Pixellari_tn,const uint8_t[], +Variable,-,u8g2_font_Pixellari_tr,const uint8_t[], +Variable,-,u8g2_font_Pixellari_tu,const uint8_t[], +Variable,-,u8g2_font_TimesNewPixel_tr,const uint8_t[], +Variable,-,u8g2_font_Untitled16PixelSansSerifBitmap_tr,const uint8_t[], +Variable,-,u8g2_font_VCR_OSD_mf,const uint8_t[], +Variable,-,u8g2_font_VCR_OSD_mn,const uint8_t[], +Variable,-,u8g2_font_VCR_OSD_mr,const uint8_t[], +Variable,-,u8g2_font_VCR_OSD_mu,const uint8_t[], +Variable,-,u8g2_font_VCR_OSD_tf,const uint8_t[], +Variable,-,u8g2_font_VCR_OSD_tn,const uint8_t[], +Variable,-,u8g2_font_VCR_OSD_tr,const uint8_t[], +Variable,-,u8g2_font_VCR_OSD_tu,const uint8_t[], +Variable,-,u8g2_font_Wizzard_tr,const uint8_t[], +Variable,-,u8g2_font_adventurer_t_all,const uint8_t[], +Variable,-,u8g2_font_adventurer_tf,const uint8_t[], +Variable,-,u8g2_font_adventurer_tr,const uint8_t[], +Variable,-,u8g2_font_amstrad_cpc_extended_8f,const uint8_t[], +Variable,-,u8g2_font_amstrad_cpc_extended_8n,const uint8_t[], +Variable,-,u8g2_font_amstrad_cpc_extended_8r,const uint8_t[], +Variable,-,u8g2_font_amstrad_cpc_extended_8u,const uint8_t[], +Variable,-,u8g2_font_artossans8_8n,const uint8_t[], +Variable,-,u8g2_font_artossans8_8r,const uint8_t[], +Variable,-,u8g2_font_artossans8_8u,const uint8_t[], +Variable,-,u8g2_font_artosserif8_8n,const uint8_t[], +Variable,-,u8g2_font_artosserif8_8r,const uint8_t[], +Variable,-,u8g2_font_artosserif8_8u,const uint8_t[], +Variable,-,u8g2_font_astragal_nbp_tf,const uint8_t[], +Variable,-,u8g2_font_astragal_nbp_tn,const uint8_t[], +Variable,-,u8g2_font_astragal_nbp_tr,const uint8_t[], +Variable,-,u8g2_font_b10_b_t_japanese1,const uint8_t[], +Variable,-,u8g2_font_b10_b_t_japanese2,const uint8_t[], +Variable,-,u8g2_font_b10_t_japanese1,const uint8_t[], +Variable,-,u8g2_font_b10_t_japanese2,const uint8_t[], +Variable,-,u8g2_font_b12_b_t_japanese1,const uint8_t[], +Variable,-,u8g2_font_b12_b_t_japanese2,const uint8_t[], +Variable,-,u8g2_font_b12_b_t_japanese3,const uint8_t[], +Variable,-,u8g2_font_b12_t_japanese1,const uint8_t[], +Variable,-,u8g2_font_b12_t_japanese2,const uint8_t[], +Variable,-,u8g2_font_b12_t_japanese3,const uint8_t[], +Variable,-,u8g2_font_b16_b_t_japanese1,const uint8_t[], +Variable,-,u8g2_font_b16_b_t_japanese2,const uint8_t[], +Variable,-,u8g2_font_b16_b_t_japanese3,const uint8_t[], +Variable,-,u8g2_font_b16_t_japanese1,const uint8_t[], +Variable,-,u8g2_font_b16_t_japanese2,const uint8_t[], +Variable,-,u8g2_font_b16_t_japanese3,const uint8_t[], +Variable,-,u8g2_font_baby_tf,const uint8_t[], +Variable,-,u8g2_font_baby_tn,const uint8_t[], +Variable,-,u8g2_font_baby_tr,const uint8_t[], +Variable,-,u8g2_font_balthasar_regular_nbp_tf,const uint8_t[], +Variable,-,u8g2_font_balthasar_regular_nbp_tn,const uint8_t[], +Variable,-,u8g2_font_balthasar_regular_nbp_tr,const uint8_t[], +Variable,-,u8g2_font_balthasar_titling_nbp_tf,const uint8_t[], +Variable,-,u8g2_font_balthasar_titling_nbp_tn,const uint8_t[], +Variable,-,u8g2_font_balthasar_titling_nbp_tr,const uint8_t[], +Variable,-,u8g2_font_battery19_tn,const uint8_t[], +Variable,-,u8g2_font_bauhaus2015_tn,const uint8_t[], +Variable,-,u8g2_font_bauhaus2015_tr,const uint8_t[], +Variable,-,u8g2_font_beanstalk_mel_tn,const uint8_t[], +Variable,-,u8g2_font_beanstalk_mel_tr,const uint8_t[], +Variable,-,u8g2_font_bitcasual_t_all,const uint8_t[], +Variable,-,u8g2_font_bitcasual_tf,const uint8_t[], +Variable,-,u8g2_font_bitcasual_tn,const uint8_t[], +Variable,-,u8g2_font_bitcasual_tr,const uint8_t[], +Variable,-,u8g2_font_bitcasual_tu,const uint8_t[], +Variable,-,u8g2_font_blipfest_07_tn,const uint8_t[], +Variable,-,u8g2_font_blipfest_07_tr,const uint8_t[], +Variable,-,u8g2_font_bracketedbabies_tr,const uint8_t[], +Variable,-,u8g2_font_bubble_tn,const uint8_t[], +Variable,-,u8g2_font_bubble_tr,const uint8_t[], +Variable,-,u8g2_font_calibration_gothic_nbp_t_all,const uint8_t[], +Variable,-,u8g2_font_calibration_gothic_nbp_tf,const uint8_t[], +Variable,-,u8g2_font_calibration_gothic_nbp_tn,const uint8_t[], +Variable,-,u8g2_font_calibration_gothic_nbp_tr,const uint8_t[], +Variable,-,u8g2_font_cardimon_pixel_tf,const uint8_t[], +Variable,-,u8g2_font_cardimon_pixel_tn,const uint8_t[], +Variable,-,u8g2_font_cardimon_pixel_tr,const uint8_t[], +Variable,-,u8g2_font_celibatemonk_tr,const uint8_t[], +Variable,-,u8g2_font_chikita_tf,const uint8_t[], +Variable,-,u8g2_font_chikita_tn,const uint8_t[], +Variable,-,u8g2_font_chikita_tr,const uint8_t[], +Variable,-,u8g2_font_chroma48medium8_8n,const uint8_t[], +Variable,-,u8g2_font_chroma48medium8_8r,const uint8_t[], +Variable,-,u8g2_font_chroma48medium8_8u,const uint8_t[], +Variable,-,u8g2_font_courB08_tf,const uint8_t[], +Variable,-,u8g2_font_courB08_tn,const uint8_t[], +Variable,-,u8g2_font_courB08_tr,const uint8_t[], +Variable,-,u8g2_font_courB10_tf,const uint8_t[], +Variable,-,u8g2_font_courB10_tn,const uint8_t[], +Variable,-,u8g2_font_courB10_tr,const uint8_t[], +Variable,-,u8g2_font_courB12_tf,const uint8_t[], +Variable,-,u8g2_font_courB12_tn,const uint8_t[], +Variable,-,u8g2_font_courB12_tr,const uint8_t[], +Variable,-,u8g2_font_courB14_tf,const uint8_t[], +Variable,-,u8g2_font_courB14_tn,const uint8_t[], +Variable,-,u8g2_font_courB14_tr,const uint8_t[], +Variable,-,u8g2_font_courB18_tf,const uint8_t[], +Variable,-,u8g2_font_courB18_tn,const uint8_t[], +Variable,-,u8g2_font_courB18_tr,const uint8_t[], +Variable,-,u8g2_font_courB24_tf,const uint8_t[], +Variable,-,u8g2_font_courB24_tn,const uint8_t[], +Variable,-,u8g2_font_courB24_tr,const uint8_t[], +Variable,-,u8g2_font_courR08_tf,const uint8_t[], +Variable,-,u8g2_font_courR08_tn,const uint8_t[], +Variable,-,u8g2_font_courR08_tr,const uint8_t[], +Variable,-,u8g2_font_courR10_tf,const uint8_t[], +Variable,-,u8g2_font_courR10_tn,const uint8_t[], +Variable,-,u8g2_font_courR10_tr,const uint8_t[], +Variable,-,u8g2_font_courR12_tf,const uint8_t[], +Variable,-,u8g2_font_courR12_tn,const uint8_t[], +Variable,-,u8g2_font_courR12_tr,const uint8_t[], +Variable,-,u8g2_font_courR14_tf,const uint8_t[], +Variable,-,u8g2_font_courR14_tn,const uint8_t[], +Variable,-,u8g2_font_courR14_tr,const uint8_t[], +Variable,-,u8g2_font_courR18_tf,const uint8_t[], +Variable,-,u8g2_font_courR18_tn,const uint8_t[], +Variable,-,u8g2_font_courR18_tr,const uint8_t[], +Variable,-,u8g2_font_courR24_tf,const uint8_t[], +Variable,-,u8g2_font_courR24_tn,const uint8_t[], +Variable,-,u8g2_font_courR24_tr,const uint8_t[], +Variable,-,u8g2_font_crox1c_mf,const uint8_t[], +Variable,-,u8g2_font_crox1c_mn,const uint8_t[], +Variable,-,u8g2_font_crox1c_mr,const uint8_t[], +Variable,-,u8g2_font_crox1c_tf,const uint8_t[], +Variable,-,u8g2_font_crox1c_tn,const uint8_t[], +Variable,-,u8g2_font_crox1c_tr,const uint8_t[], +Variable,-,u8g2_font_crox1cb_mf,const uint8_t[], +Variable,-,u8g2_font_crox1cb_mn,const uint8_t[], +Variable,-,u8g2_font_crox1cb_mr,const uint8_t[], +Variable,-,u8g2_font_crox1cb_tf,const uint8_t[], +Variable,-,u8g2_font_crox1cb_tn,const uint8_t[], +Variable,-,u8g2_font_crox1cb_tr,const uint8_t[], +Variable,-,u8g2_font_crox1h_tf,const uint8_t[], +Variable,-,u8g2_font_crox1h_tn,const uint8_t[], +Variable,-,u8g2_font_crox1h_tr,const uint8_t[], +Variable,-,u8g2_font_crox1hb_tf,const uint8_t[], +Variable,-,u8g2_font_crox1hb_tn,const uint8_t[], +Variable,-,u8g2_font_crox1hb_tr,const uint8_t[], +Variable,-,u8g2_font_crox1t_tf,const uint8_t[], +Variable,-,u8g2_font_crox1t_tn,const uint8_t[], +Variable,-,u8g2_font_crox1t_tr,const uint8_t[], +Variable,-,u8g2_font_crox1tb_tf,const uint8_t[], +Variable,-,u8g2_font_crox1tb_tn,const uint8_t[], +Variable,-,u8g2_font_crox1tb_tr,const uint8_t[], +Variable,-,u8g2_font_crox2c_mf,const uint8_t[], +Variable,-,u8g2_font_crox2c_mn,const uint8_t[], +Variable,-,u8g2_font_crox2c_mr,const uint8_t[], +Variable,-,u8g2_font_crox2c_tf,const uint8_t[], +Variable,-,u8g2_font_crox2c_tn,const uint8_t[], +Variable,-,u8g2_font_crox2c_tr,const uint8_t[], +Variable,-,u8g2_font_crox2cb_mf,const uint8_t[], +Variable,-,u8g2_font_crox2cb_mn,const uint8_t[], +Variable,-,u8g2_font_crox2cb_mr,const uint8_t[], +Variable,-,u8g2_font_crox2cb_tf,const uint8_t[], +Variable,-,u8g2_font_crox2cb_tn,const uint8_t[], +Variable,-,u8g2_font_crox2cb_tr,const uint8_t[], +Variable,-,u8g2_font_crox2h_tf,const uint8_t[], +Variable,-,u8g2_font_crox2h_tn,const uint8_t[], +Variable,-,u8g2_font_crox2h_tr,const uint8_t[], +Variable,-,u8g2_font_crox2hb_tf,const uint8_t[], +Variable,-,u8g2_font_crox2hb_tn,const uint8_t[], +Variable,-,u8g2_font_crox2hb_tr,const uint8_t[], +Variable,-,u8g2_font_crox2t_tf,const uint8_t[], +Variable,-,u8g2_font_crox2t_tn,const uint8_t[], +Variable,-,u8g2_font_crox2t_tr,const uint8_t[], +Variable,-,u8g2_font_crox2tb_tf,const uint8_t[], +Variable,-,u8g2_font_crox2tb_tn,const uint8_t[], +Variable,-,u8g2_font_crox2tb_tr,const uint8_t[], +Variable,-,u8g2_font_crox3c_mf,const uint8_t[], +Variable,-,u8g2_font_crox3c_mn,const uint8_t[], +Variable,-,u8g2_font_crox3c_mr,const uint8_t[], +Variable,-,u8g2_font_crox3c_tf,const uint8_t[], +Variable,-,u8g2_font_crox3c_tn,const uint8_t[], +Variable,-,u8g2_font_crox3c_tr,const uint8_t[], +Variable,-,u8g2_font_crox3cb_mf,const uint8_t[], +Variable,-,u8g2_font_crox3cb_mn,const uint8_t[], +Variable,-,u8g2_font_crox3cb_mr,const uint8_t[], +Variable,-,u8g2_font_crox3cb_tf,const uint8_t[], +Variable,-,u8g2_font_crox3cb_tn,const uint8_t[], +Variable,-,u8g2_font_crox3cb_tr,const uint8_t[], +Variable,-,u8g2_font_crox3h_tf,const uint8_t[], +Variable,-,u8g2_font_crox3h_tn,const uint8_t[], +Variable,-,u8g2_font_crox3h_tr,const uint8_t[], +Variable,-,u8g2_font_crox3hb_tf,const uint8_t[], +Variable,-,u8g2_font_crox3hb_tn,const uint8_t[], +Variable,-,u8g2_font_crox3hb_tr,const uint8_t[], +Variable,-,u8g2_font_crox3t_tf,const uint8_t[], +Variable,-,u8g2_font_crox3t_tn,const uint8_t[], +Variable,-,u8g2_font_crox3t_tr,const uint8_t[], +Variable,-,u8g2_font_crox3tb_tf,const uint8_t[], +Variable,-,u8g2_font_crox3tb_tn,const uint8_t[], +Variable,-,u8g2_font_crox3tb_tr,const uint8_t[], +Variable,-,u8g2_font_crox4h_tf,const uint8_t[], +Variable,-,u8g2_font_crox4h_tn,const uint8_t[], +Variable,-,u8g2_font_crox4h_tr,const uint8_t[], +Variable,-,u8g2_font_crox4hb_tf,const uint8_t[], +Variable,-,u8g2_font_crox4hb_tn,const uint8_t[], +Variable,-,u8g2_font_crox4hb_tr,const uint8_t[], +Variable,-,u8g2_font_crox4t_tf,const uint8_t[], +Variable,-,u8g2_font_crox4t_tn,const uint8_t[], +Variable,-,u8g2_font_crox4t_tr,const uint8_t[], +Variable,-,u8g2_font_crox4tb_tf,const uint8_t[], +Variable,-,u8g2_font_crox4tb_tn,const uint8_t[], +Variable,-,u8g2_font_crox4tb_tr,const uint8_t[], +Variable,-,u8g2_font_crox5h_tf,const uint8_t[], +Variable,-,u8g2_font_crox5h_tn,const uint8_t[], +Variable,-,u8g2_font_crox5h_tr,const uint8_t[], +Variable,-,u8g2_font_crox5hb_tf,const uint8_t[], +Variable,-,u8g2_font_crox5hb_tn,const uint8_t[], +Variable,-,u8g2_font_crox5hb_tr,const uint8_t[], +Variable,-,u8g2_font_crox5t_tf,const uint8_t[], +Variable,-,u8g2_font_crox5t_tn,const uint8_t[], +Variable,-,u8g2_font_crox5t_tr,const uint8_t[], +Variable,-,u8g2_font_crox5tb_tf,const uint8_t[], +Variable,-,u8g2_font_crox5tb_tn,const uint8_t[], +Variable,-,u8g2_font_crox5tb_tr,const uint8_t[], +Variable,-,u8g2_font_cu12_h_symbols,const uint8_t[], +Variable,-,u8g2_font_cu12_he,const uint8_t[], +Variable,-,u8g2_font_cu12_hf,const uint8_t[], +Variable,-,u8g2_font_cu12_hn,const uint8_t[], +Variable,-,u8g2_font_cu12_hr,const uint8_t[], +Variable,-,u8g2_font_cu12_me,const uint8_t[], +Variable,-,u8g2_font_cu12_mf,const uint8_t[], +Variable,-,u8g2_font_cu12_mn,const uint8_t[], +Variable,-,u8g2_font_cu12_mr,const uint8_t[], +Variable,-,u8g2_font_cu12_t_arabic,const uint8_t[], +Variable,-,u8g2_font_cu12_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_cu12_t_greek,const uint8_t[], +Variable,-,u8g2_font_cu12_t_hebrew,const uint8_t[], +Variable,-,u8g2_font_cu12_t_symbols,const uint8_t[], +Variable,-,u8g2_font_cu12_t_tibetan,const uint8_t[], +Variable,-,u8g2_font_cu12_te,const uint8_t[], +Variable,-,u8g2_font_cu12_tf,const uint8_t[], +Variable,-,u8g2_font_cu12_tn,const uint8_t[], +Variable,-,u8g2_font_cu12_tr,const uint8_t[], +Variable,-,u8g2_font_cube_mel_tn,const uint8_t[], +Variable,-,u8g2_font_cube_mel_tr,const uint8_t[], +Variable,-,u8g2_font_cupcakemetoyourleader_tn,const uint8_t[], +Variable,-,u8g2_font_cupcakemetoyourleader_tr,const uint8_t[], +Variable,-,u8g2_font_cupcakemetoyourleader_tu,const uint8_t[], +Variable,-,u8g2_font_cursor_tf,const uint8_t[], +Variable,-,u8g2_font_cursor_tr,const uint8_t[], +Variable,-,u8g2_font_diodesemimono_tr,const uint8_t[], +Variable,-,u8g2_font_disrespectfulteenager_tu,const uint8_t[], +Variable,-,u8g2_font_emoticons21_tr,const uint8_t[], +Variable,-,u8g2_font_etl14thai_t,const uint8_t[], +Variable,-,u8g2_font_etl16thai_t,const uint8_t[], +Variable,-,u8g2_font_etl24thai_t,const uint8_t[], +Variable,-,u8g2_font_f10_b_t_japanese1,const uint8_t[], +Variable,-,u8g2_font_f10_b_t_japanese2,const uint8_t[], +Variable,-,u8g2_font_f10_t_japanese1,const uint8_t[], +Variable,-,u8g2_font_f10_t_japanese2,const uint8_t[], +Variable,-,u8g2_font_f12_b_t_japanese1,const uint8_t[], +Variable,-,u8g2_font_f12_b_t_japanese2,const uint8_t[], +Variable,-,u8g2_font_f12_t_japanese1,const uint8_t[], +Variable,-,u8g2_font_f12_t_japanese2,const uint8_t[], +Variable,-,u8g2_font_f16_b_t_japanese1,const uint8_t[], +Variable,-,u8g2_font_f16_b_t_japanese2,const uint8_t[], +Variable,-,u8g2_font_f16_t_japanese1,const uint8_t[], +Variable,-,u8g2_font_f16_t_japanese2,const uint8_t[], +Variable,-,u8g2_font_fancypixels_tf,const uint8_t[], +Variable,-,u8g2_font_fancypixels_tr,const uint8_t[], +Variable,-,u8g2_font_fewture_tf,const uint8_t[], +Variable,-,u8g2_font_fewture_tn,const uint8_t[], +Variable,-,u8g2_font_fewture_tr,const uint8_t[], +Variable,-,u8g2_font_finderskeepers_tf,const uint8_t[], +Variable,-,u8g2_font_finderskeepers_tn,const uint8_t[], +Variable,-,u8g2_font_finderskeepers_tr,const uint8_t[], +Variable,-,u8g2_font_freedoomr10_mu,const uint8_t[], +Variable,-,u8g2_font_freedoomr10_tu,const uint8_t[], +Variable,-,u8g2_font_freedoomr25_mn,const uint8_t[], +Variable,-,u8g2_font_freedoomr25_tn,const uint8_t[], +Variable,-,u8g2_font_frikativ_t_all,const uint8_t[], +Variable,-,u8g2_font_frikativ_tf,const uint8_t[], +Variable,-,u8g2_font_frikativ_tr,const uint8_t[], +Variable,-,u8g2_font_fub11_t_symbol,const uint8_t[], +Variable,-,u8g2_font_fub11_tf,const uint8_t[], +Variable,-,u8g2_font_fub11_tn,const uint8_t[], +Variable,-,u8g2_font_fub11_tr,const uint8_t[], +Variable,-,u8g2_font_fub14_t_symbol,const uint8_t[], +Variable,-,u8g2_font_fub14_tf,const uint8_t[], +Variable,-,u8g2_font_fub14_tn,const uint8_t[], +Variable,-,u8g2_font_fub14_tr,const uint8_t[], +Variable,-,u8g2_font_fub17_t_symbol,const uint8_t[], +Variable,-,u8g2_font_fub17_tf,const uint8_t[], +Variable,-,u8g2_font_fub17_tn,const uint8_t[], +Variable,-,u8g2_font_fub17_tr,const uint8_t[], +Variable,-,u8g2_font_fub20_t_symbol,const uint8_t[], +Variable,-,u8g2_font_fub20_tf,const uint8_t[], +Variable,-,u8g2_font_fub20_tn,const uint8_t[], +Variable,-,u8g2_font_fub20_tr,const uint8_t[], +Variable,-,u8g2_font_fub25_t_symbol,const uint8_t[], +Variable,-,u8g2_font_fub25_tf,const uint8_t[], +Variable,-,u8g2_font_fub25_tn,const uint8_t[], +Variable,-,u8g2_font_fub25_tr,const uint8_t[], +Variable,-,u8g2_font_fub30_t_symbol,const uint8_t[], +Variable,-,u8g2_font_fub30_tf,const uint8_t[], +Variable,-,u8g2_font_fub30_tn,const uint8_t[], +Variable,-,u8g2_font_fub30_tr,const uint8_t[], +Variable,-,u8g2_font_fub35_t_symbol,const uint8_t[], +Variable,-,u8g2_font_fub35_tf,const uint8_t[], +Variable,-,u8g2_font_fub35_tn,const uint8_t[], +Variable,-,u8g2_font_fub35_tr,const uint8_t[], +Variable,-,u8g2_font_fub42_t_symbol,const uint8_t[], +Variable,-,u8g2_font_fub42_tf,const uint8_t[], +Variable,-,u8g2_font_fub42_tn,const uint8_t[], +Variable,-,u8g2_font_fub42_tr,const uint8_t[], +Variable,-,u8g2_font_fub49_t_symbol,const uint8_t[], +Variable,-,u8g2_font_fub49_tn,const uint8_t[], +Variable,-,u8g2_font_fur11_t_symbol,const uint8_t[], +Variable,-,u8g2_font_fur11_tf,const uint8_t[], +Variable,-,u8g2_font_fur11_tn,const uint8_t[], +Variable,-,u8g2_font_fur11_tr,const uint8_t[], +Variable,-,u8g2_font_fur14_t_symbol,const uint8_t[], +Variable,-,u8g2_font_fur14_tf,const uint8_t[], +Variable,-,u8g2_font_fur14_tn,const uint8_t[], +Variable,-,u8g2_font_fur14_tr,const uint8_t[], +Variable,-,u8g2_font_fur17_t_symbol,const uint8_t[], +Variable,-,u8g2_font_fur17_tf,const uint8_t[], +Variable,-,u8g2_font_fur17_tn,const uint8_t[], +Variable,-,u8g2_font_fur17_tr,const uint8_t[], +Variable,-,u8g2_font_fur20_t_symbol,const uint8_t[], +Variable,-,u8g2_font_fur20_tf,const uint8_t[], +Variable,-,u8g2_font_fur20_tn,const uint8_t[], +Variable,-,u8g2_font_fur20_tr,const uint8_t[], +Variable,-,u8g2_font_fur25_t_symbol,const uint8_t[], +Variable,-,u8g2_font_fur25_tf,const uint8_t[], +Variable,-,u8g2_font_fur25_tn,const uint8_t[], +Variable,-,u8g2_font_fur25_tr,const uint8_t[], +Variable,-,u8g2_font_fur30_t_symbol,const uint8_t[], +Variable,-,u8g2_font_fur30_tf,const uint8_t[], +Variable,-,u8g2_font_fur30_tn,const uint8_t[], +Variable,-,u8g2_font_fur30_tr,const uint8_t[], +Variable,-,u8g2_font_fur35_t_symbol,const uint8_t[], +Variable,-,u8g2_font_fur35_tf,const uint8_t[], +Variable,-,u8g2_font_fur35_tn,const uint8_t[], +Variable,-,u8g2_font_fur35_tr,const uint8_t[], +Variable,-,u8g2_font_fur42_t_symbol,const uint8_t[], +Variable,-,u8g2_font_fur42_tf,const uint8_t[], +Variable,-,u8g2_font_fur42_tn,const uint8_t[], +Variable,-,u8g2_font_fur42_tr,const uint8_t[], +Variable,-,u8g2_font_fur49_t_symbol,const uint8_t[], +Variable,-,u8g2_font_fur49_tn,const uint8_t[], +Variable,-,u8g2_font_ganj_nameh_sans10_t_all,const uint8_t[], +Variable,-,u8g2_font_ganj_nameh_sans12_t_all,const uint8_t[], +Variable,-,u8g2_font_ganj_nameh_sans14_t_all,const uint8_t[], +Variable,-,u8g2_font_ganj_nameh_sans16_t_all,const uint8_t[], +Variable,-,u8g2_font_gb16st_t_1,const uint8_t[], +Variable,-,u8g2_font_gb16st_t_2,const uint8_t[], +Variable,-,u8g2_font_gb16st_t_3,const uint8_t[], +Variable,-,u8g2_font_gb24st_t_1,const uint8_t[], +Variable,-,u8g2_font_gb24st_t_2,const uint8_t[], +Variable,-,u8g2_font_gb24st_t_3,const uint8_t[], +Variable,-,u8g2_font_glasstown_nbp_t_all,const uint8_t[], +Variable,-,u8g2_font_glasstown_nbp_tf,const uint8_t[], +Variable,-,u8g2_font_glasstown_nbp_tn,const uint8_t[], +Variable,-,u8g2_font_glasstown_nbp_tr,const uint8_t[], +Variable,-,u8g2_font_guildenstern_nbp_t_all,const uint8_t[], +Variable,-,u8g2_font_guildenstern_nbp_tf,const uint8_t[], +Variable,-,u8g2_font_guildenstern_nbp_tn,const uint8_t[], +Variable,-,u8g2_font_guildenstern_nbp_tr,const uint8_t[], +Variable,-,u8g2_font_habsburgchancery_t_all,const uint8_t[], +Variable,-,u8g2_font_habsburgchancery_tf,const uint8_t[], +Variable,-,u8g2_font_habsburgchancery_tn,const uint8_t[], +Variable,-,u8g2_font_habsburgchancery_tr,const uint8_t[], +Variable,-,u8g2_font_halftone_tf,const uint8_t[], +Variable,-,u8g2_font_halftone_tn,const uint8_t[], +Variable,-,u8g2_font_halftone_tr,const uint8_t[], +Variable,-,u8g2_font_haxrcorp4089_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_haxrcorp4089_tn,const uint8_t[], +Variable,-,u8g2_font_haxrcorp4089_tr,const uint8_t[], +Variable,-,u8g2_font_heavybottom_tr,const uint8_t[], +Variable,-,u8g2_font_helvB08_te,const uint8_t[], +Variable,-,u8g2_font_helvB08_tf,const uint8_t[], +Variable,-,u8g2_font_helvB08_tn,const uint8_t[], +Variable,-,u8g2_font_helvB08_tr,const uint8_t[], +Variable,-,u8g2_font_helvB10_te,const uint8_t[], +Variable,-,u8g2_font_helvB10_tf,const uint8_t[], +Variable,-,u8g2_font_helvB10_tn,const uint8_t[], +Variable,-,u8g2_font_helvB10_tr,const uint8_t[], +Variable,-,u8g2_font_helvB12_te,const uint8_t[], +Variable,-,u8g2_font_helvB12_tf,const uint8_t[], +Variable,-,u8g2_font_helvB12_tn,const uint8_t[], +Variable,-,u8g2_font_helvB12_tr,const uint8_t[], +Variable,-,u8g2_font_helvB14_te,const uint8_t[], +Variable,-,u8g2_font_helvB14_tf,const uint8_t[], +Variable,-,u8g2_font_helvB14_tn,const uint8_t[], +Variable,-,u8g2_font_helvB14_tr,const uint8_t[], +Variable,-,u8g2_font_helvB18_te,const uint8_t[], +Variable,-,u8g2_font_helvB18_tf,const uint8_t[], +Variable,-,u8g2_font_helvB18_tn,const uint8_t[], +Variable,-,u8g2_font_helvB18_tr,const uint8_t[], +Variable,-,u8g2_font_helvB24_te,const uint8_t[], +Variable,-,u8g2_font_helvB24_tf,const uint8_t[], +Variable,-,u8g2_font_helvB24_tn,const uint8_t[], +Variable,-,u8g2_font_helvB24_tr,const uint8_t[], +Variable,-,u8g2_font_helvR08_te,const uint8_t[], +Variable,-,u8g2_font_helvR08_tf,const uint8_t[], +Variable,-,u8g2_font_helvR08_tn,const uint8_t[], +Variable,-,u8g2_font_helvR08_tr,const uint8_t[], +Variable,-,u8g2_font_helvR10_te,const uint8_t[], +Variable,-,u8g2_font_helvR10_tf,const uint8_t[], +Variable,-,u8g2_font_helvR10_tn,const uint8_t[], +Variable,-,u8g2_font_helvR10_tr,const uint8_t[], +Variable,-,u8g2_font_helvR12_te,const uint8_t[], +Variable,-,u8g2_font_helvR12_tf,const uint8_t[], +Variable,-,u8g2_font_helvR12_tn,const uint8_t[], +Variable,-,u8g2_font_helvR12_tr,const uint8_t[], +Variable,-,u8g2_font_helvR14_te,const uint8_t[], +Variable,-,u8g2_font_helvR14_tf,const uint8_t[], +Variable,-,u8g2_font_helvR14_tn,const uint8_t[], +Variable,-,u8g2_font_helvR14_tr,const uint8_t[], +Variable,-,u8g2_font_helvR18_te,const uint8_t[], +Variable,-,u8g2_font_helvR18_tf,const uint8_t[], +Variable,-,u8g2_font_helvR18_tn,const uint8_t[], +Variable,-,u8g2_font_helvR18_tr,const uint8_t[], +Variable,-,u8g2_font_helvR24_te,const uint8_t[], +Variable,-,u8g2_font_helvR24_tf,const uint8_t[], +Variable,-,u8g2_font_helvR24_tn,const uint8_t[], +Variable,-,u8g2_font_helvR24_tr,const uint8_t[], +Variable,-,u8g2_font_iconquadpix_m_all,const uint8_t[], +Variable,-,u8g2_font_inb16_mf,const uint8_t[], +Variable,-,u8g2_font_inb16_mn,const uint8_t[], +Variable,-,u8g2_font_inb16_mr,const uint8_t[], +Variable,-,u8g2_font_inb19_mf,const uint8_t[], +Variable,-,u8g2_font_inb19_mn,const uint8_t[], +Variable,-,u8g2_font_inb19_mr,const uint8_t[], +Variable,-,u8g2_font_inb21_mf,const uint8_t[], +Variable,-,u8g2_font_inb21_mn,const uint8_t[], +Variable,-,u8g2_font_inb21_mr,const uint8_t[], +Variable,-,u8g2_font_inb24_mf,const uint8_t[], +Variable,-,u8g2_font_inb24_mn,const uint8_t[], +Variable,-,u8g2_font_inb24_mr,const uint8_t[], +Variable,-,u8g2_font_inb27_mf,const uint8_t[], +Variable,-,u8g2_font_inb27_mn,const uint8_t[], +Variable,-,u8g2_font_inb27_mr,const uint8_t[], +Variable,-,u8g2_font_inb30_mf,const uint8_t[], +Variable,-,u8g2_font_inb30_mn,const uint8_t[], +Variable,-,u8g2_font_inb30_mr,const uint8_t[], +Variable,-,u8g2_font_inb33_mf,const uint8_t[], +Variable,-,u8g2_font_inb33_mn,const uint8_t[], +Variable,-,u8g2_font_inb33_mr,const uint8_t[], +Variable,-,u8g2_font_inb38_mf,const uint8_t[], +Variable,-,u8g2_font_inb38_mn,const uint8_t[], +Variable,-,u8g2_font_inb38_mr,const uint8_t[], +Variable,-,u8g2_font_inb42_mf,const uint8_t[], +Variable,-,u8g2_font_inb42_mn,const uint8_t[], +Variable,-,u8g2_font_inb42_mr,const uint8_t[], +Variable,-,u8g2_font_inb46_mf,const uint8_t[], +Variable,-,u8g2_font_inb46_mn,const uint8_t[], +Variable,-,u8g2_font_inb46_mr,const uint8_t[], +Variable,-,u8g2_font_inb49_mf,const uint8_t[], +Variable,-,u8g2_font_inb49_mn,const uint8_t[], +Variable,-,u8g2_font_inb49_mr,const uint8_t[], +Variable,-,u8g2_font_inb53_mf,const uint8_t[], +Variable,-,u8g2_font_inb53_mn,const uint8_t[], +Variable,-,u8g2_font_inb53_mr,const uint8_t[], +Variable,-,u8g2_font_inb57_mn,const uint8_t[], +Variable,-,u8g2_font_inb63_mn,const uint8_t[], +Variable,-,u8g2_font_inr16_mf,const uint8_t[], +Variable,-,u8g2_font_inr16_mn,const uint8_t[], +Variable,-,u8g2_font_inr16_mr,const uint8_t[], +Variable,-,u8g2_font_inr19_mf,const uint8_t[], +Variable,-,u8g2_font_inr19_mn,const uint8_t[], +Variable,-,u8g2_font_inr19_mr,const uint8_t[], +Variable,-,u8g2_font_inr21_mf,const uint8_t[], +Variable,-,u8g2_font_inr21_mn,const uint8_t[], +Variable,-,u8g2_font_inr21_mr,const uint8_t[], +Variable,-,u8g2_font_inr24_mf,const uint8_t[], +Variable,-,u8g2_font_inr24_mn,const uint8_t[], +Variable,-,u8g2_font_inr24_mr,const uint8_t[], +Variable,-,u8g2_font_inr24_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_inr27_mf,const uint8_t[], +Variable,-,u8g2_font_inr27_mn,const uint8_t[], +Variable,-,u8g2_font_inr27_mr,const uint8_t[], +Variable,-,u8g2_font_inr27_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_inr30_mf,const uint8_t[], +Variable,-,u8g2_font_inr30_mn,const uint8_t[], +Variable,-,u8g2_font_inr30_mr,const uint8_t[], +Variable,-,u8g2_font_inr30_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_inr33_mf,const uint8_t[], +Variable,-,u8g2_font_inr33_mn,const uint8_t[], +Variable,-,u8g2_font_inr33_mr,const uint8_t[], +Variable,-,u8g2_font_inr33_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_inr38_mf,const uint8_t[], +Variable,-,u8g2_font_inr38_mn,const uint8_t[], +Variable,-,u8g2_font_inr38_mr,const uint8_t[], +Variable,-,u8g2_font_inr38_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_inr42_mf,const uint8_t[], +Variable,-,u8g2_font_inr42_mn,const uint8_t[], +Variable,-,u8g2_font_inr42_mr,const uint8_t[], +Variable,-,u8g2_font_inr42_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_inr46_mf,const uint8_t[], +Variable,-,u8g2_font_inr46_mn,const uint8_t[], +Variable,-,u8g2_font_inr46_mr,const uint8_t[], +Variable,-,u8g2_font_inr46_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_inr49_mf,const uint8_t[], +Variable,-,u8g2_font_inr49_mn,const uint8_t[], +Variable,-,u8g2_font_inr49_mr,const uint8_t[], +Variable,-,u8g2_font_inr49_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_inr53_mf,const uint8_t[], +Variable,-,u8g2_font_inr53_mn,const uint8_t[], +Variable,-,u8g2_font_inr53_mr,const uint8_t[], +Variable,-,u8g2_font_inr53_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_inr57_mn,const uint8_t[], +Variable,-,u8g2_font_inr62_mn,const uint8_t[], +Variable,-,u8g2_font_iranian_sans_10_t_all,const uint8_t[], +Variable,-,u8g2_font_iranian_sans_12_t_all,const uint8_t[], +Variable,-,u8g2_font_iranian_sans_14_t_all,const uint8_t[], +Variable,-,u8g2_font_iranian_sans_16_t_all,const uint8_t[], +Variable,-,u8g2_font_iranian_sans_8_t_all,const uint8_t[], +Variable,-,u8g2_font_jinxedwizards_tr,const uint8_t[], +Variable,-,u8g2_font_koleeko_tf,const uint8_t[], +Variable,-,u8g2_font_koleeko_tn,const uint8_t[], +Variable,-,u8g2_font_koleeko_tr,const uint8_t[], +Variable,-,u8g2_font_koleeko_tu,const uint8_t[], +Variable,-,u8g2_font_lastapprenticebold_tr,const uint8_t[], +Variable,-,u8g2_font_lastapprenticethin_tr,const uint8_t[], +Variable,-,u8g2_font_lastpriestess_tr,const uint8_t[], +Variable,-,u8g2_font_lastpriestess_tu,const uint8_t[], +Variable,-,u8g2_font_logisoso16_tf,const uint8_t[], +Variable,-,u8g2_font_logisoso16_tn,const uint8_t[], +Variable,-,u8g2_font_logisoso16_tr,const uint8_t[], +Variable,-,u8g2_font_logisoso18_tf,const uint8_t[], +Variable,-,u8g2_font_logisoso18_tn,const uint8_t[], +Variable,-,u8g2_font_logisoso18_tr,const uint8_t[], +Variable,-,u8g2_font_logisoso20_tf,const uint8_t[], +Variable,-,u8g2_font_logisoso20_tn,const uint8_t[], +Variable,-,u8g2_font_logisoso20_tr,const uint8_t[], +Variable,-,u8g2_font_logisoso22_tf,const uint8_t[], +Variable,-,u8g2_font_logisoso22_tn,const uint8_t[], +Variable,-,u8g2_font_logisoso22_tr,const uint8_t[], +Variable,-,u8g2_font_logisoso24_tf,const uint8_t[], +Variable,-,u8g2_font_logisoso24_tn,const uint8_t[], +Variable,-,u8g2_font_logisoso24_tr,const uint8_t[], +Variable,-,u8g2_font_logisoso26_tf,const uint8_t[], +Variable,-,u8g2_font_logisoso26_tn,const uint8_t[], +Variable,-,u8g2_font_logisoso26_tr,const uint8_t[], +Variable,-,u8g2_font_logisoso28_tf,const uint8_t[], +Variable,-,u8g2_font_logisoso28_tn,const uint8_t[], +Variable,-,u8g2_font_logisoso28_tr,const uint8_t[], +Variable,-,u8g2_font_logisoso30_tf,const uint8_t[], +Variable,-,u8g2_font_logisoso30_tn,const uint8_t[], +Variable,-,u8g2_font_logisoso30_tr,const uint8_t[], +Variable,-,u8g2_font_logisoso32_tf,const uint8_t[], +Variable,-,u8g2_font_logisoso32_tn,const uint8_t[], +Variable,-,u8g2_font_logisoso32_tr,const uint8_t[], +Variable,-,u8g2_font_logisoso34_tf,const uint8_t[], +Variable,-,u8g2_font_logisoso34_tn,const uint8_t[], +Variable,-,u8g2_font_logisoso34_tr,const uint8_t[], +Variable,-,u8g2_font_logisoso38_tf,const uint8_t[], +Variable,-,u8g2_font_logisoso38_tn,const uint8_t[], +Variable,-,u8g2_font_logisoso38_tr,const uint8_t[], +Variable,-,u8g2_font_logisoso42_tf,const uint8_t[], +Variable,-,u8g2_font_logisoso42_tn,const uint8_t[], +Variable,-,u8g2_font_logisoso42_tr,const uint8_t[], +Variable,-,u8g2_font_logisoso46_tf,const uint8_t[], +Variable,-,u8g2_font_logisoso46_tn,const uint8_t[], +Variable,-,u8g2_font_logisoso46_tr,const uint8_t[], +Variable,-,u8g2_font_logisoso50_tf,const uint8_t[], +Variable,-,u8g2_font_logisoso50_tn,const uint8_t[], +Variable,-,u8g2_font_logisoso50_tr,const uint8_t[], +Variable,-,u8g2_font_logisoso54_tf,const uint8_t[], +Variable,-,u8g2_font_logisoso54_tn,const uint8_t[], +Variable,-,u8g2_font_logisoso54_tr,const uint8_t[], +Variable,-,u8g2_font_logisoso58_tf,const uint8_t[], +Variable,-,u8g2_font_logisoso58_tn,const uint8_t[], +Variable,-,u8g2_font_logisoso58_tr,const uint8_t[], +Variable,-,u8g2_font_logisoso62_tn,const uint8_t[], +Variable,-,u8g2_font_logisoso78_tn,const uint8_t[], +Variable,-,u8g2_font_logisoso92_tn,const uint8_t[], +Variable,-,u8g2_font_luBIS08_te,const uint8_t[], +Variable,-,u8g2_font_luBIS08_tf,const uint8_t[], +Variable,-,u8g2_font_luBIS08_tn,const uint8_t[], +Variable,-,u8g2_font_luBIS08_tr,const uint8_t[], +Variable,-,u8g2_font_luBIS10_te,const uint8_t[], +Variable,-,u8g2_font_luBIS10_tf,const uint8_t[], +Variable,-,u8g2_font_luBIS10_tn,const uint8_t[], +Variable,-,u8g2_font_luBIS10_tr,const uint8_t[], +Variable,-,u8g2_font_luBIS12_te,const uint8_t[], +Variable,-,u8g2_font_luBIS12_tf,const uint8_t[], +Variable,-,u8g2_font_luBIS12_tn,const uint8_t[], +Variable,-,u8g2_font_luBIS12_tr,const uint8_t[], +Variable,-,u8g2_font_luBIS14_te,const uint8_t[], +Variable,-,u8g2_font_luBIS14_tf,const uint8_t[], +Variable,-,u8g2_font_luBIS14_tn,const uint8_t[], +Variable,-,u8g2_font_luBIS14_tr,const uint8_t[], +Variable,-,u8g2_font_luBIS18_te,const uint8_t[], +Variable,-,u8g2_font_luBIS18_tf,const uint8_t[], +Variable,-,u8g2_font_luBIS18_tn,const uint8_t[], +Variable,-,u8g2_font_luBIS18_tr,const uint8_t[], +Variable,-,u8g2_font_luBIS19_te,const uint8_t[], +Variable,-,u8g2_font_luBIS19_tf,const uint8_t[], +Variable,-,u8g2_font_luBIS19_tn,const uint8_t[], +Variable,-,u8g2_font_luBIS19_tr,const uint8_t[], +Variable,-,u8g2_font_luBIS24_te,const uint8_t[], +Variable,-,u8g2_font_luBIS24_tf,const uint8_t[], +Variable,-,u8g2_font_luBIS24_tn,const uint8_t[], +Variable,-,u8g2_font_luBIS24_tr,const uint8_t[], +Variable,-,u8g2_font_luBS08_te,const uint8_t[], +Variable,-,u8g2_font_luBS08_tf,const uint8_t[], +Variable,-,u8g2_font_luBS08_tn,const uint8_t[], +Variable,-,u8g2_font_luBS08_tr,const uint8_t[], +Variable,-,u8g2_font_luBS10_te,const uint8_t[], +Variable,-,u8g2_font_luBS10_tf,const uint8_t[], +Variable,-,u8g2_font_luBS10_tn,const uint8_t[], +Variable,-,u8g2_font_luBS10_tr,const uint8_t[], +Variable,-,u8g2_font_luBS12_te,const uint8_t[], +Variable,-,u8g2_font_luBS12_tf,const uint8_t[], +Variable,-,u8g2_font_luBS12_tn,const uint8_t[], +Variable,-,u8g2_font_luBS12_tr,const uint8_t[], +Variable,-,u8g2_font_luBS14_te,const uint8_t[], +Variable,-,u8g2_font_luBS14_tf,const uint8_t[], +Variable,-,u8g2_font_luBS14_tn,const uint8_t[], +Variable,-,u8g2_font_luBS14_tr,const uint8_t[], +Variable,-,u8g2_font_luBS18_te,const uint8_t[], +Variable,-,u8g2_font_luBS18_tf,const uint8_t[], +Variable,-,u8g2_font_luBS18_tn,const uint8_t[], +Variable,-,u8g2_font_luBS18_tr,const uint8_t[], +Variable,-,u8g2_font_luBS19_te,const uint8_t[], +Variable,-,u8g2_font_luBS19_tf,const uint8_t[], +Variable,-,u8g2_font_luBS19_tn,const uint8_t[], +Variable,-,u8g2_font_luBS19_tr,const uint8_t[], +Variable,-,u8g2_font_luBS24_te,const uint8_t[], +Variable,-,u8g2_font_luBS24_tf,const uint8_t[], +Variable,-,u8g2_font_luBS24_tn,const uint8_t[], +Variable,-,u8g2_font_luBS24_tr,const uint8_t[], +Variable,-,u8g2_font_luIS08_te,const uint8_t[], +Variable,-,u8g2_font_luIS08_tf,const uint8_t[], +Variable,-,u8g2_font_luIS08_tn,const uint8_t[], +Variable,-,u8g2_font_luIS08_tr,const uint8_t[], +Variable,-,u8g2_font_luIS10_te,const uint8_t[], +Variable,-,u8g2_font_luIS10_tf,const uint8_t[], +Variable,-,u8g2_font_luIS10_tn,const uint8_t[], +Variable,-,u8g2_font_luIS10_tr,const uint8_t[], +Variable,-,u8g2_font_luIS12_te,const uint8_t[], +Variable,-,u8g2_font_luIS12_tf,const uint8_t[], +Variable,-,u8g2_font_luIS12_tn,const uint8_t[], +Variable,-,u8g2_font_luIS12_tr,const uint8_t[], +Variable,-,u8g2_font_luIS14_te,const uint8_t[], +Variable,-,u8g2_font_luIS14_tf,const uint8_t[], +Variable,-,u8g2_font_luIS14_tn,const uint8_t[], +Variable,-,u8g2_font_luIS14_tr,const uint8_t[], +Variable,-,u8g2_font_luIS18_te,const uint8_t[], +Variable,-,u8g2_font_luIS18_tf,const uint8_t[], +Variable,-,u8g2_font_luIS18_tn,const uint8_t[], +Variable,-,u8g2_font_luIS18_tr,const uint8_t[], +Variable,-,u8g2_font_luIS19_te,const uint8_t[], +Variable,-,u8g2_font_luIS19_tf,const uint8_t[], +Variable,-,u8g2_font_luIS19_tn,const uint8_t[], +Variable,-,u8g2_font_luIS19_tr,const uint8_t[], +Variable,-,u8g2_font_luIS24_te,const uint8_t[], +Variable,-,u8g2_font_luIS24_tf,const uint8_t[], +Variable,-,u8g2_font_luIS24_tn,const uint8_t[], +Variable,-,u8g2_font_luIS24_tr,const uint8_t[], +Variable,-,u8g2_font_luRS08_te,const uint8_t[], +Variable,-,u8g2_font_luRS08_tf,const uint8_t[], +Variable,-,u8g2_font_luRS08_tn,const uint8_t[], +Variable,-,u8g2_font_luRS08_tr,const uint8_t[], +Variable,-,u8g2_font_luRS10_te,const uint8_t[], +Variable,-,u8g2_font_luRS10_tf,const uint8_t[], +Variable,-,u8g2_font_luRS10_tn,const uint8_t[], +Variable,-,u8g2_font_luRS10_tr,const uint8_t[], +Variable,-,u8g2_font_luRS12_te,const uint8_t[], +Variable,-,u8g2_font_luRS12_tf,const uint8_t[], +Variable,-,u8g2_font_luRS12_tn,const uint8_t[], +Variable,-,u8g2_font_luRS12_tr,const uint8_t[], +Variable,-,u8g2_font_luRS14_te,const uint8_t[], +Variable,-,u8g2_font_luRS14_tf,const uint8_t[], +Variable,-,u8g2_font_luRS14_tn,const uint8_t[], +Variable,-,u8g2_font_luRS14_tr,const uint8_t[], +Variable,-,u8g2_font_luRS18_te,const uint8_t[], +Variable,-,u8g2_font_luRS18_tf,const uint8_t[], +Variable,-,u8g2_font_luRS18_tn,const uint8_t[], +Variable,-,u8g2_font_luRS18_tr,const uint8_t[], +Variable,-,u8g2_font_luRS19_te,const uint8_t[], +Variable,-,u8g2_font_luRS19_tf,const uint8_t[], +Variable,-,u8g2_font_luRS19_tn,const uint8_t[], +Variable,-,u8g2_font_luRS19_tr,const uint8_t[], +Variable,-,u8g2_font_luRS24_te,const uint8_t[], +Variable,-,u8g2_font_luRS24_tf,const uint8_t[], +Variable,-,u8g2_font_luRS24_tn,const uint8_t[], +Variable,-,u8g2_font_luRS24_tr,const uint8_t[], +Variable,-,u8g2_font_lubB08_te,const uint8_t[], +Variable,-,u8g2_font_lubB08_tf,const uint8_t[], +Variable,-,u8g2_font_lubB08_tn,const uint8_t[], +Variable,-,u8g2_font_lubB08_tr,const uint8_t[], +Variable,-,u8g2_font_lubB10_te,const uint8_t[], +Variable,-,u8g2_font_lubB10_tf,const uint8_t[], +Variable,-,u8g2_font_lubB10_tn,const uint8_t[], +Variable,-,u8g2_font_lubB10_tr,const uint8_t[], +Variable,-,u8g2_font_lubB12_te,const uint8_t[], +Variable,-,u8g2_font_lubB12_tf,const uint8_t[], +Variable,-,u8g2_font_lubB12_tn,const uint8_t[], +Variable,-,u8g2_font_lubB12_tr,const uint8_t[], +Variable,-,u8g2_font_lubB14_te,const uint8_t[], +Variable,-,u8g2_font_lubB14_tf,const uint8_t[], +Variable,-,u8g2_font_lubB14_tn,const uint8_t[], +Variable,-,u8g2_font_lubB14_tr,const uint8_t[], +Variable,-,u8g2_font_lubB18_te,const uint8_t[], +Variable,-,u8g2_font_lubB18_tf,const uint8_t[], +Variable,-,u8g2_font_lubB18_tn,const uint8_t[], +Variable,-,u8g2_font_lubB18_tr,const uint8_t[], +Variable,-,u8g2_font_lubB19_te,const uint8_t[], +Variable,-,u8g2_font_lubB19_tf,const uint8_t[], +Variable,-,u8g2_font_lubB19_tn,const uint8_t[], +Variable,-,u8g2_font_lubB19_tr,const uint8_t[], +Variable,-,u8g2_font_lubB24_te,const uint8_t[], +Variable,-,u8g2_font_lubB24_tf,const uint8_t[], +Variable,-,u8g2_font_lubB24_tn,const uint8_t[], +Variable,-,u8g2_font_lubB24_tr,const uint8_t[], +Variable,-,u8g2_font_lubBI08_te,const uint8_t[], +Variable,-,u8g2_font_lubBI08_tf,const uint8_t[], +Variable,-,u8g2_font_lubBI08_tn,const uint8_t[], +Variable,-,u8g2_font_lubBI08_tr,const uint8_t[], +Variable,-,u8g2_font_lubBI10_te,const uint8_t[], +Variable,-,u8g2_font_lubBI10_tf,const uint8_t[], +Variable,-,u8g2_font_lubBI10_tn,const uint8_t[], +Variable,-,u8g2_font_lubBI10_tr,const uint8_t[], +Variable,-,u8g2_font_lubBI12_te,const uint8_t[], +Variable,-,u8g2_font_lubBI12_tf,const uint8_t[], +Variable,-,u8g2_font_lubBI12_tn,const uint8_t[], +Variable,-,u8g2_font_lubBI12_tr,const uint8_t[], +Variable,-,u8g2_font_lubBI14_te,const uint8_t[], +Variable,-,u8g2_font_lubBI14_tf,const uint8_t[], +Variable,-,u8g2_font_lubBI14_tn,const uint8_t[], +Variable,-,u8g2_font_lubBI14_tr,const uint8_t[], +Variable,-,u8g2_font_lubBI18_te,const uint8_t[], +Variable,-,u8g2_font_lubBI18_tf,const uint8_t[], +Variable,-,u8g2_font_lubBI18_tn,const uint8_t[], +Variable,-,u8g2_font_lubBI18_tr,const uint8_t[], +Variable,-,u8g2_font_lubBI19_te,const uint8_t[], +Variable,-,u8g2_font_lubBI19_tf,const uint8_t[], +Variable,-,u8g2_font_lubBI19_tn,const uint8_t[], +Variable,-,u8g2_font_lubBI19_tr,const uint8_t[], +Variable,-,u8g2_font_lubBI24_te,const uint8_t[], +Variable,-,u8g2_font_lubBI24_tf,const uint8_t[], +Variable,-,u8g2_font_lubBI24_tn,const uint8_t[], +Variable,-,u8g2_font_lubBI24_tr,const uint8_t[], +Variable,-,u8g2_font_lubI08_te,const uint8_t[], +Variable,-,u8g2_font_lubI08_tf,const uint8_t[], +Variable,-,u8g2_font_lubI08_tn,const uint8_t[], +Variable,-,u8g2_font_lubI08_tr,const uint8_t[], +Variable,-,u8g2_font_lubI10_te,const uint8_t[], +Variable,-,u8g2_font_lubI10_tf,const uint8_t[], +Variable,-,u8g2_font_lubI10_tn,const uint8_t[], +Variable,-,u8g2_font_lubI10_tr,const uint8_t[], +Variable,-,u8g2_font_lubI12_te,const uint8_t[], +Variable,-,u8g2_font_lubI12_tf,const uint8_t[], +Variable,-,u8g2_font_lubI12_tn,const uint8_t[], +Variable,-,u8g2_font_lubI12_tr,const uint8_t[], +Variable,-,u8g2_font_lubI14_te,const uint8_t[], +Variable,-,u8g2_font_lubI14_tf,const uint8_t[], +Variable,-,u8g2_font_lubI14_tn,const uint8_t[], +Variable,-,u8g2_font_lubI14_tr,const uint8_t[], +Variable,-,u8g2_font_lubI18_te,const uint8_t[], +Variable,-,u8g2_font_lubI18_tf,const uint8_t[], +Variable,-,u8g2_font_lubI18_tn,const uint8_t[], +Variable,-,u8g2_font_lubI18_tr,const uint8_t[], +Variable,-,u8g2_font_lubI19_te,const uint8_t[], +Variable,-,u8g2_font_lubI19_tf,const uint8_t[], +Variable,-,u8g2_font_lubI19_tn,const uint8_t[], +Variable,-,u8g2_font_lubI19_tr,const uint8_t[], +Variable,-,u8g2_font_lubI24_te,const uint8_t[], +Variable,-,u8g2_font_lubI24_tf,const uint8_t[], +Variable,-,u8g2_font_lubI24_tn,const uint8_t[], +Variable,-,u8g2_font_lubI24_tr,const uint8_t[], +Variable,-,u8g2_font_lubR08_te,const uint8_t[], +Variable,-,u8g2_font_lubR08_tf,const uint8_t[], +Variable,-,u8g2_font_lubR08_tn,const uint8_t[], +Variable,-,u8g2_font_lubR08_tr,const uint8_t[], +Variable,-,u8g2_font_lubR10_te,const uint8_t[], +Variable,-,u8g2_font_lubR10_tf,const uint8_t[], +Variable,-,u8g2_font_lubR10_tn,const uint8_t[], +Variable,-,u8g2_font_lubR10_tr,const uint8_t[], +Variable,-,u8g2_font_lubR12_te,const uint8_t[], +Variable,-,u8g2_font_lubR12_tf,const uint8_t[], +Variable,-,u8g2_font_lubR12_tn,const uint8_t[], +Variable,-,u8g2_font_lubR12_tr,const uint8_t[], +Variable,-,u8g2_font_lubR14_te,const uint8_t[], +Variable,-,u8g2_font_lubR14_tf,const uint8_t[], +Variable,-,u8g2_font_lubR14_tn,const uint8_t[], +Variable,-,u8g2_font_lubR14_tr,const uint8_t[], +Variable,-,u8g2_font_lubR18_te,const uint8_t[], +Variable,-,u8g2_font_lubR18_tf,const uint8_t[], +Variable,-,u8g2_font_lubR18_tn,const uint8_t[], +Variable,-,u8g2_font_lubR18_tr,const uint8_t[], +Variable,-,u8g2_font_lubR19_te,const uint8_t[], +Variable,-,u8g2_font_lubR19_tf,const uint8_t[], +Variable,-,u8g2_font_lubR19_tn,const uint8_t[], +Variable,-,u8g2_font_lubR19_tr,const uint8_t[], +Variable,-,u8g2_font_lubR24_te,const uint8_t[], +Variable,-,u8g2_font_lubR24_tf,const uint8_t[], +Variable,-,u8g2_font_lubR24_tn,const uint8_t[], +Variable,-,u8g2_font_lubR24_tr,const uint8_t[], +Variable,-,u8g2_font_lucasarts_scumm_subtitle_o_tf,const uint8_t[], +Variable,-,u8g2_font_lucasarts_scumm_subtitle_o_tn,const uint8_t[], +Variable,-,u8g2_font_lucasarts_scumm_subtitle_o_tr,const uint8_t[], +Variable,-,u8g2_font_lucasarts_scumm_subtitle_r_tf,const uint8_t[], +Variable,-,u8g2_font_lucasarts_scumm_subtitle_r_tn,const uint8_t[], +Variable,-,u8g2_font_lucasarts_scumm_subtitle_r_tr,const uint8_t[], +Variable,-,u8g2_font_lucasfont_alternate_tf,const uint8_t[], +Variable,-,u8g2_font_lucasfont_alternate_tn,const uint8_t[], +Variable,-,u8g2_font_lucasfont_alternate_tr,const uint8_t[], +Variable,-,u8g2_font_m2icon_5_tf,const uint8_t[], +Variable,-,u8g2_font_m2icon_7_tf,const uint8_t[], +Variable,-,u8g2_font_m2icon_9_tf,const uint8_t[], +Variable,-,u8g2_font_mademoiselle_mel_tn,const uint8_t[], +Variable,-,u8g2_font_mademoiselle_mel_tr,const uint8_t[], +Variable,-,u8g2_font_maniac_te,const uint8_t[], +Variable,-,u8g2_font_maniac_tf,const uint8_t[], +Variable,-,u8g2_font_maniac_tn,const uint8_t[], +Variable,-,u8g2_font_maniac_tr,const uint8_t[], +Variable,-,u8g2_font_mercutio_basic_nbp_t_all,const uint8_t[], +Variable,-,u8g2_font_mercutio_basic_nbp_tf,const uint8_t[], +Variable,-,u8g2_font_mercutio_basic_nbp_tn,const uint8_t[], +Variable,-,u8g2_font_mercutio_basic_nbp_tr,const uint8_t[], +Variable,-,u8g2_font_mercutio_sc_nbp_t_all,const uint8_t[], +Variable,-,u8g2_font_mercutio_sc_nbp_tf,const uint8_t[], +Variable,-,u8g2_font_mercutio_sc_nbp_tn,const uint8_t[], +Variable,-,u8g2_font_mercutio_sc_nbp_tr,const uint8_t[], +Variable,-,u8g2_font_michaelmouse_tu,const uint8_t[], +Variable,-,u8g2_font_micro_mn,const uint8_t[], +Variable,-,u8g2_font_micro_mr,const uint8_t[], +Variable,-,u8g2_font_micro_tn,const uint8_t[], +Variable,-,u8g2_font_micro_tr,const uint8_t[], +Variable,-,u8g2_font_miranda_nbp_tf,const uint8_t[], +Variable,-,u8g2_font_miranda_nbp_tn,const uint8_t[], +Variable,-,u8g2_font_miranda_nbp_tr,const uint8_t[], +Variable,-,u8g2_font_missingplanet_t_all,const uint8_t[], +Variable,-,u8g2_font_missingplanet_tf,const uint8_t[], +Variable,-,u8g2_font_missingplanet_tn,const uint8_t[], +Variable,-,u8g2_font_missingplanet_tr,const uint8_t[], +Variable,-,u8g2_font_mozart_nbp_h_all,const uint8_t[], +Variable,-,u8g2_font_mozart_nbp_t_all,const uint8_t[], +Variable,-,u8g2_font_mozart_nbp_tf,const uint8_t[], +Variable,-,u8g2_font_mozart_nbp_tn,const uint8_t[], +Variable,-,u8g2_font_mozart_nbp_tr,const uint8_t[], +Variable,-,u8g2_font_ncenB08_te,const uint8_t[], +Variable,-,u8g2_font_ncenB08_tf,const uint8_t[], +Variable,-,u8g2_font_ncenB08_tn,const uint8_t[], +Variable,-,u8g2_font_ncenB08_tr,const uint8_t[], +Variable,-,u8g2_font_ncenB10_te,const uint8_t[], +Variable,-,u8g2_font_ncenB10_tf,const uint8_t[], +Variable,-,u8g2_font_ncenB10_tn,const uint8_t[], +Variable,-,u8g2_font_ncenB10_tr,const uint8_t[], +Variable,-,u8g2_font_ncenB12_te,const uint8_t[], +Variable,-,u8g2_font_ncenB12_tf,const uint8_t[], +Variable,-,u8g2_font_ncenB12_tn,const uint8_t[], +Variable,-,u8g2_font_ncenB12_tr,const uint8_t[], +Variable,-,u8g2_font_ncenB14_te,const uint8_t[], +Variable,-,u8g2_font_ncenB14_tf,const uint8_t[], +Variable,-,u8g2_font_ncenB14_tn,const uint8_t[], +Variable,-,u8g2_font_ncenB14_tr,const uint8_t[], +Variable,-,u8g2_font_ncenB18_te,const uint8_t[], +Variable,-,u8g2_font_ncenB18_tf,const uint8_t[], +Variable,-,u8g2_font_ncenB18_tn,const uint8_t[], +Variable,-,u8g2_font_ncenB18_tr,const uint8_t[], +Variable,-,u8g2_font_ncenB24_te,const uint8_t[], +Variable,-,u8g2_font_ncenB24_tf,const uint8_t[], +Variable,-,u8g2_font_ncenB24_tn,const uint8_t[], +Variable,-,u8g2_font_ncenB24_tr,const uint8_t[], +Variable,-,u8g2_font_ncenR08_te,const uint8_t[], +Variable,-,u8g2_font_ncenR08_tf,const uint8_t[], +Variable,-,u8g2_font_ncenR08_tn,const uint8_t[], +Variable,-,u8g2_font_ncenR08_tr,const uint8_t[], +Variable,-,u8g2_font_ncenR10_te,const uint8_t[], +Variable,-,u8g2_font_ncenR10_tf,const uint8_t[], +Variable,-,u8g2_font_ncenR10_tn,const uint8_t[], +Variable,-,u8g2_font_ncenR10_tr,const uint8_t[], +Variable,-,u8g2_font_ncenR12_te,const uint8_t[], +Variable,-,u8g2_font_ncenR12_tf,const uint8_t[], +Variable,-,u8g2_font_ncenR12_tn,const uint8_t[], +Variable,-,u8g2_font_ncenR12_tr,const uint8_t[], +Variable,-,u8g2_font_ncenR14_te,const uint8_t[], +Variable,-,u8g2_font_ncenR14_tf,const uint8_t[], +Variable,-,u8g2_font_ncenR14_tn,const uint8_t[], +Variable,-,u8g2_font_ncenR14_tr,const uint8_t[], +Variable,-,u8g2_font_ncenR18_te,const uint8_t[], +Variable,-,u8g2_font_ncenR18_tf,const uint8_t[], +Variable,-,u8g2_font_ncenR18_tn,const uint8_t[], +Variable,-,u8g2_font_ncenR18_tr,const uint8_t[], +Variable,-,u8g2_font_ncenR24_te,const uint8_t[], +Variable,-,u8g2_font_ncenR24_tf,const uint8_t[], +Variable,-,u8g2_font_ncenR24_tn,const uint8_t[], +Variable,-,u8g2_font_ncenR24_tr,const uint8_t[], +Variable,-,u8g2_font_nerhoe_tf,const uint8_t[], +Variable,-,u8g2_font_nerhoe_tn,const uint8_t[], +Variable,-,u8g2_font_nerhoe_tr,const uint8_t[], +Variable,-,u8g2_font_nine_by_five_nbp_t_all,const uint8_t[], +Variable,-,u8g2_font_nine_by_five_nbp_tf,const uint8_t[], +Variable,-,u8g2_font_nine_by_five_nbp_tn,const uint8_t[], +Variable,-,u8g2_font_nine_by_five_nbp_tr,const uint8_t[], +Variable,-,u8g2_font_nokiafc22_tf,const uint8_t[], +Variable,-,u8g2_font_nokiafc22_tn,const uint8_t[], +Variable,-,u8g2_font_nokiafc22_tr,const uint8_t[], +Variable,-,u8g2_font_nokiafc22_tu,const uint8_t[], +Variable,-,u8g2_font_oldwizard_tf,const uint8_t[], +Variable,-,u8g2_font_oldwizard_tn,const uint8_t[], +Variable,-,u8g2_font_oldwizard_tr,const uint8_t[], +Variable,-,u8g2_font_oldwizard_tu,const uint8_t[], +Variable,-,u8g2_font_open_iconic_all_1x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_all_2x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_all_4x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_all_6x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_all_8x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_app_1x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_app_2x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_app_4x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_app_6x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_app_8x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_arrow_1x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_arrow_2x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_arrow_4x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_arrow_6x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_arrow_8x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_check_1x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_check_2x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_check_4x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_check_6x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_check_8x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_email_1x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_email_2x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_email_4x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_email_6x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_email_8x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_embedded_1x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_embedded_2x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_embedded_4x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_embedded_6x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_embedded_8x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_gui_1x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_gui_2x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_gui_4x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_gui_6x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_gui_8x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_human_1x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_human_2x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_human_4x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_human_6x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_human_8x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_mime_1x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_mime_2x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_mime_4x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_mime_6x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_mime_8x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_other_1x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_other_2x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_other_4x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_other_6x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_other_8x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_play_1x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_play_2x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_play_4x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_play_6x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_play_8x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_text_1x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_text_2x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_text_4x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_text_6x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_text_8x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_thing_1x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_thing_2x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_thing_4x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_thing_6x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_thing_8x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_weather_1x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_weather_2x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_weather_4x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_weather_6x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_weather_8x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_www_1x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_www_2x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_www_4x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_www_6x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_www_8x_t,const uint8_t[], +Variable,-,u8g2_font_ordinarybasis_t_all,const uint8_t[], +Variable,-,u8g2_font_ordinarybasis_tf,const uint8_t[], +Variable,-,u8g2_font_ordinarybasis_tn,const uint8_t[], +Variable,-,u8g2_font_ordinarybasis_tr,const uint8_t[], +Variable,-,u8g2_font_osb18_tf,const uint8_t[], +Variable,-,u8g2_font_osb18_tn,const uint8_t[], +Variable,-,u8g2_font_osb18_tr,const uint8_t[], +Variable,-,u8g2_font_osb21_tf,const uint8_t[], +Variable,-,u8g2_font_osb21_tn,const uint8_t[], +Variable,-,u8g2_font_osb21_tr,const uint8_t[], +Variable,-,u8g2_font_osb26_tf,const uint8_t[], +Variable,-,u8g2_font_osb26_tn,const uint8_t[], +Variable,-,u8g2_font_osb26_tr,const uint8_t[], +Variable,-,u8g2_font_osb29_tf,const uint8_t[], +Variable,-,u8g2_font_osb29_tn,const uint8_t[], +Variable,-,u8g2_font_osb29_tr,const uint8_t[], +Variable,-,u8g2_font_osb35_tf,const uint8_t[], +Variable,-,u8g2_font_osb35_tn,const uint8_t[], +Variable,-,u8g2_font_osb35_tr,const uint8_t[], +Variable,-,u8g2_font_osb41_tf,const uint8_t[], +Variable,-,u8g2_font_osb41_tn,const uint8_t[], +Variable,-,u8g2_font_osb41_tr,const uint8_t[], +Variable,-,u8g2_font_oskool_tf,const uint8_t[], +Variable,-,u8g2_font_oskool_tn,const uint8_t[], +Variable,-,u8g2_font_oskool_tr,const uint8_t[], +Variable,-,u8g2_font_osr18_tf,const uint8_t[], +Variable,-,u8g2_font_osr18_tn,const uint8_t[], +Variable,-,u8g2_font_osr18_tr,const uint8_t[], +Variable,-,u8g2_font_osr21_tf,const uint8_t[], +Variable,-,u8g2_font_osr21_tn,const uint8_t[], +Variable,-,u8g2_font_osr21_tr,const uint8_t[], +Variable,-,u8g2_font_osr26_tf,const uint8_t[], +Variable,-,u8g2_font_osr26_tn,const uint8_t[], +Variable,-,u8g2_font_osr26_tr,const uint8_t[], +Variable,-,u8g2_font_osr29_tf,const uint8_t[], +Variable,-,u8g2_font_osr29_tn,const uint8_t[], +Variable,-,u8g2_font_osr29_tr,const uint8_t[], +Variable,-,u8g2_font_osr35_tf,const uint8_t[], +Variable,-,u8g2_font_osr35_tn,const uint8_t[], +Variable,-,u8g2_font_osr35_tr,const uint8_t[], +Variable,-,u8g2_font_osr41_tf,const uint8_t[], +Variable,-,u8g2_font_osr41_tn,const uint8_t[], +Variable,-,u8g2_font_osr41_tr,const uint8_t[], +Variable,-,u8g2_font_p01type_tf,const uint8_t[], +Variable,-,u8g2_font_p01type_tn,const uint8_t[], +Variable,-,u8g2_font_p01type_tr,const uint8_t[], +Variable,-,u8g2_font_pcsenior_8f,const uint8_t[], +Variable,-,u8g2_font_pcsenior_8n,const uint8_t[], +Variable,-,u8g2_font_pcsenior_8r,const uint8_t[], +Variable,-,u8g2_font_pcsenior_8u,const uint8_t[], +Variable,-,u8g2_font_pearfont_tr,const uint8_t[], +Variable,-,u8g2_font_pieceofcake_mel_tn,const uint8_t[], +Variable,-,u8g2_font_pieceofcake_mel_tr,const uint8_t[], +Variable,-,u8g2_font_pixelle_micro_tn,const uint8_t[], +Variable,-,u8g2_font_pixelle_micro_tr,const uint8_t[], +Variable,-,u8g2_font_pixelmordred_t_all,const uint8_t[], +Variable,-,u8g2_font_pixelmordred_tf,const uint8_t[], +Variable,-,u8g2_font_pixelmordred_tn,const uint8_t[], +Variable,-,u8g2_font_pixelmordred_tr,const uint8_t[], +Variable,-,u8g2_font_pixelpoiiz_tr,const uint8_t[], +Variable,-,u8g2_font_press_mel_tn,const uint8_t[], +Variable,-,u8g2_font_press_mel_tr,const uint8_t[], +Variable,-,u8g2_font_pressstart2p_8f,const uint8_t[], +Variable,-,u8g2_font_pressstart2p_8n,const uint8_t[], +Variable,-,u8g2_font_pressstart2p_8r,const uint8_t[], +Variable,-,u8g2_font_pressstart2p_8u,const uint8_t[], +Variable,-,u8g2_font_profont10_mf,const uint8_t[], +Variable,-,u8g2_font_profont10_mn,const uint8_t[], +Variable,-,u8g2_font_profont10_mr,const uint8_t[], +Variable,-,u8g2_font_profont10_tf,const uint8_t[], +Variable,-,u8g2_font_profont10_tn,const uint8_t[], +Variable,-,u8g2_font_profont10_tr,const uint8_t[], +Variable,-,u8g2_font_profont11_mf,const uint8_t[], +Variable,-,u8g2_font_profont11_mn,const uint8_t[], +Variable,-,u8g2_font_profont11_mr,const uint8_t[], +Variable,-,u8g2_font_profont11_tf,const uint8_t[], +Variable,-,u8g2_font_profont11_tn,const uint8_t[], +Variable,-,u8g2_font_profont11_tr,const uint8_t[], +Variable,-,u8g2_font_profont12_mf,const uint8_t[], +Variable,-,u8g2_font_profont12_mn,const uint8_t[], +Variable,-,u8g2_font_profont12_mr,const uint8_t[], +Variable,-,u8g2_font_profont12_tf,const uint8_t[], +Variable,-,u8g2_font_profont12_tn,const uint8_t[], +Variable,-,u8g2_font_profont12_tr,const uint8_t[], +Variable,-,u8g2_font_profont15_mf,const uint8_t[], +Variable,-,u8g2_font_profont15_mn,const uint8_t[], +Variable,-,u8g2_font_profont15_mr,const uint8_t[], +Variable,-,u8g2_font_profont15_tf,const uint8_t[], +Variable,-,u8g2_font_profont15_tn,const uint8_t[], +Variable,-,u8g2_font_profont15_tr,const uint8_t[], +Variable,-,u8g2_font_profont17_mf,const uint8_t[], +Variable,-,u8g2_font_profont17_mn,const uint8_t[], +Variable,-,u8g2_font_profont17_mr,const uint8_t[], +Variable,-,u8g2_font_profont17_tf,const uint8_t[], +Variable,-,u8g2_font_profont17_tn,const uint8_t[], +Variable,-,u8g2_font_profont17_tr,const uint8_t[], +Variable,-,u8g2_font_profont22_mf,const uint8_t[], +Variable,-,u8g2_font_profont22_mn,const uint8_t[], +Variable,-,u8g2_font_profont22_mr,const uint8_t[], +Variable,-,u8g2_font_profont22_tf,const uint8_t[], +Variable,-,u8g2_font_profont22_tn,const uint8_t[], +Variable,-,u8g2_font_profont22_tr,const uint8_t[], +Variable,-,u8g2_font_profont29_mf,const uint8_t[], +Variable,-,u8g2_font_profont29_mn,const uint8_t[], +Variable,-,u8g2_font_profont29_mr,const uint8_t[], +Variable,-,u8g2_font_profont29_tf,const uint8_t[], +Variable,-,u8g2_font_profont29_tn,const uint8_t[], +Variable,-,u8g2_font_profont29_tr,const uint8_t[], +Variable,-,u8g2_font_prospero_bold_nbp_tf,const uint8_t[], +Variable,-,u8g2_font_prospero_bold_nbp_tn,const uint8_t[], +Variable,-,u8g2_font_prospero_bold_nbp_tr,const uint8_t[], +Variable,-,u8g2_font_prospero_nbp_tf,const uint8_t[], +Variable,-,u8g2_font_prospero_nbp_tn,const uint8_t[], +Variable,-,u8g2_font_prospero_nbp_tr,const uint8_t[], +Variable,-,u8g2_font_px437wyse700a_mf,const uint8_t[], +Variable,-,u8g2_font_px437wyse700a_mn,const uint8_t[], +Variable,-,u8g2_font_px437wyse700a_mr,const uint8_t[], +Variable,-,u8g2_font_px437wyse700a_tf,const uint8_t[], +Variable,-,u8g2_font_px437wyse700a_tn,const uint8_t[], +Variable,-,u8g2_font_px437wyse700a_tr,const uint8_t[], +Variable,-,u8g2_font_px437wyse700b_mf,const uint8_t[], +Variable,-,u8g2_font_px437wyse700b_mn,const uint8_t[], +Variable,-,u8g2_font_px437wyse700b_mr,const uint8_t[], +Variable,-,u8g2_font_px437wyse700b_tf,const uint8_t[], +Variable,-,u8g2_font_px437wyse700b_tn,const uint8_t[], +Variable,-,u8g2_font_px437wyse700b_tr,const uint8_t[], +Variable,-,u8g2_font_pxplusibmcga_8f,const uint8_t[], +Variable,-,u8g2_font_pxplusibmcga_8n,const uint8_t[], +Variable,-,u8g2_font_pxplusibmcga_8r,const uint8_t[], +Variable,-,u8g2_font_pxplusibmcga_8u,const uint8_t[], +Variable,-,u8g2_font_pxplusibmcgathin_8f,const uint8_t[], +Variable,-,u8g2_font_pxplusibmcgathin_8n,const uint8_t[], +Variable,-,u8g2_font_pxplusibmcgathin_8r,const uint8_t[], +Variable,-,u8g2_font_pxplusibmcgathin_8u,const uint8_t[], +Variable,-,u8g2_font_pxplusibmvga8_m_all,const uint8_t[], +Variable,-,u8g2_font_pxplusibmvga8_mf,const uint8_t[], +Variable,-,u8g2_font_pxplusibmvga8_mn,const uint8_t[], +Variable,-,u8g2_font_pxplusibmvga8_mr,const uint8_t[], +Variable,-,u8g2_font_pxplusibmvga8_t_all,const uint8_t[], +Variable,-,u8g2_font_pxplusibmvga8_tf,const uint8_t[], +Variable,-,u8g2_font_pxplusibmvga8_tn,const uint8_t[], +Variable,-,u8g2_font_pxplusibmvga8_tr,const uint8_t[], +Variable,-,u8g2_font_pxplusibmvga9_m_all,const uint8_t[], +Variable,-,u8g2_font_pxplusibmvga9_mf,const uint8_t[], +Variable,-,u8g2_font_pxplusibmvga9_mn,const uint8_t[], +Variable,-,u8g2_font_pxplusibmvga9_mr,const uint8_t[], +Variable,-,u8g2_font_pxplusibmvga9_t_all,const uint8_t[], +Variable,-,u8g2_font_pxplusibmvga9_tf,const uint8_t[], +Variable,-,u8g2_font_pxplusibmvga9_tn,const uint8_t[], +Variable,-,u8g2_font_pxplusibmvga9_tr,const uint8_t[], +Variable,-,u8g2_font_pxplustandynewtv_8_all,const uint8_t[], +Variable,-,u8g2_font_pxplustandynewtv_8f,const uint8_t[], +Variable,-,u8g2_font_pxplustandynewtv_8n,const uint8_t[], +Variable,-,u8g2_font_pxplustandynewtv_8r,const uint8_t[], +Variable,-,u8g2_font_pxplustandynewtv_8u,const uint8_t[], +Variable,-,u8g2_font_pxplustandynewtv_t_all,const uint8_t[], +Variable,-,u8g2_font_questgiver_tr,const uint8_t[], +Variable,-,u8g2_font_repress_mel_tn,const uint8_t[], +Variable,-,u8g2_font_repress_mel_tr,const uint8_t[], +Variable,-,u8g2_font_robot_de_niro_tf,const uint8_t[], +Variable,-,u8g2_font_robot_de_niro_tn,const uint8_t[], +Variable,-,u8g2_font_robot_de_niro_tr,const uint8_t[], +Variable,-,u8g2_font_roentgen_nbp_h_all,const uint8_t[], +Variable,-,u8g2_font_roentgen_nbp_t_all,const uint8_t[], +Variable,-,u8g2_font_roentgen_nbp_tf,const uint8_t[], +Variable,-,u8g2_font_roentgen_nbp_tn,const uint8_t[], +Variable,-,u8g2_font_roentgen_nbp_tr,const uint8_t[], +Variable,-,u8g2_font_rosencrantz_nbp_t_all,const uint8_t[], +Variable,-,u8g2_font_rosencrantz_nbp_tf,const uint8_t[], +Variable,-,u8g2_font_rosencrantz_nbp_tn,const uint8_t[], +Variable,-,u8g2_font_rosencrantz_nbp_tr,const uint8_t[], +Variable,-,u8g2_font_saikyosansbold8_8n,const uint8_t[], +Variable,-,u8g2_font_saikyosansbold8_8u,const uint8_t[], +Variable,-,u8g2_font_samim_10_t_all,const uint8_t[], +Variable,-,u8g2_font_samim_12_t_all,const uint8_t[], +Variable,-,u8g2_font_samim_14_t_all,const uint8_t[], +Variable,-,u8g2_font_samim_16_t_all,const uint8_t[], +Variable,-,u8g2_font_samim_fd_10_t_all,const uint8_t[], +Variable,-,u8g2_font_samim_fd_12_t_all,const uint8_t[], +Variable,-,u8g2_font_samim_fd_14_t_all,const uint8_t[], +Variable,-,u8g2_font_samim_fd_16_t_all,const uint8_t[], +Variable,-,u8g2_font_sandyforest_tn,const uint8_t[], +Variable,-,u8g2_font_sandyforest_tr,const uint8_t[], +Variable,-,u8g2_font_sandyforest_tu,const uint8_t[], +Variable,-,u8g2_font_secretaryhand_t_all,const uint8_t[], +Variable,-,u8g2_font_secretaryhand_tf,const uint8_t[], +Variable,-,u8g2_font_secretaryhand_tn,const uint8_t[], +Variable,-,u8g2_font_secretaryhand_tr,const uint8_t[], +Variable,-,u8g2_font_seraphimb1_tr,const uint8_t[], +Variable,-,u8g2_font_shylock_nbp_t_all,const uint8_t[], +Variable,-,u8g2_font_shylock_nbp_tf,const uint8_t[], +Variable,-,u8g2_font_shylock_nbp_tn,const uint8_t[], +Variable,-,u8g2_font_shylock_nbp_tr,const uint8_t[], +Variable,-,u8g2_font_siji_t_6x10,const uint8_t[], +Variable,-,u8g2_font_sirclive_tn,const uint8_t[], +Variable,-,u8g2_font_sirclive_tr,const uint8_t[], +Variable,-,u8g2_font_sirclivethebold_tn,const uint8_t[], +Variable,-,u8g2_font_sirclivethebold_tr,const uint8_t[], +Variable,-,u8g2_font_smart_patrol_nbp_tf,const uint8_t[], +Variable,-,u8g2_font_smart_patrol_nbp_tn,const uint8_t[], +Variable,-,u8g2_font_smart_patrol_nbp_tr,const uint8_t[], +Variable,-,u8g2_font_squirrel_tn,const uint8_t[], +Variable,-,u8g2_font_squirrel_tr,const uint8_t[], +Variable,-,u8g2_font_squirrel_tu,const uint8_t[], +Variable,-,u8g2_font_sticker_mel_tn,const uint8_t[], +Variable,-,u8g2_font_sticker_mel_tr,const uint8_t[], +Variable,-,u8g2_font_synchronizer_nbp_tf,const uint8_t[], +Variable,-,u8g2_font_synchronizer_nbp_tn,const uint8_t[], +Variable,-,u8g2_font_synchronizer_nbp_tr,const uint8_t[], +Variable,-,u8g2_font_t0_11_me,const uint8_t[], +Variable,-,u8g2_font_t0_11_mf,const uint8_t[], +Variable,-,u8g2_font_t0_11_mn,const uint8_t[], +Variable,-,u8g2_font_t0_11_mr,const uint8_t[], +Variable,-,u8g2_font_t0_11_t_all,const uint8_t[], +Variable,-,u8g2_font_t0_11_te,const uint8_t[], +Variable,-,u8g2_font_t0_11_tf,const uint8_t[], +Variable,-,u8g2_font_t0_11_tn,const uint8_t[], +Variable,-,u8g2_font_t0_11_tr,const uint8_t[], +Variable,-,u8g2_font_t0_11b_me,const uint8_t[], +Variable,-,u8g2_font_t0_11b_mf,const uint8_t[], +Variable,-,u8g2_font_t0_11b_mn,const uint8_t[], +Variable,-,u8g2_font_t0_11b_mr,const uint8_t[], +Variable,-,u8g2_font_t0_11b_te,const uint8_t[], +Variable,-,u8g2_font_t0_11b_tf,const uint8_t[], +Variable,-,u8g2_font_t0_11b_tn,const uint8_t[], +Variable,-,u8g2_font_t0_11b_tr,const uint8_t[], +Variable,-,u8g2_font_t0_12_me,const uint8_t[], +Variable,-,u8g2_font_t0_12_mf,const uint8_t[], +Variable,-,u8g2_font_t0_12_mn,const uint8_t[], +Variable,-,u8g2_font_t0_12_mr,const uint8_t[], +Variable,-,u8g2_font_t0_12_te,const uint8_t[], +Variable,-,u8g2_font_t0_12_tf,const uint8_t[], +Variable,-,u8g2_font_t0_12_tn,const uint8_t[], +Variable,-,u8g2_font_t0_12_tr,const uint8_t[], +Variable,-,u8g2_font_t0_12b_me,const uint8_t[], +Variable,-,u8g2_font_t0_12b_mf,const uint8_t[], +Variable,-,u8g2_font_t0_12b_mn,const uint8_t[], +Variable,-,u8g2_font_t0_12b_mr,const uint8_t[], +Variable,-,u8g2_font_t0_12b_te,const uint8_t[], +Variable,-,u8g2_font_t0_12b_tf,const uint8_t[], +Variable,-,u8g2_font_t0_12b_tn,const uint8_t[], +Variable,-,u8g2_font_t0_12b_tr,const uint8_t[], +Variable,-,u8g2_font_t0_13_me,const uint8_t[], +Variable,-,u8g2_font_t0_13_mf,const uint8_t[], +Variable,-,u8g2_font_t0_13_mn,const uint8_t[], +Variable,-,u8g2_font_t0_13_mr,const uint8_t[], +Variable,-,u8g2_font_t0_13_te,const uint8_t[], +Variable,-,u8g2_font_t0_13_tf,const uint8_t[], +Variable,-,u8g2_font_t0_13_tn,const uint8_t[], +Variable,-,u8g2_font_t0_13_tr,const uint8_t[], +Variable,-,u8g2_font_t0_13b_me,const uint8_t[], +Variable,-,u8g2_font_t0_13b_mf,const uint8_t[], +Variable,-,u8g2_font_t0_13b_mn,const uint8_t[], +Variable,-,u8g2_font_t0_13b_mr,const uint8_t[], +Variable,-,u8g2_font_t0_13b_te,const uint8_t[], +Variable,-,u8g2_font_t0_13b_tf,const uint8_t[], +Variable,-,u8g2_font_t0_13b_tn,const uint8_t[], +Variable,-,u8g2_font_t0_13b_tr,const uint8_t[], +Variable,-,u8g2_font_t0_14_me,const uint8_t[], +Variable,-,u8g2_font_t0_14_mf,const uint8_t[], +Variable,-,u8g2_font_t0_14_mn,const uint8_t[], +Variable,-,u8g2_font_t0_14_mr,const uint8_t[], +Variable,-,u8g2_font_t0_14_te,const uint8_t[], +Variable,-,u8g2_font_t0_14_tf,const uint8_t[], +Variable,-,u8g2_font_t0_14_tn,const uint8_t[], +Variable,-,u8g2_font_t0_14_tr,const uint8_t[], +Variable,-,u8g2_font_t0_14b_me,const uint8_t[], +Variable,-,u8g2_font_t0_14b_mf,const uint8_t[], +Variable,-,u8g2_font_t0_14b_mn,const uint8_t[], +Variable,-,u8g2_font_t0_14b_mr,const uint8_t[], +Variable,-,u8g2_font_t0_14b_te,const uint8_t[], +Variable,-,u8g2_font_t0_14b_tf,const uint8_t[], +Variable,-,u8g2_font_t0_14b_tn,const uint8_t[], +Variable,-,u8g2_font_t0_14b_tr,const uint8_t[], +Variable,-,u8g2_font_t0_15_me,const uint8_t[], +Variable,-,u8g2_font_t0_15_mf,const uint8_t[], +Variable,-,u8g2_font_t0_15_mn,const uint8_t[], +Variable,-,u8g2_font_t0_15_mr,const uint8_t[], +Variable,-,u8g2_font_t0_15_te,const uint8_t[], +Variable,-,u8g2_font_t0_15_tf,const uint8_t[], +Variable,-,u8g2_font_t0_15_tn,const uint8_t[], +Variable,-,u8g2_font_t0_15_tr,const uint8_t[], +Variable,-,u8g2_font_t0_15b_me,const uint8_t[], +Variable,-,u8g2_font_t0_15b_mf,const uint8_t[], +Variable,-,u8g2_font_t0_15b_mn,const uint8_t[], +Variable,-,u8g2_font_t0_15b_mr,const uint8_t[], +Variable,-,u8g2_font_t0_15b_te,const uint8_t[], +Variable,-,u8g2_font_t0_15b_tf,const uint8_t[], +Variable,-,u8g2_font_t0_15b_tn,const uint8_t[], +Variable,-,u8g2_font_t0_15b_tr,const uint8_t[], +Variable,-,u8g2_font_t0_16_me,const uint8_t[], +Variable,-,u8g2_font_t0_16_mf,const uint8_t[], +Variable,-,u8g2_font_t0_16_mn,const uint8_t[], +Variable,-,u8g2_font_t0_16_mr,const uint8_t[], +Variable,-,u8g2_font_t0_16_te,const uint8_t[], +Variable,-,u8g2_font_t0_16_tf,const uint8_t[], +Variable,-,u8g2_font_t0_16_tn,const uint8_t[], +Variable,-,u8g2_font_t0_16_tr,const uint8_t[], +Variable,-,u8g2_font_t0_16b_me,const uint8_t[], +Variable,-,u8g2_font_t0_16b_mf,const uint8_t[], +Variable,-,u8g2_font_t0_16b_mn,const uint8_t[], +Variable,-,u8g2_font_t0_16b_mr,const uint8_t[], +Variable,-,u8g2_font_t0_16b_te,const uint8_t[], +Variable,-,u8g2_font_t0_16b_tf,const uint8_t[], +Variable,-,u8g2_font_t0_16b_tn,const uint8_t[], +Variable,-,u8g2_font_t0_16b_tr,const uint8_t[], +Variable,-,u8g2_font_t0_17_me,const uint8_t[], +Variable,-,u8g2_font_t0_17_mf,const uint8_t[], +Variable,-,u8g2_font_t0_17_mn,const uint8_t[], +Variable,-,u8g2_font_t0_17_mr,const uint8_t[], +Variable,-,u8g2_font_t0_17_te,const uint8_t[], +Variable,-,u8g2_font_t0_17_tf,const uint8_t[], +Variable,-,u8g2_font_t0_17_tn,const uint8_t[], +Variable,-,u8g2_font_t0_17_tr,const uint8_t[], +Variable,-,u8g2_font_t0_17b_me,const uint8_t[], +Variable,-,u8g2_font_t0_17b_mf,const uint8_t[], +Variable,-,u8g2_font_t0_17b_mn,const uint8_t[], +Variable,-,u8g2_font_t0_17b_mr,const uint8_t[], +Variable,-,u8g2_font_t0_17b_te,const uint8_t[], +Variable,-,u8g2_font_t0_17b_tf,const uint8_t[], +Variable,-,u8g2_font_t0_17b_tn,const uint8_t[], +Variable,-,u8g2_font_t0_17b_tr,const uint8_t[], +Variable,-,u8g2_font_t0_18_me,const uint8_t[], +Variable,-,u8g2_font_t0_18_mf,const uint8_t[], +Variable,-,u8g2_font_t0_18_mn,const uint8_t[], +Variable,-,u8g2_font_t0_18_mr,const uint8_t[], +Variable,-,u8g2_font_t0_18_te,const uint8_t[], +Variable,-,u8g2_font_t0_18_tf,const uint8_t[], +Variable,-,u8g2_font_t0_18_tn,const uint8_t[], +Variable,-,u8g2_font_t0_18_tr,const uint8_t[], +Variable,-,u8g2_font_t0_18b_me,const uint8_t[], +Variable,-,u8g2_font_t0_18b_mf,const uint8_t[], +Variable,-,u8g2_font_t0_18b_mn,const uint8_t[], +Variable,-,u8g2_font_t0_18b_mr,const uint8_t[], +Variable,-,u8g2_font_t0_18b_te,const uint8_t[], +Variable,-,u8g2_font_t0_18b_tf,const uint8_t[], +Variable,-,u8g2_font_t0_18b_tn,const uint8_t[], +Variable,-,u8g2_font_t0_18b_tr,const uint8_t[], +Variable,-,u8g2_font_t0_22_me,const uint8_t[], +Variable,-,u8g2_font_t0_22_mf,const uint8_t[], +Variable,-,u8g2_font_t0_22_mn,const uint8_t[], +Variable,-,u8g2_font_t0_22_mr,const uint8_t[], +Variable,-,u8g2_font_t0_22_te,const uint8_t[], +Variable,-,u8g2_font_t0_22_tf,const uint8_t[], +Variable,-,u8g2_font_t0_22_tn,const uint8_t[], +Variable,-,u8g2_font_t0_22_tr,const uint8_t[], +Variable,-,u8g2_font_t0_22b_me,const uint8_t[], +Variable,-,u8g2_font_t0_22b_mf,const uint8_t[], +Variable,-,u8g2_font_t0_22b_mn,const uint8_t[], +Variable,-,u8g2_font_t0_22b_mr,const uint8_t[], +Variable,-,u8g2_font_t0_22b_te,const uint8_t[], +Variable,-,u8g2_font_t0_22b_tf,const uint8_t[], +Variable,-,u8g2_font_t0_22b_tn,const uint8_t[], +Variable,-,u8g2_font_t0_22b_tr,const uint8_t[], +Variable,-,u8g2_font_tallpix_tr,const uint8_t[], +Variable,-,u8g2_font_tenfatguys_t_all,const uint8_t[], +Variable,-,u8g2_font_tenfatguys_tf,const uint8_t[], +Variable,-,u8g2_font_tenfatguys_tn,const uint8_t[], +Variable,-,u8g2_font_tenfatguys_tr,const uint8_t[], +Variable,-,u8g2_font_tenfatguys_tu,const uint8_t[], +Variable,-,u8g2_font_tenstamps_mf,const uint8_t[], +Variable,-,u8g2_font_tenstamps_mn,const uint8_t[], +Variable,-,u8g2_font_tenstamps_mr,const uint8_t[], +Variable,-,u8g2_font_tenstamps_mu,const uint8_t[], +Variable,-,u8g2_font_tenthinguys_t_all,const uint8_t[], +Variable,-,u8g2_font_tenthinguys_tf,const uint8_t[], +Variable,-,u8g2_font_tenthinguys_tn,const uint8_t[], +Variable,-,u8g2_font_tenthinguys_tr,const uint8_t[], +Variable,-,u8g2_font_tenthinguys_tu,const uint8_t[], +Variable,-,u8g2_font_tenthinnerguys_t_all,const uint8_t[], +Variable,-,u8g2_font_tenthinnerguys_tf,const uint8_t[], +Variable,-,u8g2_font_tenthinnerguys_tn,const uint8_t[], +Variable,-,u8g2_font_tenthinnerguys_tr,const uint8_t[], +Variable,-,u8g2_font_tenthinnerguys_tu,const uint8_t[], +Variable,-,u8g2_font_timB08_tf,const uint8_t[], +Variable,-,u8g2_font_timB08_tn,const uint8_t[], +Variable,-,u8g2_font_timB08_tr,const uint8_t[], +Variable,-,u8g2_font_timB10_tf,const uint8_t[], +Variable,-,u8g2_font_timB10_tn,const uint8_t[], +Variable,-,u8g2_font_timB10_tr,const uint8_t[], +Variable,-,u8g2_font_timB12_tf,const uint8_t[], +Variable,-,u8g2_font_timB12_tn,const uint8_t[], +Variable,-,u8g2_font_timB12_tr,const uint8_t[], +Variable,-,u8g2_font_timB14_tf,const uint8_t[], +Variable,-,u8g2_font_timB14_tn,const uint8_t[], +Variable,-,u8g2_font_timB14_tr,const uint8_t[], +Variable,-,u8g2_font_timB18_tf,const uint8_t[], +Variable,-,u8g2_font_timB18_tn,const uint8_t[], +Variable,-,u8g2_font_timB18_tr,const uint8_t[], +Variable,-,u8g2_font_timB24_tf,const uint8_t[], +Variable,-,u8g2_font_timB24_tn,const uint8_t[], +Variable,-,u8g2_font_timB24_tr,const uint8_t[], +Variable,-,u8g2_font_timR08_tf,const uint8_t[], +Variable,-,u8g2_font_timR08_tn,const uint8_t[], +Variable,-,u8g2_font_timR08_tr,const uint8_t[], +Variable,-,u8g2_font_timR10_tf,const uint8_t[], +Variable,-,u8g2_font_timR10_tn,const uint8_t[], +Variable,-,u8g2_font_timR10_tr,const uint8_t[], +Variable,-,u8g2_font_timR12_tf,const uint8_t[], +Variable,-,u8g2_font_timR12_tn,const uint8_t[], +Variable,-,u8g2_font_timR12_tr,const uint8_t[], +Variable,-,u8g2_font_timR14_tf,const uint8_t[], +Variable,-,u8g2_font_timR14_tn,const uint8_t[], +Variable,-,u8g2_font_timR14_tr,const uint8_t[], +Variable,-,u8g2_font_timR18_tf,const uint8_t[], +Variable,-,u8g2_font_timR18_tn,const uint8_t[], +Variable,-,u8g2_font_timR18_tr,const uint8_t[], +Variable,-,u8g2_font_timR24_tf,const uint8_t[], +Variable,-,u8g2_font_timR24_tn,const uint8_t[], +Variable,-,u8g2_font_timR24_tr,const uint8_t[], +Variable,-,u8g2_font_tinytim_tf,const uint8_t[], +Variable,-,u8g2_font_tinytim_tn,const uint8_t[], +Variable,-,u8g2_font_tinytim_tr,const uint8_t[], +Variable,-,u8g2_font_tom_thumb_4x6_me,const uint8_t[], +Variable,-,u8g2_font_tom_thumb_4x6_mf,const uint8_t[], +Variable,-,u8g2_font_tom_thumb_4x6_mn,const uint8_t[], +Variable,-,u8g2_font_tom_thumb_4x6_mr,const uint8_t[], +Variable,-,u8g2_font_tom_thumb_4x6_t_all,const uint8_t[], +Variable,-,u8g2_font_tom_thumb_4x6_te,const uint8_t[], +Variable,-,u8g2_font_tom_thumb_4x6_tf,const uint8_t[], +Variable,-,u8g2_font_tom_thumb_4x6_tn,const uint8_t[], +Variable,-,u8g2_font_tom_thumb_4x6_tr,const uint8_t[], +Variable,-,u8g2_font_tooseornament_tf,const uint8_t[], +Variable,-,u8g2_font_tooseornament_tn,const uint8_t[], +Variable,-,u8g2_font_tooseornament_tr,const uint8_t[], +Variable,-,u8g2_font_torussansbold8_8n,const uint8_t[], +Variable,-,u8g2_font_torussansbold8_8r,const uint8_t[], +Variable,-,u8g2_font_torussansbold8_8u,const uint8_t[], +Variable,-,u8g2_font_trixel_square_tf,const uint8_t[], +Variable,-,u8g2_font_trixel_square_tn,const uint8_t[], +Variable,-,u8g2_font_trixel_square_tr,const uint8_t[], +Variable,-,u8g2_font_twelvedings_t_all,const uint8_t[], +Variable,-,u8g2_font_u8glib_4_hf,const uint8_t[], +Variable,-,u8g2_font_u8glib_4_hr,const uint8_t[], +Variable,-,u8g2_font_u8glib_4_tf,const uint8_t[], +Variable,-,u8g2_font_u8glib_4_tr,const uint8_t[], +Variable,-,u8g2_font_unifont_h_symbols,const uint8_t[], +Variable,-,u8g2_font_unifont_t_0_72_73,const uint8_t[], +Variable,-,u8g2_font_unifont_t_0_75,const uint8_t[], +Variable,-,u8g2_font_unifont_t_0_76,const uint8_t[], +Variable,-,u8g2_font_unifont_t_0_77,const uint8_t[], +Variable,-,u8g2_font_unifont_t_0_78_79,const uint8_t[], +Variable,-,u8g2_font_unifont_t_0_86,const uint8_t[], +Variable,-,u8g2_font_unifont_t_72_73,const uint8_t[], +Variable,-,u8g2_font_unifont_t_75,const uint8_t[], +Variable,-,u8g2_font_unifont_t_76,const uint8_t[], +Variable,-,u8g2_font_unifont_t_77,const uint8_t[], +Variable,-,u8g2_font_unifont_t_78_79,const uint8_t[], +Variable,-,u8g2_font_unifont_t_86,const uint8_t[], +Variable,-,u8g2_font_unifont_t_animals,const uint8_t[], +Variable,-,u8g2_font_unifont_t_arabic,const uint8_t[], +Variable,-,u8g2_font_unifont_t_bengali,const uint8_t[], +Variable,-,u8g2_font_unifont_t_cards,const uint8_t[], +Variable,-,u8g2_font_unifont_t_chinese1,const uint8_t[], +Variable,-,u8g2_font_unifont_t_chinese2,const uint8_t[], +Variable,-,u8g2_font_unifont_t_chinese3,const uint8_t[], +Variable,-,u8g2_font_unifont_t_cyrillic,const uint8_t[], +Variable,-,u8g2_font_unifont_t_devanagari,const uint8_t[], +Variable,-,u8g2_font_unifont_t_domino,const uint8_t[], +Variable,-,u8g2_font_unifont_t_emoticons,const uint8_t[], +Variable,-,u8g2_font_unifont_t_extended,const uint8_t[], +Variable,-,u8g2_font_unifont_t_greek,const uint8_t[], +Variable,-,u8g2_font_unifont_t_hebrew,const uint8_t[], +Variable,-,u8g2_font_unifont_t_japanese1,const uint8_t[], +Variable,-,u8g2_font_unifont_t_japanese2,const uint8_t[], +Variable,-,u8g2_font_unifont_t_japanese3,const uint8_t[], +Variable,-,u8g2_font_unifont_t_korean1,const uint8_t[], +Variable,-,u8g2_font_unifont_t_korean2,const uint8_t[], +Variable,-,u8g2_font_unifont_t_latin,const uint8_t[], +Variable,-,u8g2_font_unifont_t_polish,const uint8_t[], +Variable,-,u8g2_font_unifont_t_symbols,const uint8_t[], +Variable,-,u8g2_font_unifont_t_tibetan,const uint8_t[], +Variable,-,u8g2_font_unifont_t_urdu,const uint8_t[], +Variable,-,u8g2_font_unifont_t_vietnamese1,const uint8_t[], +Variable,-,u8g2_font_unifont_t_vietnamese2,const uint8_t[], +Variable,-,u8g2_font_unifont_t_weather,const uint8_t[], +Variable,-,u8g2_font_unifont_te,const uint8_t[], +Variable,-,u8g2_font_unifont_tf,const uint8_t[], +Variable,-,u8g2_font_unifont_tr,const uint8_t[], +Variable,-,u8g2_font_victoriabold8_8n,const uint8_t[], +Variable,-,u8g2_font_victoriabold8_8r,const uint8_t[], +Variable,-,u8g2_font_victoriabold8_8u,const uint8_t[], +Variable,-,u8g2_font_victoriamedium8_8n,const uint8_t[], +Variable,-,u8g2_font_victoriamedium8_8r,const uint8_t[], +Variable,-,u8g2_font_victoriamedium8_8u,const uint8_t[], +Variable,-,u8g2_font_wqy12_t_chinese1,const uint8_t[], +Variable,-,u8g2_font_wqy12_t_chinese2,const uint8_t[], +Variable,-,u8g2_font_wqy12_t_chinese3,const uint8_t[], +Variable,-,u8g2_font_wqy12_t_gb2312,const uint8_t[], +Variable,-,u8g2_font_wqy12_t_gb2312a,const uint8_t[], +Variable,-,u8g2_font_wqy12_t_gb2312b,const uint8_t[], +Variable,-,u8g2_font_wqy13_t_chinese1,const uint8_t[], +Variable,-,u8g2_font_wqy13_t_chinese2,const uint8_t[], +Variable,-,u8g2_font_wqy13_t_chinese3,const uint8_t[], +Variable,-,u8g2_font_wqy13_t_gb2312,const uint8_t[], +Variable,-,u8g2_font_wqy13_t_gb2312a,const uint8_t[], +Variable,-,u8g2_font_wqy13_t_gb2312b,const uint8_t[], +Variable,-,u8g2_font_wqy14_t_chinese1,const uint8_t[], +Variable,-,u8g2_font_wqy14_t_chinese2,const uint8_t[], +Variable,-,u8g2_font_wqy14_t_chinese3,const uint8_t[], +Variable,-,u8g2_font_wqy14_t_gb2312,const uint8_t[], +Variable,-,u8g2_font_wqy14_t_gb2312a,const uint8_t[], +Variable,-,u8g2_font_wqy14_t_gb2312b,const uint8_t[], +Variable,-,u8g2_font_wqy15_t_chinese1,const uint8_t[], +Variable,-,u8g2_font_wqy15_t_chinese2,const uint8_t[], +Variable,-,u8g2_font_wqy15_t_chinese3,const uint8_t[], +Variable,-,u8g2_font_wqy15_t_gb2312,const uint8_t[], +Variable,-,u8g2_font_wqy15_t_gb2312a,const uint8_t[], +Variable,-,u8g2_font_wqy15_t_gb2312b,const uint8_t[], +Variable,-,u8g2_font_wqy16_t_chinese1,const uint8_t[], +Variable,-,u8g2_font_wqy16_t_chinese2,const uint8_t[], +Variable,-,u8g2_font_wqy16_t_chinese3,const uint8_t[], +Variable,-,u8g2_font_wqy16_t_gb2312,const uint8_t[], +Variable,-,u8g2_font_wqy16_t_gb2312a,const uint8_t[], +Variable,-,u8g2_font_wqy16_t_gb2312b,const uint8_t[], +Variable,-,u8x8_font_5x7_f,const uint8_t[], +Variable,-,u8x8_font_5x7_n,const uint8_t[], +Variable,-,u8x8_font_5x7_r,const uint8_t[], +Variable,-,u8x8_font_5x8_f,const uint8_t[], +Variable,-,u8x8_font_5x8_n,const uint8_t[], +Variable,-,u8x8_font_5x8_r,const uint8_t[], +Variable,-,u8x8_font_7x14B_1x2_f,const uint8_t[], +Variable,-,u8x8_font_7x14B_1x2_n,const uint8_t[], +Variable,-,u8x8_font_7x14B_1x2_r,const uint8_t[], +Variable,-,u8x8_font_7x14_1x2_f,const uint8_t[], +Variable,-,u8x8_font_7x14_1x2_n,const uint8_t[], +Variable,-,u8x8_font_7x14_1x2_r,const uint8_t[], +Variable,-,u8x8_font_8x13B_1x2_f,const uint8_t[], +Variable,-,u8x8_font_8x13B_1x2_n,const uint8_t[], +Variable,-,u8x8_font_8x13B_1x2_r,const uint8_t[], +Variable,-,u8x8_font_8x13_1x2_f,const uint8_t[], +Variable,-,u8x8_font_8x13_1x2_n,const uint8_t[], +Variable,-,u8x8_font_8x13_1x2_r,const uint8_t[], +Variable,-,u8x8_font_amstrad_cpc_extended_f,const uint8_t[], +Variable,-,u8x8_font_amstrad_cpc_extended_n,const uint8_t[], +Variable,-,u8x8_font_amstrad_cpc_extended_r,const uint8_t[], +Variable,-,u8x8_font_amstrad_cpc_extended_u,const uint8_t[], +Variable,-,u8x8_font_artossans8_n,const uint8_t[], +Variable,-,u8x8_font_artossans8_r,const uint8_t[], +Variable,-,u8x8_font_artossans8_u,const uint8_t[], +Variable,-,u8x8_font_artosserif8_n,const uint8_t[], +Variable,-,u8x8_font_artosserif8_r,const uint8_t[], +Variable,-,u8x8_font_artosserif8_u,const uint8_t[], +Variable,-,u8x8_font_chroma48medium8_n,const uint8_t[], +Variable,-,u8x8_font_chroma48medium8_r,const uint8_t[], +Variable,-,u8x8_font_chroma48medium8_u,const uint8_t[], +Variable,-,u8x8_font_courB18_2x3_f,const uint8_t[], +Variable,-,u8x8_font_courB18_2x3_n,const uint8_t[], +Variable,-,u8x8_font_courB18_2x3_r,const uint8_t[], +Variable,-,u8x8_font_courB24_3x4_f,const uint8_t[], +Variable,-,u8x8_font_courB24_3x4_n,const uint8_t[], +Variable,-,u8x8_font_courB24_3x4_r,const uint8_t[], +Variable,-,u8x8_font_courR18_2x3_f,const uint8_t[], +Variable,-,u8x8_font_courR18_2x3_n,const uint8_t[], +Variable,-,u8x8_font_courR18_2x3_r,const uint8_t[], +Variable,-,u8x8_font_courR24_3x4_f,const uint8_t[], +Variable,-,u8x8_font_courR24_3x4_n,const uint8_t[], +Variable,-,u8x8_font_courR24_3x4_r,const uint8_t[], +Variable,-,u8x8_font_inb21_2x4_f,const uint8_t[], +Variable,-,u8x8_font_inb21_2x4_n,const uint8_t[], +Variable,-,u8x8_font_inb21_2x4_r,const uint8_t[], +Variable,-,u8x8_font_inb33_3x6_f,const uint8_t[], +Variable,-,u8x8_font_inb33_3x6_n,const uint8_t[], +Variable,-,u8x8_font_inb33_3x6_r,const uint8_t[], +Variable,-,u8x8_font_inb46_4x8_f,const uint8_t[], +Variable,-,u8x8_font_inb46_4x8_n,const uint8_t[], +Variable,-,u8x8_font_inb46_4x8_r,const uint8_t[], +Variable,-,u8x8_font_inr21_2x4_f,const uint8_t[], +Variable,-,u8x8_font_inr21_2x4_n,const uint8_t[], +Variable,-,u8x8_font_inr21_2x4_r,const uint8_t[], +Variable,-,u8x8_font_inr33_3x6_f,const uint8_t[], +Variable,-,u8x8_font_inr33_3x6_n,const uint8_t[], +Variable,-,u8x8_font_inr33_3x6_r,const uint8_t[], +Variable,-,u8x8_font_inr46_4x8_f,const uint8_t[], +Variable,-,u8x8_font_inr46_4x8_n,const uint8_t[], +Variable,-,u8x8_font_inr46_4x8_r,const uint8_t[], +Variable,-,u8x8_font_lucasarts_scumm_subtitle_o_2x2_f,const uint8_t[], +Variable,-,u8x8_font_lucasarts_scumm_subtitle_o_2x2_n,const uint8_t[], +Variable,-,u8x8_font_lucasarts_scumm_subtitle_o_2x2_r,const uint8_t[], +Variable,-,u8x8_font_lucasarts_scumm_subtitle_r_2x2_f,const uint8_t[], +Variable,-,u8x8_font_lucasarts_scumm_subtitle_r_2x2_n,const uint8_t[], +Variable,-,u8x8_font_lucasarts_scumm_subtitle_r_2x2_r,const uint8_t[], +Variable,-,u8x8_font_open_iconic_arrow_1x1,const uint8_t[], +Variable,-,u8x8_font_open_iconic_arrow_2x2,const uint8_t[], +Variable,-,u8x8_font_open_iconic_arrow_4x4,const uint8_t[], +Variable,-,u8x8_font_open_iconic_arrow_8x8,const uint8_t[], +Variable,-,u8x8_font_open_iconic_check_1x1,const uint8_t[], +Variable,-,u8x8_font_open_iconic_check_2x2,const uint8_t[], +Variable,-,u8x8_font_open_iconic_check_4x4,const uint8_t[], +Variable,-,u8x8_font_open_iconic_check_8x8,const uint8_t[], +Variable,-,u8x8_font_open_iconic_embedded_1x1,const uint8_t[], +Variable,-,u8x8_font_open_iconic_embedded_2x2,const uint8_t[], +Variable,-,u8x8_font_open_iconic_embedded_4x4,const uint8_t[], +Variable,-,u8x8_font_open_iconic_embedded_8x8,const uint8_t[], +Variable,-,u8x8_font_open_iconic_play_1x1,const uint8_t[], +Variable,-,u8x8_font_open_iconic_play_2x2,const uint8_t[], +Variable,-,u8x8_font_open_iconic_play_4x4,const uint8_t[], +Variable,-,u8x8_font_open_iconic_play_8x8,const uint8_t[], +Variable,-,u8x8_font_open_iconic_thing_1x1,const uint8_t[], +Variable,-,u8x8_font_open_iconic_thing_2x2,const uint8_t[], +Variable,-,u8x8_font_open_iconic_thing_4x4,const uint8_t[], +Variable,-,u8x8_font_open_iconic_thing_8x8,const uint8_t[], +Variable,-,u8x8_font_open_iconic_weather_1x1,const uint8_t[], +Variable,-,u8x8_font_open_iconic_weather_2x2,const uint8_t[], +Variable,-,u8x8_font_open_iconic_weather_4x4,const uint8_t[], +Variable,-,u8x8_font_open_iconic_weather_8x8,const uint8_t[], +Variable,-,u8x8_font_pcsenior_f,const uint8_t[], +Variable,-,u8x8_font_pcsenior_n,const uint8_t[], +Variable,-,u8x8_font_pcsenior_r,const uint8_t[], +Variable,-,u8x8_font_pcsenior_u,const uint8_t[], +Variable,-,u8x8_font_pressstart2p_f,const uint8_t[], +Variable,-,u8x8_font_pressstart2p_n,const uint8_t[], +Variable,-,u8x8_font_pressstart2p_r,const uint8_t[], +Variable,-,u8x8_font_pressstart2p_u,const uint8_t[], +Variable,-,u8x8_font_profont29_2x3_f,const uint8_t[], +Variable,-,u8x8_font_profont29_2x3_n,const uint8_t[], +Variable,-,u8x8_font_profont29_2x3_r,const uint8_t[], +Variable,-,u8x8_font_px437wyse700a_2x2_f,const uint8_t[], +Variable,-,u8x8_font_px437wyse700a_2x2_n,const uint8_t[], +Variable,-,u8x8_font_px437wyse700a_2x2_r,const uint8_t[], +Variable,-,u8x8_font_px437wyse700b_2x2_f,const uint8_t[], +Variable,-,u8x8_font_px437wyse700b_2x2_n,const uint8_t[], +Variable,-,u8x8_font_px437wyse700b_2x2_r,const uint8_t[], +Variable,-,u8x8_font_pxplusibmcga_f,const uint8_t[], +Variable,-,u8x8_font_pxplusibmcga_n,const uint8_t[], +Variable,-,u8x8_font_pxplusibmcga_r,const uint8_t[], +Variable,-,u8x8_font_pxplusibmcga_u,const uint8_t[], +Variable,-,u8x8_font_pxplusibmcgathin_f,const uint8_t[], +Variable,-,u8x8_font_pxplusibmcgathin_n,const uint8_t[], +Variable,-,u8x8_font_pxplusibmcgathin_r,const uint8_t[], +Variable,-,u8x8_font_pxplusibmcgathin_u,const uint8_t[], +Variable,-,u8x8_font_pxplustandynewtv_f,const uint8_t[], +Variable,-,u8x8_font_pxplustandynewtv_n,const uint8_t[], +Variable,-,u8x8_font_pxplustandynewtv_r,const uint8_t[], +Variable,-,u8x8_font_pxplustandynewtv_u,const uint8_t[], +Variable,-,u8x8_font_saikyosansbold8_n,const uint8_t[], +Variable,-,u8x8_font_saikyosansbold8_u,const uint8_t[], +Variable,-,u8x8_font_torussansbold8_n,const uint8_t[], +Variable,-,u8x8_font_torussansbold8_r,const uint8_t[], +Variable,-,u8x8_font_torussansbold8_u,const uint8_t[], +Variable,-,u8x8_font_victoriabold8_n,const uint8_t[], +Variable,-,u8x8_font_victoriabold8_r,const uint8_t[], +Variable,-,u8x8_font_victoriabold8_u,const uint8_t[], +Variable,-,u8x8_font_victoriamedium8_n,const uint8_t[], +Variable,-,u8x8_font_victoriamedium8_r,const uint8_t[], +Variable,-,u8x8_font_victoriamedium8_u,const uint8_t[], Variable,+,usb_ccid,FuriHalUsbInterface, Variable,+,usb_cdc_dual,FuriHalUsbInterface, Variable,+,usb_cdc_single,FuriHalUsbInterface, From 8d5c14e283867c585ee34a92cf3a1eea8bd778cd Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 11 Jan 2026 09:57:30 +0300 Subject: [PATCH 032/160] sort menu in alphabetical order --- applications/services/loader/loader_menu.c | 16 ++++++++-------- applications/settings/about/application.fam | 2 +- .../settings/bt_settings_app/application.fam | 2 +- .../settings/clock_settings/application.fam | 2 +- .../settings/desktop_settings/application.fam | 2 +- .../settings/dolphin_passport/application.fam | 2 +- .../expansion_settings_app/application.fam | 2 +- .../settings/input_settings_app/application.fam | 2 +- .../notification_settings/application.fam | 2 +- .../settings/power_settings_app/application.fam | 2 +- .../settings/storage_settings/application.fam | 2 +- applications/settings/system/application.fam | 2 +- 12 files changed, 19 insertions(+), 19 deletions(-) diff --git a/applications/services/loader/loader_menu.c b/applications/services/loader/loader_menu.c index 4fec926fe..7fa94ba38 100644 --- a/applications/services/loader/loader_menu.c +++ b/applications/services/loader/loader_menu.c @@ -134,14 +134,6 @@ static void loader_menu_build_menu(LoaderMenuApp* app, LoaderMenu* menu) { } static void loader_menu_build_submenu(LoaderMenuApp* app, LoaderMenu* loader_menu) { - for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { - submenu_add_item_ex( - app->settings_menu, - FLIPPER_SETTINGS_APPS[i].name, - (uint32_t)FLIPPER_SETTINGS_APPS[i].name, - loader_menu_settings_menu_callback, - loader_menu); - } for(size_t i = 0; i < FLIPPER_EXTSETTINGS_APPS_COUNT; i++) { submenu_add_item_ex( app->settings_menu, @@ -150,6 +142,14 @@ static void loader_menu_build_submenu(LoaderMenuApp* app, LoaderMenu* loader_men loader_menu_settings_menu_callback, loader_menu); } + for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { + submenu_add_item_ex( + app->settings_menu, + FLIPPER_SETTINGS_APPS[i].name, + (uint32_t)FLIPPER_SETTINGS_APPS[i].name, + loader_menu_settings_menu_callback, + loader_menu); + } } static LoaderMenuApp* loader_menu_app_alloc(LoaderMenu* loader_menu) { diff --git a/applications/settings/about/application.fam b/applications/settings/about/application.fam index 0534c5a28..76d04f852 100644 --- a/applications/settings/about/application.fam +++ b/applications/settings/about/application.fam @@ -9,7 +9,7 @@ App( "dialogs", ], stack_size=1 * 1024, - order=1000, + order=10, fap_libs=["assets"], fap_category="assets", ) diff --git a/applications/settings/bt_settings_app/application.fam b/applications/settings/bt_settings_app/application.fam index 451c837df..67e1cf17c 100644 --- a/applications/settings/bt_settings_app/application.fam +++ b/applications/settings/bt_settings_app/application.fam @@ -8,7 +8,7 @@ App( "bt", "gui", ], - order=10, + order=20, fap_libs=["assets"], fap_category="assets", ) diff --git a/applications/settings/clock_settings/application.fam b/applications/settings/clock_settings/application.fam index d6a96d2e5..ce8a84fff 100644 --- a/applications/settings/clock_settings/application.fam +++ b/applications/settings/clock_settings/application.fam @@ -6,7 +6,7 @@ App( requires=["gui"], provides=["clock_settings_start"], stack_size=1 * 1024, - order=90, + order=30, fap_libs=["assets"], fap_category="assets", ) diff --git a/applications/settings/desktop_settings/application.fam b/applications/settings/desktop_settings/application.fam index 5e6da74de..fe658fd12 100644 --- a/applications/settings/desktop_settings/application.fam +++ b/applications/settings/desktop_settings/application.fam @@ -8,7 +8,7 @@ App( "gui", ], stack_size=1 * 1024, - order=50, + order=40, fap_libs=["assets"], fap_category="assets", ) diff --git a/applications/settings/dolphin_passport/application.fam b/applications/settings/dolphin_passport/application.fam index 142840ece..3d63ea918 100644 --- a/applications/settings/dolphin_passport/application.fam +++ b/applications/settings/dolphin_passport/application.fam @@ -9,7 +9,7 @@ App( "dolphin", ], stack_size=1 * 1024, - order=60, + order=80, fap_libs=["assets"], fap_category="assets", ) diff --git a/applications/settings/expansion_settings_app/application.fam b/applications/settings/expansion_settings_app/application.fam index e3c1881bf..a5876f5e6 100644 --- a/applications/settings/expansion_settings_app/application.fam +++ b/applications/settings/expansion_settings_app/application.fam @@ -5,7 +5,7 @@ App( entry_point="expansion_settings_app", requires=["gui"], stack_size=1 * 1024, - order=80, + order=50, fap_libs=["assets"], fap_category="assets", ) diff --git a/applications/settings/input_settings_app/application.fam b/applications/settings/input_settings_app/application.fam index b15c0956a..ebec401d5 100644 --- a/applications/settings/input_settings_app/application.fam +++ b/applications/settings/input_settings_app/application.fam @@ -5,7 +5,7 @@ App( entry_point="input_settings_app", requires=["input"], stack_size=1 * 1024, - order=100, + order=60, fap_libs=["assets"], fap_category="assets", ) diff --git a/applications/settings/notification_settings/application.fam b/applications/settings/notification_settings/application.fam index ae242c966..cdcf98e0b 100644 --- a/applications/settings/notification_settings/application.fam +++ b/applications/settings/notification_settings/application.fam @@ -5,7 +5,7 @@ App( entry_point="notification_settings_app", requires=["notification"], stack_size=1 * 1024, - order=20, + order=70, fap_libs=["assets"], fap_category="assets", ) diff --git a/applications/settings/power_settings_app/application.fam b/applications/settings/power_settings_app/application.fam index 6f3589e1a..a2906d0b7 100644 --- a/applications/settings/power_settings_app/application.fam +++ b/applications/settings/power_settings_app/application.fam @@ -10,5 +10,5 @@ App( ], flags=["InsomniaSafe"], stack_size=1 * 1024, - order=40, + order=10, ) diff --git a/applications/settings/storage_settings/application.fam b/applications/settings/storage_settings/application.fam index 1ba0ccd44..41ff6d081 100644 --- a/applications/settings/storage_settings/application.fam +++ b/applications/settings/storage_settings/application.fam @@ -5,5 +5,5 @@ App( entry_point="storage_settings_app", requires=["storage"], stack_size=2 * 1024, - order=30, + order=20, ) diff --git a/applications/settings/system/application.fam b/applications/settings/system/application.fam index 69a8f1239..b72451bc3 100644 --- a/applications/settings/system/application.fam +++ b/applications/settings/system/application.fam @@ -5,5 +5,5 @@ App( entry_point="system_settings_app", requires=["gui", "locale"], stack_size=1 * 1024, - order=70, + order=30, ) From 50b5ee103c23dd0b63f137517c023ca0a42b4dae Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 12 Jan 2026 08:13:05 +0300 Subject: [PATCH 033/160] bipki removal procedure don't worry, they are in other app --- ReadMe.md | 2 +- .../resources/unit_tests/Manifest_test | 3 - .../unit_tests/subghz/cenmax_raw.sub | 15 - .../unit_tests/subghz/kia_seed_raw.sub | 25 - .../subghz/scher_khan_magic_code.sub | 22 - .../unit_tests/tests/subghz/subghz_test.c | 25 - .../scenes/subghz_scene_receiver_config.c | 12 +- .../desktop_settings/helpers/pin_code.c | 2 +- .../views/desktop_view_pin_input.c | 2 +- documentation/FAQ.md | 47 +- documentation/SubGHzSupportedSystems.md | 3 - lib/subghz/protocols/kia.c | 276 ------- lib/subghz/protocols/kia.h | 74 -- lib/subghz/protocols/protocol_items.c | 78 +- lib/subghz/protocols/protocol_items.h | 3 - lib/subghz/protocols/revers_rb2.c | 3 +- lib/subghz/protocols/scher_khan.c | 320 -------- lib/subghz/protocols/scher_khan.h | 74 -- lib/subghz/protocols/star_line.c | 747 ------------------ lib/subghz/protocols/star_line.h | 109 --- lib/subghz/types.h | 2 +- 21 files changed, 64 insertions(+), 1780 deletions(-) delete mode 100644 applications/debug/unit_tests/resources/unit_tests/subghz/cenmax_raw.sub delete mode 100644 applications/debug/unit_tests/resources/unit_tests/subghz/kia_seed_raw.sub delete mode 100644 applications/debug/unit_tests/resources/unit_tests/subghz/scher_khan_magic_code.sub delete mode 100644 lib/subghz/protocols/kia.c delete mode 100644 lib/subghz/protocols/kia.h delete mode 100644 lib/subghz/protocols/scher_khan.c delete mode 100644 lib/subghz/protocols/scher_khan.h delete mode 100644 lib/subghz/protocols/star_line.c delete mode 100644 lib/subghz/protocols/star_line.h diff --git a/ReadMe.md b/ReadMe.md index 7c353fd27..891fe9b8f 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -84,7 +84,7 @@ Before getting started: > - FAAC SLH, BFT Mitto / Somfy Telis / Nice Flor S / CAME Atomo, etc. manual creation with programming new remote into receiver (use button 0xF for BFT Mitto, 0x8 (Prog) on Somfy Telis, (right arrow button for other protocols)) > - Debug mode counter increase settings (+1 → +5, +10, default: +1) > - Debug PIN output settings for protocol development -> - Ignore options - Alarms: Hollarm, GangQi | Cars: Kia, Starline, ScherKhan | Sensors: Magellan, Honeywell Sec, Honeywell WDB (doorbells), Legrand (doorbells), Feron (RGB lights) +> - Ignore options - Alarms: Hollarm, GangQi | ReversRB2: Revers RB-2(M) protocol | Sensors: Magellan, Honeywell Sec, Honeywell WDB (doorbells), Legrand (doorbells), Feron (RGB lights) | NiceFlorS: Nice Flor-S protocol >
>
diff --git a/applications/debug/unit_tests/resources/unit_tests/Manifest_test b/applications/debug/unit_tests/resources/unit_tests/Manifest_test index db2979ee6..16c7baa24 100644 --- a/applications/debug/unit_tests/resources/unit_tests/Manifest_test +++ b/applications/debug/unit_tests/resources/unit_tests/Manifest_test @@ -24,7 +24,6 @@ F:0156915c656d8c038c6d555d34349a36:6877:subghz/came_atomo_raw.sub F:111a8b796661f3cbd6f49f756cf91107:8614:subghz/came_raw.sub F:2101b0a5a72c87f9dce77223b2885aa7:162:subghz/came_twee.sub F:c608b78b8e4646eeb94db37644623254:10924:subghz/came_twee_raw.sub -F:c4a55acddb68fc3111d592c9292022a8:21703:subghz/cenmax_raw.sub F:51d6bd600345954b9c84a5bc6e999313:159:subghz/clemsa.sub F:14fa0d5931a32674bfb2ddf288f3842b:21499:subghz/clemsa_raw.sub F:f38b6dfa0920199200887b2cd5c0a385:161:subghz/doitrand.sub @@ -44,7 +43,6 @@ F:20bba4b0aec006ced7e82513f9459e31:15532:subghz/hormann_hsm_raw.sub F:3392f2db6aa7777e937db619b86203bb:10637:subghz/ido_117_111_raw.sub F:cc5c7968527cc233ef11a08986e31bf2:167:subghz/intertechno_v3.sub F:70bceb941739260ab9f6162cfdeb0347:18211:subghz/intertechno_v3_raw.sub -F:bc9a4622f3e22fd7f82eb3f26e61f59b:44952:subghz/kia_seed_raw.sub F:6b6e95fc70ea481dc6184d291466d16a:159:subghz/linear.sub F:77aaa9005db54c0357451ced081857b2:14619:subghz/linear_raw.sub F:1a618e21e6ffa9984d465012e704c450:161:subghz/magellan.sub @@ -64,7 +62,6 @@ F:2b1192e4898aaf274caebbb493b9f96e:164:subghz/power_smart.sub F:8b8195cab1d9022fe38e802383fb923a:3648:subghz/power_smart_raw.sub F:1ccf1289533e0486a1d010d934ad7b06:170:subghz/princeton.sub F:8bccc506a61705ec429aecb879e5d7ce:7344:subghz/princeton_raw.sub -F:0bda91d783e464165190c3b3d16666a7:38724:subghz/scher_khan_magic_code.sub F:116d7e1a532a0c9e00ffeee105f7138b:166:subghz/security_pls_1_0.sub F:441fc7fc6fa11ce0068fde3f6145177b:69413:subghz/security_pls_1_0_raw.sub F:e5e33c24c5e55f592ca892b5aa8fa31f:208:subghz/security_pls_2_0.sub diff --git a/applications/debug/unit_tests/resources/unit_tests/subghz/cenmax_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/cenmax_raw.sub deleted file mode 100644 index 2b78115f2..000000000 --- a/applications/debug/unit_tests/resources/unit_tests/subghz/cenmax_raw.sub +++ /dev/null @@ -1,15 +0,0 @@ -Filetype: Flipper SubGhz RAW File -Version: 1 -Frequency: 433920000 -Preset: FuriHalSubGhzPresetOok650Async -Protocol: RAW -RAW_Data: 32700 -1024 977 -1010 971 -1046 967 -1012 1007 -1014 1001 -1008 503 -528 523 -518 485 -550 259 -288 491 -556 231 -296 501 -560 265 -268 267 -270 497 -522 489 -550 259 -290 227 -298 267 -306 239 -308 241 -274 507 -524 261 -256 259 -296 265 -268 503 -558 495 -554 229 -296 503 -560 493 -522 259 -256 257 -296 497 -526 525 -520 261 -292 499 -560 497 -524 263 -260 525 -520 261 -290 227 -298 267 -270 505 -558 231 -332 237 -274 507 -524 521 -518 487 -548 259 -286 227 -298 269 -306 239 -308 239 -276 507 -522 261 -258 261 -296 263 -268 269 -268 271 -306 239 -306 241 -274 273 -270 499 -522 489 -550 259 -288 227 -298 503 -558 233 -332 237 -274 999 -1012 977 -1016 1007 -1018 977 -1014 985 -1008 1013 -1014 521 -524 493 -552 477 -546 239 -314 477 -558 231 -298 501 -562 265 -268 267 -270 497 -520 521 -518 259 -290 227 -300 269 -306 239 -306 241 -276 507 -522 261 -258 259 -296 265 -266 501 -558 497 -556 229 -296 503 -558 493 -522 259 -256 257 -294 497 -556 493 -522 263 -292 499 -560 499 -522 263 -260 523 -522 259 -292 227 -298 267 -270 505 -560 229 -300 269 -274 505 -524 489 -550 487 -550 259 -286 227 -298 269 -306 239 -306 241 -276 507 -522 261 -256 259 -296 267 -268 267 -270 271 -304 239 -306 241 -276 273 -270 497 -522 489 -550 259 -290 225 -298 505 -558 231 -300 269 -272 1001 -1008 979 -1014 1009 -1020 977 -1014 997 -1010 983 -1040 507 -508 511 -546 477 -546 257 -280 513 -520 261 -296 499 -558 265 -268 269 -268 497 -522 489 -552 261 -288 227 -296 271 -304 241 -306 241 -276 507 -522 259 -258 259 -296 267 -266 503 -558 495 -556 229 -296 501 -562 495 -518 259 -256 257 -296 497 -524 525 -520 261 -294 499 -558 499 -524 263 -260 523 -522 259 -290 227 -298 267 -270 505 -558 231 -300 271 -272 505 -526 489 -552 485 -550 227 -318 225 -298 269 -306 239 -306 241 -276 507 -522 261 -258 259 -296 265 -266 269 -270 271 -304 239 -308 239 -276 273 -270 497 -522 489 -550 261 -288 227 -296 505 -558 231 -300 271 -272 999 -1012 981 -1024 1007 -992 1007 -1010 1003 -982 1001 -1048 479 -548 477 -548 479 -546 257 -282 511 -554 231 -294 499 -560 265 -268 269 -268 497 -522 521 -520 259 -290 225 -298 269 -306 239 -308 239 -276 507 -522 261 -258 259 -296 265 -266 503 -556 495 -556 229 -296 503 -560 493 -520 261 -256 257 -294 499 -524 525 -520 261 -294 499 -560 497 -524 261 -262 523 -522 259 -292 227 -296 267 -270 505 -558 231 -332 237 -274 -RAW_Data: 505 -526 491 -550 485 -550 227 -318 225 -298 269 -306 239 -306 241 -276 507 -522 261 -258 259 -296 265 -266 269 -270 271 -304 239 -306 241 -276 271 -270 499 -522 489 -550 259 -288 227 -298 505 -560 231 -298 271 -272 999 -1012 977 -1018 1003 -1020 977 -1016 1001 -1008 979 -1040 515 -518 483 -552 485 -552 225 -306 501 -548 227 -318 493 -556 267 -266 267 -270 497 -522 489 -552 259 -288 227 -300 267 -304 239 -308 241 -276 505 -524 261 -258 259 -296 265 -268 501 -558 495 -554 229 -296 503 -528 527 -520 259 -256 257 -296 497 -524 525 -520 261 -294 501 -558 499 -524 261 -260 523 -522 259 -290 227 -298 269 -268 505 -560 231 -300 269 -274 505 -524 489 -552 487 -550 227 -286 257 -296 269 -306 239 -308 239 -276 507 -522 261 -258 259 -296 265 -266 269 -270 269 -306 239 -308 241 -274 273 -270 497 -522 487 -552 261 -288 225 -298 503 -558 233 -332 237 -274 999 -1010 977 -1016 1007 -1020 977 -1014 999 -1014 993 -1012 513 -514 513 -548 479 -548 225 -310 509 -520 261 -294 499 -558 267 -268 269 -268 497 -524 487 -552 259 -288 227 -298 269 -306 239 -308 241 -274 507 -524 259 -258 259 -296 265 -268 501 -558 497 -552 231 -296 501 -560 493 -520 261 -256 257 -294 497 -558 493 -554 129 -32700 261 -332 131 -534 329 -98 32700 -1002 979 -1048 989 -1006 989 -1012 977 -1024 1007 -1034 225 -284 255 -292 263 -264 267 -268 501 -558 231 -298 267 -306 477 -560 231 -296 229 -296 495 -522 523 -520 521 -518 261 -294 265 -304 239 -276 273 -272 497 -522 259 -258 521 -524 261 -296 497 -558 231 -300 505 -528 525 -522 485 -550 483 -550 485 -548 487 -550 261 -294 495 -560 265 -268 267 -270 497 -522 261 -260 259 -296 267 -268 505 -560 231 -298 271 -274 507 -522 521 -520 485 -548 259 -288 227 -296 271 -306 239 -308 239 -276 507 -522 261 -258 259 -296 265 -266 269 -270 271 -272 273 -306 241 -274 273 -270 497 -522 489 -550 259 -288 261 -264 503 -560 231 -300 269 -274 999 -1012 977 -1024 1007 -992 1009 -1000 1005 -982 1033 -1016 257 -248 279 -252 259 -296 265 -268 503 -560 231 -296 267 -304 477 -560 231 -296 229 -296 495 -522 523 -518 523 -520 261 -292 265 -304 239 -276 273 -270 497 -522 259 -290 491 -522 263 -294 497 -558 231 -300 505 -528 527 -522 485 -548 483 -550 485 -550 487 -552 259 -292 495 -560 265 -268 267 -268 497 -522 261 -292 227 -296 267 -270 505 -558 231 -300 269 -274 507 -524 487 -550 487 -550 257 -288 227 -296 271 -304 239 -308 -RAW_Data: 241 -276 505 -524 259 -258 259 -296 265 -268 269 -270 271 -270 273 -308 239 -276 273 -270 497 -522 489 -550 259 -288 227 -298 505 -558 231 -300 269 -274 997 -1008 1009 -988 1009 -996 1013 -1014 991 -1014 991 -1012 271 -288 251 -256 253 -292 251 -288 485 -558 231 -300 269 -306 475 -560 229 -296 229 -298 495 -524 523 -518 521 -518 261 -294 263 -304 241 -274 273 -270 499 -520 261 -290 491 -524 261 -294 499 -558 231 -298 503 -562 493 -520 487 -548 485 -548 487 -550 485 -550 261 -290 497 -558 267 -266 269 -268 497 -522 263 -290 227 -296 267 -268 505 -560 231 -300 271 -272 505 -524 489 -552 487 -550 225 -318 227 -296 271 -304 241 -306 241 -276 505 -522 261 -258 259 -296 265 -266 269 -270 271 -304 239 -308 241 -274 273 -270 497 -522 489 -550 259 -288 227 -298 501 -560 231 -334 237 -274 1001 -1012 979 -1014 1005 -986 1007 -1014 1001 -1006 983 -1040 271 -254 253 -292 253 -292 253 -284 481 -558 231 -296 267 -304 477 -562 231 -294 229 -296 497 -524 489 -550 489 -552 261 -292 265 -302 239 -276 273 -270 499 -522 259 -290 491 -522 263 -294 499 -558 231 -296 503 -560 495 -520 487 -550 485 -548 487 -548 489 -548 261 -290 497 -558 265 -268 269 -268 497 -522 261 -292 227 -296 267 -268 507 -558 231 -298 271 -272 507 -522 489 -552 487 -550 227 -286 257 -298 269 -306 239 -308 241 -274 507 -524 259 -258 257 -296 265 -268 269 -268 271 -306 239 -306 241 -276 273 -270 497 -522 489 -550 259 -288 227 -296 505 -558 231 -300 271 -272 997 -1014 975 -1016 1009 -1020 977 -1016 1001 -1012 989 -1044 237 -288 253 -290 217 -292 253 -290 485 -562 231 -298 269 -306 475 -562 229 -296 229 -296 495 -524 523 -518 523 -518 261 -292 265 -304 239 -274 273 -270 499 -520 261 -292 491 -524 261 -294 495 -558 231 -300 503 -562 493 -522 485 -550 485 -548 485 -550 487 -552 261 -290 497 -560 231 -300 267 -270 497 -522 261 -290 227 -296 267 -268 507 -558 231 -300 269 -274 505 -524 519 -518 487 -550 259 -288 227 -296 271 -304 239 -308 241 -274 507 -524 259 -260 259 -294 233 -300 267 -270 271 -306 239 -308 239 -276 271 -270 497 -522 489 -550 259 -288 227 -298 501 -560 231 -334 237 -274 1001 -1010 979 -1014 1007 -1020 977 -1016 1001 -1008 979 -1044 237 -288 255 -290 255 -290 251 -282 479 -556 231 -296 269 -304 475 -562 231 -296 229 -296 495 -524 521 -518 523 -518 261 -292 265 -304 239 -276 273 -270 497 -522 261 -290 491 -524 263 -292 497 -558 231 -298 -RAW_Data: 505 -560 495 -520 485 -550 485 -548 485 -552 487 -550 261 -290 497 -558 267 -266 267 -268 497 -522 263 -290 227 -296 267 -270 505 -560 231 -298 271 -272 507 -524 487 -552 485 -550 227 -318 227 -298 269 -306 239 -306 241 -276 505 -522 261 -258 259 -296 265 -268 267 -270 271 -306 237 -308 241 -274 273 -270 497 -522 489 -550 259 -288 227 -300 503 -558 231 -300 269 -272 999 -1008 1007 -988 1005 -996 1013 -1012 987 -1004 997 -1044 225 -278 247 -284 255 -296 267 -268 503 -558 231 -296 269 -304 475 -562 229 -296 229 -296 497 -524 521 -518 523 -518 261 -292 265 -302 241 -276 273 -270 497 -522 259 -290 491 -524 263 -292 499 -556 231 -300 505 -558 495 -522 485 -548 485 -550 485 -550 485 -550 261 -292 497 -558 265 -268 267 -270 497 -520 261 -290 229 -296 267 -270 505 -558 231 -300 271 -272 507 -524 489 -550 485 -548 259 -288 225 -298 269 -306 239 -308 241 -274 507 -524 261 -258 259 -294 265 -266 269 -270 269 -306 239 -306 241 -274 273 -270 497 -524 487 -550 259 -290 227 -296 503 -558 231 -334 237 -274 997 -1014 977 -1016 1007 -1018 977 -1016 1001 -1008 981 -1038 257 -274 245 -280 251 -290 263 -266 503 -560 231 -294 267 -306 475 -562 229 -296 229 -296 495 -522 523 -520 521 -518 261 -294 265 -302 239 -276 273 -270 499 -522 259 -290 491 -524 261 -294 497 -556 233 -298 505 -560 493 -520 487 -550 485 -550 485 -550 487 -550 259 -292 495 -558 267 -266 269 -268 497 -522 261 -288 227 -298 269 -270 505 -556 231 -298 271 -274 505 -524 489 -550 485 -548 261 -288 225 -298 269 -306 239 -306 241 -274 507 -524 261 -258 259 -294 265 -268 269 -268 271 -306 237 -308 241 -274 273 -270 497 -522 489 -548 261 -288 227 -296 503 -560 231 -300 271 -272 997 -1010 1003 -1004 999 -1008 991 -1010 1011 -982 1009 -1020 257 -282 251 -286 227 -296 265 -268 503 -558 231 -298 267 -304 477 -560 231 -296 227 -296 495 -524 523 -520 489 -550 261 -292 265 -304 239 -276 273 -270 499 -520 259 -290 491 -522 263 -294 499 -558 231 -296 505 -560 493 -522 485 -550 485 -550 485 -548 489 -548 261 -290 497 -558 267 -266 269 -268 497 -522 261 -290 227 -296 267 -270 505 -560 231 -298 269 -272 507 -524 491 -550 485 -548 259 -288 225 -298 269 -306 239 -308 241 -274 507 -524 259 -258 257 -296 265 -266 269 -270 271 -304 239 -308 241 -274 273 -270 497 -522 489 -550 259 -288 227 -298 505 -558 231 -300 269 -274 997 -1012 979 -1024 1007 -992 1007 -1016 991 -1008 -RAW_Data: 989 -1042 237 -288 253 -290 255 -254 255 -288 487 -560 231 -300 269 -306 475 -562 229 -296 229 -296 495 -524 523 -518 489 -550 261 -292 265 -304 239 -276 273 -270 497 -522 259 -290 493 -524 263 -292 497 -556 231 -300 505 -560 493 -520 485 -550 485 -548 487 -548 487 -550 259 -292 497 -560 265 -268 267 -268 497 -522 259 -292 227 -296 267 -270 505 -558 233 -300 269 -272 507 -524 489 -550 487 -550 227 -286 257 -296 269 -306 239 -308 241 -274 507 -524 259 -258 257 -296 267 -266 269 -270 269 -306 239 -306 241 -274 273 -270 497 -522 489 -550 259 -288 227 -298 503 -560 231 -332 237 -274 999 -1012 981 -1016 1003 -986 1009 -1018 1003 -1006 983 -1044 237 -292 253 -292 217 -292 249 -280 509 -556 229 -296 267 -306 477 -560 229 -298 229 -296 495 -522 523 -518 523 -518 261 -292 265 -304 239 -274 273 -272 497 -522 259 -290 491 -524 261 -294 497 -558 231 -300 503 -560 493 -520 487 -548 487 -548 485 -548 487 -550 261 -292 495 -560 265 -268 267 -268 497 -522 263 -290 227 -296 267 -270 503 -560 231 -300 269 -274 505 -526 489 -552 485 -550 227 -286 257 -296 269 -306 239 -306 241 -276 507 -522 259 -258 259 -296 265 -268 267 -270 271 -306 239 -306 241 -276 273 -270 495 -522 487 -552 261 -288 225 -298 503 -558 231 -332 239 -274 999 -1012 979 -1016 1007 -986 1009 -1016 999 -1012 987 -1012 271 -288 253 -290 219 -290 255 -288 485 -558 231 -300 269 -306 475 -560 231 -296 229 -296 495 -524 523 -518 521 -518 261 -292 265 -302 241 -276 273 -270 497 -522 259 -290 491 -524 261 -294 497 -558 231 -298 507 -560 493 -522 485 -548 485 -548 487 -550 489 -548 261 -290 497 -560 233 -300 267 -266 497 -522 261 -290 227 -298 267 -268 505 -558 231 -300 269 -274 505 -524 491 -550 485 -548 259 -286 227 -298 269 -306 239 -308 241 -274 507 -522 261 -256 259 -296 267 -266 269 -270 271 -304 239 -306 241 -276 271 -270 499 -522 487 -550 261 -288 225 -298 505 -558 231 -300 269 -274 997 -1010 981 -1016 1003 -1020 971 -1006 1025 -1008 987 -1042 225 -276 247 -282 255 -294 265 -268 503 -558 229 -296 267 -304 477 -562 229 -296 229 -296 495 -524 523 -518 523 -518 261 -292 265 -304 239 -274 273 -272 497 -522 259 -292 491 -524 263 -294 497 -558 231 -298 503 -560 493 -520 487 -550 485 -548 485 -548 487 -550 261 -292 497 -560 231 -300 269 -268 497 -522 259 -290 227 -298 267 -268 505 -560 231 -332 237 -274 505 -524 489 -550 485 -548 259 -288 227 -300 -RAW_Data: 267 -304 239 -308 241 -274 509 -524 259 -258 257 -296 265 -268 269 -268 271 -306 239 -306 241 -274 273 -270 497 -522 487 -550 261 -288 227 -298 503 -558 233 -298 271 -274 999 -1012 979 -1016 1007 -1016 975 -1002 999 -1018 995 -1046 237 -288 251 -292 253 -256 253 -290 485 -562 233 -298 269 -306 475 -562 229 -296 229 -298 497 -522 491 -550 491 -548 261 -292 265 -304 239 -274 273 -270 499 -520 261 -290 491 -522 263 -294 497 -558 231 -298 505 -558 495 -520 487 -548 485 -550 485 -548 487 -550 261 -292 495 -558 267 -268 267 -268 499 -522 261 -290 227 -296 267 -270 505 -558 233 -298 269 -272 507 -522 489 -552 487 -550 227 -286 257 -296 271 -304 239 -308 239 -32700 165 -164 97 -1950 465 -232 393 -198 557 -7530 865 -1122 915 -1114 159 -346 187 -348 187 -348 445 -618 419 -584 455 -618 195 -354 429 -596 459 -554 227 -320 225 -294 229 -332 467 -560 229 -330 467 -560 497 -558 229 -296 229 -296 229 -300 497 -558 229 -294 265 -302 237 -308 243 -274 273 -270 233 -298 263 -266 265 -268 501 -558 231 -296 267 -306 241 -276 273 -270 497 -522 261 -258 257 -296 267 -270 507 -556 265 -266 271 -274 507 -524 519 -518 487 -548 259 -256 291 -264 269 -274 273 -310 241 -274 505 -524 259 -258 257 -296 265 -268 269 -270 271 -272 273 -306 241 -276 273 -270 495 -522 521 -516 259 -290 259 -264 505 -558 265 -266 271 -274 1001 -1010 1005 -990 1005 -996 1007 -1014 987 -1016 993 -1010 257 -276 247 -282 255 -294 499 -522 527 -520 523 -520 263 -296 503 -526 527 -520 259 -256 257 -294 265 -268 503 -558 231 -296 501 -560 497 -524 261 -262 259 -296 265 -266 497 -524 261 -296 265 -270 271 -308 241 -274 273 -270 233 -298 231 -298 265 -268 503 -556 231 -296 267 -306 239 -276 273 -270 497 -522 259 -258 291 -266 267 -270 505 -558 265 -266 271 -272 507 -522 521 -516 485 -550 257 -288 261 -266 269 -272 275 -306 241 -276 505 -522 261 -256 259 -296 265 -268 269 -270 271 -270 273 -308 241 -274 273 -270 497 -520 521 -518 261 -256 291 -264 503 -560 265 -266 269 -274 999 -1008 1003 -986 1007 -1004 1013 -980 1023 -1008 991 -1042 225 -276 247 -282 255 -294 501 -524 527 -518 527 -520 261 -296 503 -526 525 -520 259 -256 257 -294 265 -268 503 -526 263 -296 501 -560 497 -524 261 -262 261 -296 263 -266 499 -522 263 -294 265 -270 271 -308 241 -276 273 -270 233 -298 229 -298 265 -268 501 -558 231 -298 267 -304 241 -276 273 -270 495 -522 259 -290 261 -264 -RAW_Data: 269 -270 505 -558 231 -300 271 -272 507 -522 521 -518 485 -550 259 -254 291 -264 271 -272 273 -308 241 -274 507 -524 259 -258 257 -296 265 -268 269 -270 271 -272 271 -308 241 -276 271 -270 497 -520 521 -520 259 -256 291 -266 503 -558 265 -266 271 -274 999 -1014 977 -1016 1007 -984 1007 -1014 999 -1016 991 -1010 271 -290 253 -254 291 -254 495 -542 499 -558 493 -522 263 -296 503 -526 525 -522 259 -256 257 -294 267 -268 503 -554 231 -298 501 -558 499 -524 261 -260 261 -298 231 -298 499 -524 261 -294 265 -268 273 -308 241 -276 271 -270 233 -298 231 -298 265 -266 503 -558 231 -298 267 -304 241 -274 273 -270 499 -520 259 -258 291 -266 267 -270 507 -558 233 -296 269 -274 505 -524 521 -520 485 -548 259 -256 291 -264 269 -272 275 -308 239 -276 507 -522 261 -256 259 -296 265 -268 267 -270 271 -272 273 -306 241 -276 271 -270 497 -520 523 -518 259 -290 259 -264 503 -560 265 -266 269 -274 999 -1008 1005 -986 1017 -994 1007 -1012 991 -1014 991 -1012 259 -276 245 -282 253 -294 499 -522 527 -520 525 -518 263 -296 501 -526 527 -520 259 -256 257 -294 265 -268 503 -558 231 -296 503 -558 501 -522 263 -260 259 -294 263 -266 499 -524 261 -296 265 -270 273 -308 241 -274 273 -270 233 -296 231 -296 267 -268 503 -556 231 -296 267 -304 241 -276 273 -270 499 -522 259 -256 259 -296 267 -272 505 -558 233 -298 271 -272 507 -522 521 -516 485 -550 259 -288 259 -264 271 -272 273 -308 241 -276 507 -522 261 -256 259 -296 265 -266 269 -270 271 -272 273 -308 241 -274 273 -270 497 -520 521 -518 259 -288 261 -266 503 -558 265 -266 271 -274 999 -1010 981 -1026 981 -1026 1007 -978 997 -1012 1019 -1006 255 -276 245 -280 255 -294 497 -524 525 -520 525 -520 261 -296 503 -526 527 -520 259 -256 257 -294 267 -268 503 -558 231 -296 499 -560 497 -524 261 -262 261 -296 263 -266 499 -524 261 -294 267 -268 273 -308 239 -276 273 -270 233 -296 231 -298 265 -268 503 -558 231 -296 267 -304 241 -274 273 -270 499 -520 259 -258 259 -298 267 -270 505 -558 265 -266 271 -274 507 -522 521 -516 485 -548 259 -288 259 -266 269 -272 275 -306 243 -274 507 -524 259 -258 257 -296 265 -268 269 -270 269 -272 273 -308 241 -276 271 -270 497 -520 521 -518 259 -290 259 -264 505 -560 263 -266 271 -274 999 -1008 1003 -986 1009 -1000 1011 -1006 1001 -1000 1003 -1018 259 -280 249 -286 261 -264 501 -522 527 -520 525 -518 263 -296 503 -526 525 -522 259 -256 257 -294 267 -266 -RAW_Data: 505 -556 231 -296 501 -558 499 -522 263 -260 261 -296 265 -264 501 -524 261 -294 265 -270 271 -308 241 -274 273 -270 233 -298 231 -298 265 -266 503 -558 231 -296 267 -306 239 -276 273 -270 499 -522 259 -258 257 -296 269 -270 505 -560 231 -298 269 -272 507 -522 521 -518 487 -548 259 -288 259 -264 271 -272 273 -308 241 -276 507 -522 259 -258 257 -296 267 -268 269 -268 271 -272 273 -306 241 -276 271 -270 497 -522 519 -516 261 -288 261 -266 503 -558 265 -266 271 -274 997 -1014 979 -1014 1007 -984 1009 -1016 987 -1006 1013 -1014 273 -290 255 -254 253 -290 485 -526 527 -522 523 -520 263 -294 505 -526 525 -520 259 -256 257 -294 265 -268 501 -558 231 -298 501 -558 499 -522 263 -260 261 -296 263 -266 499 -522 263 -294 267 -268 273 -308 241 -274 273 -270 233 -298 231 -298 265 -266 503 -556 231 -296 269 -306 241 -274 273 -270 497 -520 261 -288 227 -298 269 -270 505 -556 265 -266 271 -274 507 -522 521 -516 487 -548 259 -288 259 -264 269 -272 275 -308 241 -274 507 -522 261 -256 259 -296 265 -268 267 -270 271 -272 275 -306 241 -276 271 -270 497 -520 521 -518 259 -288 259 -266 503 -558 267 -266 269 -274 999 -1006 1005 -986 1007 -1004 1011 -1014 987 -1014 993 -1012 271 -290 253 -254 255 -290 491 -536 503 -558 495 -554 231 -298 503 -524 527 -520 259 -256 257 -296 265 -268 501 -558 231 -298 501 -558 499 -524 261 -260 261 -296 263 -266 499 -522 263 -294 265 -270 273 -306 243 -274 273 -270 233 -298 231 -296 267 -268 501 -558 231 -296 267 -306 239 -276 271 -270 497 -522 261 -258 259 -296 267 -270 507 -560 231 -298 269 -274 505 -524 521 -518 487 -550 259 -254 257 -298 269 -272 275 -308 241 -274 507 -522 261 -256 257 -296 267 -266 269 -270 271 -272 273 -306 241 -276 273 -270 495 -522 519 -518 259 -290 261 -264 505 -558 231 -300 271 -272 999 -1008 1015 -980 1009 -988 1007 -1016 1001 -1010 983 -1044 237 -292 253 -292 253 -254 491 -560 497 -522 527 -520 263 -294 503 -528 527 -518 259 -256 257 -296 265 -268 503 -526 263 -296 501 -558 497 -524 261 -262 261 -296 231 -298 499 -524 261 -294 267 -268 273 -308 241 -274 273 -270 233 -298 229 -298 265 -268 503 -558 231 -298 267 -304 241 -274 273 -270 497 -522 259 -290 259 -266 267 -270 505 -558 265 -266 271 -272 507 -522 521 -520 487 -550 259 -254 257 -298 269 -272 273 -306 243 -274 507 -524 259 -258 257 -296 265 -268 269 -270 271 -270 273 -308 241 -274 273 -270 497 -522 -RAW_Data: 519 -518 259 -288 261 -266 505 -558 231 -300 271 -272 997 -1012 1009 -982 1009 -986 1009 -1014 999 -1016 989 -1012 271 -288 253 -290 253 -256 495 -540 501 -558 495 -522 263 -296 501 -528 527 -520 259 -256 257 -294 265 -268 503 -556 233 -296 501 -558 499 -522 263 -260 261 -296 263 -266 499 -524 261 -294 267 -268 273 -308 241 -276 271 -270 233 -298 229 -300 265 -268 501 -556 231 -298 267 -306 241 -276 271 -270 499 -520 259 -258 259 -296 267 -272 505 -558 233 -298 271 -272 507 -522 521 -520 485 -552 259 -252 291 -264 271 -272 273 -308 241 -276 505 -522 259 -258 259 -296 265 -268 269 -270 271 -270 273 -308 241 -274 273 -270 497 -520 521 -518 259 -288 261 -266 503 -558 265 -266 269 -274 1001 -1006 1005 -984 1019 -998 1005 -1004 987 -1004 997 -1044 257 -248 279 -252 259 -296 501 -522 525 -520 525 -520 261 -296 503 -528 525 -520 259 -256 257 -294 267 -268 501 -558 231 -296 501 -560 497 -524 261 -262 259 -296 265 -264 501 -522 263 -294 265 -270 271 -308 241 -276 271 -270 233 -298 229 -298 267 -266 503 -558 231 -296 267 -306 239 -276 273 -270 497 -520 259 -290 227 -298 269 -270 505 -558 231 -298 271 -274 507 -522 521 -518 485 -550 257 -256 291 -264 269 -272 273 -308 241 -276 507 -522 259 -258 257 -296 265 -268 269 -270 271 -270 273 -308 241 -274 273 -270 497 -520 521 -518 259 -288 259 -264 503 -560 265 -266 271 -274 997 -1012 1011 -984 1005 -988 1007 -1014 1001 -1010 979 -1040 255 -274 245 -278 253 -292 495 -524 527 -520 525 -520 261 -296 499 -528 527 -520 259 -256 257 -294 265 -268 503 -556 231 -298 501 -560 499 -522 261 -260 261 -296 263 -266 501 -522 263 -294 265 -268 273 -308 241 -276 271 -270 231 -298 231 -298 267 -266 501 -558 231 -298 267 -304 241 -274 273 -270 499 -520 259 -258 259 -296 267 -270 507 -558 231 -300 271 -272 507 -522 521 -516 487 -550 259 -254 291 -266 269 -304 241 -308 241 -274 507 -524 259 -258 257 -296 265 -268 269 -270 271 -270 273 -308 241 -274 273 -270 497 -520 489 -548 261 -288 261 -264 503 -558 265 -266 271 -274 1001 -1010 977 -1028 981 -1024 1011 -978 997 -1014 1017 -1008 273 -252 255 -290 255 -290 491 -534 499 -522 527 -522 263 -294 503 -528 525 -520 259 -256 257 -294 267 -266 505 -558 231 -294 501 -558 499 -522 263 -260 261 -296 231 -298 499 -524 261 -296 265 -268 273 -306 241 -276 273 -270 231 -298 231 -296 267 -266 503 -558 231 -296 269 -304 239 -276 273 -270 497 -522 -RAW_Data: 259 -258 259 -296 269 -270 505 -558 231 -300 271 -272 505 -524 521 -520 485 -552 227 -286 255 -298 269 -272 273 -308 241 -276 505 -524 259 -258 257 -296 265 -268 269 -270 271 -270 273 -308 241 -274 273 -270 497 -520 521 -518 259 -288 259 -266 503 -558 265 -266 271 -276 997 -1014 975 -1018 1009 -986 1009 -1018 985 -1002 1009 -1006 257 -274 275 -276 249 -286 493 -526 525 -520 523 -520 263 -296 501 -526 529 -520 259 -256 255 -296 265 -268 267 -32700 99 -100 529 -100 397 -134 231 diff --git a/applications/debug/unit_tests/resources/unit_tests/subghz/kia_seed_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/kia_seed_raw.sub deleted file mode 100644 index c78e6d34a..000000000 --- a/applications/debug/unit_tests/resources/unit_tests/subghz/kia_seed_raw.sub +++ /dev/null @@ -1,25 +0,0 @@ -Filetype: Flipper SubGhz RAW File -Version: 1 -Frequency: 433920000 -Preset: FuriHalSubGhzPresetOok650Async -Protocol: RAW -RAW_Data: 51 -5136 1113 -104 127 -606 179 -126 325 -102 147 -200 205 -80 107 -190 81 -54 135 -378 181 -204 199 -104 121 -146 51 -230 75 -76 227 -102 415 -236 159 -54 159 -212 77 -312 73 -74 75 -128 155 -102 125 -358 125 -198 173 -608 75 -248 203 -558 53 -186 367 -180 151 -132 133 -138 135 -424 51 -240 53 -132 703 -80 79 -80 129 -294 77 -102 193 -270 77 -52 131 -180 51 -76 77 -76 51 -666 77 -104 101 -54 77 -164 107 -622 615 -294 133 -138 217 -180 75 -104 185 -80 107 -134 159 -398 181 -74 97 -198 73 -76 99 -102 127 -248 71 -128 211 -106 109 -104 101 -384 311 -398 51 -240 111 -84 81 -110 81 -668 105 -54 77 -158 79 -342 493 -78 153 -152 179 -122 223 -696 139 -590 81 -212 83 -322 129 -132 307 -346 129 -78 77 -232 77 -104 503 -52 187 -290 159 -108 159 -108 51 -136 53 -132 103 -566 177 -326 129 -176 177 -52 355 -308 129 -176 73 -104 151 -262 193 -168 111 -162 247 -52 131 -54 107 -84 83 -218 135 -402 107 -300 105 -220 81 -82 137 -82 163 -238 51 -192 293 -184 319 -454 81 -132 131 -132 79 -866 131 -212 163 -112 133 -106 211 -110 189 -214 51 -410 107 -454 131 -562 157 -52 367 -378 165 -110 81 -134 81 -82 75 -104 217 -638 81 -84 109 -160 81 -160 135 -54 53 -478 239 -78 209 -54 107 -52 155 -238 53 -184 105 -318 105 -370 233 -54 109 -246 217 -110 245 -110 209 -80 129 -514 79 -54 79 -314 155 -156 109 -292 79 -504 51 -644 157 -132 53 -208 53 -76 103 -76 77 -260 105 -82 133 -212 163 -136 53 -380 313 -178 193 -172 207 -82 79 -186 107 -136 53 -136 159 -156 97 -98 99 -254 179 -106 135 -214 307 -310 77 -76 123 -242 129 -52 103 -584 103 -178 203 -324 101 -572 253 -78 125 -126 129 -408 131 -52 129 -76 51 -132 79 -248 79 -414 51 -338 717 -322 79 -180 105 -294 109 -254 241 -76 251 -52 101 -152 125 -260 155 -80 77 -292 51 -226 209 -338 147 -100 51 -366 53 -348 133 -268 79 -366 55 -224 111 -248 81 -218 137 -168 79 -288 291 -132 51 -238 79 -78 103 -102 329 -102 123 -178 53 -202 51 -130 79 -138 51 -126 151 -180 99 -388 75 -126 51 -636 329 -150 99 -152 73 -122 177 -124 151 -386 297 -72 103 -130 51 -256 207 -354 75 -124 71 -148 351 -262 51 -540 77 -200 101 -132 77 -362 77 -254 103 -106 79 -296 51 -130 361 -240 51 -358 51 -284 201 -158 185 -288 183 -424 77 -130 -RAW_Data: 121 -146 99 -124 327 -74 99 -148 99 -252 183 -112 161 -216 263 -232 77 -102 103 -416 77 -382 345 -160 131 -110 167 -138 79 -158 133 -54 163 -84 107 -80 107 -108 107 -136 225 -82 321 -108 79 -106 107 -106 55 -162 103 -160 133 -192 53 -84 269 -106 77 -162 53 -136 161 -82 135 -346 77 -864 107 -140 55 -250 189 -128 201 -502 157 -564 105 -52 107 -1150 53 -218 237 -76 159 -1010 129 -196 139 -244 101 -270 77 -106 133 -110 109 -254 501 -496 237 -692 107 -54 159 -134 347 -210 51 -190 55 -276 103 -184 229 -98 149 -252 123 -156 75 -150 537 -236 103 -204 101 -100 73 -368 283 -102 77 -652 229 -206 99 -150 197 -206 53 -80 131 -274 101 -186 159 -396 51 -188 81 -188 83 -350 105 -428 129 -128 79 -78 53 -104 351 -284 235 -130 79 -242 51 -186 77 -134 135 -434 131 -552 53 -136 107 -140 141 -252 53 -54 53 -82 51 -770 79 -130 103 -432 127 -208 153 -226 131 -248 101 -902 125 -206 129 -102 77 -154 77 -188 105 -322 105 -166 133 -474 77 -728 161 -190 107 -54 133 -80 79 -190 53 -162 53 -404 77 -334 105 -52 153 -728 423 -700 133 -476 53 -162 53 -542 159 -168 189 -134 163 -134 81 -106 133 -54 267 -108 163 -242 165 -56 167 -294 81 -136 185 -660 51 -304 157 -54 109 -378 133 -272 159 -304 135 -110 53 -402 105 -630 185 -78 257 -422 173 -252 247 -100 123 -330 107 -166 109 -502 127 -156 219 -76 101 -348 71 -586 149 -154 73 -74 77 -358 131 -270 81 -108 159 -516 295 -346 53 -240 157 -240 55 -562 133 -110 213 -320 103 -560 79 -286 51 -134 55 -452 79 -136 79 -80 77 -52 185 -504 79 -216 79 -242 135 -262 75 -206 125 -472 111 -564 79 -322 79 -432 217 -456 167 -272 103 -664 53 -302 127 -138 241 -184 53 -80 81 -192 395 -604 133 -136 53 -1044 105 -166 215 -426 133 -1222 101 -348 127 -124 123 -248 153 -492 177 -102 103 -180 77 -204 151 -282 101 -74 103 -76 101 -170 73 -506 101 -368 51 -124 193 -236 53 -310 77 -130 155 -366 229 -526 129 -428 83 -922 51 -106 131 -82 219 -706 79 -80 81 -162 133 -276 195 -220 51 -266 81 -54 51 -238 53 -686 77 -354 229 -164 195 -164 81 -294 81 -132 197 -238 73 -202 181 -180 149 -128 207 -192 111 -56 187 -808 77 -608 79 -898 77 -208 97 -200 73 -184 75 -78 203 -664 105 -384 103 -102 129 -238 131 -1346 137 -526 105 -390 129 -138 81 -484 103 -222 109 -268 51 -240 -RAW_Data: 81 -658 53 -626 79 -562 79 -52 77 -266 107 -54 109 -410 105 -514 107 -110 53 -334 79 -928 121 -498 105 -184 149 -174 73 -908 129 -388 199 -450 153 -862 51 -896 101 -776 51 -990 129 -154 177 -412 169 -254 77 -902 105 -474 77 -2390 103 -1000 107 -2112 151 -402 51 -428 337 -440 129 -590 197 -538 53 -138 81 -584 81 -1958 107 -4714 57 -786 53 -684 137 -442 105 -654 53 -696 51 -2382 105 -376 83 -822 155 -6282 103 -560 77 -252 79 -1518 103 -3648 51 -6150 75 -4986 75 -2042 53 -2798 171 -804 2247 -130 357 -168 309 -168 307 -170 293 -172 305 -192 279 -224 253 -224 279 -196 265 -224 261 -222 253 -224 253 -224 279 -214 245 -232 243 -252 253 -224 251 -226 241 -222 253 -246 251 -224 253 -224 251 -252 213 -248 261 -222 251 -226 251 -254 223 -242 245 -232 245 -250 225 -252 253 -224 241 -222 253 -246 251 -226 251 -224 253 -252 213 -248 233 -248 253 -224 253 -252 223 -242 247 -230 245 -252 223 -252 253 -224 241 -222 255 -244 251 -226 251 -224 253 -252 213 -248 233 -250 251 -226 251 -252 225 -242 245 -230 245 -252 225 -252 251 -226 241 -222 253 -246 251 -224 253 -224 251 -254 213 -246 235 -248 251 -226 251 -254 223 -242 245 -232 245 -252 225 -252 251 -224 253 -214 245 -236 247 -252 253 -224 251 -226 241 -246 231 -246 251 -226 251 -224 253 -252 213 -248 233 -250 251 -226 253 -252 223 -242 245 -232 243 -254 223 -254 251 -224 253 -214 245 -236 247 -254 251 -224 253 -224 241 -246 231 -246 251 -226 251 -252 225 -252 213 -248 261 -224 251 -226 251 -252 225 -252 213 -250 261 -222 253 -224 253 -252 225 -242 245 -230 245 -252 225 -252 251 -226 241 -220 255 -246 249 -226 251 -226 251 -254 213 -248 233 -248 251 -226 251 -254 223 -242 245 -232 245 -252 223 -252 253 -224 241 -222 253 -246 251 -226 251 -224 253 -252 213 -248 233 -248 253 -224 253 -252 223 -242 245 -232 245 -252 223 -252 253 -224 241 -222 255 -244 251 -226 251 -224 253 -252 213 -246 235 -248 251 -254 223 -252 225 -242 245 -232 245 -252 223 -254 251 -226 241 -222 253 -246 251 -224 253 -224 251 -254 213 -248 233 -248 251 -226 251 -254 223 -242 245 -230 245 -252 225 -252 251 -226 241 -222 253 -246 251 -224 253 -224 251 -254 213 -248 233 -248 253 -224 253 -252 225 -252 213 -248 261 -224 251 -226 251 -252 225 -242 245 -230 245 -254 223 -252 253 -224 241 -222 253 -246 251 -226 251 -224 251 -254 213 -248 259 -224 251 -226 -RAW_Data: 251 -254 223 -242 245 -230 245 -252 225 -252 251 -226 251 -214 247 -234 249 -252 251 -226 251 -224 241 -248 229 -248 251 -224 253 -224 251 -254 213 -246 261 -224 251 -226 251 -252 225 -242 245 -230 247 -252 223 -252 253 -224 243 -220 255 -244 251 -226 251 -226 251 -252 213 -248 233 -248 251 -252 225 -252 225 -242 245 -232 245 -252 223 -254 251 -224 253 -214 247 -236 247 -252 251 -226 251 -226 241 -246 231 -246 251 -224 253 -224 251 -254 213 -248 233 -248 253 -252 223 -254 223 -242 245 -232 245 -252 223 -254 251 -226 241 -220 255 -244 251 -226 251 -226 251 -252 213 -248 233 -250 251 -226 251 -252 225 -242 245 -230 245 -254 223 -252 253 -224 241 -222 253 -246 251 -224 253 -224 253 -252 213 -246 235 -248 251 -226 251 -254 223 -242 245 -232 245 -252 223 -254 251 -226 251 -214 247 -234 247 -254 251 -224 253 -224 241 -246 231 -246 251 -226 251 -226 251 -252 213 -248 261 -222 253 -224 253 -252 225 -242 245 -230 245 -254 223 -252 253 -224 253 -214 245 -236 247 -252 253 -224 251 -226 241 -246 231 -246 251 -226 251 -252 225 -252 213 -248 235 -248 251 -254 223 -252 225 -242 245 -230 247 -252 223 -252 253 -224 241 -222 253 -246 251 -226 251 -224 253 -252 215 -246 235 -248 251 -224 479 -484 501 -482 461 -492 483 -466 255 -234 245 -252 223 -254 251 -226 241 -222 487 -480 253 -222 489 -480 251 -246 465 -482 251 -246 231 -246 483 -468 255 -234 481 -488 233 -246 233 -248 483 -466 255 -234 245 -252 225 -252 251 -226 469 -494 483 -488 483 -482 221 -250 473 -488 479 -490 231 -248 231 -246 251 -226 251 -226 251 -252 467 -476 249 -252 223 -252 469 -494 481 -470 485 -484 247 -252 469 -462 481 -498 229 -252 243 -252 225 -252 223 -254 251 -214 477 -484 247 -250 251 -214 247 -234 247 -252 481 -460 261 -244 251 -226 479 -486 1435 -1456 231 -236 247 -252 225 -252 253 -224 241 -222 253 -246 251 -224 253 -224 253 -252 213 -246 261 -222 251 -226 251 -252 225 -242 245 -230 247 -252 481 -462 493 -480 481 -492 481 -462 255 -224 263 -222 253 -252 223 -254 223 -242 475 -484 249 -222 505 -488 245 -222 469 -496 247 -252 223 -254 469 -490 249 -224 477 -482 237 -250 249 -226 479 -484 239 -246 251 -226 251 -226 251 -252 467 -474 481 -490 491 -456 271 -224 469 -494 481 -492 229 -236 245 -252 225 -252 251 -226 241 -222 487 -482 251 -246 231 -246 483 -468 487 -482 473 -486 265 -222 485 -492 461 -484 247 -250 -RAW_Data: 253 -214 245 -234 247 -252 225 -252 473 -486 243 -252 225 -254 223 -254 251 -214 477 -486 245 -252 223 -242 477 -484 1463 -1444 249 -222 253 -224 241 -246 233 -248 251 -226 251 -254 223 -252 213 -248 261 -224 251 -226 251 -254 223 -242 245 -232 245 -252 223 -252 253 -224 469 -496 483 -488 457 -506 479 -462 259 -244 223 -252 253 -224 251 -226 241 -246 467 -478 253 -246 467 -480 251 -248 465 -480 251 -248 229 -248 483 -468 255 -232 483 -474 255 -224 265 -224 483 -492 229 -236 249 -252 223 -252 253 -224 469 -496 479 -482 491 -480 225 -246 485 -482 491 -462 245 -252 253 -224 253 -224 241 -246 231 -246 483 -488 229 -250 241 -252 457 -490 489 -460 497 -484 243 -224 483 -490 489 -458 249 -248 249 -240 249 -226 251 -226 251 -226 493 -472 249 -252 223 -252 223 -242 245 -234 483 -488 233 -246 233 -248 483 -468 1451 -1448 229 -492 247 -248 79 -400 157 -566 133 -108 379 -218 109 -54 163 -164 51 -102 315 -260 263 -80 463 -234 151 -76 149 -154 249 -126 99 -130 125 -270 127 -188 427 -210 131 -222 593 -106 241 -562 239 -84 305 -262 183 -80 53 -524 125 -480 227 -328 51 -350 211 -82 181 -108 215 -106 147 -200 183 -104 397 -52 131 -102 147 -172 335 -618 177 -206 131 -220 129 -158 213 -52 187 -164 135 -334 157 -410 73 -120 225 -234 133 -108 81 -138 599 -238 131 -262 77 -368 209 -130 103 -76 335 -78 101 -232 253 -280 97 -74 73 -74 97 -52 383 -272 125 -104 81 -82 455 -106 159 -78 127 -52 183 -358 55 -170 139 -86 53 -108 299 -52 129 -282 385 -104 101 -514 75 -232 153 -510 75 -174 97 -128 151 -152 101 -206 103 -76 227 -308 77 -302 129 -76 77 -592 175 -202 75 -314 157 -400 343 -52 185 -104 135 -136 129 -108 111 -112 271 -266 161 -108 107 -240 343 -342 213 -128 99 -124 181 -54 103 -200 101 -274 157 -104 131 -154 123 -588 105 -108 107 -54 161 -52 349 -184 83 -84 53 -54 133 -540 105 -52 53 -160 105 -334 481 -180 101 -304 257 -176 77 -286 79 -106 179 -102 73 -554 285 -184 77 -396 103 -264 185 -106 233 -732 235 -108 53 -82 185 -140 137 -188 285 -294 281 -338 127 -378 77 -242 239 -112 327 -106 219 -240 55 -54 109 -584 51 -134 79 -80 215 -80 109 -54 81 -264 157 -310 51 -130 161 -140 375 -290 129 -886 263 -78 51 -342 55 -104 207 -288 271 -108 179 -74 75 -460 257 -280 77 -106 51 -104 53 -150 125 -174 155 -80 221 -108 161 -310 -RAW_Data: 77 -104 51 -208 79 -452 379 -130 51 -318 237 -214 257 -180 77 -298 79 -604 103 -398 187 -346 181 -154 97 -174 285 -156 51 -102 583 -78 75 -74 151 -102 255 -158 339 -80 77 -234 155 -102 101 -250 75 -76 147 -150 123 -100 75 -78 259 -180 251 -80 51 -104 77 -130 77 -52 159 -236 103 -622 173 -1016 131 -184 153 -156 73 -274 331 -292 105 -204 199 -516 103 -210 157 -104 287 -304 153 -78 129 -78 385 -332 179 -286 181 -178 145 -176 121 -76 169 -146 123 -102 181 -180 51 -176 147 -230 103 -172 75 -208 199 -52 153 -52 75 -134 265 -80 51 -182 157 -110 237 -104 183 -198 213 -168 219 -132 75 -78 101 -76 101 -306 231 -130 99 -152 125 -130 105 -132 135 -110 133 -476 213 -54 325 -322 209 -404 303 -106 81 -166 403 -134 105 -242 403 -104 129 -182 55 -174 165 -168 83 -304 185 -130 133 -108 135 -134 103 -52 181 -362 207 -54 179 -228 231 -236 105 -214 53 -158 77 -452 319 -106 79 -348 349 -406 133 -84 195 -104 239 -158 197 -164 79 -80 79 -54 79 -156 201 -374 941 -492 77 -174 73 -230 75 -278 177 -52 477 -306 129 -106 79 -108 113 -196 127 -328 51 -102 125 -76 75 -102 153 -76 99 -146 373 -134 185 -134 105 -352 105 -436 127 -246 51 -106 79 -238 131 -82 165 -270 109 -108 79 -634 157 -242 105 -78 129 -52 131 -266 215 -270 329 -162 51 -478 209 -52 157 -372 79 -82 367 -560 129 -210 53 -54 133 -106 133 -292 77 -106 159 -84 185 -80 509 -54 473 -80 103 -108 105 -158 51 -180 123 -122 71 -208 129 -210 371 -212 75 -110 341 -164 425 -130 181 -54 313 -278 51 -52 129 -386 263 -78 245 -344 287 -134 133 -130 81 -276 105 -114 129 -106 487 -78 127 -182 179 -146 127 -148 125 -186 133 -182 127 -76 195 -96 103 -76 75 -52 101 -204 77 -102 405 -102 75 -224 125 -276 153 -100 147 -350 259 -156 77 -128 463 -76 77 -234 103 -252 51 -286 75 -232 201 -102 75 -176 175 -124 151 -100 51 -254 97 -74 123 -122 123 -174 201 -154 129 -190 53 -136 81 -78 79 -216 133 -106 111 -84 137 -136 163 -324 103 -78 51 -56 109 -106 177 -168 75 -492 131 -52 131 -180 73 -74 359 -104 101 -102 101 -492 159 -290 215 -80 187 -214 103 -160 135 -130 175 -126 107 -54 75 -78 77 -152 199 -604 97 -74 101 -284 127 -52 177 -434 153 -122 781 -208 79 -80 105 -292 135 -84 247 -318 51 -430 79 -162 109 -56 135 -190 185 -78 159 -130 -RAW_Data: 185 -188 137 -108 331 -56 79 -132 167 -188 107 -320 393 -310 99 -154 51 -180 153 -74 101 -76 229 -128 183 -184 249 -108 299 -82 191 -532 295 -400 103 -80 79 -272 53 -276 213 -84 55 -110 291 -106 123 -204 101 -102 77 -104 157 -102 51 -126 51 -126 183 -140 83 -264 53 -134 261 -128 81 -82 81 -298 81 -266 77 -52 51 -474 265 -366 103 -226 239 -166 677 -232 175 -150 205 -76 123 -76 97 -176 127 -284 77 -76 357 -182 73 -326 171 -104 675 -236 301 -216 53 -84 107 -52 157 -78 237 -136 289 -130 215 -350 77 -320 187 -110 347 -240 159 -134 79 -486 207 -272 129 -82 293 -188 105 -212 77 -216 445 -836 151 -150 73 -262 75 -102 253 -52 101 -102 281 -386 149 -230 355 -212 51 -130 329 -224 149 -52 75 -204 77 -108 85 -194 341 -134 269 -132 161 -56 81 -556 187 -448 395 -130 177 -136 107 -184 239 -136 53 -214 135 -266 79 -368 109 -372 315 -78 79 -78 103 -132 53 -82 81 -104 129 -182 125 -74 103 -236 211 -294 205 -216 131 -108 211 -236 79 -54 103 -104 161 -54 265 -54 187 -162 107 -134 183 -190 237 -104 51 -186 107 -164 137 -102 77 -206 197 -238 107 -52 53 -78 155 -126 201 -78 125 -204 103 -102 75 -104 253 -76 105 -238 159 -366 209 -216 165 -56 55 -322 585 -80 183 -108 81 -136 109 -168 211 -236 295 -674 337 -78 211 -312 77 -242 297 -378 215 -190 79 -298 161 -108 183 -122 121 -252 103 -516 105 -54 123 -226 291 -78 77 -104 53 -484 197 -452 51 -306 77 -106 127 -178 51 -256 209 -264 101 -76 101 -126 151 -126 251 -1152 359 -126 325 -254 551 -156 83 -666 161 -236 105 -186 103 -108 161 -80 157 -54 51 -344 159 -82 349 -160 141 -270 131 -578 189 -162 287 -134 161 -712 127 -106 51 -108 345 -704 431 -362 51 -52 415 -208 233 -342 257 -288 131 -80 77 -252 53 -330 105 -160 83 -280 393 -358 103 -480 161 -134 51 -54 259 -104 129 -130 105 -80 217 -350 269 -192 57 -302 79 -264 81 -326 157 -80 79 -214 51 -370 129 -236 53 -136 105 -82 57 -140 137 -52 79 -236 103 -80 55 -192 293 -188 53 -348 185 -236 207 -56 135 -54 215 -216 587 -132 103 -160 133 -158 365 -52 103 -54 107 -80 185 -298 267 -136 159 -110 109 -82 241 -78 77 -78 101 -82 141 -226 55 -462 79 -188 81 -216 511 -210 79 -162 161 -160 101 -388 157 -180 101 -100 197 -336 581 -130 211 -264 155 -52 297 -180 75 -100 73 -100 247 -130 -RAW_Data: 133 -346 505 -108 105 -80 243 -292 79 -104 339 -78 75 -128 287 -398 99 -300 479 -104 257 -130 153 -78 359 -152 79 -300 77 -348 109 -82 217 -108 243 -80 185 -430 133 -460 211 -234 207 -52 291 -80 77 -54 81 -82 265 -78 101 -132 255 -122 73 -512 129 -126 77 -158 213 -168 81 -82 479 -160 159 -108 157 -158 133 -236 129 -128 485 -126 153 -412 99 -250 255 -274 173 -358 231 -76 53 -78 131 -54 135 -290 77 -102 305 -128 77 -310 183 -80 239 -80 135 -166 189 -104 81 -140 111 -164 477 -488 51 -134 53 -80 429 -240 529 -476 287 -80 189 -136 327 -84 79 -160 293 -348 133 -148 179 -52 231 -102 175 -76 125 -100 425 -228 77 -200 183 -154 231 -212 253 -78 299 -132 145 -124 337 -150 101 -132 99 -274 153 -182 53 -158 51 -160 453 -134 427 -182 77 -134 275 -528 77 -108 79 -110 109 -110 245 -136 171 -164 473 -106 265 -80 267 -184 179 -330 287 -212 185 -350 129 -630 467 -350 489 -166 107 -56 79 -270 53 -84 757 -624 207 -102 51 -416 287 -288 103 -406 73 -132 51 -214 135 -644 103 -146 73 -358 629 -736 309 -150 275 -254 51 -106 53 -54 105 -80 53 -180 77 -110 297 -106 79 -418 261 -80 161 -80 77 -480 79 -156 215 -190 601 -130 353 -76 73 -76 127 -198 125 -100 531 -78 77 -438 103 -134 191 -312 291 -108 53 -134 53 -214 317 -80 277 -182 279 -302 329 -104 479 -182 203 -98 273 -222 247 -250 241 -252 219 -248 221 -254 243 -252 225 -254 223 -252 253 -214 245 -236 247 -252 251 -226 251 -224 241 -222 255 -246 251 -226 251 -226 251 -252 213 -248 235 -248 253 -224 253 -252 225 -242 245 -230 245 -252 223 -254 251 -224 253 -214 247 -236 247 -252 251 -226 251 -226 241 -222 255 -246 251 -224 253 -224 251 -254 213 -248 233 -248 253 -224 253 -252 223 -242 247 -230 245 -252 225 -252 253 -224 251 -214 247 -236 247 -254 251 -224 253 -224 241 -246 231 -246 251 -226 251 -224 253 -252 213 -248 235 -248 251 -226 251 -254 223 -242 245 -232 245 -252 223 -254 251 -224 241 -222 253 -246 251 -224 253 -224 253 -252 213 -248 233 -248 251 -226 253 -252 223 -242 245 -232 245 -252 225 -252 253 -224 251 -214 247 -236 247 -252 253 -224 251 -226 241 -246 231 -246 251 -224 253 -252 225 -252 213 -248 233 -248 253 -252 225 -252 223 -244 245 -230 245 -254 223 -252 253 -224 253 -214 245 -236 247 -252 253 -224 251 -226 241 -246 231 -246 251 -224 253 -252 223 -252 -RAW_Data: 213 -248 263 -222 251 -226 251 -254 223 -242 245 -232 245 -252 223 -254 251 -224 253 -214 247 -234 249 -252 251 -226 251 -224 241 -246 231 -246 251 -226 251 -254 223 -252 213 -248 261 -222 253 -252 223 -254 223 -242 245 -232 245 -252 225 -252 251 -226 241 -222 253 -246 251 -224 253 -224 253 -252 213 -246 261 -222 251 -226 251 -254 223 -242 245 -232 245 -252 223 -254 251 -224 241 -222 253 -246 251 -224 253 -224 253 -252 213 -248 235 -248 251 -224 251 -254 223 -242 245 -232 245 -252 225 -252 251 -226 241 -222 253 -246 251 -224 253 -224 253 -252 213 -246 261 -222 251 -226 251 -254 223 -242 245 -232 245 -252 223 -254 251 -224 243 -220 253 -246 251 -226 251 -224 251 -254 213 -248 233 -248 251 -254 223 -254 223 -242 245 -232 245 -252 225 -252 251 -226 241 -222 253 -246 251 -224 253 -224 253 -252 213 -248 233 -248 251 -226 251 -252 225 -242 245 -230 247 -252 223 -254 251 -224 253 -214 245 -236 247 -254 251 -224 253 -224 241 -246 231 -246 251 -224 253 -224 253 -242 219 -256 243 -254 223 -254 251 -224 253 -214 245 -236 247 -252 251 -226 251 -224 243 -246 229 -248 251 -224 253 -252 223 -254 213 -246 261 -224 251 -226 251 -254 223 -242 245 -232 245 -252 223 -252 253 -224 241 -222 253 -246 251 -226 251 -224 253 -252 213 -248 233 -248 253 -224 253 -252 223 -254 213 -248 263 -222 253 -224 253 -252 223 -242 245 -232 245 -252 223 -254 251 -226 241 -220 253 -246 251 -226 251 -224 253 -252 213 -248 261 -222 251 -226 251 -254 223 -242 245 -232 243 -252 225 -252 253 -224 241 -222 253 -246 251 -226 251 -224 251 -254 213 -246 261 -222 253 -224 253 -252 223 -242 247 -230 245 -252 223 -254 251 -224 243 -220 255 -246 249 -226 251 -226 251 -254 213 -246 235 -248 251 -226 251 -252 225 -242 245 -230 245 -252 225 -252 253 -224 251 -214 247 -236 247 -254 251 -224 253 -224 241 -246 231 -246 251 -226 251 -224 253 -252 213 -248 261 -222 251 -226 253 -252 223 -242 245 -232 245 -252 225 -252 253 -224 251 -214 247 -234 249 -252 251 -226 251 -224 241 -246 231 -246 251 -226 251 -226 251 -254 213 -248 261 -220 253 -252 225 -252 223 -242 247 -230 245 -254 479 -462 495 -482 479 -490 481 -470 229 -254 245 -250 225 -252 223 -254 251 -214 503 -458 249 -248 481 -484 243 -224 495 -472 249 -252 223 -252 471 -490 249 -224 479 -486 473 -482 241 -242 477 -482 247 -250 253 -214 245 -234 247 -252 481 -462 495 -482 -RAW_Data: 465 -488 245 -252 479 -480 473 -488 243 -252 213 -246 261 -224 251 -224 253 -252 469 -466 245 -254 251 -224 473 -486 481 -480 485 -482 247 -224 505 -458 499 -484 243 -252 223 -252 225 -252 223 -242 247 -232 483 -490 485 -472 249 -252 473 -484 243 -224 483 -492 231 -234 485 -488 487 -472 1445 -1448 237 -248 251 -226 251 -224 253 -252 213 -246 261 -222 251 -254 223 -252 225 -242 245 -230 247 -252 223 -254 251 -224 243 -220 255 -244 251 -226 477 -482 501 -454 507 -480 479 -462 259 -244 251 -224 253 -224 251 -226 241 -246 493 -464 241 -242 475 -484 249 -222 505 -484 225 -246 251 -242 485 -470 229 -254 477 -480 485 -482 247 -224 495 -464 273 -224 253 -224 251 -226 241 -246 493 -480 479 -470 481 -480 233 -266 459 -488 485 -476 247 -252 223 -254 251 -214 245 -234 247 -252 481 -462 259 -244 251 -226 479 -486 469 -482 481 -492 247 -224 477 -482 503 -464 241 -242 245 -232 245 -254 223 -252 253 -224 469 -496 483 -486 229 -252 477 -476 227 -248 497 -480 227 -254 477 -480 483 -482 1439 -1452 245 -252 223 -254 223 -252 253 -214 245 -234 247 -252 225 -252 251 -226 241 -222 253 -246 251 -226 251 -226 251 -252 213 -248 261 -222 253 -224 479 -484 501 -482 461 -492 483 -466 255 -234 245 -252 225 -252 253 -224 241 -222 487 -480 253 -222 489 -480 251 -248 463 -482 251 -246 231 -246 483 -488 229 -252 477 -478 485 -480 223 -248 479 -484 247 -250 251 -214 247 -234 247 -252 481 -460 493 -482 479 -492 249 -224 477 -480 477 -488 243 -240 245 -234 245 -252 223 -254 251 -226 469 -494 247 -224 253 -252 469 -488 483 -470 485 -482 247 -224 497 -462 483 -490 231 -248 233 -248 251 -226 251 -252 225 -242 475 -484 475 -484 239 -250 483 -468 255 -232 483 -490 231 -246 493 -480 481 -470 1445 -1448 239 -772 105 -194 247 -314 105 -176 125 -126 151 -382 51 -266 51 -104 55 -400 129 -114 243 -210 343 -78 161 -108 107 -110 53 -214 83 -242 209 -80 155 -82 53 -268 391 -80 79 -214 211 -132 131 -320 77 -320 157 -138 191 -136 103 -202 99 -446 213 -406 131 -286 101 -258 51 -188 55 -82 81 -162 237 -130 183 -512 291 -80 193 -342 77 -106 159 -272 77 -52 53 -78 183 -544 79 -106 277 -338 185 -132 153 -108 107 -108 163 -54 107 -134 235 -356 523 -108 137 -134 291 -80 79 -214 213 -266 137 -54 53 -162 165 -84 191 -78 53 -132 213 -318 79 -264 215 -320 159 -82 53 -246 131 -132 175 -102 227 -228 -RAW_Data: 315 -106 53 -872 139 -136 209 -332 177 -272 417 -180 51 -52 181 -338 77 -130 51 -104 151 -52 127 -152 99 -76 155 -126 203 -180 151 -126 101 -200 179 -384 123 -592 153 -80 127 -466 75 -100 121 -98 123 -126 97 -336 359 -104 107 -192 55 -80 103 -190 81 -132 79 -78 207 -128 109 -216 183 -270 105 -80 129 -52 51 -354 85 -194 135 -238 243 -82 81 -370 295 -130 135 -136 137 -190 211 -188 81 -184 53 -80 159 -82 55 -350 319 -160 355 -210 99 -462 53 -130 277 -204 619 -184 471 -78 131 -378 453 -162 171 -86 165 -222 81 -82 315 -210 101 -78 383 -102 101 -180 207 -416 183 -310 259 -200 225 -146 333 -460 185 -78 211 -192 85 -84 353 -82 79 -80 213 -158 75 -156 131 -226 133 -54 107 -134 105 -106 131 -80 267 -132 187 -192 271 -110 105 -82 79 -270 135 -102 185 -134 185 -54 191 -134 249 -368 53 -238 79 -54 185 -526 51 -376 243 -586 109 -346 81 -82 179 -78 267 -206 177 -100 125 -104 173 -74 77 -152 155 -186 83 -190 351 -164 135 -106 109 -142 337 -214 81 -188 79 -78 103 -228 101 -226 175 -214 315 -52 79 -184 77 -240 291 -54 79 -80 51 -624 135 -134 203 -146 223 -74 135 -238 133 -134 129 -380 133 -190 79 -108 241 -186 181 -416 155 -134 157 -128 305 -134 425 -508 283 -128 181 -826 127 -268 77 -368 261 -54 189 -374 415 -156 201 -178 177 -206 127 -234 79 -380 133 -54 161 -236 53 -184 79 -298 53 -294 77 -312 177 -154 77 -208 369 -78 53 -160 215 -106 557 -320 473 -274 343 -78 99 -100 119 -72 155 -98 123 -76 257 -280 51 -260 157 -78 127 -52 99 -74 569 -302 131 -428 77 -336 101 -102 177 -230 97 -124 51 -102 75 -156 251 -126 173 -326 79 -428 123 -380 281 -238 161 -158 157 -230 395 -202 123 -220 255 -104 97 -198 77 -100 551 -76 101 -256 231 -410 77 -102 75 -230 105 -158 51 -132 105 -340 215 -108 241 -134 129 -160 191 -292 51 -852 155 -186 77 -52 103 -578 77 -106 209 -132 107 -130 53 -164 455 -78 155 -244 185 -160 217 -216 381 -130 127 -514 209 -82 55 -136 103 -104 173 -226 231 -176 73 -130 205 -102 319 -244 53 -160 107 -162 57 -350 97 -230 203 -252 127 -360 79 -316 103 -180 101 -178 185 -216 101 -302 257 -182 103 -126 75 -152 103 -102 77 -284 413 -612 177 -432 73 -460 79 -78 53 -556 155 -664 75 -214 327 -134 79 -134 133 -136 51 -82 103 -130 145 -74 199 -128 51 -102 103 -482 -RAW_Data: 179 -100 177 -52 103 -158 191 -110 81 -190 217 -326 51 -280 147 -602 209 -76 99 -124 293 -108 193 -192 241 -184 131 -106 159 -52 77 -132 53 -104 101 -188 79 -538 105 -80 107 -52 213 -428 243 -84 81 -132 265 -140 77 -80 51 -214 189 -140 301 -162 75 -102 231 -178 123 -264 123 -98 125 -76 103 -238 77 -228 183 -140 165 -552 297 -54 291 -186 185 -234 155 -78 79 -180 53 -82 505 -182 103 -128 123 -280 133 -158 103 -644 213 -330 77 -106 79 -424 155 -212 163 -192 189 -508 369 -80 79 -220 111 -166 79 -304 133 -108 139 -140 189 -78 51 -348 289 -104 187 -54 109 -508 131 -108 283 -516 99 -100 299 -380 199 -152 325 -304 229 -476 75 -148 101 -102 75 -208 77 -74 125 -74 73 -76 181 -176 179 -186 235 -130 79 -184 77 -152 121 -304 127 -484 103 -152 173 -100 157 -176 185 -82 177 -156 309 -106 79 -132 51 -236 179 -154 73 -236 77 -74 71 -160 235 -130 105 -108 247 -56 53 -208 75 -74 75 -128 505 -154 179 -76 51 -278 103 -178 99 -126 183 -54 161 -526 133 -80 79 -298 105 -236 77 -264 139 -54 243 -164 459 -208 51 -236 105 -370 79 -374 77 -182 129 -202 77 -158 107 -108 107 -82 245 -244 109 -82 81 -292 179 -52 129 -164 423 -52 153 -102 151 -100 125 -76 259 -78 365 -240 107 -162 105 -244 163 -56 163 -108 159 -52 79 -260 79 -502 133 -82 323 -552 105 -210 699 -78 189 -192 105 -128 165 -188 105 -158 77 -158 79 -54 131 -498 131 -130 101 -176 125 -170 213 -52 77 -106 53 -292 389 -104 133 -402 133 -80 109 -54 53 -104 79 -182 505 -54 161 -264 181 -212 107 -164 83 -244 315 -234 127 -130 147 -150 231 -456 101 -124 73 -104 287 -320 81 -134 107 -244 267 -78 157 -108 137 -84 133 -54 79 -186 107 -262 77 -80 81 -240 53 -82 107 -136 245 -110 185 -294 259 -134 135 -80 159 -566 107 -190 187 -190 79 -54 107 -80 107 -54 135 -164 165 -56 79 -54 349 -78 75 -104 157 -320 53 -82 421 -180 97 -172 105 -106 111 -280 163 -132 193 -250 107 -318 155 -266 109 -162 183 -242 105 -484 79 -106 125 -246 99 -492 75 -180 127 -100 95 -196 75 -152 537 -214 53 -186 103 -134 81 -108 109 -560 51 -382 153 -104 51 -188 373 -240 53 -266 129 -622 51 -132 81 -58 137 -364 263 -78 235 -82 177 -486 105 -276 157 -108 237 -80 105 -132 131 -258 289 -102 51 -104 103 -104 73 -508 283 -102 51 -230 99 -178 105 -106 -RAW_Data: 53 -190 105 -160 157 -158 129 -80 241 -162 277 -260 77 -312 157 -320 193 -108 77 -184 77 -102 125 -286 107 -82 371 -266 447 -218 271 -106 51 -162 107 -194 333 -264 99 -76 75 -150 345 -444 105 -696 75 -154 185 -348 105 -108 159 -296 161 -80 107 -222 81 -106 239 -80 75 -78 105 -52 323 -246 51 -162 79 -130 157 -618 241 -82 107 -106 133 -294 137 -108 53 -104 107 -80 51 -80 267 -106 77 -212 105 -84 81 -56 131 -132 211 -78 187 -138 131 -104 53 -78 311 -210 77 -80 109 -160 239 -208 51 -292 443 -158 167 -138 185 -232 293 -78 181 -136 53 -186 107 -108 53 -80 395 -130 299 -160 53 -162 109 -56 135 -468 75 -102 229 -396 105 -98 277 -386 339 -356 125 -226 291 -270 165 -80 79 -106 77 -244 189 -162 215 -672 343 -184 75 -450 131 -208 57 -114 107 -420 53 -106 81 -188 103 -136 501 -110 211 -76 161 -294 107 -54 55 -206 75 -100 75 -432 77 -248 51 -78 419 -52 535 -106 207 -230 99 -124 179 -100 71 -76 77 -400 53 -340 185 -188 235 -106 105 -220 55 -134 53 -346 53 -192 291 -346 209 -242 185 -158 51 -128 75 -176 153 -282 159 -158 73 -330 105 -634 323 -242 79 -210 181 -52 103 -54 107 -108 105 -330 105 -272 51 -206 227 -154 129 -194 285 -80 79 -266 127 -492 131 -432 181 -108 213 -242 107 -346 207 -78 157 -160 53 -108 53 -322 83 -674 317 -188 243 -186 81 -166 111 -84 535 -78 181 -134 327 -240 103 -206 77 -78 177 -152 121 -70 75 -100 535 -152 75 -78 101 -368 267 -168 217 -688 383 -222 247 -234 275 -224 251 -226 251 -224 241 -222 255 -246 251 -224 253 -224 251 -252 215 -246 261 -222 253 -224 253 -252 223 -242 245 -232 245 -252 225 -252 253 -224 253 -214 245 -236 247 -252 253 -224 251 -226 241 -246 231 -246 251 -224 251 -254 223 -242 221 -254 245 -252 225 -252 251 -226 251 -214 247 -236 247 -252 253 -224 251 -226 241 -246 229 -246 251 -226 251 -254 223 -252 213 -248 261 -224 251 -226 251 -252 225 -242 245 -230 245 -254 223 -252 253 -224 253 -214 245 -236 247 -252 251 -226 251 -224 243 -246 229 -248 251 -224 253 -252 223 -254 213 -248 261 -222 251 -226 251 -254 223 -242 245 -232 245 -252 223 -254 251 -224 243 -220 255 -244 251 -226 251 -226 251 -252 213 -248 261 -220 251 -226 251 -254 223 -242 245 -232 245 -252 223 -254 251 -224 243 -220 255 -246 249 -226 251 -226 251 -252 213 -248 235 -248 251 -226 251 -252 -RAW_Data: 225 -242 245 -230 247 -252 223 -252 253 -224 243 -220 255 -244 251 -226 251 -226 251 -252 213 -248 233 -248 251 -226 251 -254 223 -242 245 -232 245 -252 223 -254 251 -224 253 -214 247 -234 249 -252 251 -226 251 -224 241 -246 231 -246 251 -226 251 -226 251 -252 213 -248 261 -224 251 -226 251 -252 225 -242 245 -230 245 -252 225 -252 253 -224 253 -212 247 -236 247 -252 253 -224 251 -226 241 -246 231 -246 251 -224 253 -252 225 -252 213 -248 261 -222 253 -224 253 -252 223 -242 247 -230 245 -252 225 -252 251 -226 241 -222 253 -246 251 -224 253 -224 251 -252 213 -248 233 -250 251 -224 253 -252 225 -242 245 -230 245 -252 225 -252 251 -226 241 -222 253 -246 251 -224 253 -224 253 -252 213 -248 233 -250 251 -224 253 -252 223 -242 245 -232 245 -252 223 -254 251 -224 253 -214 247 -236 247 -252 253 -224 251 -226 241 -246 231 -246 251 -224 253 -252 223 -252 213 -248 261 -224 251 -252 223 -254 223 -242 245 -232 245 -252 225 -252 251 -226 241 -222 253 -246 251 -224 253 -224 251 -254 213 -246 261 -224 251 -226 251 -252 225 -242 245 -230 245 -252 223 -254 251 -224 243 -220 255 -244 251 -226 251 -226 251 -252 213 -248 261 -222 251 -226 251 -254 223 -242 245 -232 243 -252 225 -252 253 -224 241 -222 253 -246 251 -226 251 -224 253 -252 213 -248 233 -248 251 -254 223 -252 225 -242 245 -232 245 -252 223 -254 251 -224 241 -222 255 -244 251 -226 251 -226 251 -254 213 -246 235 -248 251 -226 251 -254 223 -242 245 -230 245 -252 225 -252 251 -226 241 -222 253 -246 251 -224 253 -224 251 -254 213 -248 233 -248 251 -226 251 -254 223 -242 245 -232 245 -252 223 -254 251 -226 241 -220 255 -246 249 -226 253 -224 251 -254 213 -246 235 -248 251 -226 251 -252 225 -242 245 -230 245 -252 225 -252 253 -224 241 -220 255 -246 249 -226 251 -226 251 -252 213 -248 261 -222 253 -224 253 -252 223 -242 247 -230 245 -252 225 -252 251 -226 251 -214 247 -234 249 -252 251 -226 251 -224 241 -248 229 -248 249 -226 253 -252 223 -252 213 -248 263 -222 251 -226 251 -254 223 -242 245 -230 245 -254 223 -252 253 -224 241 -222 255 -244 251 -226 251 -226 251 -252 213 -248 233 -250 251 -226 251 -252 225 -252 213 -248 263 -222 251 -226 251 -254 223 -242 245 -232 245 -252 225 -252 251 -226 241 -222 253 -246 485 -488 457 -504 481 -462 493 -480 227 -246 251 -244 251 -226 251 -224 253 -224 493 -474 247 -252 475 -486 243 -222 485 -492 -RAW_Data: 231 -234 247 -252 481 -462 493 -480 225 -248 251 -244 251 -224 479 -486 237 -246 251 -226 251 -224 253 -252 467 -474 481 -492 489 -458 245 -250 469 -494 481 -480 231 -238 247 -252 253 -224 253 -224 241 -246 465 -488 243 -240 245 -234 481 -488 487 -472 481 -492 229 -236 485 -474 485 -478 249 -250 251 -226 241 -246 231 -246 251 -224 479 -486 237 -248 485 -470 253 -232 245 -252 223 -254 473 -486 243 -224 251 -254 1439 -1448 249 -224 251 -226 251 -224 241 -246 233 -248 251 -226 251 -254 223 -242 245 -230 245 -252 225 -252 251 -226 241 -222 253 -246 249 -226 253 -224 497 -462 483 -490 485 -472 479 -480 259 -244 223 -254 251 -224 253 -224 241 -246 467 -488 243 -240 477 -484 247 -250 469 -494 247 -224 253 -224 499 -462 481 -488 233 -248 233 -248 251 -224 477 -486 239 -248 253 -224 253 -252 223 -254 467 -476 479 -490 491 -458 271 -224 469 -496 479 -480 233 -238 249 -254 251 -224 253 -224 241 -222 489 -482 269 -212 247 -234 483 -500 483 -480 481 -460 261 -244 485 -460 485 -478 247 -246 223 -248 261 -222 249 -222 247 -252 479 -488 243 -238 479 -482 225 -248 249 -242 251 -226 479 -486 237 -246 251 -226 1443 -1446 243 -252 225 -252 225 -252 253 -212 247 -234 247 -252 253 -224 251 -226 241 -246 231 -246 251 -226 251 -224 253 -252 213 -248 261 -222 251 -226 477 -484 503 -462 489 -490 479 -482 229 -238 247 -252 223 -254 251 -224 243 -220 489 -480 251 -246 467 -480 251 -248 465 -488 243 -240 247 -232 481 -488 487 -472 249 -252 223 -254 223 -242 475 -486 245 -252 223 -242 247 -234 247 -252 481 -460 493 -482 481 -490 249 -224 477 -482 475 -480 243 -240 247 -234 247 -252 251 -226 251 -224 469 -496 247 -254 223 -252 469 -490 483 -462 483 -478 247 -252 473 -486 479 -478 231 -246 261 -224 251 -254 223 -252 225 -242 475 -482 249 -222 505 -486 245 -224 241 -222 255 -246 483 -468 255 -232 245 -252 1445 -1446 243 -460 421 -100 233 -78 103 -126 73 -364 133 -274 163 -238 509 -132 51 -238 211 -812 77 -208 245 -276 261 -184 309 -1392 587 -182 209 -182 101 -122 121 -128 99 -300 175 -154 283 -210 51 -136 163 -506 655 -132 77 -76 157 -242 265 -214 243 -242 163 -574 605 -336 101 -102 331 -78 741 -52 255 -128 51 -178 127 -200 129 -462 179 -132 165 -108 53 -78 159 -728 157 -134 109 -162 129 -108 239 -344 199 -328 99 -102 209 -384 101 -154 229 -78 157 -52 103 -976 259 -102 123 -76 123 -102 -RAW_Data: 73 -200 79 -52 131 -212 55 -402 285 -212 315 -56 573 -110 81 -54 161 -214 53 -390 351 -106 53 -316 129 -230 131 -162 163 -136 55 -140 263 -54 137 -192 313 -184 211 -322 53 -108 139 -56 719 -104 323 -236 263 -138 355 -162 135 -266 155 -156 103 -76 251 -284 335 -102 123 -252 185 -190 237 -394 75 -78 79 -132 81 -328 109 -82 179 -530 163 -160 85 -56 375 -52 351 -416 79 -160 107 -492 53 -108 109 -280 53 -52 235 -216 303 -84 131 -160 79 -80 243 -54 215 -82 165 -82 77 -182 207 -330 107 -264 451 -402 131 -134 53 -464 103 -354 51 -188 163 -154 133 -266 105 -52 209 -430 51 -108 107 -186 131 -426 51 -108 55 -82 179 -164 135 -104 399 -52 105 -214 105 -312 135 -188 51 -242 107 -134 79 -314 77 -54 133 -54 105 -164 135 -318 81 -232 151 -180 127 -102 99 -102 453 -130 299 -126 99 -798 235 -206 149 -100 79 -108 955 -80 79 -210 107 -132 131 -196 291 -134 159 -80 377 -312 159 -242 107 -52 53 -156 51 -132 79 -54 133 -274 157 -54 105 -134 387 -104 129 -234 77 -254 361 -52 77 -104 101 -52 53 -54 561 -80 163 -54 109 -216 51 -498 535 -82 163 -210 51 -182 259 -102 75 -76 305 -102 253 -172 215 -268 77 -52 81 -186 133 -106 333 -162 111 -220 569 -102 215 -54 131 -196 433 -80 51 -158 129 -108 53 -188 261 -52 101 -100 227 -402 201 -182 77 -78 175 -126 75 -306 231 -100 149 -178 489 -228 221 -154 77 -220 81 -52 51 -308 233 -104 77 -156 73 -286 181 -132 133 -144 165 -160 109 -54 105 -236 153 -76 211 -372 133 -140 105 -104 77 -320 653 -54 159 -54 181 -162 133 -406 213 -80 79 -132 211 -154 233 -138 189 -84 165 -200 217 -298 107 -272 161 -110 135 -172 103 -102 291 -56 109 -56 317 -52 105 -54 587 -1018 53 -132 109 -56 187 -80 109 -160 81 -80 107 -188 53 -56 237 -158 79 -154 127 -76 51 -204 103 -106 83 -54 313 -52 187 -186 183 -82 189 -474 133 -82 189 -110 155 -136 55 -192 133 -80 183 -106 233 -52 79 -188 187 -158 77 -106 133 -242 111 -106 81 -108 53 -130 245 -290 131 -54 163 -356 287 -156 51 -80 155 -86 687 -104 53 -290 341 -108 217 -160 51 -188 215 -52 133 -210 161 -186 185 -244 51 -210 51 -184 187 -84 133 -108 101 -126 123 -52 77 -150 255 -132 79 -820 183 -108 263 -340 79 -110 137 -82 243 -80 81 -162 51 -132 131 -136 83 -78 181 -126 299 -80 571 -134 105 -80 -RAW_Data: 187 -216 109 -112 359 -316 79 -108 189 -82 133 -266 319 -544 311 -314 51 -162 165 -136 107 -162 193 -194 427 -104 269 -136 107 -80 343 -106 207 -266 53 -80 75 -178 99 -74 169 -506 51 -150 149 -620 207 -266 325 -106 183 -184 161 -106 141 -86 137 -134 239 -214 289 -104 51 -52 77 -106 129 -344 51 -372 75 -302 361 -214 393 -290 103 -106 135 -82 81 -82 185 -136 55 -194 81 -164 81 -78 101 -168 83 -186 81 -222 105 -52 105 -186 79 -418 129 -324 125 -128 75 -256 407 -414 131 -108 107 -80 135 -54 693 -52 369 -80 159 -162 53 -370 79 -162 55 -164 463 -236 77 -230 99 -178 153 -230 129 -80 161 -82 241 -322 79 -216 105 -216 81 -244 105 -326 289 -210 105 -82 299 -52 473 -496 159 -52 79 -108 249 -80 179 -132 107 -84 303 -370 239 -162 239 -126 149 -430 75 -52 123 -304 637 -238 109 -160 379 -190 647 -370 157 -294 235 -292 133 -108 135 -900 183 -56 241 -414 77 -210 161 -190 53 -184 185 -54 103 -394 131 -196 135 -546 151 -76 73 -100 201 -102 125 -316 259 -208 351 -160 81 -456 107 -232 129 -126 75 -228 101 -78 75 -230 431 -102 101 -172 201 -132 107 -108 303 -166 55 -458 203 -76 51 -232 131 -168 85 -198 137 -80 79 -84 81 -80 131 -194 585 -292 155 -722 221 -588 371 -132 101 -246 107 -270 81 -136 81 -262 289 -108 217 -218 77 -104 219 -342 259 -106 187 -78 133 -594 51 -132 267 -80 107 -54 53 -134 131 -192 243 -52 77 -102 155 -78 79 -104 79 -286 353 -192 53 -84 133 -184 75 -198 127 -132 123 -464 407 -130 103 -102 335 -202 103 -104 129 -176 289 -188 357 -754 255 -386 53 -138 255 -140 135 -426 53 -134 237 -52 187 -196 401 -54 157 -344 159 -192 55 -82 219 -202 215 -164 55 -166 81 -350 105 -158 101 -52 51 -284 129 -366 103 -392 53 -52 367 -312 133 -248 111 -272 211 -242 51 -158 165 -136 163 -54 133 -132 125 -374 229 -230 173 -304 103 -480 75 -78 175 -128 77 -362 127 -246 275 -76 313 -156 105 -158 247 -436 235 -132 71 -222 177 -236 345 -78 343 -78 341 -190 297 -188 77 -78 101 -76 99 -152 333 -154 101 -74 147 -122 75 -152 175 -452 453 -182 261 -284 149 -156 103 -170 109 -236 155 -110 295 -206 77 -132 81 -110 141 -1406 365 -214 79 -110 105 -484 87 -198 53 -106 185 -140 111 -322 77 -444 131 -78 239 -80 103 -182 131 -184 51 -106 107 -270 239 -134 213 -132 53 -316 513 -236 77 -80 -RAW_Data: 163 -664 131 -188 269 -110 135 -200 73 -126 95 -380 53 -128 195 -98 271 -158 147 -224 103 -132 125 -360 231 -336 229 -374 643 -180 247 -104 75 -434 79 -322 107 -138 107 -322 51 -776 157 -78 105 -184 51 -264 433 -82 53 -344 79 -82 161 -110 253 -106 77 -52 101 -78 127 -804 157 -148 73 -74 75 -256 301 -126 99 -76 235 -52 155 -460 77 -130 73 -222 283 -134 53 -110 55 -162 53 -106 263 -78 105 -214 133 -192 107 -208 133 -164 243 -346 105 -276 73 -52 77 -226 131 -408 189 -138 217 -508 77 -214 53 -78 235 -52 213 -372 219 -108 53 -210 207 -52 207 -184 99 -200 103 -54 129 -76 101 -104 101 -74 73 -406 181 -174 509 -300 143 -378 177 -254 101 -216 243 -616 239 -154 99 -312 335 -52 75 -180 127 -202 75 -108 189 -214 101 -384 267 -528 153 -260 367 -214 161 -108 183 -136 107 -130 77 -296 211 -132 189 -134 133 -54 107 -326 51 -266 103 -76 263 -242 313 -284 129 -132 185 -54 275 -138 239 -136 165 -316 129 -212 319 -214 55 -110 237 -312 77 -54 79 -210 227 -76 101 -102 125 -76 251 -104 187 -192 105 -162 79 -404 557 -486 159 -272 157 -84 141 -650 187 -130 205 -596 257 -102 135 -160 101 -270 355 -162 109 -196 187 -104 75 -52 159 -52 107 -266 129 -128 565 -52 133 -54 241 -160 187 -598 51 -184 797 -164 81 -132 161 -160 179 -54 111 -108 159 -164 53 -82 107 -158 161 -162 153 -458 329 -312 79 -218 77 -238 241 -270 307 -110 135 -314 131 -106 53 -354 157 -186 291 -260 563 -80 133 -80 77 -234 219 -84 215 -292 81 -82 135 -54 79 -270 55 -186 77 -78 215 -192 211 -220 109 -158 71 -104 51 -186 263 -230 99 -152 227 -52 75 -102 127 -104 157 -318 107 -112 111 -116 159 -82 105 -218 239 -160 305 -188 99 -52 279 -102 149 -148 259 -180 51 -52 131 -466 135 -460 183 -580 77 -130 51 -106 77 -80 135 -304 107 -160 709 -372 79 -164 53 -158 53 -184 233 -180 107 -466 187 -78 79 -134 291 -78 51 -52 101 -78 75 -78 77 -416 283 -278 131 -106 137 -108 311 -236 247 -252 251 -226 251 -224 243 -220 255 -244 251 -226 251 -226 251 -252 215 -246 235 -248 251 -224 253 -252 223 -244 245 -230 245 -252 225 -252 251 -226 241 -220 255 -246 249 -226 251 -226 251 -252 213 -248 261 -222 251 -254 223 -252 225 -242 245 -230 247 -252 223 -252 253 -224 243 -220 255 -244 251 -226 251 -226 251 -252 213 -248 235 -248 251 -226 251 -252 -RAW_Data: 225 -242 245 -230 245 -252 223 -254 251 -224 243 -220 255 -244 251 -226 251 -226 251 -254 213 -246 235 -248 251 -226 251 -252 225 -242 245 -230 245 -254 223 -252 253 -224 253 -212 247 -236 247 -252 253 -224 251 -226 241 -246 231 -246 251 -224 253 -252 223 -254 213 -246 263 -222 251 -254 223 -254 223 -242 245 -232 245 -252 225 -252 251 -226 241 -222 253 -246 251 -224 253 -224 253 -252 213 -246 235 -248 251 -226 251 -254 223 -242 245 -232 245 -252 223 -254 251 -224 253 -214 247 -236 247 -252 251 -226 251 -224 243 -246 229 -246 251 -226 251 -226 251 -252 213 -248 261 -222 253 -224 253 -252 223 -242 245 -232 245 -252 225 -252 251 -224 241 -222 253 -246 251 -226 251 -224 251 -254 213 -248 233 -250 251 -226 251 -254 223 -242 245 -232 245 -252 223 -254 251 -224 243 -220 255 -244 251 -226 251 -226 251 -252 213 -248 259 -222 253 -224 253 -252 223 -242 247 -230 245 -252 225 -252 251 -226 241 -220 255 -244 251 -226 251 -226 251 -252 215 -246 235 -248 253 -224 253 -252 223 -254 213 -248 261 -224 251 -224 253 -252 225 -242 245 -230 245 -252 225 -252 253 -224 241 -222 253 -246 251 -226 251 -224 251 -254 213 -248 233 -250 251 -226 251 -254 223 -242 245 -230 245 -252 223 -254 251 -226 241 -220 255 -246 251 -224 253 -224 251 -254 213 -248 233 -248 251 -226 251 -254 223 -242 245 -232 245 -252 223 -254 251 -224 243 -220 255 -244 251 -226 251 -226 251 -254 213 -246 235 -248 251 -226 251 -254 223 -252 215 -248 261 -222 253 -224 253 -252 223 -242 247 -230 245 -252 225 -252 253 -224 241 -222 253 -246 251 -226 251 -224 253 -252 213 -248 259 -222 251 -226 251 -254 223 -242 245 -232 245 -252 225 -252 251 -226 251 -214 247 -234 249 -252 251 -226 251 -224 241 -248 229 -248 249 -226 253 -252 223 -254 213 -246 261 -224 251 -254 223 -252 225 -242 245 -230 247 -252 223 -252 253 -224 241 -222 253 -246 251 -226 251 -224 253 -252 213 -248 259 -224 251 -226 251 -252 225 -242 245 -230 245 -252 225 -252 253 -224 251 -214 247 -236 247 -254 251 -224 253 -224 241 -246 231 -246 251 -226 251 -252 225 -252 213 -248 261 -222 251 -226 251 -254 223 -242 245 -230 247 -252 223 -254 251 -224 243 -220 255 -244 251 -226 251 -226 251 -254 213 -248 233 -248 251 -226 251 -252 225 -242 245 -230 245 -254 223 -252 253 -224 241 -222 255 -244 251 -226 251 -226 251 -252 213 -248 233 -248 251 -254 223 -254 223 -242 245 -232 -RAW_Data: 245 -252 223 -254 251 -226 241 -220 255 -244 251 -226 251 -226 251 -252 213 -248 261 -222 251 -254 223 -252 225 -242 245 -230 245 -254 223 -252 253 -224 241 -222 253 -246 251 -224 253 -224 251 -254 213 -248 233 -250 251 -224 253 -252 225 -242 243 -232 245 -252 225 -252 253 -224 241 -222 253 -246 251 -226 251 -224 253 -252 213 -248 233 -248 251 -226 477 -486 501 -456 487 -494 483 -466 255 -232 247 -252 223 -254 251 -226 251 -214 503 -458 243 -252 469 -496 247 -224 477 -486 239 -250 251 -226 477 -486 473 -480 253 -246 467 -488 241 -242 475 -484 247 -224 247 -264 221 -252 251 -226 471 -488 479 -476 485 -502 221 -252 473 -486 479 -490 231 -248 229 -248 249 -226 251 -254 223 -242 477 -482 247 -252 223 -242 475 -482 479 -486 481 -480 253 -232 481 -488 487 -472 247 -252 223 -254 223 -242 245 -232 247 -252 483 -460 493 -488 467 -488 479 -490 231 -248 231 -248 483 -466 487 -484 247 -250 1433 -1456 225 -246 251 -240 251 -224 253 -224 251 -226 241 -246 231 -248 251 -226 251 -254 223 -242 245 -230 245 -252 223 -254 251 -224 253 -214 247 -234 483 -498 483 -482 477 -486 471 -488 243 -250 213 -248 235 -248 251 -254 223 -254 467 -490 249 -224 477 -482 237 -248 485 -468 255 -232 245 -252 481 -462 493 -482 225 -248 483 -480 225 -248 485 -480 251 -222 255 -244 251 -226 251 -252 469 -464 483 -498 483 -482 247 -224 471 -488 481 -480 253 -234 245 -252 223 -252 253 -224 251 -214 505 -460 245 -252 251 -214 503 -458 505 -462 483 -498 229 -250 477 -480 485 -482 247 -224 251 -252 213 -248 233 -250 251 -226 477 -486 475 -488 489 -492 483 -462 231 -248 261 -224 483 -492 463 -484 249 -248 1445 -1430 255 -234 245 -252 223 -254 251 -224 253 -214 245 -236 247 -252 251 -226 251 -226 241 -246 231 -246 251 -224 253 -252 223 -254 213 -248 235 -248 485 -492 459 -484 479 -486 483 -500 227 -250 241 -252 223 -254 223 -252 225 -242 477 -484 247 -250 469 -494 247 -224 479 -488 237 -246 251 -226 479 -486 471 -480 251 -222 489 -480 253 -246 465 -480 243 -240 245 -236 247 -252 253 -224 473 -486 481 -478 485 -482 247 -224 503 -460 497 -484 243 -224 251 -254 225 -252 223 -242 247 -232 481 -474 255 -226 265 -222 485 -490 489 -456 505 -462 247 -252 477 -482 471 -482 243 -240 247 -232 247 -252 225 -252 251 -226 467 -496 481 -468 487 -482 497 -458 267 -224 251 -254 449 -484 503 -464 241 -240 1447 -1454 229 -804 209 -238 diff --git a/applications/debug/unit_tests/resources/unit_tests/subghz/scher_khan_magic_code.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/scher_khan_magic_code.sub deleted file mode 100644 index 19d6c8160..000000000 --- a/applications/debug/unit_tests/resources/unit_tests/subghz/scher_khan_magic_code.sub +++ /dev/null @@ -1,22 +0,0 @@ -Filetype: Flipper SubGhz RAW File -Version: 1 -Frequency: 433920000 -Preset: FuriHalSubGhzPresetOok650Async -Protocol: RAW -RAW_Data: 95 -240 191 -412 187 -152 95 -120 263 -220 373 -116 199 -88 239 -334 503 -142 167 -174 85 -172 143 -86 85 -96 119 -196 259 -96 167 -148 201 -96 481 -120 237 -264 143 -144 105 -790 257 -88 243 -144 143 -86 553 -216 103 -174 143 -142 119 -144 119 -224 307 -144 239 -120 127 -390 189 -168 119 -312 191 -142 215 -96 103 -86 307 -274 191 -104 143 -96 167 -120 357 -390 651 -218 197 -170 143 -164 85 -210 143 -116 143 -86 255 -160 95 -114 199 -88 545 -288 173 -114 115 -202 85 -316 145 -144 113 -562 105 -254 85 -144 287 -116 115 -202 87 -346 287 -244 103 -370 143 -230 143 -144 85 -88 113 -230 231 -984 119 -144 171 -144 201 -174 115 -288 113 -192 277 -114 345 -202 249 -316 83 -228 119 -146 151 -116 85 -202 85 -144 437 -272 115 -144 85 -86 173 -142 163 -260 205 -280 339 -88 229 -194 363 -144 585 -394 599 -144 85 -100 151 -574 171 -174 85 -114 239 -288 211 -410 115 -144 489 -116 115 -116 201 -336 95 -96 93 -120 95 -128 115 -116 257 -174 141 -292 113 -162 165 -192 287 -192 161 -192 1125 -202 85 -222 461 -144 113 -116 115 -114 201 -288 259 -288 401 -174 85 -106 119 -96 431 -130 85 -114 375 -494 95 -96 167 -288 281 -104 411 -214 335 -144 119 -534 85 -144 143 -144 229 -246 97 -82 85 -260 201 -304 403 -116 391 -172 229 -448 81 -82 95 -116 201 -86 521 -144 119 -336 119 -142 95 -144 119 -96 267 -170 283 -288 95 -190 167 -288 199 -116 247 -144 87 -144 85 -114 215 -260 115 -116 113 -338 103 -240 167 -96 119 -120 95 -96 405 -188 85 -116 191 -334 143 -164 85 -230 115 -154 119 -166 143 -288 195 -144 87 -86 343 -232 113 -202 115 -86 201 -278 201 -86 85 -86 303 -286 95 -120 95 -168 167 -118 129 -94 95 -432 151 -218 119 -186 235 -230 167 -632 143 -144 231 -156 153 -282 147 -96 143 -592 261 -120 191 -96 167 -576 333 -342 171 -462 173 -514 157 -432 87 -312 397 -378 287 -374 403 -230 117 -264 257 -170 189 -346 137 -528 117 -240 805 -454 539 -288 171 -86 173 -286 153 -288 115 -172 173 -158 399 -114 85 -116 201 -116 85 -216 215 -432 113 -100 113 -338 123 -146 289 -86 143 -114 343 -94 95 -96 311 -110 171 -86 143 -88 969 -312 119 -316 401 -134 255 -202 323 -86 87 -114 253 -228 95 -172 85 -170 165 -86 343 -192 119 -144 213 -112 191 -334 287 -96 359 -500 137 -120 261 -242 119 -118 283 -210 167 -178 287 -174 343 -268 -RAW_Data: 185 -96 119 -978 215 -120 213 -96 265 -172 261 -168 225 -462 307 -312 87 -172 115 -288 423 -84 87 -230 143 -404 109 -114 233 -216 165 -240 95 -288 95 -192 215 -238 335 -116 199 -170 135 -144 109 -408 285 -130 97 -98 115 -86 85 -86 87 -120 167 -144 119 -264 171 -316 231 -202 257 -274 115 -114 421 -86 85 -202 143 -144 201 -86 229 -86 143 -116 115 -86 115 -114 85 -202 143 -288 163 -186 483 -202 167 -212 373 -288 115 -86 171 -116 113 -230 231 -230 201 -172 171 -318 113 -390 101 -200 317 -404 287 -220 171 -232 199 -490 171 -144 173 -168 223 -202 173 -200 115 -172 119 -288 209 -220 85 -86 85 -480 423 -450 201 -364 411 -216 143 -120 219 -538 513 -330 199 -120 119 -96 127 -138 141 -140 117 -312 429 -182 259 -422 1027 -280 303 -210 131 -168 85 -86 201 -230 547 -174 113 -88 259 -202 109 -96 215 -144 291 -168 151 -316 85 -258 287 -260 279 -302 171 -284 189 -168 95 -96 309 -240 167 -384 165 -96 169 -226 95 -216 271 -122 195 -102 113 -116 339 -168 85 -192 583 -114 297 -406 167 -326 209 -212 119 -262 143 -86 87 -114 125 -172 115 -172 173 -576 219 -192 335 -120 85 -116 171 -202 711 -116 85 -172 373 -232 381 -144 95 -244 173 -210 119 -198 85 -86 143 -312 211 -96 115 -86 113 -528 103 -150 191 -144 119 -98 333 -172 215 -114 87 -86 529 -490 85 -356 239 -374 143 -260 457 -312 157 -394 131 -116 353 -172 229 -490 171 -144 189 -166 305 -144 85 -288 201 -356 147 -106 167 -740 143 -312 95 -242 137 -88 465 -126 239 -358 167 -120 1385 -130 385 -192 95 -120 817 -218 805 -140 171 -394 143 -86 371 -430 143 -216 187 -84 143 -316 173 -86 115 -202 85 -114 215 -96 167 -316 107 -368 313 -120 95 -382 197 -216 289 -388 119 -264 109 -86 113 -202 963 -172 111 -104 113 -346 115 -266 255 -88 229 -202 109 -288 357 -348 365 -226 381 -144 455 -144 901 -532 531 -108 103 -142 225 -144 143 -230 85 -144 141 -142 645 -82 167 -116 143 -172 403 -230 85 -144 87 -288 229 -144 115 -144 371 -82 107 -306 333 -116 113 -88 143 -86 229 -174 617 -96 677 -286 95 -240 95 -168 141 -216 95 -212 209 -120 95 -144 95 -240 165 -116 765 -230 229 -88 141 -192 97 -86 111 -114 231 -172 143 -144 365 -96 291 -144 129 -144 87 -168 141 -120 215 -144 143 -238 215 -192 95 -96 95 -144 403 -216 163 -102 155 -120 95 -120 263 -120 403 -374 431 -230 303 -134 791 -288 -RAW_Data: 201 -138 251 -262 95 -376 287 -230 143 -114 143 -144 259 -214 231 -238 167 -288 95 -166 119 -120 411 -144 143 -546 243 -260 143 -404 113 -450 137 -184 143 -230 375 -144 85 -230 129 -104 133 -112 171 -258 115 -316 259 -86 163 -96 95 -88 113 -350 167 -780 847 -174 143 -404 85 -314 109 -278 287 -86 101 -172 201 -258 115 -86 143 -144 115 -114 547 -86 423 -116 85 -144 507 -144 133 -518 85 -424 167 -246 143 -96 261 -192 109 -240 167 -240 117 -168 239 -192 85 -116 137 -264 143 -304 119 -96 191 -144 141 -264 95 -96 119 -144 95 -96 121 -478 229 -88 575 -230 85 -312 81 -102 103 -390 93 -96 119 -144 143 -238 215 -288 277 -96 115 -114 87 -288 113 -120 143 -114 261 -146 153 -116 335 -144 259 -136 85 -258 87 -144 85 -86 661 -86 161 -120 95 -110 191 -86 135 -408 103 -144 125 -192 119 -336 113 -86 173 -114 173 -216 335 -116 321 -186 559 -116 229 -316 115 -512 141 -168 191 -130 113 -120 143 -288 127 -174 215 -96 85 -318 1169 -174 85 -86 563 -146 315 -162 163 -96 339 -222 215 -230 229 -88 109 -218 493 -120 189 -264 253 -466 239 -240 157 -288 219 -268 309 -192 121 -156 241 -192 215 -144 95 -168 261 -86 397 -428 569 -88 411 -268 251 -168 167 -268 143 -288 453 -144 163 -86 115 -144 113 -296 81 -224 163 -458 171 -310 161 -88 85 -316 461 -508 201 -162 229 -114 145 -144 143 -86 143 -114 259 -144 345 -346 85 -124 143 -302 83 -116 113 -96 261 -84 297 -116 201 -240 143 -120 861 -144 117 -158 167 -96 215 -454 273 -304 239 -96 95 -204 189 -346 345 -286 545 -88 339 -104 171 -284 95 -360 239 -144 289 -96 95 -120 225 -106 197 -144 219 -208 145 -144 187 -282 95 -408 95 -338 187 -250 229 -86 115 -402 87 -86 143 -202 283 -98 329 -134 167 -88 229 -172 221 -138 169 -202 171 -196 111 -108 85 -144 479 -100 623 -212 133 -116 113 -144 403 -88 257 -462 287 -144 373 -210 239 -144 115 -172 289 -168 143 -98 119 -96 95 -96 357 -96 119 -216 143 -144 311 -192 95 -166 175 -416 351 -100 145 -94 119 -360 427 -94 95 -144 263 -144 115 -366 97 -98 95 -190 95 -264 541 -288 131 -140 85 -202 409 -226 229 -518 143 -202 363 -260 85 -86 269 -142 95 -120 215 -168 189 -208 239 -96 285 -456 129 -144 517 -114 589 -344 115 -288 235 -98 105 -282 109 -278 85 -312 171 -116 287 -316 87 -172 335 -430 119 -274 143 -164 229 -216 167 -232 343 -260 -RAW_Data: 143 -86 565 -144 87 -460 115 -508 363 -86 143 -276 671 -144 115 -86 515 -116 199 -236 185 -140 143 -82 113 -116 85 -116 85 -408 95 -284 199 -88 315 -116 143 -114 717 -202 85 -86 173 -86 201 -144 333 -200 115 -86 85 -174 401 -174 263 -244 229 -86 143 -434 229 -202 231 -164 143 -86 165 -182 167 -172 85 -346 771 -252 81 -106 217 -96 119 -96 287 -140 85 -86 143 -374 143 -116 85 -114 83 -118 119 -164 201 -86 153 -166 359 -116 283 -86 187 -120 459 -280 201 -144 229 -258 143 -408 427 -144 373 -294 197 -120 287 -96 119 -264 143 -120 119 -528 95 -168 119 -192 117 -558 97 -148 143 -120 185 -188 167 -264 95 -176 215 -254 201 -258 263 -158 215 -168 119 -312 873 -388 95 -192 359 -278 341 -96 171 -116 143 -432 173 -316 403 -84 85 -144 113 -174 287 -346 243 -216 95 -394 161 -144 317 -200 199 -140 95 -86 143 -278 139 -86 143 -144 201 -114 191 -264 119 -238 163 -114 143 -766 143 -144 167 -604 349 -390 459 -86 201 -172 633 -114 549 -432 339 -114 201 -174 325 -220 287 -116 123 -264 137 -86 173 -336 171 -422 133 -144 661 -86 163 -96 93 -96 215 -168 105 -114 259 -238 115 -86 315 -86 229 -298 167 -168 319 -432 189 -336 167 -120 123 -250 95 -144 167 -346 97 -96 429 -86 517 -120 95 -480 85 -86 307 -84 109 -112 121 -136 227 -112 115 -114 85 -202 201 -230 201 -88 143 -144 229 -96 347 -172 143 -656 201 -508 199 -174 139 -192 171 -172 257 -86 223 -216 143 -144 215 -120 85 -264 185 -212 271 -112 85 -374 85 -116 113 -88 113 -174 431 -202 315 -264 87 -116 373 -336 201 -172 173 -374 201 -172 115 -114 115 -86 115 -86 489 -280 119 -86 115 -144 137 -144 253 -480 1225 -1598 631 -828 709 -782 689 -792 1063 -1152 1105 -1066 1141 -1076 761 -734 1125 -1090 761 -696 765 -698 817 -672 1183 -1012 1197 -1022 819 -686 775 -710 775 -680 835 -646 839 -646 1181 -1018 801 -710 1139 -1078 1151 -1066 813 -646 843 -644 843 -622 841 -650 1187 -1014 1205 -1018 825 -656 829 -652 1197 -1024 1197 -1016 1209 -990 1167 -1074 789 -676 1179 -1032 831 -644 839 -644 843 -650 813 -678 795 -684 769 -712 775 -708 777 -728 783 -676 817 -646 1205 -1006 1219 -998 845 -632 1189 -1044 1177 -980 1527 -1456 1483 -1440 1537 -1388 839 -672 817 -648 843 -676 1127 -1088 1177 -1022 1199 -1020 817 -648 1213 -1010 831 -624 833 -648 839 -646 1213 -1018 1191 -1022 815 -678 783 -710 779 -710 769 -684 773 -734 1115 -1078 785 -710 1147 -1068 -RAW_Data: 1183 -992 855 -630 827 -664 839 -646 815 -644 1209 -1014 1191 -1050 765 -708 771 -738 1113 -1080 1181 -1006 1199 -1020 1185 -1042 815 -646 1181 -1032 827 -668 811 -670 815 -648 839 -676 769 -714 779 -710 773 -712 775 -708 777 -676 835 -644 1213 -1018 1143 -1078 763 -702 1177 -1008 1199 -994 1575 -1376 1525 -1428 1503 -1438 779 -718 817 -646 843 -650 1209 -1012 1179 -1024 1201 -1016 843 -644 1181 -1032 831 -622 831 -668 839 -644 1181 -1034 1197 -1024 811 -684 781 -712 771 -712 775 -680 775 -706 1177 -1024 807 -710 1137 -1076 1159 -1014 831 -652 835 -646 841 -646 839 -644 1183 -1040 1193 -996 837 -656 833 -686 1143 -1074 1161 -1016 1195 -1026 1185 -1012 831 -648 1207 -996 831 -684 771 -710 775 -702 809 -676 817 -646 817 -672 817 -672 817 -674 767 -734 771 -710 1137 -1076 1131 -1066 803 -642 1209 -1020 1197 -1018 1521 -1392 1549 -1416 1519 -1392 815 -670 841 -678 761 -736 1119 -1092 1155 -1018 1217 -1022 789 -702 1183 -1016 815 -648 815 -674 819 -648 1211 -1012 1199 -1022 833 -684 749 -712 769 -736 751 -678 829 -668 1179 -1016 797 -710 1139 -1078 1133 -1090 817 -644 819 -674 815 -676 789 -676 1153 -1064 1179 -1020 801 -712 773 -708 1141 -1076 1133 -1068 1187 -992 1197 -1046 793 -648 1209 -1012 829 -668 815 -674 819 -648 841 -674 761 -706 761 -732 767 -712 769 -712 777 -678 833 -648 1205 -1016 1161 -1074 817 -624 1207 -1006 1197 -996 1575 -1358 1573 -1386 1547 -1380 835 -686 775 -710 773 -704 1203 -996 1195 -1042 1187 -1018 831 -656 1195 -1026 811 -654 765 -736 771 -712 1139 -1078 1153 -1034 835 -646 817 -670 817 -650 841 -676 761 -704 1149 -1062 809 -646 1211 -1016 1191 -1024 839 -678 771 -710 775 -686 779 -712 1137 -1080 1129 -1040 835 -646 841 -646 1211 -1016 1193 -1022 1179 -1014 1197 -1022 835 -658 1143 -1068 817 -648 843 -674 765 -712 777 -712 769 -710 773 -704 781 -674 839 -648 845 -646 815 -674 1179 -1034 1201 -994 793 -714 1141 -1074 1159 -988 1557 -1404 1559 -1386 1509 -1438 809 -668 843 -674 813 -676 1135 -1070 1159 -1020 1169 -1072 817 -648 1207 -1012 839 -622 841 -646 843 -646 1179 -1034 1197 -1024 821 -686 749 -714 775 -710 775 -702 779 -694 1181 -1018 801 -708 1139 -1076 1127 -1088 811 -646 845 -646 841 -624 843 -650 1181 -1036 1203 -994 835 -658 829 -656 1191 -1050 1177 -1012 1179 -1000 1203 -1016 841 -646 1211 -1018 775 -710 777 -730 759 -702 815 -644 843 -646 817 -674 815 -678 785 -712 753 -734 773 -712 1115 -1076 1155 -1038 833 -648 1203 -994 1211 -1018 1519 -1388 1573 -1362 2045 -2332 103 -86 691 -116 229 -144 239 -120 135 -216 93 -202 315 -202 -RAW_Data: 231 -432 229 -114 403 -116 569 -86 575 -404 133 -120 239 -96 95 -96 93 -240 95 -144 95 -96 95 -168 141 -250 431 -174 113 -116 401 -116 173 -144 143 -172 85 -230 115 -260 137 -96 129 -86 605 -172 257 -168 229 -314 113 -88 257 -466 197 -96 81 -330 139 -86 85 -260 277 -200 87 -202 229 -88 219 -168 109 -86 119 -96 143 -216 143 -364 523 -118 95 -120 225 -330 83 -170 115 -86 81 -302 125 -256 95 -144 117 -96 95 -96 119 -168 167 -386 173 -132 515 -232 277 -144 229 -376 229 -202 455 -262 175 -88 171 -174 85 -86 85 -508 143 -174 315 -130 105 -202 115 -114 173 -432 111 -144 221 -162 273 -118 143 -380 257 -356 315 -236 119 -124 325 -214 115 -530 193 -168 105 -86 109 -144 119 -352 93 -96 119 -216 387 -224 197 -120 463 -144 93 -1134 85 -86 259 -86 201 -192 173 -198 185 -144 307 -200 85 -116 115 -192 95 -104 143 -202 229 -120 285 -120 239 -144 143 -392 519 -296 95 -144 229 -202 85 -202 85 -116 95 -120 101 -200 119 -96 95 -96 95 -172 119 -142 143 -216 81 -316 119 -144 269 -286 167 -130 231 -324 221 -96 167 -240 119 -102 113 -116 143 -192 191 -288 143 -144 309 -114 187 -378 231 -172 171 -458 413 -430 201 -120 469 -94 143 -504 261 -96 95 -144 237 -120 455 -334 163 -116 191 -280 169 -288 99 -492 85 -458 141 -260 171 -244 713 -168 359 -96 195 -154 733 -168 119 -364 143 -88 171 -86 85 -116 339 -86 173 -334 359 -144 95 -540 95 -120 185 -144 317 -114 87 -86 113 -254 373 -86 345 -288 85 -96 151 -122 429 -202 113 -342 247 -202 139 -86 229 -172 143 -88 87 -296 755 -220 447 -330 259 -330 241 -118 95 -340 245 -194 239 -112 201 -200 367 -1020 431 -408 279 -120 95 -96 95 -166 95 -216 281 -116 549 -140 257 -166 157 -192 263 -186 95 -286 119 -170 287 -230 173 -258 343 -366 171 -144 143 -116 85 -86 115 -86 243 -422 319 -120 243 -86 115 -172 143 -116 259 -86 201 -202 257 -664 763 -356 289 -114 85 -86 113 -486 271 -144 229 -116 115 -122 423 -314 969 -144 171 -116 201 -230 101 -202 143 -200 317 -86 85 -116 85 -462 181 -172 115 -202 309 -114 287 -316 139 -430 157 -192 191 -84 137 -168 113 -116 259 -114 373 -86 201 -116 199 -88 85 -172 173 -86 169 -240 119 -174 85 -286 137 -200 143 -172 259 -244 147 -144 115 -116 201 -140 423 -172 85 -144 87 -200 87 -202 85 -86 345 -174 143 -202 315 -404 229 -144 141 -212 -RAW_Data: 119 -114 231 -114 201 -318 431 -404 201 -82 167 -88 85 -114 81 -144 85 -202 85 -134 109 -144 461 -114 189 -354 171 -226 311 -152 115 -178 117 -360 239 -240 143 -286 143 -288 119 -268 315 -82 163 -196 173 -288 173 -192 215 -118 489 -88 143 -230 477 -110 459 -172 115 -172 403 -282 113 -116 143 -288 143 -172 139 -144 95 -214 167 -484 191 -444 95 -96 95 -202 117 -168 167 -120 325 -172 239 -202 229 -144 85 -404 115 -86 85 -528 143 -166 83 -172 403 -144 115 -144 507 -258 403 -156 171 -192 95 -120 293 -166 115 -86 547 -230 143 -192 315 -340 129 -84 229 -86 221 -202 143 -86 215 -178 85 -288 143 -164 141 -96 95 -144 287 -120 189 -216 143 -144 533 -192 85 -260 85 -86 115 -244 129 -134 229 -86 287 -174 171 -346 373 -86 229 -260 469 -100 83 -84 143 -118 95 -100 143 -116 431 -124 115 -114 345 -114 81 -314 199 -144 173 -192 95 -114 85 -88 171 -278 239 -288 171 -86 287 -202 201 -114 219 -336 199 -382 145 -144 121 -288 167 -240 299 -188 161 -96 117 -96 239 -120 213 -96 119 -336 127 -88 171 -390 163 -202 201 -216 119 -144 95 -144 157 -86 655 -206 699 -410 111 -126 135 -88 85 -172 115 -576 85 -116 85 -518 143 -86 87 -266 149 -120 129 -168 215 -110 167 -96 119 -168 95 -118 269 -306 201 -202 513 -96 99 -346 229 -288 115 -216 147 -172 173 -230 211 -124 87 -364 85 -172 259 -230 87 -114 143 -140 237 -88 85 -120 215 -238 95 -718 129 -214 167 -168 95 -262 665 -204 215 -418 97 -142 143 -288 95 -144 191 -168 301 -86 115 -202 113 -144 257 -116 173 -288 285 -198 85 -374 539 -244 119 -432 259 -400 175 -302 87 -402 259 -134 171 -88 113 -144 479 -202 85 -260 335 -266 131 -144 147 -144 143 -230 287 -144 231 -518 113 -144 143 -174 167 -172 201 -86 201 -230 171 -194 135 -86 345 -220 259 -144 85 -316 135 -406 191 -262 119 -96 113 -116 143 -144 143 -86 229 -260 115 -142 223 -318 85 -172 201 -86 373 -88 287 -490 105 -144 573 -116 695 -86 113 -82 209 -190 231 -172 605 -86 85 -646 143 -168 209 -168 153 -86 205 -144 143 -238 701 -262 163 -186 191 -96 197 -432 87 -114 341 -202 227 -120 335 -118 95 -240 191 -118 147 -144 87 -144 143 -172 115 -148 119 -130 345 -172 115 -358 493 -250 85 -172 167 -144 81 -548 143 -96 309 -282 159 -130 119 -96 95 -146 311 -86 191 -144 189 -120 155 -84 103 -96 165 -384 287 -120 527 -454 -RAW_Data: 115 -138 349 -212 143 -116 143 -748 143 -148 95 -168 535 -164 403 -316 201 -144 85 -86 105 -120 95 -144 453 -106 167 -144 213 -192 365 -110 143 -96 119 -120 191 -88 229 -114 173 -144 95 -120 107 -462 173 -200 335 -266 377 -118 167 -568 85 -144 85 -318 247 -174 223 -288 123 -128 143 -336 399 -220 263 -192 161 -144 85 -116 257 -260 229 -174 143 -230 115 -172 115 -258 285 -172 143 -142 153 -432 143 -142 145 -96 267 -202 143 -120 95 -142 167 -116 143 -172 287 -116 171 -116 115 -230 315 -86 423 -360 95 -352 253 -96 407 -96 143 -478 311 -168 167 -164 85 -202 85 -202 85 -114 459 -202 421 -230 85 -174 85 -116 85 -86 85 -374 311 -302 171 -116 201 -172 575 -190 373 -116 403 -432 143 -202 115 -86 113 -290 167 -84 243 -172 345 -88 201 -200 113 -312 99 -112 155 -294 171 -430 239 -220 85 -336 95 -96 117 -144 215 -120 95 -144 287 -310 311 -374 85 -174 171 -86 133 -116 153 -102 143 -144 215 -250 85 -512 201 -116 267 -120 279 -356 213 -120 191 -110 335 -144 95 -216 191 -142 95 -216 119 -190 191 -96 95 -240 191 -164 333 -170 267 -120 95 -192 165 -158 229 -202 85 -144 259 -174 191 -116 113 -86 113 -258 173 -144 113 -174 257 -88 417 -110 169 -144 87 -114 173 -114 221 -94 105 -288 85 -88 85 -144 259 -214 149 -258 115 -86 85 -86 403 -192 95 -306 231 -144 113 -86 115 -200 115 -260 171 -236 95 -240 113 -312 197 -166 191 -168 95 -96 165 -96 167 -120 287 -138 339 -216 117 -98 105 -110 597 -144 359 -186 283 -96 261 -312 127 -140 113 -318 171 -174 143 -318 143 -200 345 -576 143 -116 143 -144 229 -316 143 -346 229 -786 85 -316 229 -244 339 -96 603 -304 173 -432 543 -84 111 -116 113 -466 103 -150 141 -88 381 -104 273 -98 215 -318 143 -100 87 -114 85 -174 201 -86 345 -144 521 -172 113 -86 85 -164 199 -174 85 -202 575 -114 87 -144 257 -146 199 -246 237 -274 329 -184 147 -96 311 -130 195 -312 93 -240 163 -140 141 -168 119 -168 455 -144 259 -202 85 -288 143 -174 113 -260 171 -174 633 -440 243 -250 391 -88 287 -144 143 -144 191 -86 239 -142 263 -246 105 -120 143 -142 263 -96 215 -168 85 -260 87 -480 277 -86 143 -144 403 -114 85 -462 767 -200 85 -174 315 -94 147 -408 85 -260 171 -112 143 -114 903 -116 201 -116 115 -86 173 -344 87 -114 115 -288 143 -288 85 -86 365 -230 143 -316 201 -86 569 -202 171 -202 143 -442 -RAW_Data: 375 -172 211 -96 85 -264 429 -168 119 -116 163 -148 239 -168 95 -192 215 -230 95 -216 119 -144 167 -364 115 -316 115 -346 85 -116 229 -288 103 -480 305 -116 143 -86 85 -304 261 -168 167 -96 141 -144 95 -144 455 -106 113 -144 87 -86 229 -202 143 -316 143 -232 199 -174 233 -216 547 -278 143 -116 345 -288 369 -290 153 -316 305 -230 143 -116 545 -230 287 -168 237 -120 95 -370 201 -288 143 -258 173 -138 361 -82 345 -288 197 -168 165 -240 143 -186 263 -216 195 -202 171 -144 465 -194 501 -192 159 -172 143 -144 85 -192 253 -96 219 -300 205 -86 143 -86 311 -120 269 -634 185 -116 113 -456 97 -96 85 -174 85 -288 115 -144 173 -114 245 -144 119 -120 119 -96 93 -138 199 -144 173 -88 315 -202 157 -120 143 -96 167 -120 271 -268 287 -86 231 -144 143 -144 113 -346 259 -104 441 -204 249 -272 231 -114 345 -116 85 -86 85 -142 127 -100 169 -156 119 -96 167 -238 141 -86 143 -230 115 -114 115 -202 137 -168 143 -312 167 -110 193 -338 281 -230 721 -124 95 -120 309 -110 143 -144 563 -460 171 -88 143 -490 201 -144 85 -232 171 -144 201 -144 171 -144 95 -124 109 -572 633 -316 215 -264 161 -236 215 -202 115 -86 229 -260 257 -144 173 -172 259 -86 171 -264 129 -202 503 -350 161 -112 195 -144 401 -116 201 -230 287 -144 191 -96 167 -284 161 -164 119 -224 143 -376 209 -82 85 -144 201 -116 403 -114 231 -238 107 -174 85 -86 387 -200 173 -86 85 -116 87 -200 201 -174 287 -114 623 -86 143 -260 567 -108 113 -246 99 -396 115 -168 137 -396 85 -116 171 -86 87 -114 231 -144 235 -196 85 -144 305 -126 95 -218 417 -330 133 -116 85 -346 371 -134 345 -114 173 -372 111 -144 345 -402 115 -144 85 -86 87 -144 517 -86 413 -86 403 -120 431 -214 119 -264 191 -374 195 -86 287 -86 143 -608 143 -120 95 -216 263 -96 167 -120 113 -336 157 -192 285 -136 287 -200 87 -292 119 -216 109 -168 253 -118 167 -96 309 -96 191 -264 117 -170 119 -96 95 -406 167 -96 95 -120 167 -188 185 -96 417 -120 759 -144 85 -144 115 -86 173 -202 411 -188 263 -306 259 -288 229 -116 113 -88 171 -116 201 -114 365 -220 119 -398 181 -124 143 -202 85 -288 143 -288 229 -86 87 -114 229 -86 287 -88 143 -114 115 -258 287 -260 143 -86 335 -86 267 -240 119 -144 95 -238 119 -96 119 -246 405 -144 105 -144 147 -222 117 -110 129 -202 171 -86 229 -174 85 -96 109 -108 81 -86 95 -216 -RAW_Data: 247 -86 113 -144 459 -140 115 -86 143 -144 229 -652 273 -96 81 -114 115 -172 87 -594 115 -230 85 -462 85 -86 85 -86 287 -240 263 -96 85 -458 363 -480 95 -192 119 -120 167 -288 105 -288 201 -172 201 -172 345 -144 115 -312 255 -144 167 -112 155 -96 167 -134 173 -114 201 -86 105 -114 347 -86 201 -144 173 -258 143 -260 215 -234 173 -114 229 -174 117 -168 335 -114 231 -114 191 -216 589 -120 141 -96 95 -168 335 -150 201 -230 259 -268 125 -100 287 -114 85 -174 201 -288 161 -166 125 -144 345 -116 575 -336 237 -120 421 -96 95 -96 119 -96 543 -258 115 -86 85 -116 85 -202 257 -202 409 -84 169 -114 115 -374 173 -374 85 -144 215 -168 195 -116 345 -230 173 -114 85 -398 81 -86 143 -144 345 -114 115 -86 173 -222 93 -116 113 -86 375 -114 153 -326 401 -116 87 -288 143 -460 143 -168 95 -168 253 -216 469 -96 167 -96 265 -244 111 -114 1439 -114 115 -140 119 -134 201 -144 199 -346 229 -202 489 -288 459 -222 81 -172 229 -288 335 -198 201 -200 143 -140 119 -134 383 -216 579 -86 85 -288 167 -116 143 -312 287 -192 113 -174 403 -460 287 -308 545 -284 333 -114 119 -190 145 -114 115 -96 153 -220 539 -192 829 -162 201 -216 143 -258 143 -116 171 -86 115 -86 115 -638 213 -120 431 -192 287 -144 239 -94 167 -192 95 -120 417 -162 95 -96 119 -142 167 -120 357 -168 431 -214 81 -516 197 -114 361 -86 257 -136 141 -288 87 -86 143 -288 143 -86 115 -172 143 -174 113 -174 85 -144 171 -144 143 -144 85 -116 257 -116 219 -176 949 -342 107 -140 115 -144 359 -142 95 -120 119 -240 95 -96 167 -96 95 -164 185 -172 197 -112 101 -116 171 -144 229 -202 85 -202 115 -114 263 -168 143 -122 213 -216 95 -96 381 -168 319 -202 171 -230 271 -278 259 -278 95 -220 489 -144 259 -132 315 -202 113 -86 143 -144 287 -174 393 -116 173 -346 143 -262 129 -142 119 -86 115 -138 399 -230 257 -422 315 -306 147 -96 285 -192 455 -130 263 -144 113 -144 461 -278 369 -120 97 -136 81 -144 113 -232 85 -258 317 -144 633 -86 173 -316 119 -192 163 -96 115 -86 173 -518 85 -174 285 -108 107 -488 201 -264 93 -232 85 -240 215 -124 215 -344 169 -94 143 -120 119 -120 179 -140 255 -146 119 -280 141 -316 143 -418 147 -442 127 -174 201 -172 115 -172 85 -346 115 -144 85 -144 259 -172 201 -316 87 -86 127 -96 263 -192 173 -114 367 -120 133 -552 313 -144 143 -96 85 -260 109 -614 -RAW_Data: 333 -140 141 -114 287 -394 257 -88 145 -314 113 -86 113 -178 367 -198 199 -136 229 -662 489 -174 181 -134 171 -82 201 -288 367 -196 85 -88 171 -172 259 -116 85 -144 505 -260 85 -318 489 -114 143 -116 143 -172 115 -116 401 -278 167 -96 335 -120 143 -168 249 -184 95 -86 229 -144 187 -114 87 -86 171 -398 461 -326 95 -96 287 -112 181 -124 115 -178 95 -106 85 -192 109 -120 311 -470 95 -190 825 -114 317 -86 113 -146 113 -174 199 -88 85 -192 261 -332 85 -86 115 -116 661 -86 115 -114 287 -144 259 -202 143 -174 113 -322 297 -202 673 -106 111 -202 171 -232 305 -518 173 -346 113 -404 229 -86 253 -226 113 -144 487 -106 249 -302 195 -120 95 -120 311 -216 209 -192 95 -96 171 -96 95 -168 215 -214 167 -140 311 -140 83 -82 191 -336 95 -216 167 -354 107 -234 315 -88 85 -172 113 -86 315 -236 115 -172 201 -316 115 -374 141 -82 185 -190 325 -274 115 -86 143 -164 191 -86 201 -114 215 -170 95 -264 143 -96 119 -196 229 -82 289 -234 143 -264 201 -86 115 -346 229 -172 143 -202 143 -86 345 -86 173 -138 95 -102 575 -144 143 -230 221 -158 251 -168 103 -96 133 -172 173 -336 143 -188 309 -86 143 -116 85 -144 85 -306 201 -116 215 -286 283 -396 305 -148 317 -216 115 -490 115 -186 111 -144 201 -86 143 -192 285 -128 137 -86 85 -116 173 -216 119 -118 215 -96 95 -216 107 -82 173 -258 115 -168 263 -182 459 -288 143 -86 115 -490 143 -230 115 -144 229 -764 93 -112 81 -118 249 -144 229 -174 201 -374 201 -230 171 -88 223 -304 115 -200 143 -86 87 -174 85 -116 169 -172 429 -168 165 -216 603 -188 119 -120 269 -86 249 -120 141 -216 229 -174 85 -202 251 -186 87 -114 121 -254 649 -144 399 -86 201 -104 169 -162 103 -122 165 -168 119 -120 213 -84 143 -86 143 -168 173 -258 85 -232 315 -86 229 -116 95 -288 217 -124 335 -144 191 -120 333 -120 191 -216 143 -574 375 -86 311 -110 143 -202 287 -86 113 -174 345 -96 511 -88 109 -96 143 -638 133 -120 167 -360 95 -96 95 -144 143 -116 403 -480 341 -88 85 -114 115 -230 111 -226 115 -86 171 -404 259 -144 215 -288 405 -240 105 -402 255 -572 115 -168 113 -216 115 -144 143 -116 143 -374 85 -116 113 -116 287 -162 87 -86 219 -240 113 -116 863 -86 305 -126 113 -202 143 -378 143 -376 391 -88 229 -144 171 -200 259 -86 87 -144 109 -140 85 -116 327 -140 363 -114 143 -244 85 -116 335 -96 309 -352 -RAW_Data: 95 -168 219 -96 95 -168 95 -312 333 -144 117 -290 119 -94 373 -240 215 -96 229 -338 135 -202 257 -490 201 -116 85 -202 257 -144 113 -346 85 -86 289 -230 143 -144 109 -168 167 -96 189 -144 239 -114 143 -144 199 -116 85 -202 85 -174 165 -88 113 -112 315 -116 229 -164 119 -110 113 -116 115 -144 85 -202 113 -116 115 -200 115 -86 231 -114 85 -86 287 -168 93 -168 85 -88 257 -144 201 -230 715 -86 115 -144 373 -202 85 -116 85 -194 217 -144 201 -202 143 -172 143 -86 163 -202 115 -402 187 -244 251 -152 191 -336 117 -216 95 -144 253 -114 201 -456 95 -646 85 -288 85 -84 443 -576 115 -116 143 -432 115 -346 257 -334 621 -96 95 -264 171 -198 147 -452 229 -144 215 -288 93 -96 287 -96 165 -96 287 -138 777 -202 363 -190 191 -240 81 -114 119 -118 283 -138 95 -166 229 -194 119 -198 189 -192 167 -168 215 -94 119 -124 81 -196 351 -286 183 -140 969 -346 171 -586 87 -172 201 -164 267 -130 113 -144 191 -98 191 -96 243 -202 201 -174 199 -202 713 -454 95 -144 107 -144 451 -110 201 -174 143 -116 143 -144 285 -84 83 -328 117 -424 119 -144 95 -214 135 -402 115 -114 115 -174 257 -406 215 -336 193 -288 113 -116 229 -86 345 -260 113 -232 101 -264 167 -94 95 -216 401 -202 373 -114 173 -232 279 -690 259 -172 143 -404 229 -220 115 -114 173 -230 171 -318 309 -156 113 -170 223 -172 287 -174 315 -116 229 -332 111 -116 85 -258 431 -404 201 -86 171 -106 115 -96 369 -124 239 -206 115 -230 389 -200 115 -86 565 -488 83 -82 585 -172 459 -198 87 -86 85 -116 143 -202 371 -96 287 -392 221 -174 85 -230 461 -474 93 -120 95 -274 171 -144 339 -226 143 -184 81 -230 141 -216 143 -216 117 -120 167 -216 167 -96 265 -108 165 -86 315 -260 229 -172 87 -312 587 -150 341 -200 187 -432 171 -84 85 -202 85 -116 85 -116 431 -114 201 -84 169 -86 85 -114 313 -346 85 -86 85 -142 159 -646 143 -88 119 -120 521 -134 173 -128 315 -462 99 -362 227 -144 167 -120 165 -246 215 -86 825 -168 443 -536 835 -316 85 -174 113 -144 85 -144 173 -458 143 -288 81 -170 143 -268 215 -192 285 -360 113 -258 225 -168 163 -334 113 -116 257 -296 287 -312 277 -116 603 -82 255 -96 95 -336 301 -82 95 -552 141 -332 281 -110 201 -172 145 -200 115 -144 95 -344 201 -116 171 -96 119 -120 143 -144 421 -96 199 -394 107 -110 115 -114 145 -316 315 -288 115 -200 87 -114 115 -288 -RAW_Data: 85 -374 259 -260 113 -174 287 -144 507 -202 229 -144 221 -142 115 -124 143 -216 95 -96 117 -216 143 -144 85 -144 143 -144 201 -144 85 -284 469 -190 149 -86 143 -316 283 -290 95 -216 119 -180 167 -200 375 -86 111 -192 143 -144 213 -404 85 -144 719 -202 85 -434 143 -144 143 -172 287 -264 111 -114 315 -96 115 -576 85 -230 85 -144 143 -174 281 -198 201 -86 201 -144 575 -116 85 -174 143 -164 315 -168 171 -268 85 -536 111 -172 153 -462 239 -158 333 -174 361 -258 343 -96 453 -240 119 -256 113 -88 171 -172 259 -230 173 -110 113 -202 113 -88 113 -232 315 -100 165 -422 99 -316 311 -262 191 -120 555 -280 85 -174 431 -86 259 -210 119 -168 885 -462 433 -106 107 -116 113 -644 127 -278 115 -86 87 -226 159 -346 115 -144 85 -144 85 -768 541 -168 113 -86 87 -374 113 -144 747 -230 187 -268 521 -346 311 -1194 383 -478 313 -110 229 -202 171 -144 287 -722 285 -138 225 -188 133 -346 85 -174 199 -374 229 -112 135 -194 95 -216 143 -120 377 -86 245 -120 93 -96 95 -178 217 -86 277 -312 517 -530 505 -192 259 -106 119 -94 143 -336 293 -348 219 -316 87 -258 85 -174 143 -86 85 -116 171 -398 167 -88 85 -116 85 -202 459 -314 143 -202 459 -222 253 -202 171 -462 143 -490 143 -264 249 -340 147 -88 143 -144 113 -144 461 -258 85 -86 115 -202 171 -86 317 -86 115 -114 283 -86 287 -116 373 -86 287 -156 659 -158 87 -114 201 -124 95 -86 287 -172 87 -172 113 -144 663 -230 143 -162 95 -116 143 -116 113 -86 173 -356 99 -198 391 -140 191 -144 219 -172 171 -318 191 -374 201 -328 87 -230 85 -86 143 -116 195 -96 99 -226 383 -382 119 -264 431 -120 167 -120 95 -312 191 -106 85 -172 143 -520 95 -238 299 -288 359 -108 375 -172 185 -150 213 -168 119 -120 127 -146 171 -86 143 -202 115 -144 113 -202 201 -116 113 -144 365 -142 143 -22490 523 -858 969 -1190 1065 -1160 1067 -1146 683 -754 1133 -1100 747 -712 775 -708 779 -702 1125 -1102 1119 -1094 767 -698 763 -728 759 -734 755 -710 757 -738 1117 -1070 815 -648 1207 -1010 1197 -1024 835 -658 779 -710 771 -710 779 -706 1115 -1102 1133 -1066 815 -644 843 -650 1203 -1010 1207 -998 1197 -1042 1153 -1020 803 -710 1141 -1076 791 -678 785 -708 767 -712 773 -710 775 -704 779 -704 815 -646 839 -646 843 -648 813 -656 1205 -1012 1205 -1020 1193 -1020 815 -644 843 -624 1551 -1394 1553 -1364 1575 -1390 819 -672 841 -680 755 -712 1141 -1076 1185 -1016 1191 -1050 763 -704 -RAW_Data: 1183 -1014 813 -646 841 -644 843 -648 1203 -1010 1207 -996 805 -714 775 -710 775 -678 835 -648 813 -672 1181 -1016 799 -710 1139 -1076 1151 -1064 811 -646 845 -646 843 -622 843 -650 1205 -1012 1177 -1022 805 -712 775 -714 1139 -1076 1149 -1034 1205 -998 1177 -1040 811 -670 1183 -1012 855 -626 835 -674 817 -644 843 -648 843 -624 845 -674 761 -732 755 -712 779 -714 773 -710 1139 -1080 1127 -1092 1149 -1024 811 -658 831 -658 1499 -1406 1555 -1404 1557 -1408 805 -668 815 -676 817 -678 1131 -1092 1159 -1018 1213 -1022 815 -676 1131 -1092 789 -642 843 -646 841 -648 1185 -1036 1181 -1018 801 -710 775 -678 829 -668 815 -644 845 -646 1181 -1038 831 -650 1207 -992 1211 -1048 791 -650 843 -676 763 -706 763 -734 1119 -1094 1153 -1018 823 -656 829 -676 1179 -1022 1159 -1070 1179 -1006 1191 -1022 815 -706 1125 -1066 813 -648 845 -646 841 -650 815 -678 783 -710 755 -712 779 -710 769 -710 775 -706 835 -646 1181 -1020 1193 -1022 1185 -1016 833 -654 833 -624 1559 -1410 1515 -1384 1569 -1414 789 -674 843 -674 761 -730 1133 -1068 1177 -1010 1195 -1026 817 -678 1151 -1066 813 -646 817 -672 819 -646 1209 -1012 1197 -1024 835 -658 769 -710 799 -710 749 -690 835 -640 1211 -1018 777 -736 1115 -1078 1151 -1064 809 -644 841 -646 841 -624 841 -650 1201 -1010 1205 -1018 803 -712 773 -704 1145 -1076 1121 -1092 1157 -1016 1185 -1048 791 -674 1179 -1012 835 -648 841 -646 843 -646 843 -674 767 -708 769 -714 777 -714 747 -734 777 -668 843 -644 1205 -1006 1193 -1048 1177 -1012 805 -668 843 -620 1545 -1418 1521 -1388 1575 -1360 841 -672 819 -682 769 -712 1139 -1076 1157 -1040 1197 -1026 835 -658 1143 -1072 817 -620 845 -646 843 -674 1185 -988 1205 -1018 801 -712 777 -706 781 -674 841 -646 817 -648 1207 -1008 831 -652 1199 -1024 1199 -1042 817 -644 817 -648 841 -676 765 -706 1149 -1064 1179 -1020 829 -658 825 -654 1197 -1024 1179 -1012 1205 -992 1183 -1072 789 -674 1183 -1010 837 -650 841 -644 843 -646 843 -678 789 -676 763 -706 793 -710 769 -712 775 -706 781 -674 1205 -1022 1139 -1098 1157 -1014 827 -652 829 -640 1537 -1388 1567 -1388 1541 -1392 813 -698 815 -676 767 -734 1133 -1076 1131 -1040 1195 -1052 811 -678 1133 -1070 819 -620 843 -646 843 -676 1125 -1090 1179 -994 859 -632 797 -710 775 -702 839 -622 841 -644 1211 -992 801 -710 1139 -1078 1151 -1062 813 -646 843 -646 843 -622 841 -650 1205 -1010 1203 -1020 823 -658 825 -654 1195 -1022 1201 -1040 1155 -1016 1185 -1046 815 -650 1177 -1034 833 -644 843 -646 819 -674 815 -676 767 -710 769 -712 775 -710 775 -678 861 -620 841 -646 1205 -1008 -RAW_Data: 1221 -1022 1185 -1016 813 -646 841 -618 1573 -1364 1577 -1362 1811 -2658 227 -138 191 -120 333 -488 345 -86 403 -86 115 -604 283 -82 343 -202 143 -316 87 -128 311 -230 119 -264 165 -168 247 -216 199 -166 283 -230 81 -132 487 -114 115 -142 921 -260 345 -114 373 -116 115 -114 115 -166 191 -192 171 -116 417 -242 167 -240 285 -120 283 -86 257 -230 335 -244 167 -96 167 -188 161 -96 85 -232 173 -114 201 -144 363 -144 87 -86 507 -88 143 -490 103 -124 143 -460 517 -144 219 -202 173 -144 113 -318 229 -174 401 -442 143 -88 603 -144 259 -86 115 -116 113 -144 113 -142 297 -202 171 -86 201 -86 115 -374 163 -364 471 -104 169 -88 201 -144 237 -234 203 -160 113 -86 269 -96 95 -240 431 -94 295 -328 191 -144 239 -240 165 -96 119 -168 421 -238 191 -144 119 -168 143 -120 143 -96 209 -164 239 -240 335 -116 201 -316 115 -172 201 -114 115 -172 173 -86 431 -202 143 -86 229 -116 171 -86 317 -162 143 -174 113 -174 85 -228 85 -142 139 -196 305 -106 85 -232 171 -168 531 -86 85 -86 173 -172 143 -260 137 -342 257 -174 85 -100 115 -170 139 -174 829 -96 191 -192 311 -240 311 -82 211 -144 475 -114 201 -86 85 -286 239 -144 95 -264 227 -120 387 -202 251 -142 143 -316 345 -450 85 -174 315 -372 251 -258 143 -230 221 -156 431 -170 85 -114 431 -364 633 -174 421 -114 259 -86 201 -116 115 -86 229 -174 103 -96 115 -244 307 -86 345 -356 259 -450 693 -98 263 -456 191 -96 357 -116 85 -86 115 -230 201 -88 161 -518 259 -340 173 -116 315 -140 107 -218 517 -96 285 -124 95 -382 119 -144 167 -168 357 -168 119 -144 287 -142 95 -200 143 -260 201 -306 173 -604 479 -224 285 -106 507 -116 165 -408 359 -288 97 -116 225 -430 85 -144 449 -374 113 -120 95 -96 241 -106 101 -86 123 -120 117 -214 107 -144 263 -268 119 -120 141 -96 119 -216 229 -306 287 -150 135 -172 287 -114 215 -168 143 -172 115 -462 113 -144 143 -490 199 -116 403 -116 171 -590 637 -304 113 -86 143 -100 111 -534 149 -312 237 -236 143 -202 85 -202 171 -488 109 -572 201 -238 95 -174 397 -202 283 -164 87 -662 201 -244 315 -562 143 -86 325 -96 575 -190 191 -144 85 -202 189 -358 287 -618 835 -160 163 -142 85 -172 139 -144 215 -82 287 -114 87 -144 541 -438 143 -240 167 -144 359 -190 95 -120 263 -108 109 -184 215 -100 113 -288 119 -144 95 -406 81 -114 87 -256 315 -316 171 -100 105 -144 263 -302 229 -174 -RAW_Data: 113 -232 197 -176 143 -200 187 -240 537 -96 95 -118 263 -432 141 -96 119 -216 761 -282 119 -526 119 -120 185 -116 171 -168 81 -86 143 -172 173 -86 113 -144 489 -202 143 -174 287 -186 373 -168 373 -174 85 -168 119 -330 325 -174 113 -144 373 -202 143 -138 195 -174 185 -192 119 -412 115 -114 283 -120 143 -360 525 -120 119 -120 367 -116 115 -144 345 -114 87 -120 287 -240 239 -96 503 -168 459 -144 317 -242 95 -104 255 -82 227 -172 307 -314 119 -264 901 -282 171 -202 171 -346 201 -576 167 -196 201 -288 315 -116 85 -144 85 -290 143 -264 303 -532 173 -120 215 -272 603 -86 143 -86 85 -190 167 -144 431 -238 119 -96 119 -96 455 -96 285 -144 287 -618 85 -288 253 -592 105 -104 139 -188 335 -120 511 -166 431 -202 373 -86 87 -114 231 -206 83 -190 199 -288 201 -86 171 -88 195 -120 201 -116 257 -202 161 -156 229 -144 143 -298 263 -166 119 -158 115 -326 455 -166 95 -144 119 -168 141 -216 455 -334 95 -144 95 -214 143 -96 143 -196 143 -190 479 -364 287 -114 163 -86 287 -130 297 -96 167 -96 431 -144 95 -190 119 -144 141 -120 335 -144 285 -188 497 -112 429 -258 143 -140 111 -232 87 -116 143 -96 285 -204 273 -632 371 -144 85 -202 115 -172 499 -144 143 -120 119 -120 95 -360 143 -258 173 -930 315 -134 431 -144 115 -114 257 -740 373 -174 95 -144 297 -268 167 -96 143 -834 171 -168 95 -172 119 -96 85 -88 199 -88 315 -172 259 -216 311 -202 85 -260 257 -144 657 -120 119 -116 223 -286 233 -130 115 -202 85 -144 143 -172 115 -88 85 -114 95 -114 345 -288 85 -116 471 -124 173 -114 335 -260 115 -658 339 -260 113 -86 201 -480 217 -470 105 -114 259 -134 137 -86 171 -326 191 -120 263 -144 95 -148 289 -124 121 -384 95 -322 171 -142 193 -288 143 -172 211 -266 109 -144 325 -168 213 -96 685 -310 239 -262 143 -216 143 -316 393 -126 215 -216 387 -202 201 -230 143 -116 85 -144 201 -268 143 -262 311 -86 115 -316 167 -86 229 -116 335 -144 117 -302 113 -116 241 -86 143 -202 201 -116 453 -288 293 -272 367 -120 651 -170 565 -116 143 -882 557 -116 181 -588 119 -168 287 -168 119 -118 191 -168 143 -282 115 -88 171 -404 719 -202 115 -172 253 -144 143 -532 121 -144 239 -96 167 -120 119 -456 199 -114 311 -86 201 -352 111 -144 115 -114 173 -86 85 -538 113 -88 257 -116 143 -96 95 -144 121 -198 127 -172 173 -114 229 -116 143 -144 173 -368 111 -200 163 -116 -RAW_Data: 113 -292 169 -200 145 -86 85 -230 259 -86 85 -86 439 -96 85 -116 115 -86 113 -86 85 -192 191 -214 263 -264 119 -96 345 -116 85 -86 173 -288 85 -104 145 -130 85 -662 243 -390 263 -96 129 -422 223 -288 219 -172 655 -108 361 -96 271 -432 167 -120 421 -278 217 -248 143 -96 165 -240 109 -628 99 -96 95 -168 95 -216 119 -144 171 -172 115 -86 85 -174 387 -190 239 -384 143 -344 115 -114 143 -86 233 -140 85 -724 119 -82 85 -144 115 -144 115 -144 143 -114 201 -174 215 -96 109 -144 85 -144 599 -144 115 -258 249 -206 171 -86 143 -110 255 -86 85 -86 287 -208 225 -100 193 -200 143 -288 139 -460 113 -498 85 -144 143 -88 85 -144 229 -144 85 -144 171 -288 261 -202 113 -88 87 -114 143 -288 373 -366 229 -202 201 -172 173 -172 421 -280 153 -120 81 -160 137 -116 201 -250 141 -230 115 -318 863 -206 119 -462 143 -144 85 -86 201 -230 407 -96 223 -112 143 -94 95 -106 479 -86 113 -174 171 -284 119 -158 239 -190 167 -204 185 -408 215 -168 259 -202 201 -86 85 -202 87 -448 249 -332 363 -490 85 -172 115 -114 145 -114 259 -144 101 -142 119 -240 143 -188 387 -384 425 -144 173 -506 137 -162 139 -174 253 -116 131 -106 115 -130 117 -144 95 -86 239 -192 407 -120 237 -144 143 -82 487 -102 439 -112 199 -88 201 -262 269 -230 229 -192 219 -252 133 -96 191 -346 135 -288 621 -232 661 -202 327 -164 143 -144 139 -536 115 -114 143 -174 85 -100 99 -86 85 -174 85 -144 345 -172 243 -408 115 -86 115 -202 229 -114 87 -114 229 -740 801 -158 143 -168 479 -124 103 -264 119 -240 171 -88 219 -278 431 -402 513 -264 465 -256 141 -168 115 -358 251 -316 387 -172 101 -96 683 -192 95 -120 191 -120 95 -462 261 -96 121 -180 167 -878 287 -86 143 -86 311 -118 287 -168 191 -96 167 -158 85 -86 315 -434 165 -822 171 -316 231 -84 415 -174 87 -296 229 -222 93 -192 167 -190 143 -96 95 -96 237 -168 259 -86 115 -346 171 -116 115 -114 317 -114 95 -140 373 -116 143 -286 207 -260 171 -202 171 -134 119 -320 453 -96 293 -168 143 -144 119 -172 143 -202 237 -360 225 -86 287 -86 201 -202 109 -120 133 -214 215 -116 85 -260 267 -122 335 -316 111 -604 87 -172 259 -258 235 -96 173 -230 339 -140 115 -86 287 -288 143 -186 95 -96 95 -96 339 -256 147 -158 143 -246 223 -264 213 -202 85 -110 95 -168 95 -118 119 -168 95 -264 191 -316 119 -144 119 -382 167 -120 diff --git a/applications/debug/unit_tests/tests/subghz/subghz_test.c b/applications/debug/unit_tests/tests/subghz/subghz_test.c index b49101620..993d15bb1 100644 --- a/applications/debug/unit_tests/tests/subghz/subghz_test.c +++ b/applications/debug/unit_tests/tests/subghz/subghz_test.c @@ -425,13 +425,6 @@ MU_TEST(subghz_decoder_keeloq_test) { "Test decoder " SUBGHZ_PROTOCOL_KEELOQ_NAME " error\r\n"); } -MU_TEST(subghz_decoder_kia_seed_test) { - mu_assert( - subghz_decoder_test( - EXT_PATH("unit_tests/subghz/kia_seed_raw.sub"), SUBGHZ_PROTOCOL_KIA_NAME), - "Test decoder " SUBGHZ_PROTOCOL_KIA_NAME " error\r\n"); -} - MU_TEST(subghz_decoder_nero_radio_test) { mu_assert( subghz_decoder_test( @@ -467,14 +460,6 @@ MU_TEST(subghz_decoder_princeton_test) { "Test decoder " SUBGHZ_PROTOCOL_PRINCETON_NAME " error\r\n"); } -MU_TEST(subghz_decoder_scher_khan_magic_code_test) { - mu_assert( - subghz_decoder_test( - EXT_PATH("unit_tests/subghz/scher_khan_magic_code.sub"), - SUBGHZ_PROTOCOL_SCHER_KHAN_NAME), - "Test decoder " SUBGHZ_PROTOCOL_SCHER_KHAN_NAME " error\r\n"); -} - MU_TEST(subghz_decoder_somfy_keytis_test) { mu_assert( subghz_decoder_test( @@ -489,13 +474,6 @@ MU_TEST(subghz_decoder_somfy_telis_test) { "Test decoder " SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME " error\r\n"); } -MU_TEST(subghz_decoder_star_line_test) { - mu_assert( - subghz_decoder_test( - EXT_PATH("unit_tests/subghz/cenmax_raw.sub"), SUBGHZ_PROTOCOL_STAR_LINE_NAME), - "Test decoder " SUBGHZ_PROTOCOL_STAR_LINE_NAME " error\r\n"); -} - MU_TEST(subghz_decoder_linear_test) { mu_assert( subghz_decoder_test( @@ -949,16 +927,13 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_decoder_hormann_hsm_test); MU_RUN_TEST(subghz_decoder_ido_test); MU_RUN_TEST(subghz_decoder_keeloq_test); - MU_RUN_TEST(subghz_decoder_kia_seed_test); MU_RUN_TEST(subghz_decoder_nero_radio_test); MU_RUN_TEST(subghz_decoder_nero_sketch_test); MU_RUN_TEST(subghz_decoder_nice_flo_test); MU_RUN_TEST(subghz_decoder_nice_flor_s_test); MU_RUN_TEST(subghz_decoder_princeton_test); - MU_RUN_TEST(subghz_decoder_scher_khan_magic_code_test); MU_RUN_TEST(subghz_decoder_somfy_keytis_test); MU_RUN_TEST(subghz_decoder_somfy_telis_test); - MU_RUN_TEST(subghz_decoder_star_line_test); MU_RUN_TEST(subghz_decoder_linear_test); MU_RUN_TEST(subghz_decoder_linear_delta3_test); MU_RUN_TEST(subghz_decoder_megacode_test); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index 23415474c..a6e3324be 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -8,7 +8,7 @@ enum SubGhzSettingIndex { SubGhzSettingIndexHopping, SubGhzSettingIndexModulation, SubGhzSettingIndexBinRAW, - SubGhzSettingIndexIgnoreCars, + SubGhzSettingIndexIgnoreReversRB2, SubGhzSettingIndexIgnoreAlarms, SubGhzSettingIndexIgnoreSensors, SubGhzSettingIndexIgnorePrinceton, @@ -301,8 +301,8 @@ static inline bool subghz_scene_receiver_config_ignore_filter_get_index( return READ_BIT(filter, flag) > 0; } -static void subghz_scene_receiver_config_set_cars(VariableItem* item) { - subghz_scene_receiver_config_set_ignore_filter(item, SubGhzProtocolFlag_Cars); +static void subghz_scene_receiver_config_set_reversrb2(VariableItem* item) { + subghz_scene_receiver_config_set_ignore_filter(item, SubGhzProtocolFlag_ReversRB2); } static void subghz_scene_receiver_config_set_alarms(VariableItem* item) { @@ -447,13 +447,13 @@ void subghz_scene_receiver_config_on_enter(void* context) { SubGhzCustomEventManagerSet) { item = variable_item_list_add( subghz->variable_item_list, - "Ignore Cars", + "Ignore ReversRB2", COMBO_BOX_COUNT, - subghz_scene_receiver_config_set_cars, + subghz_scene_receiver_config_set_reversrb2, subghz); value_index = subghz_scene_receiver_config_ignore_filter_get_index( - subghz->ignore_filter, SubGhzProtocolFlag_Cars); + subghz->ignore_filter, SubGhzProtocolFlag_ReversRB2); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, combobox_text[value_index]); diff --git a/applications/settings/desktop_settings/helpers/pin_code.c b/applications/settings/desktop_settings/helpers/pin_code.c index f4a39da6f..b2eee2c3d 100644 --- a/applications/settings/desktop_settings/helpers/pin_code.c +++ b/applications/settings/desktop_settings/helpers/pin_code.c @@ -1 +1 @@ -#include \ No newline at end of file +#include diff --git a/applications/settings/desktop_settings/views/desktop_view_pin_input.c b/applications/settings/desktop_settings/views/desktop_view_pin_input.c index 4d3dbb156..56ed98f53 100644 --- a/applications/settings/desktop_settings/views/desktop_view_pin_input.c +++ b/applications/settings/desktop_settings/views/desktop_view_pin_input.c @@ -1 +1 @@ -#include \ No newline at end of file +#include diff --git a/documentation/FAQ.md b/documentation/FAQ.md index 7dea58c5d..cd38ad7a8 100644 --- a/documentation/FAQ.md +++ b/documentation/FAQ.md @@ -38,6 +38,29 @@ See default pack and extra pack (for `e` build) list [here](https://github.com/x 4. Open the map file and select your previously created file 5. Use buttons to send the subghz signal files that you selected in map config at step 2 +## Where can I find what SubGHz protocols (manufacturers) are supported and what frequency and modulation to use with them? + +Here - [link](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSupportedSystems.md). + +## I want to request or make new SubGHz protocol, my remote (is not car keyfob) and is not supported, how to record RAW signal properly? + +1. Open SubGHz app, (if you know the frequency skip that step and go to Read) select Frequency analyzer, press and hold button on your remote and place it near IR window on flipper +You will find a approx. frequency that remote uses, release button on the remote and wait until frequency will be placed in history list +Hold OK on flipper to jump into Read mode, now try pressing your remote couple times holding it for at least 2 seconds +Try different modulations, AM650/FM238/FM476/FM12K - nothing works? Lets make RAW recording for analysis +2. Knowing the frequency open Read RAW and set it here in config page +Make sure RSSI Threshold is set to (----) +You need to make 1 RAW for each modulation AM650/FM238/FM476/FM12K +Press REC and on your remote press 1 button 5 times holding it for 1-2 seconds - then 5 times holding it for 5 seconds each time +If your remote has more than 1 button - record each button in similar way +Label each raw - what button you recorded +3. Copy all that RAW files to PC and create issue in firmware repo, attach raw's in archive +Provide high quality photos of the remote, if possible - photos of disassembled remote too +Its model, manufacturer, any known information +If you have access to receiver board, add a photo too +Done! If your remote appears not to be encrypted and very unique, it might be added soon +In case if you want to help us or analyze that signals youself there's a great online tool - https://lab.flipper.net/pulse-plotter + ## How to build (compile) the firmware? Follow this [link](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToBuild.md#how-to-build-by-yourself). @@ -139,7 +162,7 @@ The server will remain active and will be automatically updated [Guide](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md) -## How to use Flipper as new remote (Nice FlorS, BFT Mitto, Somfy Telis, Aprimatic, AN-Motors, etc..) +## How to use Flipper as new SubGHz remote (Nice FlorS, BFT Mitto, Somfy Telis, Aprimatic, AN-Motors, etc..) [Guide](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md) @@ -162,22 +185,6 @@ Please read [this](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/d No, and trying to do so with Read RAW will lead to key desync or unpair with blacklist which means re-pair is very hard to do and requires service tools -## Will Unleashed Firmware support car keyfobs decoding, cloning, emulating? - -No, never! - -## Where can I find jamming files? - -Nowhere, this is illegal in almost every country in the world! - -## I saw something on TikTok and want to ask how to do it. I just wanna be like real hacker! - -You might be banned for that in our communities since 99% of that content is fake or illegal. We do NOT like TikTok questions. - -## I was banned from the Unleashed Discord / Telegram / etc.. How do I get unbanned? I created a GitHub issue, and it was removed too! - -Not possible, rules are rules, read them before sending messages in our communities - ## How to clean .DS_Store and other dot files left from macOS `sudo dot_clean -mn /Volumes/Flipper\ SD` -> `Flipper\ SD` may be named differently for you, replace it with your microSD card name @@ -214,12 +221,12 @@ Reboot it by holding `Left` + `Back` buttons 1. Turn off the device - hold back button -> `Turn Off` **If you can't turn it off, try the next step but hold the buttons for 30-40 seconds)** 2. Hold Up + Back for `~5 sec` -> You will see a reset screen -> Hold Right to reset (and Down arrow to exit if you don't want to reset your pin code) -3. Done, internal memory (dolphin level, settings, pin code) is erased to default settings +3. Done, user config (some settings, pin code) is erased to default factory setup, user files on microSD will stay ## What are the differences between x, y, and z firmware? If you just got your flipper and not sure what will work better for you, start with original official firmware, if you think you need more features or want to remove subghz region locks then:
-* Try installing **Unleashed firmware**, which is fork of official firmware with many new features and preinstalled plugins (check out `e` build).
+* Try installing **Unleashed firmware**, which is fork of official firmware with many new features and preinstalled apps (check out `e` build).
* In other case, If you want to experiment more with UI and other things look for existing forks of Unleashed Firmware.
* Or, create your own fork with your own customisations
* Also, before reporting any found issues, make sure you are in correct repo, if you are not using **Unleashed**, but a different fork or the original firmware, do not report issue in **Unleashed firmware** repo or UL communities (Telegram, Discord, etc..) @@ -287,7 +294,7 @@ To access the Serial CLI, click one of the following based on your platform.
  • Connect your Flipper via USB.
  • Ensure qFlipper and any other serial terminals are closed.
  • -
  • Open my.flipp.dev in one of the aforementioned browsers.
  • +
  • Open lab.flipper.net/cli in one of the aforementioned browsers.
  • Click CONNECT and select USB Serial Device from the list.
  • Wait until you can see your device details on screen.
  • Select the 💻 CLI item from the left sidebar.
  • diff --git a/documentation/SubGHzSupportedSystems.md b/documentation/SubGHzSupportedSystems.md index 6ad6ec09d..4f7214abd 100644 --- a/documentation/SubGHzSupportedSystems.md +++ b/documentation/SubGHzSupportedSystems.md @@ -69,9 +69,6 @@ That list is only for default SubGHz app, apps like *Weather Station* have their ### Alarms - Hollarm `433.92MHz` `AM650` (42 bits, Static) - Bike alarms -- Scher Khan `433.92MHz` `AM650` (35-82 bits, Dynamic) - Russian external car alarm system (Decode and display only), 200x year -- Kia `433/434MHz` `FSK476` (61 bits, Dynamic) - Car alarm system (Decode and display only) -- Star Line `433.92MHz` `AM650` (KeeLoq based, 64 bits) - Russian external car alarm system, 200x year - GangQi `433.92MHz` `AM650` (34 bits, Static) - Bike alarms diff --git a/lib/subghz/protocols/kia.c b/lib/subghz/protocols/kia.c deleted file mode 100644 index 093bf966d..000000000 --- a/lib/subghz/protocols/kia.c +++ /dev/null @@ -1,276 +0,0 @@ -#include "kia.h" - -#include "../blocks/const.h" -#include "../blocks/decoder.h" -#include "../blocks/encoder.h" -#include "../blocks/generic.h" -#include "../blocks/math.h" - -#define TAG "SubGhzProtocoKia" - -static const SubGhzBlockConst subghz_protocol_kia_const = { - .te_short = 250, - .te_long = 500, - .te_delta = 100, - .min_count_bit_for_found = 61, -}; - -struct SubGhzProtocolDecoderKIA { - SubGhzProtocolDecoderBase base; - - SubGhzBlockDecoder decoder; - SubGhzBlockGeneric generic; - - uint16_t header_count; -}; - -struct SubGhzProtocolEncoderKIA { - SubGhzProtocolEncoderBase base; - - SubGhzProtocolBlockEncoder encoder; - SubGhzBlockGeneric generic; -}; - -typedef enum { - KIADecoderStepReset = 0, - KIADecoderStepCheckPreambula, - KIADecoderStepSaveDuration, - KIADecoderStepCheckDuration, -} KIADecoderStep; - -const SubGhzProtocolDecoder subghz_protocol_kia_decoder = { - .alloc = subghz_protocol_decoder_kia_alloc, - .free = subghz_protocol_decoder_kia_free, - - .feed = subghz_protocol_decoder_kia_feed, - .reset = subghz_protocol_decoder_kia_reset, - - .get_hash_data = subghz_protocol_decoder_kia_get_hash_data, - .serialize = subghz_protocol_decoder_kia_serialize, - .deserialize = subghz_protocol_decoder_kia_deserialize, - .get_string = subghz_protocol_decoder_kia_get_string, -}; - -const SubGhzProtocolEncoder subghz_protocol_kia_encoder = { - .alloc = NULL, - .free = NULL, - - .deserialize = NULL, - .stop = NULL, - .yield = NULL, -}; - -const SubGhzProtocol subghz_protocol_kia = { - .name = SUBGHZ_PROTOCOL_KIA_NAME, - .type = SubGhzProtocolTypeDynamic, - .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable | - SubGhzProtocolFlag_Cars, - - .decoder = &subghz_protocol_kia_decoder, - .encoder = &subghz_protocol_kia_encoder, -}; - -void* subghz_protocol_decoder_kia_alloc(SubGhzEnvironment* environment) { - UNUSED(environment); - SubGhzProtocolDecoderKIA* instance = malloc(sizeof(SubGhzProtocolDecoderKIA)); - instance->base.protocol = &subghz_protocol_kia; - instance->generic.protocol_name = instance->base.protocol->name; - - return instance; -} - -void subghz_protocol_decoder_kia_free(void* context) { - furi_assert(context); - SubGhzProtocolDecoderKIA* instance = context; - free(instance); -} - -void subghz_protocol_decoder_kia_reset(void* context) { - furi_assert(context); - SubGhzProtocolDecoderKIA* instance = context; - instance->decoder.parser_step = KIADecoderStepReset; -} - -void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t duration) { - furi_assert(context); - SubGhzProtocolDecoderKIA* instance = context; - - switch(instance->decoder.parser_step) { - case KIADecoderStepReset: - if((level) && (DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) < - subghz_protocol_kia_const.te_delta)) { - instance->decoder.parser_step = KIADecoderStepCheckPreambula; - instance->decoder.te_last = duration; - instance->header_count = 0; - } - break; - case KIADecoderStepCheckPreambula: - if(level) { - if((DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) < - subghz_protocol_kia_const.te_delta) || - (DURATION_DIFF(duration, subghz_protocol_kia_const.te_long) < - subghz_protocol_kia_const.te_delta)) { - instance->decoder.te_last = duration; - } else { - instance->decoder.parser_step = KIADecoderStepReset; - } - } else if( - (DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) < - subghz_protocol_kia_const.te_delta) && - (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_short) < - subghz_protocol_kia_const.te_delta)) { - // Found header - instance->header_count++; - break; - } else if( - (DURATION_DIFF(duration, subghz_protocol_kia_const.te_long) < - subghz_protocol_kia_const.te_delta) && - (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_long) < - subghz_protocol_kia_const.te_delta)) { - // Found start bit - if(instance->header_count > 15) { - instance->decoder.parser_step = KIADecoderStepSaveDuration; - instance->decoder.decode_data = 0; - instance->decoder.decode_count_bit = 1; - subghz_protocol_blocks_add_bit(&instance->decoder, 1); - } else { - instance->decoder.parser_step = KIADecoderStepReset; - } - } else { - instance->decoder.parser_step = KIADecoderStepReset; - } - break; - case KIADecoderStepSaveDuration: - if(level) { - if(duration >= - (subghz_protocol_kia_const.te_long + subghz_protocol_kia_const.te_delta * 2UL)) { - //Found stop bit - instance->decoder.parser_step = KIADecoderStepReset; - if(instance->decoder.decode_count_bit == - subghz_protocol_kia_const.min_count_bit_for_found) { - instance->generic.data = instance->decoder.decode_data; - instance->generic.data_count_bit = instance->decoder.decode_count_bit; - if(instance->base.callback) - instance->base.callback(&instance->base, instance->base.context); - } - instance->decoder.decode_data = 0; - instance->decoder.decode_count_bit = 0; - break; - } else { - instance->decoder.te_last = duration; - instance->decoder.parser_step = KIADecoderStepCheckDuration; - } - - } else { - instance->decoder.parser_step = KIADecoderStepReset; - } - break; - case KIADecoderStepCheckDuration: - if(!level) { - if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_short) < - subghz_protocol_kia_const.te_delta) && - (DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) < - subghz_protocol_kia_const.te_delta)) { - subghz_protocol_blocks_add_bit(&instance->decoder, 0); - instance->decoder.parser_step = KIADecoderStepSaveDuration; - } else if( - (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_long) < - subghz_protocol_kia_const.te_delta) && - (DURATION_DIFF(duration, subghz_protocol_kia_const.te_long) < - subghz_protocol_kia_const.te_delta)) { - subghz_protocol_blocks_add_bit(&instance->decoder, 1); - instance->decoder.parser_step = KIADecoderStepSaveDuration; - } else { - instance->decoder.parser_step = KIADecoderStepReset; - } - } else { - instance->decoder.parser_step = KIADecoderStepReset; - } - break; - } -} - -uint8_t subghz_protocol_kia_crc8(uint8_t* data, size_t len) { - uint8_t crc = 0x08; - size_t i, j; - for(i = 0; i < len; i++) { - crc ^= data[i]; - for(j = 0; j < 8; j++) { - if((crc & 0x80) != 0) - crc = (uint8_t)((crc << 1) ^ 0x7F); - else - crc <<= 1; - } - } - return crc; -} - -/** - * Analysis of received data - * @param instance Pointer to a SubGhzBlockGeneric* instance - */ -static void subghz_protocol_kia_check_remote_controller(SubGhzBlockGeneric* instance) { - /* - * 0x0F 0112 43B04EC 1 7D - * 0x0F 0113 43B04EC 1 DF - * 0x0F 0114 43B04EC 1 30 - * 0x0F 0115 43B04EC 2 13 - * 0x0F 0116 43B04EC 3 F5 - * CNT Serial K CRC8 Kia (CRC8, poly 0x7f, start_crc 0x08) - */ - - instance->serial = (uint32_t)((instance->data >> 12) & 0x0FFFFFFF); - instance->btn = (instance->data >> 8) & 0x0F; - instance->cnt = (instance->data >> 40) & 0xFFFF; -} - -uint8_t subghz_protocol_decoder_kia_get_hash_data(void* context) { - furi_assert(context); - SubGhzProtocolDecoderKIA* instance = context; - return subghz_protocol_blocks_get_hash_data( - &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); -} - -SubGhzProtocolStatus subghz_protocol_decoder_kia_serialize( - void* context, - FlipperFormat* flipper_format, - SubGhzRadioPreset* preset) { - furi_assert(context); - SubGhzProtocolDecoderKIA* instance = context; - return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); -} - -SubGhzProtocolStatus - subghz_protocol_decoder_kia_deserialize(void* context, FlipperFormat* flipper_format) { - furi_assert(context); - SubGhzProtocolDecoderKIA* instance = context; - return subghz_block_generic_deserialize_check_count_bit( - &instance->generic, flipper_format, subghz_protocol_kia_const.min_count_bit_for_found); -} - -void subghz_protocol_decoder_kia_get_string(void* context, FuriString* output) { - furi_assert(context); - SubGhzProtocolDecoderKIA* instance = context; - - subghz_protocol_kia_check_remote_controller(&instance->generic); - uint32_t code_found_hi = instance->generic.data >> 32; - uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; - - // use 'Cntr:' instead of 'Cnt:' to exclude this protocol counter from Counter edit - subghz_block_generic_global.cnt_length_bit = 16; - subghz_block_generic_global.current_cnt = instance->generic.cnt; - - furi_string_cat_printf( - output, - "%s %dbit\r\n" - "Key:%08lX%08lX\r\n" - "Sn:%07lX Btn:%X\r\n" - "Cntr:%04lX\r\n", - instance->generic.protocol_name, - instance->generic.data_count_bit, - code_found_hi, - code_found_lo, - instance->generic.serial, - instance->generic.btn, - instance->generic.cnt); -} diff --git a/lib/subghz/protocols/kia.h b/lib/subghz/protocols/kia.h deleted file mode 100644 index 749ff8afd..000000000 --- a/lib/subghz/protocols/kia.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include "base.h" - -#define SUBGHZ_PROTOCOL_KIA_NAME "KIA Seed" - -typedef struct SubGhzProtocolDecoderKIA SubGhzProtocolDecoderKIA; -typedef struct SubGhzProtocolEncoderKIA SubGhzProtocolEncoderKIA; - -extern const SubGhzProtocolDecoder subghz_protocol_kia_decoder; -extern const SubGhzProtocolEncoder subghz_protocol_kia_encoder; -extern const SubGhzProtocol subghz_protocol_kia; - -/** - * Allocate SubGhzProtocolDecoderKIA. - * @param environment Pointer to a SubGhzEnvironment instance - * @return SubGhzProtocolDecoderKIA* pointer to a SubGhzProtocolDecoderKIA instance - */ -void* subghz_protocol_decoder_kia_alloc(SubGhzEnvironment* environment); - -/** - * Free SubGhzProtocolDecoderKIA. - * @param context Pointer to a SubGhzProtocolDecoderKIA instance - */ -void subghz_protocol_decoder_kia_free(void* context); - -/** - * Reset decoder SubGhzProtocolDecoderKIA. - * @param context Pointer to a SubGhzProtocolDecoderKIA instance - */ -void subghz_protocol_decoder_kia_reset(void* context); - -/** - * Parse a raw sequence of levels and durations received from the air. - * @param context Pointer to a SubGhzProtocolDecoderKIA instance - * @param level Signal level true-high false-low - * @param duration Duration of this level in, us - */ -void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t duration); - -/** - * Getting the hash sum of the last randomly received parcel. - * @param context Pointer to a SubGhzProtocolDecoderKIA instance - * @return hash Hash sum - */ -uint8_t subghz_protocol_decoder_kia_get_hash_data(void* context); - -/** - * Serialize data SubGhzProtocolDecoderKIA. - * @param context Pointer to a SubGhzProtocolDecoderKIA instance - * @param flipper_format Pointer to a FlipperFormat instance - * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return status - */ -SubGhzProtocolStatus subghz_protocol_decoder_kia_serialize( - void* context, - FlipperFormat* flipper_format, - SubGhzRadioPreset* preset); - -/** - * Deserialize data SubGhzProtocolDecoderKIA. - * @param context Pointer to a SubGhzProtocolDecoderKIA instance - * @param flipper_format Pointer to a FlipperFormat instance - * @return status - */ -SubGhzProtocolStatus - subghz_protocol_decoder_kia_deserialize(void* context, FlipperFormat* flipper_format); - -/** - * Getting a textual representation of the received data. - * @param context Pointer to a SubGhzProtocolDecoderKIA instance - * @param output Resulting text - */ -void subghz_protocol_decoder_kia_get_string(void* context, FuriString* output); diff --git a/lib/subghz/protocols/protocol_items.c b/lib/subghz/protocols/protocol_items.c index e7b282b8a..c15d578bb 100644 --- a/lib/subghz/protocols/protocol_items.c +++ b/lib/subghz/protocols/protocol_items.c @@ -1,59 +1,31 @@ #include "protocol_items.h" // IWYU pragma: keep const SubGhzProtocol* const subghz_protocol_registry_items[] = { - &subghz_protocol_gate_tx, - &subghz_protocol_keeloq, - &subghz_protocol_star_line, - &subghz_protocol_nice_flo, - &subghz_protocol_came, - &subghz_protocol_faac_slh, - &subghz_protocol_nice_flor_s, - &subghz_protocol_came_twee, - &subghz_protocol_came_atomo, - &subghz_protocol_nero_sketch, - &subghz_protocol_ido, - &subghz_protocol_kia, - &subghz_protocol_hormann, - &subghz_protocol_nero_radio, - &subghz_protocol_somfy_telis, - &subghz_protocol_somfy_keytis, - &subghz_protocol_scher_khan, - &subghz_protocol_princeton, - &subghz_protocol_raw, - &subghz_protocol_linear, - &subghz_protocol_secplus_v2, - &subghz_protocol_secplus_v1, - &subghz_protocol_megacode, - &subghz_protocol_holtek, - &subghz_protocol_chamb_code, - &subghz_protocol_power_smart, - &subghz_protocol_marantec, - &subghz_protocol_bett, - &subghz_protocol_doitrand, - &subghz_protocol_phoenix_v2, - &subghz_protocol_honeywell_wdb, - &subghz_protocol_magellan, - &subghz_protocol_intertechno_v3, - &subghz_protocol_clemsa, - &subghz_protocol_ansonic, - &subghz_protocol_smc5326, - &subghz_protocol_holtek_th12x, - &subghz_protocol_linear_delta3, - &subghz_protocol_dooya, - &subghz_protocol_alutech_at_4n, - &subghz_protocol_kinggates_stylo_4k, - &subghz_protocol_bin_raw, - &subghz_protocol_mastercode, - &subghz_protocol_honeywell, - &subghz_protocol_legrand, - &subghz_protocol_dickert_mahs, - &subghz_protocol_gangqi, - &subghz_protocol_marantec24, - &subghz_protocol_hollarm, - &subghz_protocol_hay21, - &subghz_protocol_revers_rb2, - &subghz_protocol_feron, - &subghz_protocol_roger, + &subghz_protocol_gate_tx, &subghz_protocol_keeloq, + &subghz_protocol_nice_flo, &subghz_protocol_came, + &subghz_protocol_faac_slh, &subghz_protocol_nice_flor_s, + &subghz_protocol_came_twee, &subghz_protocol_came_atomo, + &subghz_protocol_nero_sketch, &subghz_protocol_ido, + &subghz_protocol_hormann, &subghz_protocol_nero_radio, + &subghz_protocol_somfy_telis, &subghz_protocol_somfy_keytis, + &subghz_protocol_princeton, &subghz_protocol_raw, + &subghz_protocol_linear, &subghz_protocol_secplus_v2, + &subghz_protocol_secplus_v1, &subghz_protocol_megacode, + &subghz_protocol_holtek, &subghz_protocol_chamb_code, + &subghz_protocol_power_smart, &subghz_protocol_marantec, + &subghz_protocol_bett, &subghz_protocol_doitrand, + &subghz_protocol_phoenix_v2, &subghz_protocol_honeywell_wdb, + &subghz_protocol_magellan, &subghz_protocol_intertechno_v3, + &subghz_protocol_clemsa, &subghz_protocol_ansonic, + &subghz_protocol_smc5326, &subghz_protocol_holtek_th12x, + &subghz_protocol_linear_delta3, &subghz_protocol_dooya, + &subghz_protocol_alutech_at_4n, &subghz_protocol_kinggates_stylo_4k, + &subghz_protocol_bin_raw, &subghz_protocol_mastercode, + &subghz_protocol_honeywell, &subghz_protocol_legrand, + &subghz_protocol_dickert_mahs, &subghz_protocol_gangqi, + &subghz_protocol_marantec24, &subghz_protocol_hollarm, + &subghz_protocol_hay21, &subghz_protocol_revers_rb2, + &subghz_protocol_feron, &subghz_protocol_roger, &subghz_protocol_elplast, }; diff --git a/lib/subghz/protocols/protocol_items.h b/lib/subghz/protocols/protocol_items.h index 9820ee9e7..863f601b4 100644 --- a/lib/subghz/protocols/protocol_items.h +++ b/lib/subghz/protocols/protocol_items.h @@ -4,7 +4,6 @@ #include "princeton.h" #include "keeloq.h" -#include "star_line.h" #include "nice_flo.h" #include "came.h" #include "faac_slh.h" @@ -13,12 +12,10 @@ #include "came_atomo.h" #include "nero_sketch.h" #include "ido.h" -#include "kia.h" #include "hormann.h" #include "nero_radio.h" #include "somfy_telis.h" #include "somfy_keytis.h" -#include "scher_khan.h" #include "gate_tx.h" #include "raw.h" #include "linear.h" diff --git a/lib/subghz/protocols/revers_rb2.c b/lib/subghz/protocols/revers_rb2.c index e6524174f..3d60a0730 100644 --- a/lib/subghz/protocols/revers_rb2.c +++ b/lib/subghz/protocols/revers_rb2.c @@ -64,7 +64,8 @@ const SubGhzProtocol subghz_protocol_revers_rb2 = { .name = SUBGHZ_PROTOCOL_REVERSRB2_NAME, .type = SubGhzProtocolTypeStatic, .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | - SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send | + SubGhzProtocolFlag_ReversRB2, .decoder = &subghz_protocol_revers_rb2_decoder, .encoder = &subghz_protocol_revers_rb2_encoder, diff --git a/lib/subghz/protocols/scher_khan.c b/lib/subghz/protocols/scher_khan.c deleted file mode 100644 index 4ce050f6d..000000000 --- a/lib/subghz/protocols/scher_khan.c +++ /dev/null @@ -1,320 +0,0 @@ -#include "scher_khan.h" - -#include "../blocks/const.h" -#include "../blocks/decoder.h" -#include "../blocks/encoder.h" -#include "../blocks/generic.h" -#include "../blocks/math.h" - -//https://phreakerclub.com/72 -//https://phreakerclub.com/forum/showthread.php?t=7&page=2 -//https://phreakerclub.com/forum/showthread.php?t=274&highlight=magicar -//!!! https://phreakerclub.com/forum/showthread.php?t=489&highlight=magicar&page=5 - -#define TAG "SubGhzProtocolScherKhan" - -static const SubGhzBlockConst subghz_protocol_scher_khan_const = { - .te_short = 750, - .te_long = 1100, - .te_delta = 150, - .min_count_bit_for_found = 35, -}; - -struct SubGhzProtocolDecoderScherKhan { - SubGhzProtocolDecoderBase base; - - SubGhzBlockDecoder decoder; - SubGhzBlockGeneric generic; - - uint16_t header_count; - const char* protocol_name; -}; - -struct SubGhzProtocolEncoderScherKhan { - SubGhzProtocolEncoderBase base; - - SubGhzProtocolBlockEncoder encoder; - SubGhzBlockGeneric generic; -}; - -typedef enum { - ScherKhanDecoderStepReset = 0, - ScherKhanDecoderStepCheckPreambula, - ScherKhanDecoderStepSaveDuration, - ScherKhanDecoderStepCheckDuration, -} ScherKhanDecoderStep; - -const SubGhzProtocolDecoder subghz_protocol_scher_khan_decoder = { - .alloc = subghz_protocol_decoder_scher_khan_alloc, - .free = subghz_protocol_decoder_scher_khan_free, - - .feed = subghz_protocol_decoder_scher_khan_feed, - .reset = subghz_protocol_decoder_scher_khan_reset, - - .get_hash_data = subghz_protocol_decoder_scher_khan_get_hash_data, - .serialize = subghz_protocol_decoder_scher_khan_serialize, - .deserialize = subghz_protocol_decoder_scher_khan_deserialize, - .get_string = subghz_protocol_decoder_scher_khan_get_string, -}; - -const SubGhzProtocolEncoder subghz_protocol_scher_khan_encoder = { - .alloc = NULL, - .free = NULL, - - .deserialize = NULL, - .stop = NULL, - .yield = NULL, -}; - -const SubGhzProtocol subghz_protocol_scher_khan = { - .name = SUBGHZ_PROTOCOL_SCHER_KHAN_NAME, - .type = SubGhzProtocolTypeDynamic, - .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable | - SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Cars, - - .decoder = &subghz_protocol_scher_khan_decoder, - .encoder = &subghz_protocol_scher_khan_encoder, -}; - -void* subghz_protocol_decoder_scher_khan_alloc(SubGhzEnvironment* environment) { - UNUSED(environment); - SubGhzProtocolDecoderScherKhan* instance = malloc(sizeof(SubGhzProtocolDecoderScherKhan)); - instance->base.protocol = &subghz_protocol_scher_khan; - instance->generic.protocol_name = instance->base.protocol->name; - - return instance; -} - -void subghz_protocol_decoder_scher_khan_free(void* context) { - furi_assert(context); - SubGhzProtocolDecoderScherKhan* instance = context; - free(instance); -} - -void subghz_protocol_decoder_scher_khan_reset(void* context) { - furi_assert(context); - SubGhzProtocolDecoderScherKhan* instance = context; - instance->decoder.parser_step = ScherKhanDecoderStepReset; -} - -void subghz_protocol_decoder_scher_khan_feed(void* context, bool level, uint32_t duration) { - furi_assert(context); - SubGhzProtocolDecoderScherKhan* instance = context; - - switch(instance->decoder.parser_step) { - case ScherKhanDecoderStepReset: - if((level) && (DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_short * 2) < - subghz_protocol_scher_khan_const.te_delta)) { - instance->decoder.parser_step = ScherKhanDecoderStepCheckPreambula; - instance->decoder.te_last = duration; - instance->header_count = 0; - } - break; - case ScherKhanDecoderStepCheckPreambula: - if(level) { - if((DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_short * 2) < - subghz_protocol_scher_khan_const.te_delta) || - (DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_short) < - subghz_protocol_scher_khan_const.te_delta)) { - instance->decoder.te_last = duration; - } else { - instance->decoder.parser_step = ScherKhanDecoderStepReset; - } - } else if( - (DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_short * 2) < - subghz_protocol_scher_khan_const.te_delta) || - (DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_short) < - subghz_protocol_scher_khan_const.te_delta)) { - if(DURATION_DIFF( - instance->decoder.te_last, subghz_protocol_scher_khan_const.te_short * 2) < - subghz_protocol_scher_khan_const.te_delta) { - // Found header - instance->header_count++; - break; - } else if( - DURATION_DIFF( - instance->decoder.te_last, subghz_protocol_scher_khan_const.te_short) < - subghz_protocol_scher_khan_const.te_delta) { - // Found start bit - if(instance->header_count >= 2) { - instance->decoder.parser_step = ScherKhanDecoderStepSaveDuration; - instance->decoder.decode_data = 0; - instance->decoder.decode_count_bit = 1; - } else { - instance->decoder.parser_step = ScherKhanDecoderStepReset; - } - } else { - instance->decoder.parser_step = ScherKhanDecoderStepReset; - } - } else { - instance->decoder.parser_step = ScherKhanDecoderStepReset; - } - break; - case ScherKhanDecoderStepSaveDuration: - if(level) { - if(duration >= (subghz_protocol_scher_khan_const.te_delta * 2UL + - subghz_protocol_scher_khan_const.te_long)) { - //Found stop bit - instance->decoder.parser_step = ScherKhanDecoderStepReset; - if(instance->decoder.decode_count_bit >= - subghz_protocol_scher_khan_const.min_count_bit_for_found) { - instance->generic.data = instance->decoder.decode_data; - instance->generic.data_count_bit = instance->decoder.decode_count_bit; - if(instance->base.callback) - instance->base.callback(&instance->base, instance->base.context); - } - instance->decoder.decode_data = 0; - instance->decoder.decode_count_bit = 0; - break; - } else { - instance->decoder.te_last = duration; - instance->decoder.parser_step = ScherKhanDecoderStepCheckDuration; - } - - } else { - instance->decoder.parser_step = ScherKhanDecoderStepReset; - } - break; - case ScherKhanDecoderStepCheckDuration: - if(!level) { - if((DURATION_DIFF( - instance->decoder.te_last, subghz_protocol_scher_khan_const.te_short) < - subghz_protocol_scher_khan_const.te_delta) && - (DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_short) < - subghz_protocol_scher_khan_const.te_delta)) { - subghz_protocol_blocks_add_bit(&instance->decoder, 0); - instance->decoder.parser_step = ScherKhanDecoderStepSaveDuration; - } else if( - (DURATION_DIFF( - instance->decoder.te_last, subghz_protocol_scher_khan_const.te_long) < - subghz_protocol_scher_khan_const.te_delta) && - (DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_long) < - subghz_protocol_scher_khan_const.te_delta)) { - subghz_protocol_blocks_add_bit(&instance->decoder, 1); - instance->decoder.parser_step = ScherKhanDecoderStepSaveDuration; - } else { - instance->decoder.parser_step = ScherKhanDecoderStepReset; - } - } else { - instance->decoder.parser_step = ScherKhanDecoderStepReset; - } - break; - } -} - -/** - * Analysis of received data - * @param instance Pointer to a SubGhzBlockGeneric* instance - * @param protocol_name - */ -static void subghz_protocol_scher_khan_check_remote_controller( - SubGhzBlockGeneric* instance, - const char** protocol_name) { - /* - * MAGICAR 51 bit 00000001A99121DE83C3 MAGIC CODE, Dynamic - * 0E8C1619E830C -> 000011101000110000010110 0001 1001 1110 1000001100001100 - * 0E8C1629D830D -> 000011101000110000010110 0010 1001 1101 1000001100001101 - * 0E8C1649B830E -> 000011101000110000010110 0100 1001 1011 1000001100001110 - * 0E8C16897830F -> 000011101000110000010110 1000 1001 0111 1000001100001111 - * Serial Key Ser ~Key CNT - */ - - switch(instance->data_count_bit) { - case 35: //MAGIC CODE, Static - *protocol_name = "MAGIC CODE, Static"; - instance->serial = 0; - instance->btn = 0; - instance->cnt = 0; - break; - case 51: //MAGIC CODE, Dynamic - *protocol_name = "MAGIC CODE, Dynamic"; - instance->serial = ((instance->data >> 24) & 0xFFFFFF0) | ((instance->data >> 20) & 0x0F); - instance->btn = (instance->data >> 24) & 0x0F; - instance->cnt = instance->data & 0xFFFF; - break; - case 57: //MAGIC CODE PRO / PRO2 - *protocol_name = "MAGIC CODE PRO/PRO2"; - instance->serial = 0; - instance->btn = 0; - instance->cnt = 0; - break; - case 63: //MAGIC CODE, Dynamic Response - *protocol_name = "MAGIC CODE, Response"; - instance->serial = 0; - instance->btn = 0; - instance->cnt = 0; - break; - case 64: //MAGICAR, Response ??? - *protocol_name = "MAGICAR, Response"; - instance->serial = 0; - instance->btn = 0; - instance->cnt = 0; - break; - case 81: // MAGIC CODE PRO / PRO2 Response ??? - case 82: // MAGIC CODE PRO / PRO2 Response ??? - *protocol_name = "MAGIC CODE PRO,\n Response"; - instance->serial = 0; - instance->btn = 0; - instance->cnt = 0; - break; - - default: - *protocol_name = "Unknown"; - instance->serial = 0; - instance->btn = 0; - instance->cnt = 0; - break; - } -} - -uint8_t subghz_protocol_decoder_scher_khan_get_hash_data(void* context) { - furi_assert(context); - SubGhzProtocolDecoderScherKhan* instance = context; - return subghz_protocol_blocks_get_hash_data( - &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); -} - -SubGhzProtocolStatus subghz_protocol_decoder_scher_khan_serialize( - void* context, - FlipperFormat* flipper_format, - SubGhzRadioPreset* preset) { - furi_assert(context); - SubGhzProtocolDecoderScherKhan* instance = context; - return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); -} - -SubGhzProtocolStatus - subghz_protocol_decoder_scher_khan_deserialize(void* context, FlipperFormat* flipper_format) { - furi_assert(context); - SubGhzProtocolDecoderScherKhan* instance = context; - return subghz_block_generic_deserialize(&instance->generic, flipper_format); -} - -void subghz_protocol_decoder_scher_khan_get_string(void* context, FuriString* output) { - furi_assert(context); - SubGhzProtocolDecoderScherKhan* instance = context; - - subghz_protocol_scher_khan_check_remote_controller( - &instance->generic, &instance->protocol_name); - - // use 'Cntr:' instead of 'Cnt:' to exclude this protocol counter from Counter edit - // push protocol data to global variable - subghz_block_generic_global.cnt_length_bit = 16; - subghz_block_generic_global.current_cnt = instance->generic.cnt; - - furi_string_cat_printf( - output, - "%s %dbit\r\n" - "Key:0x%lX%08lX\r\n" - "Sn:%07lX Btn:%X\r\n" - "Cntr:%04lX\r\n" - "Pt: %s\r\n", - instance->generic.protocol_name, - instance->generic.data_count_bit, - (uint32_t)(instance->generic.data >> 32), - (uint32_t)instance->generic.data, - instance->generic.serial, - instance->generic.btn, - instance->generic.cnt, - instance->protocol_name); -} diff --git a/lib/subghz/protocols/scher_khan.h b/lib/subghz/protocols/scher_khan.h deleted file mode 100644 index 58545069c..000000000 --- a/lib/subghz/protocols/scher_khan.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include "base.h" - -#define SUBGHZ_PROTOCOL_SCHER_KHAN_NAME "Scher-Khan" - -typedef struct SubGhzProtocolDecoderScherKhan SubGhzProtocolDecoderScherKhan; -typedef struct SubGhzProtocolEncoderScherKhan SubGhzProtocolEncoderScherKhan; - -extern const SubGhzProtocolDecoder subghz_protocol_scher_khan_decoder; -extern const SubGhzProtocolEncoder subghz_protocol_scher_khan_encoder; -extern const SubGhzProtocol subghz_protocol_scher_khan; - -/** - * Allocate SubGhzProtocolDecoderScherKhan. - * @param environment Pointer to a SubGhzEnvironment instance - * @return SubGhzProtocolDecoderScherKhan* pointer to a SubGhzProtocolDecoderScherKhan instance - */ -void* subghz_protocol_decoder_scher_khan_alloc(SubGhzEnvironment* environment); - -/** - * Free SubGhzProtocolDecoderScherKhan. - * @param context Pointer to a SubGhzProtocolDecoderScherKhan instance - */ -void subghz_protocol_decoder_scher_khan_free(void* context); - -/** - * Reset decoder SubGhzProtocolDecoderScherKhan. - * @param context Pointer to a SubGhzProtocolDecoderScherKhan instance - */ -void subghz_protocol_decoder_scher_khan_reset(void* context); - -/** - * Parse a raw sequence of levels and durations received from the air. - * @param context Pointer to a SubGhzProtocolDecoderScherKhan instance - * @param level Signal level true-high false-low - * @param duration Duration of this level in, us - */ -void subghz_protocol_decoder_scher_khan_feed(void* context, bool level, uint32_t duration); - -/** - * Getting the hash sum of the last randomly received parcel. - * @param context Pointer to a SubGhzProtocolDecoderScherKhan instance - * @return hash Hash sum - */ -uint8_t subghz_protocol_decoder_scher_khan_get_hash_data(void* context); - -/** - * Serialize data SubGhzProtocolDecoderScherKhan. - * @param context Pointer to a SubGhzProtocolDecoderScherKhan instance - * @param flipper_format Pointer to a FlipperFormat instance - * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return status - */ -SubGhzProtocolStatus subghz_protocol_decoder_scher_khan_serialize( - void* context, - FlipperFormat* flipper_format, - SubGhzRadioPreset* preset); - -/** - * Deserialize data SubGhzProtocolDecoderScherKhan. - * @param context Pointer to a SubGhzProtocolDecoderScherKhan instance - * @param flipper_format Pointer to a FlipperFormat instance - * @return status - */ -SubGhzProtocolStatus - subghz_protocol_decoder_scher_khan_deserialize(void* context, FlipperFormat* flipper_format); - -/** - * Getting a textual representation of the received data. - * @param context Pointer to a SubGhzProtocolDecoderScherKhan instance - * @param output Resulting text - */ -void subghz_protocol_decoder_scher_khan_get_string(void* context, FuriString* output); diff --git a/lib/subghz/protocols/star_line.c b/lib/subghz/protocols/star_line.c deleted file mode 100644 index 3fd236202..000000000 --- a/lib/subghz/protocols/star_line.c +++ /dev/null @@ -1,747 +0,0 @@ -#include "star_line.h" -#include "keeloq_common.h" - -#include "../subghz_keystore.h" -#include - -#include "../blocks/const.h" -#include "../blocks/decoder.h" -#include "../blocks/encoder.h" -#include "../blocks/generic.h" -#include "../blocks/math.h" - -#include "../subghz_keystore_i.h" - -#define TAG "SubGhzProtocolStarLine" - -static const SubGhzBlockConst subghz_protocol_star_line_const = { - .te_short = 250, - .te_long = 500, - .te_delta = 120, - .min_count_bit_for_found = 64, -}; - -struct SubGhzProtocolDecoderStarLine { - SubGhzProtocolDecoderBase base; - - SubGhzBlockDecoder decoder; - SubGhzBlockGeneric generic; - - uint16_t header_count; - SubGhzKeystore* keystore; - const char* manufacture_name; - - FuriString* manufacture_from_file; -}; - -struct SubGhzProtocolEncoderStarLine { - SubGhzProtocolEncoderBase base; - - SubGhzProtocolBlockEncoder encoder; - SubGhzBlockGeneric generic; - - SubGhzKeystore* keystore; - const char* manufacture_name; - - FuriString* manufacture_from_file; -}; - -typedef enum { - StarLineDecoderStepReset = 0, - StarLineDecoderStepCheckPreambula, - StarLineDecoderStepSaveDuration, - StarLineDecoderStepCheckDuration, -} StarLineDecoderStep; - -const SubGhzProtocolDecoder subghz_protocol_star_line_decoder = { - .alloc = subghz_protocol_decoder_star_line_alloc, - .free = subghz_protocol_decoder_star_line_free, - - .feed = subghz_protocol_decoder_star_line_feed, - .reset = subghz_protocol_decoder_star_line_reset, - - .get_hash_data = subghz_protocol_decoder_star_line_get_hash_data, - .serialize = subghz_protocol_decoder_star_line_serialize, - .deserialize = subghz_protocol_decoder_star_line_deserialize, - .get_string = subghz_protocol_decoder_star_line_get_string, -}; - -const SubGhzProtocolEncoder subghz_protocol_star_line_encoder = { - .alloc = subghz_protocol_encoder_star_line_alloc, - .free = subghz_protocol_encoder_star_line_free, - - .deserialize = subghz_protocol_encoder_star_line_deserialize, - .stop = subghz_protocol_encoder_star_line_stop, - .yield = subghz_protocol_encoder_star_line_yield, -}; - -const SubGhzProtocol subghz_protocol_star_line = { - .name = SUBGHZ_PROTOCOL_STAR_LINE_NAME, - .type = SubGhzProtocolTypeDynamic, - .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | - SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send | - SubGhzProtocolFlag_Cars, - - .decoder = &subghz_protocol_star_line_decoder, - .encoder = &subghz_protocol_star_line_encoder, -}; - -/** - * Analysis of received data - * @param instance Pointer to a SubGhzBlockGeneric* instance - * @param keystore Pointer to a SubGhzKeystore* instance - * @param manufacture_name - */ -static void subghz_protocol_star_line_check_remote_controller( - SubGhzBlockGeneric* instance, - SubGhzKeystore* keystore, - const char** manufacture_name); - -void* subghz_protocol_encoder_star_line_alloc(SubGhzEnvironment* environment) { - SubGhzProtocolEncoderStarLine* instance = malloc(sizeof(SubGhzProtocolEncoderStarLine)); - - instance->base.protocol = &subghz_protocol_star_line; - instance->generic.protocol_name = instance->base.protocol->name; - instance->keystore = subghz_environment_get_keystore(environment); - - instance->manufacture_from_file = furi_string_alloc(); - - instance->encoder.repeat = 10; - instance->encoder.size_upload = 256; - instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_running = false; - - return instance; -} - -void subghz_protocol_encoder_star_line_free(void* context) { - furi_assert(context); - SubGhzProtocolEncoderStarLine* instance = context; - furi_string_free(instance->manufacture_from_file); - free(instance->encoder.upload); - free(instance); -} - -/** - * Key generation from simple data - * @param instance Pointer to a SubGhzProtocolEncoderKeeloq* instance - * @param btn Button number, 4 bit - */ -static bool - subghz_protocol_star_line_gen_data(SubGhzProtocolEncoderStarLine* instance, uint8_t btn) { - // Check for OFEX (overflow experimental) mode - if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { - // standart counter mode. PULL data from subghz_block_generic_global variables - if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { - // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value - if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { - instance->generic.cnt = 0; - } else { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); - } - } - } else { - if((instance->generic.cnt + 0x1) > 0xFFFF) { - instance->generic.cnt = 0; - } else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xFFFE) { - instance->generic.cnt = 0xFFFE; - } else { - instance->generic.cnt++; - } - } - uint32_t fix = btn << 24 | instance->generic.serial; - uint32_t decrypt = btn << 24 | (instance->generic.serial & 0xFF) << 16 | instance->generic.cnt; - uint32_t hop = 0; - uint64_t man = 0; - uint64_t code_found_reverse; - int res = 0; - - if(instance->manufacture_name == 0x0) { - instance->manufacture_name = ""; - } - - if(strcmp(instance->manufacture_name, "Unknown") == 0) { - code_found_reverse = subghz_protocol_blocks_reverse_key( - instance->generic.data, instance->generic.data_count_bit); - hop = code_found_reverse & 0x00000000ffffffff; - } else { - uint8_t kl_type_en = instance->keystore->kl_type; - for - M_EACH( - manufacture_code, - *subghz_keystore_get_data(instance->keystore), - SubGhzKeyArray_t) { - res = strcmp( - furi_string_get_cstr(manufacture_code->name), instance->manufacture_name); - if(res == 0) { - switch(manufacture_code->type) { - case KEELOQ_LEARNING_SIMPLE: - //Simple Learning - hop = - subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key); - break; - case KEELOQ_LEARNING_NORMAL: - //Normal Learning - man = subghz_protocol_keeloq_common_normal_learning( - fix, manufacture_code->key); - hop = subghz_protocol_keeloq_common_encrypt(decrypt, man); - break; - case KEELOQ_LEARNING_UNKNOWN: - if(kl_type_en == 1) { - hop = subghz_protocol_keeloq_common_encrypt( - decrypt, manufacture_code->key); - } - if(kl_type_en == 2) { - man = subghz_protocol_keeloq_common_normal_learning( - fix, manufacture_code->key); - hop = subghz_protocol_keeloq_common_encrypt(decrypt, man); - } - break; - } - break; - } - } - } - if(hop) { - uint64_t yek = (uint64_t)fix << 32 | hop; - instance->generic.data = - subghz_protocol_blocks_reverse_key(yek, instance->generic.data_count_bit); - return true; - } else { - instance->manufacture_name = "Unknown"; - return false; - } -} - -bool subghz_protocol_star_line_create_data( - void* context, - FlipperFormat* flipper_format, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - const char* manufacture_name, - SubGhzRadioPreset* preset) { - furi_assert(context); - SubGhzProtocolEncoderStarLine* instance = context; - instance->generic.serial = serial; - instance->generic.cnt = cnt; - instance->manufacture_name = manufacture_name; - instance->generic.data_count_bit = 64; - bool res = subghz_protocol_star_line_gen_data(instance, btn); - if(res) { - return SubGhzProtocolStatusOk == - subghz_block_generic_serialize(&instance->generic, flipper_format, preset); - } - return res; -} - -/** - * Generating an upload from data. - * @param instance Pointer to a SubGhzProtocolEncoderKeeloq instance - * @return true On success - */ -static bool subghz_protocol_encoder_star_line_get_upload( - SubGhzProtocolEncoderStarLine* instance, - uint8_t btn) { - furi_assert(instance); - - // Gen new key - if(!subghz_protocol_star_line_gen_data(instance, btn)) { - return false; - } - - size_t index = 0; - size_t size_upload = 6 * 2 + (instance->generic.data_count_bit * 2); - if(size_upload > instance->encoder.size_upload) { - FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); - return false; - } else { - instance->encoder.size_upload = size_upload; - } - - //Send header - for(uint8_t i = 6; i > 0; i--) { - instance->encoder.upload[index++] = - level_duration_make(true, (uint32_t)subghz_protocol_star_line_const.te_long * 2); - instance->encoder.upload[index++] = - level_duration_make(false, (uint32_t)subghz_protocol_star_line_const.te_long * 2); - } - - //Send key data - for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { - if(bit_read(instance->generic.data, i - 1)) { - //send bit 1 - instance->encoder.upload[index++] = - level_duration_make(true, (uint32_t)subghz_protocol_star_line_const.te_long); - instance->encoder.upload[index++] = - level_duration_make(false, (uint32_t)subghz_protocol_star_line_const.te_long); - } else { - //send bit 0 - instance->encoder.upload[index++] = - level_duration_make(true, (uint32_t)subghz_protocol_star_line_const.te_short); - instance->encoder.upload[index++] = - level_duration_make(false, (uint32_t)subghz_protocol_star_line_const.te_short); - } - } - - return true; -} - -SubGhzProtocolStatus - subghz_protocol_encoder_star_line_deserialize(void* context, FlipperFormat* flipper_format) { - furi_assert(context); - SubGhzProtocolEncoderStarLine* instance = context; - SubGhzProtocolStatus res = SubGhzProtocolStatusError; - do { - if(SubGhzProtocolStatusOk != - subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - - // Read manufacturer from file - if(flipper_format_read_string( - flipper_format, "Manufacture", instance->manufacture_from_file)) { - instance->manufacture_name = furi_string_get_cstr(instance->manufacture_from_file); - instance->keystore->mfname = instance->manufacture_name; - } else { - FURI_LOG_D(TAG, "ENCODER: Missing Manufacture"); - } - - subghz_protocol_star_line_check_remote_controller( - &instance->generic, instance->keystore, &instance->manufacture_name); - - //optional parameter parameter - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - - subghz_protocol_encoder_star_line_get_upload(instance, instance->generic.btn); - - if(!flipper_format_rewind(flipper_format)) { - FURI_LOG_E(TAG, "Rewind error"); - break; - } - uint8_t key_data[sizeof(uint64_t)] = {0}; - for(size_t i = 0; i < sizeof(uint64_t); i++) { - key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data >> i * 8) & 0xFF; - } - if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { - FURI_LOG_E(TAG, "Unable to add Key"); - break; - } - - instance->encoder.is_running = true; - - res = SubGhzProtocolStatusOk; - } while(false); - - return res; -} - -void subghz_protocol_encoder_star_line_stop(void* context) { - SubGhzProtocolEncoderStarLine* instance = context; - instance->encoder.is_running = false; -} - -LevelDuration subghz_protocol_encoder_star_line_yield(void* context) { - SubGhzProtocolEncoderStarLine* instance = context; - - if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { - instance->encoder.is_running = false; - return level_duration_reset(); - } - - LevelDuration ret = instance->encoder.upload[instance->encoder.front]; - - if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; - instance->encoder.front = 0; - } - - return ret; -} - -void* subghz_protocol_decoder_star_line_alloc(SubGhzEnvironment* environment) { - SubGhzProtocolDecoderStarLine* instance = malloc(sizeof(SubGhzProtocolDecoderStarLine)); - instance->base.protocol = &subghz_protocol_star_line; - instance->generic.protocol_name = instance->base.protocol->name; - - instance->manufacture_from_file = furi_string_alloc(); - - instance->keystore = subghz_environment_get_keystore(environment); - - return instance; -} - -void subghz_protocol_decoder_star_line_free(void* context) { - furi_assert(context); - SubGhzProtocolDecoderStarLine* instance = context; - furi_string_free(instance->manufacture_from_file); - - free(instance); -} - -void subghz_protocol_decoder_star_line_reset(void* context) { - furi_assert(context); - SubGhzProtocolDecoderStarLine* instance = context; - instance->decoder.parser_step = StarLineDecoderStepReset; - // TODO - instance->keystore->mfname = ""; - instance->keystore->kl_type = 0; -} - -void subghz_protocol_decoder_star_line_feed(void* context, bool level, uint32_t duration) { - furi_assert(context); - SubGhzProtocolDecoderStarLine* instance = context; - - switch(instance->decoder.parser_step) { - case StarLineDecoderStepReset: - if(level) { - if(DURATION_DIFF(duration, subghz_protocol_star_line_const.te_long * 2) < - subghz_protocol_star_line_const.te_delta * 2) { - instance->decoder.parser_step = StarLineDecoderStepCheckPreambula; - instance->header_count++; - } else if(instance->header_count > 4) { - instance->decoder.decode_data = 0; - instance->decoder.decode_count_bit = 0; - instance->decoder.te_last = duration; - instance->decoder.parser_step = StarLineDecoderStepCheckDuration; - } - } else { - instance->header_count = 0; - } - break; - case StarLineDecoderStepCheckPreambula: - if((!level) && (DURATION_DIFF(duration, subghz_protocol_star_line_const.te_long * 2) < - subghz_protocol_star_line_const.te_delta * 2)) { - //Found Preambula - instance->decoder.parser_step = StarLineDecoderStepReset; - } else { - instance->header_count = 0; - instance->decoder.parser_step = StarLineDecoderStepReset; - } - break; - case StarLineDecoderStepSaveDuration: - if(level) { - if(duration >= (subghz_protocol_star_line_const.te_long + - subghz_protocol_star_line_const.te_delta)) { - instance->decoder.parser_step = StarLineDecoderStepReset; - if((instance->decoder.decode_count_bit >= - subghz_protocol_star_line_const.min_count_bit_for_found) && - (instance->decoder.decode_count_bit <= - subghz_protocol_star_line_const.min_count_bit_for_found + 2)) { - if(instance->generic.data != instance->decoder.decode_data) { - instance->generic.data = instance->decoder.decode_data; - instance->generic.data_count_bit = - subghz_protocol_star_line_const.min_count_bit_for_found; - if(instance->base.callback) - instance->base.callback(&instance->base, instance->base.context); - } - } - instance->decoder.decode_data = 0; - instance->decoder.decode_count_bit = 0; - instance->header_count = 0; - break; - } else { - instance->decoder.te_last = duration; - instance->decoder.parser_step = StarLineDecoderStepCheckDuration; - } - - } else { - instance->decoder.parser_step = StarLineDecoderStepReset; - } - break; - case StarLineDecoderStepCheckDuration: - if(!level) { - if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_star_line_const.te_short) < - subghz_protocol_star_line_const.te_delta) && - (DURATION_DIFF(duration, subghz_protocol_star_line_const.te_short) < - subghz_protocol_star_line_const.te_delta)) { - if(instance->decoder.decode_count_bit < - subghz_protocol_star_line_const.min_count_bit_for_found) { - subghz_protocol_blocks_add_bit(&instance->decoder, 0); - } else { - instance->decoder.decode_count_bit++; - } - instance->decoder.parser_step = StarLineDecoderStepSaveDuration; - } else if( - (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_star_line_const.te_long) < - subghz_protocol_star_line_const.te_delta) && - (DURATION_DIFF(duration, subghz_protocol_star_line_const.te_long) < - subghz_protocol_star_line_const.te_delta)) { - if(instance->decoder.decode_count_bit < - subghz_protocol_star_line_const.min_count_bit_for_found) { - subghz_protocol_blocks_add_bit(&instance->decoder, 1); - } else { - instance->decoder.decode_count_bit++; - } - instance->decoder.parser_step = StarLineDecoderStepSaveDuration; - } else { - instance->decoder.parser_step = StarLineDecoderStepReset; - } - } else { - instance->decoder.parser_step = StarLineDecoderStepReset; - } - break; - } -} - -/** - * Validation of decrypt data. - * @param instance Pointer to a SubGhzBlockGeneric instance - * @param decrypt Decrypd data - * @param btn Button number, 4 bit - * @param end_serial decrement the last 10 bits of the serial number - * @return true On success - */ -static inline bool subghz_protocol_star_line_check_decrypt( - SubGhzBlockGeneric* instance, - uint32_t decrypt, - uint8_t btn, - uint32_t end_serial) { - furi_assert(instance); - if((decrypt >> 24 == btn) && ((((uint16_t)(decrypt >> 16)) & 0x00FF) == end_serial)) { - instance->cnt = decrypt & 0x0000FFFF; - return true; - } - return false; -} - -/** - * Checking the accepted code against the database manafacture key - * @param instance Pointer to a SubGhzBlockGeneric* instance - * @param fix Fix part of the parcel - * @param hop Hop encrypted part of the parcel - * @param keystore Pointer to a SubGhzKeystore* instance - * @param manufacture_name - * @return true on successful search - */ -static uint8_t subghz_protocol_star_line_check_remote_controller_selector( - SubGhzBlockGeneric* instance, - uint32_t fix, - uint32_t hop, - SubGhzKeystore* keystore, - const char** manufacture_name) { - uint16_t end_serial = (uint16_t)(fix & 0xFF); - uint8_t btn = (uint8_t)(fix >> 24); - uint32_t decrypt = 0; - uint64_t man_normal_learning; - bool mf_not_set = false; - // TODO: - // if(mfname == 0x0) { - // mfname = ""; - // } - - const char* mfname = keystore->mfname; - - if(strcmp(mfname, "Unknown") == 0) { - return 1; - } else if(strcmp(mfname, "") == 0) { - mf_not_set = true; - } - for - M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) { - if(mf_not_set || (strcmp(furi_string_get_cstr(manufacture_code->name), mfname) == 0)) { - switch(manufacture_code->type) { - case KEELOQ_LEARNING_SIMPLE: - // Simple Learning - decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); - if(subghz_protocol_star_line_check_decrypt( - instance, decrypt, btn, end_serial)) { - *manufacture_name = furi_string_get_cstr(manufacture_code->name); - keystore->mfname = *manufacture_name; - return 1; - } - break; - case KEELOQ_LEARNING_NORMAL: - // Normal Learning - // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37 - man_normal_learning = - subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); - decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning); - if(subghz_protocol_star_line_check_decrypt( - instance, decrypt, btn, end_serial)) { - *manufacture_name = furi_string_get_cstr(manufacture_code->name); - keystore->mfname = *manufacture_name; - return 1; - } - break; - case KEELOQ_LEARNING_UNKNOWN: - // Simple Learning - decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); - if(subghz_protocol_star_line_check_decrypt( - instance, decrypt, btn, end_serial)) { - *manufacture_name = furi_string_get_cstr(manufacture_code->name); - keystore->mfname = *manufacture_name; - keystore->kl_type = 1; - return 1; - } - // Check for mirrored man - uint64_t man_rev = 0; - uint64_t man_rev_byte = 0; - for(uint8_t i = 0; i < 64; i += 8) { - man_rev_byte = (uint8_t)(manufacture_code->key >> i); - man_rev = man_rev | man_rev_byte << (56 - i); - } - decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev); - if(subghz_protocol_star_line_check_decrypt( - instance, decrypt, btn, end_serial)) { - *manufacture_name = furi_string_get_cstr(manufacture_code->name); - keystore->mfname = *manufacture_name; - keystore->kl_type = 1; - return 1; - } - //########################### - // Normal Learning - // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37 - man_normal_learning = - subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); - decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning); - if(subghz_protocol_star_line_check_decrypt( - instance, decrypt, btn, end_serial)) { - *manufacture_name = furi_string_get_cstr(manufacture_code->name); - keystore->mfname = *manufacture_name; - keystore->kl_type = 2; - return 1; - } - // Check for mirrored man - man_normal_learning = - subghz_protocol_keeloq_common_normal_learning(fix, man_rev); - decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning); - if(subghz_protocol_star_line_check_decrypt( - instance, decrypt, btn, end_serial)) { - *manufacture_name = furi_string_get_cstr(manufacture_code->name); - keystore->mfname = *manufacture_name; - keystore->kl_type = 2; - return 1; - } - break; - } - } - } - - *manufacture_name = "Unknown"; - keystore->mfname = "Unknown"; - instance->cnt = 0; - - return 0; -} - -/** - * Analysis of received data - * @param instance Pointer to a SubGhzBlockGeneric* instance - * @param keystore Pointer to a SubGhzKeystore* instance - * @param manufacture_name - */ -static void subghz_protocol_star_line_check_remote_controller( - SubGhzBlockGeneric* instance, - SubGhzKeystore* keystore, - const char** manufacture_name) { - uint64_t key = subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit); - uint32_t key_fix = key >> 32; - uint32_t key_hop = key & 0x00000000ffffffff; - - subghz_protocol_star_line_check_remote_controller_selector( - instance, key_fix, key_hop, keystore, manufacture_name); - - instance->serial = key_fix & 0x00FFFFFF; - instance->btn = key_fix >> 24; -} - -uint8_t subghz_protocol_decoder_star_line_get_hash_data(void* context) { - furi_assert(context); - SubGhzProtocolDecoderStarLine* instance = context; - return subghz_protocol_blocks_get_hash_data( - &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); -} - -SubGhzProtocolStatus subghz_protocol_decoder_star_line_serialize( - void* context, - FlipperFormat* flipper_format, - SubGhzRadioPreset* preset) { - furi_assert(context); - SubGhzProtocolDecoderStarLine* instance = context; - subghz_protocol_star_line_check_remote_controller( - &instance->generic, instance->keystore, &instance->manufacture_name); - SubGhzProtocolStatus ret = - subghz_block_generic_serialize(&instance->generic, flipper_format, preset); - - if((ret == SubGhzProtocolStatusOk) && - !flipper_format_write_string_cstr( - flipper_format, "Manufacture", instance->manufacture_name)) { - FURI_LOG_E(TAG, "Unable to add manufacture name"); - ret = SubGhzProtocolStatusErrorParserOthers; - } - if((ret == SubGhzProtocolStatusOk) && - instance->generic.data_count_bit != - subghz_protocol_star_line_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - ret = SubGhzProtocolStatusErrorParserOthers; - } - return ret; -} - -SubGhzProtocolStatus - subghz_protocol_decoder_star_line_deserialize(void* context, FlipperFormat* flipper_format) { - furi_assert(context); - SubGhzProtocolDecoderStarLine* instance = context; - SubGhzProtocolStatus res = SubGhzProtocolStatusError; - do { - if(SubGhzProtocolStatusOk != - subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - - // Read manufacturer from file - if(flipper_format_read_string( - flipper_format, "Manufacture", instance->manufacture_from_file)) { - instance->manufacture_name = furi_string_get_cstr(instance->manufacture_from_file); - instance->keystore->mfname = instance->manufacture_name; - } else { - FURI_LOG_D(TAG, "DECODER: Missing Manufacture"); - } - - res = SubGhzProtocolStatusOk; - } while(false); - - return res; -} - -void subghz_protocol_decoder_star_line_get_string(void* context, FuriString* output) { - furi_assert(context); - SubGhzProtocolDecoderStarLine* instance = context; - - subghz_protocol_star_line_check_remote_controller( - &instance->generic, instance->keystore, &instance->manufacture_name); - - uint32_t code_found_hi = instance->generic.data >> 32; - uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; - - uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key( - instance->generic.data, instance->generic.data_count_bit); - uint32_t code_found_reverse_hi = code_found_reverse >> 32; - uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; - - // push protocol data to global variable - subghz_block_generic_global.cnt_is_available = true; - subghz_block_generic_global.cnt_length_bit = 16; - subghz_block_generic_global.current_cnt = instance->generic.cnt; - - furi_string_cat_printf( - output, - "%s %dbit\r\n" - "Key:%08lX%08lX\r\n" - "Fix:0x%08lX Cnt:%04lX\r\n" - "Hop:0x%08lX Btn:%02X\r\n" - "MF:%s\r\n", - instance->generic.protocol_name, - instance->generic.data_count_bit, - code_found_hi, - code_found_lo, - code_found_reverse_hi, - instance->generic.cnt, - code_found_reverse_lo, - instance->generic.btn, - instance->manufacture_name); -} diff --git a/lib/subghz/protocols/star_line.h b/lib/subghz/protocols/star_line.h deleted file mode 100644 index e7b15ca0b..000000000 --- a/lib/subghz/protocols/star_line.h +++ /dev/null @@ -1,109 +0,0 @@ -#pragma once - -#include "base.h" - -#define SUBGHZ_PROTOCOL_STAR_LINE_NAME "Star Line" - -typedef struct SubGhzProtocolDecoderStarLine SubGhzProtocolDecoderStarLine; -typedef struct SubGhzProtocolEncoderStarLine SubGhzProtocolEncoderStarLine; - -extern const SubGhzProtocolDecoder subghz_protocol_star_line_decoder; -extern const SubGhzProtocolEncoder subghz_protocol_star_line_encoder; -extern const SubGhzProtocol subghz_protocol_star_line; - -/** - * Allocate SubGhzProtocolEncoderStarLine. - * @param environment Pointer to a SubGhzEnvironment instance - * @return SubGhzProtocolEncoderStarLine* pointer to a SubGhzProtocolEncoderStarLine instance - */ -void* subghz_protocol_encoder_star_line_alloc(SubGhzEnvironment* environment); - -/** - * Free SubGhzProtocolEncoderStarLine. - * @param context Pointer to a SubGhzProtocolEncoderStarLine instance - */ -void subghz_protocol_encoder_star_line_free(void* context); - -/** - * Deserialize and generating an upload to send. - * @param context Pointer to a SubGhzProtocolEncoderStarLine instance - * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success - */ -SubGhzProtocolStatus - subghz_protocol_encoder_star_line_deserialize(void* context, FlipperFormat* flipper_format); - -/** - * Forced transmission stop. - * @param context Pointer to a SubGhzProtocolEncoderStarLine instance - */ -void subghz_protocol_encoder_star_line_stop(void* context); - -/** - * Getting the level and duration of the upload to be loaded into DMA. - * @param context Pointer to a SubGhzProtocolEncoderStarLine instance - * @return LevelDuration - */ -LevelDuration subghz_protocol_encoder_star_line_yield(void* context); - -/** - * Allocate SubGhzProtocolDecoderStarLine. - * @param environment Pointer to a SubGhzEnvironment instance - * @return SubGhzProtocolDecoderStarLine* pointer to a SubGhzProtocolDecoderStarLine instance - */ -void* subghz_protocol_decoder_star_line_alloc(SubGhzEnvironment* environment); - -/** - * Free SubGhzProtocolDecoderStarLine. - * @param context Pointer to a SubGhzProtocolDecoderStarLine instance - */ -void subghz_protocol_decoder_star_line_free(void* context); - -/** - * Reset decoder SubGhzProtocolDecoderStarLine. - * @param context Pointer to a SubGhzProtocolDecoderStarLine instance - */ -void subghz_protocol_decoder_star_line_reset(void* context); - -/** - * Parse a raw sequence of levels and durations received from the air. - * @param context Pointer to a SubGhzProtocolDecoderStarLine instance - * @param level Signal level true-high false-low - * @param duration Duration of this level in, us - */ -void subghz_protocol_decoder_star_line_feed(void* context, bool level, uint32_t duration); - -/** - * Getting the hash sum of the last randomly received parcel. - * @param context Pointer to a SubGhzProtocolDecoderStarLine instance - * @return hash Hash sum - */ -uint8_t subghz_protocol_decoder_star_line_get_hash_data(void* context); - -/** - * Serialize data SubGhzProtocolDecoderStarLine. - * @param context Pointer to a SubGhzProtocolDecoderStarLine instance - * @param flipper_format Pointer to a FlipperFormat instance - * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return status - */ -SubGhzProtocolStatus subghz_protocol_decoder_star_line_serialize( - void* context, - FlipperFormat* flipper_format, - SubGhzRadioPreset* preset); - -/** - * Deserialize data SubGhzProtocolDecoderStarLine. - * @param context Pointer to a SubGhzProtocolDecoderStarLine instance - * @param flipper_format Pointer to a FlipperFormat instance - * @return status - */ -SubGhzProtocolStatus - subghz_protocol_decoder_star_line_deserialize(void* context, FlipperFormat* flipper_format); - -/** - * Getting a textual representation of the received data. - * @param context Pointer to a SubGhzProtocolDecoderStarLine instance - * @param output Resulting text - */ -void subghz_protocol_decoder_star_line_get_string(void* context, FuriString* output); diff --git a/lib/subghz/types.h b/lib/subghz/types.h index cd7f74ba9..3c962730a 100644 --- a/lib/subghz/types.h +++ b/lib/subghz/types.h @@ -125,7 +125,7 @@ typedef enum { SubGhzProtocolFlag_Load = (1 << 8), SubGhzProtocolFlag_Send = (1 << 9), SubGhzProtocolFlag_BinRAW = (1 << 10), - SubGhzProtocolFlag_Cars = (1 << 11), + SubGhzProtocolFlag_ReversRB2 = (1 << 11), SubGhzProtocolFlag_Alarms = (1 << 12), SubGhzProtocolFlag_Sensors = (1 << 13), SubGhzProtocolFlag_Princeton = (1 << 14), From 5bb5b41e6ae99ae1a86de247b7376b58aeb30f57 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 12 Jan 2026 08:26:20 +0300 Subject: [PATCH 034/160] api update --- lib/subghz/protocols/public_api.h | 20 -------------------- targets/f7/api_symbols.csv | 1 - 2 files changed, 21 deletions(-) diff --git a/lib/subghz/protocols/public_api.h b/lib/subghz/protocols/public_api.h index 76cdb2525..c9a866f2c 100644 --- a/lib/subghz/protocols/public_api.h +++ b/lib/subghz/protocols/public_api.h @@ -159,26 +159,6 @@ bool subghz_protocol_nice_flor_s_create_data( SubGhzRadioPreset* preset, bool nice_one); -/** - * Key generation from simple data. - * @param context Pointer to a SubGhzProtocolEncoderStarLine instance - * @param flipper_format Pointer to a FlipperFormat instance - * @param serial Serial number, 24 bit - * @param btn Button number, 8 bit - * @param cnt Counter value, 16 bit - * @param manufacture_name Name of manufacturer's key - * @param preset Modulation, SubGhzRadioPreset - * @return true On success - */ -bool subghz_protocol_star_line_create_data( - void* context, - FlipperFormat* flipper_format, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - const char* manufacture_name, - SubGhzRadioPreset* preset); - /** * Key generation from simple data. * @param context Pointer to a SubGhzProtocolEncoderSomfyTelis instance diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index a293d7430..2e59c7d51 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -3742,7 +3742,6 @@ Function,+,subghz_protocol_secplus_v1_check_fixed,_Bool,uint32_t Function,+,subghz_protocol_secplus_v2_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint32_t, SubGhzRadioPreset*" Function,+,subghz_protocol_somfy_keytis_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*" Function,+,subghz_protocol_somfy_telis_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*" -Function,+,subghz_protocol_star_line_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, const char*, SubGhzRadioPreset*" Function,+,subghz_receiver_alloc_init,SubGhzReceiver*,SubGhzEnvironment* Function,+,subghz_receiver_decode,void,"SubGhzReceiver*, _Bool, uint32_t" Function,+,subghz_receiver_free,void,SubGhzReceiver* From 161db6ebc6c8fd907abc1965836f49454323d29e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 13 Jan 2026 05:29:30 +0300 Subject: [PATCH 035/160] Fix button mapping for faac rc xt --- lib/subghz/protocols/keeloq.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 6b03badb9..a13066ed2 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -1366,6 +1366,12 @@ static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code) { case 0xF: btn = 0x1; break; + case 0x9: + btn = 0x2; + break; + case 0x6: + btn = 0x2; + break; default: btn = 0x1; @@ -1391,6 +1397,12 @@ static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code) { case 0xF: btn = 0x4; break; + case 0x9: + btn = 0x4; + break; + case 0x6: + btn = 0x4; + break; default: btn = 0x4; @@ -1416,6 +1428,12 @@ static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code) { case 0xF: btn = 0x8; break; + case 0x9: + btn = 0x6; + break; + case 0x6: + btn = 0x9; + break; default: btn = 0x8; @@ -1441,9 +1459,15 @@ static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code) { case 0xF: btn = 0x2; break; + case 0x9: + btn = last_btn_code; + break; + case 0x6: + btn = last_btn_code; + break; default: - btn = 0x2; + btn = last_btn_code; break; } } From 6265dad0b735de36db4d0a41c214390141a1c1ec Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 15 Jan 2026 03:22:32 +0300 Subject: [PATCH 036/160] Fix for sommer? [ci skip] --- documentation/SubGHzSupportedSystems.md | 2 +- lib/subghz/devices/cc1101_configs.c | 2 +- lib/subghz/devices/preset.h | 2 +- lib/subghz/protocols/keeloq.c | 8 ++++++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/documentation/SubGHzSupportedSystems.md b/documentation/SubGHzSupportedSystems.md index 4f7214abd..b011bc36c 100644 --- a/documentation/SubGHzSupportedSystems.md +++ b/documentation/SubGHzSupportedSystems.md @@ -119,7 +119,7 @@ The following manufacturers have KeeLoq support in Unleashed firmware: - Nice Smilo - `433.92MHz` `AM650` (KeeLoq, 64 bits) (8bit serial part in Hop - simple learning) - Normstahl - `433.92MHz` `AM650` (KeeLoq, 64 bits) - Novoferm - `433.92MHz` `AM650` (KeeLoq, 64 bits) -- Sommer `434.42MHz, 868.80MHz` `FSK12K (or FSK476)` (KeeLoq, 64 bits) (normal learning) +- Sommer `434.42MHz, 868.80MHz` `FSK12K (or FSK476)` (KeeLoq, 64 bits) (normal learning) (TX03-868-4, Pearl, and maybe other models are supported (SOMloq2)) - Steelmate - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) - Stilmatic - `433.92MHz` `AM650` (KeeLoq, 64 bits) (normal learning) diff --git a/lib/subghz/devices/cc1101_configs.c b/lib/subghz/devices/cc1101_configs.c index 971c3cb28..5a550ba5d 100644 --- a/lib/subghz/devices/cc1101_configs.c +++ b/lib/subghz/devices/cc1101_configs.c @@ -248,7 +248,7 @@ const uint8_t subghz_device_cc1101_preset_2fsk_dev12khz_async_regs[] = { CC1101_MDMCFG4, 0x67, //Rx BW filter is 270.833333 kHz CC1101_DEVIATN, - 0x30, //Deviation ~12 kHz + 0x30, //Deviation 12.695312 kHz /* Main Radio Control State Machine */ CC1101_MCSM0, diff --git a/lib/subghz/devices/preset.h b/lib/subghz/devices/preset.h index 6f67594af..e80b4b4bd 100644 --- a/lib/subghz/devices/preset.h +++ b/lib/subghz/devices/preset.h @@ -6,7 +6,7 @@ typedef enum { FuriHalSubGhzPresetOok270Async, /**< OOK, bandwidth 270kHz, asynchronous */ FuriHalSubGhzPresetOok650Async, /**< OOK, bandwidth 650kHz, asynchronous */ FuriHalSubGhzPreset2FSKDev238Async, /**< FM, deviation 2.380371 kHz, asynchronous */ - FuriHalSubGhzPreset2FSKDev12KAsync, /**< FM, deviation ~12 kHz, asynchronous */ + FuriHalSubGhzPreset2FSKDev12KAsync, /**< FM, deviation 12.695312 kHz, asynchronous */ FuriHalSubGhzPreset2FSKDev476Async, /**< FM, deviation 47.60742 kHz, asynchronous */ FuriHalSubGhzPresetMSK99_97KbAsync, /**< MSK, deviation 47.60742 kHz, 99.97Kb/s, asynchronous */ FuriHalSubGhzPresetGFSK9_99KbAsync, /**< GFSK, deviation 19.042969 kHz, 9.996Kb/s, asynchronous */ diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index a13066ed2..e0bfaef57 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -526,6 +526,11 @@ static bool klq_last_custom_btn = 0xD; } + uint32_t gap_duration = subghz_protocol_keeloq_const.te_short * 40; + if((strcmp(instance->manufacture_name, "Sommer") == 0)) { + gap_duration = subghz_protocol_keeloq_const.te_short * 29; + } + btn = subghz_protocol_keeloq_get_btn_code(klq_last_custom_btn); // Generate new key @@ -580,8 +585,7 @@ static bool // send end instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short); - instance->encoder.upload[index++] = - level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_short * 40); + instance->encoder.upload[index++] = level_duration_make(false, gap_duration); return true; } From edb86fa279b3c5451c30fa309dc4ef970df2187e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 17 Jan 2026 01:55:08 +0300 Subject: [PATCH 037/160] subghz: add treadmill37 protocol --- documentation/SubGHzSupportedSystems.md | 1 + lib/subghz/protocols/protocol_items.c | 2 +- lib/subghz/protocols/protocol_items.h | 1 + lib/subghz/protocols/treadmill37.c | 349 ++++++++++++++++++++++++ lib/subghz/protocols/treadmill37.h | 109 ++++++++ 5 files changed, 461 insertions(+), 1 deletion(-) create mode 100644 lib/subghz/protocols/treadmill37.c create mode 100644 lib/subghz/protocols/treadmill37.h diff --git a/documentation/SubGHzSupportedSystems.md b/documentation/SubGHzSupportedSystems.md index b011bc36c..a30a9e475 100644 --- a/documentation/SubGHzSupportedSystems.md +++ b/documentation/SubGHzSupportedSystems.md @@ -78,6 +78,7 @@ That list is only for default SubGHz app, apps like *Weather Station* have their - Princeton (PT2262, PT****) `315MHz, 433.92MHz, Any other frequency` `AM650` (24 bits, Static) - SMC5326 `315MHz, 433.92MHz, Any other frequency` `AM650` (25 bits, Static) - Hay21 `433.92MHz` `AM650` (21 bits, Dynamic) +- Treadmill37 (QH-433) `433.92MHz` `AM650` (37 bits, Static) --- diff --git a/lib/subghz/protocols/protocol_items.c b/lib/subghz/protocols/protocol_items.c index c15d578bb..230b9a508 100644 --- a/lib/subghz/protocols/protocol_items.c +++ b/lib/subghz/protocols/protocol_items.c @@ -26,7 +26,7 @@ const SubGhzProtocol* const subghz_protocol_registry_items[] = { &subghz_protocol_marantec24, &subghz_protocol_hollarm, &subghz_protocol_hay21, &subghz_protocol_revers_rb2, &subghz_protocol_feron, &subghz_protocol_roger, - &subghz_protocol_elplast, + &subghz_protocol_elplast, &subghz_protocol_treadmill37, }; const SubGhzProtocolRegistry subghz_protocol_registry = { diff --git a/lib/subghz/protocols/protocol_items.h b/lib/subghz/protocols/protocol_items.h index 863f601b4..223dd1712 100644 --- a/lib/subghz/protocols/protocol_items.h +++ b/lib/subghz/protocols/protocol_items.h @@ -53,3 +53,4 @@ #include "feron.h" #include "roger.h" #include "elplast.h" +#include "treadmill37.h" diff --git a/lib/subghz/protocols/treadmill37.c b/lib/subghz/protocols/treadmill37.c new file mode 100644 index 000000000..215b48e71 --- /dev/null +++ b/lib/subghz/protocols/treadmill37.c @@ -0,0 +1,349 @@ +#include "treadmill37.h" +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocolTreadmill37" + +static const SubGhzBlockConst subghz_protocol_treadmill37_const = { + .te_short = 300, + .te_long = 900, + .te_delta = 150, + .min_count_bit_for_found = 37, +}; + +struct SubGhzProtocolDecoderTreadmill37 { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; +}; + +struct SubGhzProtocolEncoderTreadmill37 { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + Treadmill37DecoderStepReset = 0, + Treadmill37DecoderStepSaveDuration, + Treadmill37DecoderStepCheckDuration, +} Treadmill37DecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_treadmill37_decoder = { + .alloc = subghz_protocol_decoder_treadmill37_alloc, + .free = subghz_protocol_decoder_treadmill37_free, + + .feed = subghz_protocol_decoder_treadmill37_feed, + .reset = subghz_protocol_decoder_treadmill37_reset, + + .get_hash_data = subghz_protocol_decoder_treadmill37_get_hash_data, + .serialize = subghz_protocol_decoder_treadmill37_serialize, + .deserialize = subghz_protocol_decoder_treadmill37_deserialize, + .get_string = subghz_protocol_decoder_treadmill37_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_treadmill37_encoder = { + .alloc = subghz_protocol_encoder_treadmill37_alloc, + .free = subghz_protocol_encoder_treadmill37_free, + + .deserialize = subghz_protocol_encoder_treadmill37_deserialize, + .stop = subghz_protocol_encoder_treadmill37_stop, + .yield = subghz_protocol_encoder_treadmill37_yield, +}; + +const SubGhzProtocol subghz_protocol_treadmill37 = { + .name = SUBGHZ_PROTOCOL_TREADMILL37_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_treadmill37_decoder, + .encoder = &subghz_protocol_treadmill37_encoder, +}; + +void* subghz_protocol_encoder_treadmill37_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderTreadmill37* instance = malloc(sizeof(SubGhzProtocolEncoderTreadmill37)); + + instance->base.protocol = &subghz_protocol_treadmill37; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 256; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + return instance; +} + +void subghz_protocol_encoder_treadmill37_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderTreadmill37* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderTreadmill37 instance + */ +static void + subghz_protocol_encoder_treadmill37_get_upload(SubGhzProtocolEncoderTreadmill37* instance) { + furi_assert(instance); + size_t index = 0; + + // Send key and GAP + for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { + if(bit_read(instance->generic.data, i - 1)) { + // Send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_treadmill37_const.te_long); + if(i == 1) { + //Send gap if bit was last + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_treadmill37_const.te_short * 20); + } else { + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_treadmill37_const.te_short); + } + } else { + // Send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_treadmill37_const.te_short); + if(i == 1) { + //Send gap if bit was last + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_treadmill37_const.te_short * 20); + } else { + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_treadmill37_const.te_long); + } + } + } + + instance->encoder.size_upload = index; + return; +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_treadmill37_check_remote_controller(SubGhzBlockGeneric* instance) { + instance->serial = instance->data >> 17; + instance->cnt = (instance->data >> 1) & 0xFFFF; +} + +SubGhzProtocolStatus + subghz_protocol_encoder_treadmill37_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderTreadmill37* instance = context; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; + do { + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_treadmill37_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_treadmill37_check_remote_controller(&instance->generic); + subghz_protocol_encoder_treadmill37_get_upload(instance); + instance->encoder.is_running = true; + } while(false); + + return ret; +} + +void subghz_protocol_encoder_treadmill37_stop(void* context) { + SubGhzProtocolEncoderTreadmill37* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_treadmill37_yield(void* context) { + SubGhzProtocolEncoderTreadmill37* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_treadmill37_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderTreadmill37* instance = malloc(sizeof(SubGhzProtocolDecoderTreadmill37)); + instance->base.protocol = &subghz_protocol_treadmill37; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_treadmill37_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderTreadmill37* instance = context; + free(instance); +} + +void subghz_protocol_decoder_treadmill37_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderTreadmill37* instance = context; + instance->decoder.parser_step = Treadmill37DecoderStepReset; +} + +void subghz_protocol_decoder_treadmill37_feed( + void* context, + bool level, + volatile uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderTreadmill37* instance = context; + + // Treadmill37 (QH-433) Decoder + // 2026 - @xMasterX (MMX) + + // Key samples + // serial button stop + // 1800001830 = 00011000000000000000000 0000110000011000 0 + // 180000061E = 00011000000000000000000 0000001100001111 0 + // 180000142C = 00011000000000000000000 0000101000010110 0 + // 1800000C24 = 00011000000000000000000 0000011000010010 0 + // 180001556C = 00011000000000000000000 1010101010110110 0 + // 180001334A = 00011000000000000000000 1001100110100101 0 + + switch(instance->decoder.parser_step) { + case Treadmill37DecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_treadmill37_const.te_short * 20) < + subghz_protocol_treadmill37_const.te_delta * 4)) { + //Found GAP + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + instance->decoder.parser_step = Treadmill37DecoderStepSaveDuration; + } + break; + case Treadmill37DecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = Treadmill37DecoderStepCheckDuration; + } else { + instance->decoder.parser_step = Treadmill37DecoderStepReset; + } + break; + case Treadmill37DecoderStepCheckDuration: + if(!level) { + // Bit 0 is short and long timing = 300us HIGH (te_last) and 900us LOW + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_treadmill37_const.te_short) < + subghz_protocol_treadmill37_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_treadmill37_const.te_long) < + subghz_protocol_treadmill37_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = Treadmill37DecoderStepSaveDuration; + // Bit 1 is long and short timing = 900us HIGH (te_last) and 300us LOW + } else if( + (DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_treadmill37_const.te_long) < + subghz_protocol_treadmill37_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_treadmill37_const.te_short) < + subghz_protocol_treadmill37_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = Treadmill37DecoderStepSaveDuration; + } else if( + // End of the key + DURATION_DIFF(duration, subghz_protocol_treadmill37_const.te_short * 20) < + subghz_protocol_treadmill37_const.te_delta * 4) { + //Found next GAP and add bit 0 or 1 (only bit 0 was found on the remotes) + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_treadmill37_const.te_short) < + subghz_protocol_treadmill37_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + } + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_treadmill37_const.te_long) < + subghz_protocol_treadmill37_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + } + // If got 37 bits key reading is finished + if(instance->decoder.decode_count_bit == + subghz_protocol_treadmill37_const.min_count_bit_for_found) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + instance->decoder.parser_step = Treadmill37DecoderStepReset; + } else { + instance->decoder.parser_step = Treadmill37DecoderStepReset; + } + } else { + instance->decoder.parser_step = Treadmill37DecoderStepReset; + } + break; + } +} + +uint8_t subghz_protocol_decoder_treadmill37_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderTreadmill37* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +SubGhzProtocolStatus subghz_protocol_decoder_treadmill37_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolDecoderTreadmill37* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +SubGhzProtocolStatus + subghz_protocol_decoder_treadmill37_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderTreadmill37* instance = context; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_treadmill37_const.min_count_bit_for_found); +} + +void subghz_protocol_decoder_treadmill37_get_string(void* context, FuriString* output) { + furi_assert(context); + SubGhzProtocolDecoderTreadmill37* instance = context; + + subghz_protocol_treadmill37_check_remote_controller(&instance->generic); + + uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key( + instance->generic.data, instance->generic.data_count_bit); + + furi_string_cat_printf( + output, + "%s %db\r\n" + "Key: 0x%08llX\r\n" + "Yek: 0x%08llX\r\n" + "Serial: 0x%06lX\r\n" + "Btn: %04lX", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint64_t)(instance->generic.data & 0xFFFFFFFFFF), + (code_found_reverse & 0xFFFFFFFFFF), + instance->generic.serial, + instance->generic.cnt); +} diff --git a/lib/subghz/protocols/treadmill37.h b/lib/subghz/protocols/treadmill37.h new file mode 100644 index 000000000..8954266f6 --- /dev/null +++ b/lib/subghz/protocols/treadmill37.h @@ -0,0 +1,109 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_TREADMILL37_NAME "Treadmill37" + +typedef struct SubGhzProtocolDecoderTreadmill37 SubGhzProtocolDecoderTreadmill37; +typedef struct SubGhzProtocolEncoderTreadmill37 SubGhzProtocolEncoderTreadmill37; + +extern const SubGhzProtocolDecoder subghz_protocol_treadmill37_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_treadmill37_encoder; +extern const SubGhzProtocol subghz_protocol_treadmill37; + +/** + * Allocate SubGhzProtocolEncoderTreadmill37. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderTreadmill37* pointer to a SubGhzProtocolEncoderTreadmill37 instance + */ +void* subghz_protocol_encoder_treadmill37_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderTreadmill37. + * @param context Pointer to a SubGhzProtocolEncoderTreadmill37 instance + */ +void subghz_protocol_encoder_treadmill37_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderTreadmill37 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return status + */ +SubGhzProtocolStatus + subghz_protocol_encoder_treadmill37_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderTreadmill37 instance + */ +void subghz_protocol_encoder_treadmill37_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderTreadmill37 instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_treadmill37_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderTreadmill37. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderTreadmill37* pointer to a SubGhzProtocolDecoderTreadmill37 instance + */ +void* subghz_protocol_decoder_treadmill37_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderTreadmill37. + * @param context Pointer to a SubGhzProtocolDecoderTreadmill37 instance + */ +void subghz_protocol_decoder_treadmill37_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderTreadmill37. + * @param context Pointer to a SubGhzProtocolDecoderTreadmill37 instance + */ +void subghz_protocol_decoder_treadmill37_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderTreadmill37 instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_treadmill37_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderTreadmill37 instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_treadmill37_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderTreadmill37. + * @param context Pointer to a SubGhzProtocolDecoderTreadmill37 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return status + */ +SubGhzProtocolStatus subghz_protocol_decoder_treadmill37_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data SubGhzProtocolDecoderTreadmill37. + * @param context Pointer to a SubGhzProtocolDecoderTreadmill37 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return status + */ +SubGhzProtocolStatus + subghz_protocol_decoder_treadmill37_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderTreadmill37 instance + * @param output Resulting text + */ +void subghz_protocol_decoder_treadmill37_get_string(void* context, FuriString* output); From db2dc8f64ff1814cab1f7b5b84071dcd28ff31e8 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 21 Jan 2026 07:58:42 +0300 Subject: [PATCH 038/160] subghz: add beninca arc protocol --- .../main/subghz/helpers/subghz_custom_event.h | 1 + .../main/subghz/helpers/subghz_gen_info.c | 9 + .../main/subghz/helpers/subghz_gen_info.h | 6 + .../helpers/subghz_txrx_create_protocol_key.c | 30 + .../helpers/subghz_txrx_create_protocol_key.h | 8 + .../resources/subghz/assets/keeloq_mfcodes | 135 ++-- .../subghz/scenes/subghz_scene_set_button.c | 5 + .../subghz/scenes/subghz_scene_set_counter.c | 16 + .../subghz/scenes/subghz_scene_set_seed.c | 2 + .../subghz/scenes/subghz_scene_set_serial.c | 9 + .../subghz/scenes/subghz_scene_set_type.c | 13 +- lib/subghz/protocols/aes_common.c | 252 +++++++ lib/subghz/protocols/aes_common.h | 10 + lib/subghz/protocols/beninca_arc.c | 679 ++++++++++++++++++ lib/subghz/protocols/beninca_arc.h | 108 +++ lib/subghz/protocols/keeloq_common.h | 1 + lib/subghz/protocols/protocol_items.c | 1 + lib/subghz/protocols/protocol_items.h | 1 + lib/subghz/protocols/public_api.h | 18 + targets/f7/api_symbols.csv | 3 +- 20 files changed, 1238 insertions(+), 69 deletions(-) create mode 100644 lib/subghz/protocols/aes_common.c create mode 100644 lib/subghz/protocols/aes_common.h create mode 100644 lib/subghz/protocols/beninca_arc.c create mode 100644 lib/subghz/protocols/beninca_arc.h diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index e52cf1897..4fb40f5c0 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -71,6 +71,7 @@ typedef enum { SetTypeBFTMitto, SetTypeSomfyTelis, SetTypeKingGatesStylo4k, + SetTypeBenincaARC, SetTypeANMotorsAT4, SetTypeAlutechAT4N, SetTypePhoenix_V2_433, diff --git a/applications/main/subghz/helpers/subghz_gen_info.c b/applications/main/subghz/helpers/subghz_gen_info.c index 388327da2..a0f07a1d8 100644 --- a/applications/main/subghz/helpers/subghz_gen_info.c +++ b/applications/main/subghz/helpers/subghz_gen_info.c @@ -532,6 +532,15 @@ void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType ty .kinggates_stylo_4k.btn = 0x0E, .kinggates_stylo_4k.cnt = 0x03}; break; + case SetTypeBenincaARC: + gen_info = (GenInfo){ + .type = GenBenincaARC, + .mod = "AM650", + .freq = 433920000, + .beninca_arc.serial = key & 0x00FFFFFF, + .beninca_arc.btn = 0x02, + .beninca_arc.cnt = 0x03}; + break; case SetTypeMotorline433: gen_info = (GenInfo){ .type = GenKeeloq, diff --git a/applications/main/subghz/helpers/subghz_gen_info.h b/applications/main/subghz/helpers/subghz_gen_info.h index f54992738..e47c218d6 100644 --- a/applications/main/subghz/helpers/subghz_gen_info.h +++ b/applications/main/subghz/helpers/subghz_gen_info.h @@ -11,6 +11,7 @@ typedef enum { GenAlutechAt4n, GenSomfyTelis, GenKingGatesStylo4k, + GenBenincaARC, GenNiceFlorS, GenSecPlus1, GenSecPlus2, @@ -67,6 +68,11 @@ typedef struct { uint8_t btn; uint16_t cnt; } kinggates_stylo_4k; + struct { + uint32_t serial; + uint8_t btn; + uint32_t cnt; + } beninca_arc; struct { uint32_t serial; uint8_t btn; diff --git a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c index 1c0add497..075720dfc 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c +++ b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c @@ -365,6 +365,36 @@ bool subghz_txrx_gen_kinggates_stylo_4k_protocol( return res; } +bool subghz_txrx_gen_beninca_arc_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint32_t cnt) { + SubGhzTxRx* txrx = context; + + bool res = false; + + txrx->transmitter = + subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_BENINCA_ARC_NAME); + subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); + + if(txrx->transmitter && subghz_protocol_beninca_arc_create_data( + subghz_transmitter_get_protocol_instance(txrx->transmitter), + txrx->fff_data, + serial, + btn, + cnt, + txrx->preset)) { + res = true; + } + + subghz_transmitter_free(txrx->transmitter); + + return res; +} + bool subghz_txrx_gen_secplus_v2_protocol( SubGhzTxRx* instance, const char* name_preset, diff --git a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h index 590f9fa5b..afc1059b5 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h +++ b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h @@ -116,6 +116,14 @@ bool subghz_txrx_gen_kinggates_stylo_4k_protocol( uint8_t btn, uint16_t cnt); +bool subghz_txrx_gen_beninca_arc_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint32_t cnt); + bool subghz_txrx_gen_came_atomo_protocol( void* context, const char* preset_name, diff --git a/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes b/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes index fddea5abd..b55548844 100644 --- a/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes +++ b/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes @@ -1,70 +1,71 @@ Filetype: Flipper SubGhz Keystore File Version: 0 Encryption: 1 -IV: 46 75 72 72 79 20 49 56 20 4F 77 4F 20 55 77 55 -30A13FCF86676F7027AF9D7BECBAA6A08C83B0DB00E4FFFB6F53249D0EA057AD -2D3AA216E454121B2C4DAC9EEE2502ECADCDC0B29C383102CDD7A078ED813A6C -B08365492BC7FBAE96B0A38FFAE7DF72E86BA1979860585582D69FF740E85C1A -7FA151F83A3550AB4EF7710325E54525A59DC499F2CE53885F886C1E848C6A18 -CFAB501321D7EF01946308915B43EBB7FDACBDBFC7BDD797437B6F2797225609E13738CD0D90A2C4A1432FA9E34618C3 -322A0030702A3930977D1AD1C762356161F3402BFA6435F184F14BFBDAEC3F4A -BAB2E4702DA0FC7D0BA9581A04A1728D2FD9B986E4B180550BBC59DF1B04BC0A -CD87059AE7E0CA962065FBDF55EDBBD45253D5A01B714EDF28F7744F11A35C65 -6226EDFC8F7C7C51A06FADAF98241EE92CA2E827217AEB7A2C917DE431BC91A4 -057FEF7D36FF24D3C5F6C59FBA9C09197575E1A6E674A73692CCF8118C6B3C6E -5BA3EB99D621A7DD9D2EBBC4A24CE935D29A78EB200D82ED295B4ABBB6425525F82A502A09ECC9C310401BEF7E354CDD -8303490AC2E6576FF1E159342754AC45B38323836D1164AFDEE2578F5B70C70229A7DB64FB5283DA4F83A616AB11E394 -79208032CC01AA421851310727CCF2E81448671AFA07D7156C2C40707787C856 -9846F3ACF236D210A0AD138B3949A3CDA9A2E841F11BF9F531F299B33FD97B40 -6BD0CCA70D86E2D71645D2E6C223B2AF501ED9A5EDA24643FC90AAC7C3840E4E -69D9A4E90065AA5A1D7A6E40FBB2FC6BF4A72CF591E1FD51822A8B59CB6DBB22 -9032CDF1F5AF42EEE6121DFFA12F578F2088D25B9F260357E02590B19560462980D11A81462AD23D61A7927D2ECCF49B -1528C0F81E0F0510AA65D07C61EB29149C7238F474B3512F4BEDB0C4BA4966BB -80ADFA97303DA2907FC982E705DB45902BB251E08EC322B5429F70EDC6D7E2C9 -561F49B1A85F2FD839FC022ABD22A11E036891FC8B52220BFDE7194192C43F173637F76FFA1AEE4A4344647886EE3E3B -0AAFA120E57966064AFCD0B3F3571CE92118379160131C646B0E46262E4844883111DF28B2B17A46750D481216375055 -45E76A7B85593DCA6E0A9A71067AA0031590CA4C60161887D8E6BE54F254128A -537091AC4E7FD1841E03B352B1E62855AD26233DE167087A7F818804EA9DA56D -84DE10BB68269D0BF1723F29A683569F0D17FE247898C76523E6155AD4931195 -CF16625381ADFBEA6D89142A13CDA19FEA8345511692A0FBBA66E178BAF8126E -D25962A77350E7B7222983150A1C92053364F9954142A85AEA4FEC1D3B524C71 -A76F292F18E464511FD3232B604893985F9A823BBD9D73B2D84E43D4BDF7C5A8 -F92496E57B1B0F57C155ED15A6CBDDBF6A9C309A3A3B2B2D3118E51F8B8B718B -E59C00F03AA3DA0B961E04ACE90E85005DB3C4E402BF9A280775BCE9FC7EDE05 -494CB3B66A924E90DD180A96F77182F708C7CCC3E379D302D436FED839EBEEDB -D93838B8AC08491FE0F29EC5077F5BAB6F75DAE77C6F305A963F0555346B9EE1 -569E5F5EA968A636C657D009525BB3C416546D19ADDC05B9D005B023B0957DFA -A16CE196104A013E064663AE9DD0393BBF87E4FAFA1489C6ABA367928A2905F7 -4FF57FB9C064CCC452473D0713E0EE17EA85726CD00203F359252ABE613BF054 -C489D64C0CF7535117D21461EDC3FEBEDAFD2D2E55C0DC87943E9E8D0461EB60 -F9BB5CBF9E514F5B2918880D8336C2552D67346C5365DFAB816517F1793D26E3 -7258ACEBE2090849F6756E6033A7F92AD3D75D753C0438F266B22F270FA5535A -0B4CF3F92742FF775A14B66540FBC214F455CD992DFCEEF925EB0E38B21745A3 -5B17E197557BACB4C355F23D28C22280F9860A756CE2FC0959F1B07B9A6572A9 -0067A9EB86AEE637DA8E9E03512D1129252F5C530602B03D5C3383E0744F23BD -658FEA8B449D1EC5530FACBCDE3E3DF6CB0644B49D96C3FE1231FCDACE266BC1 -11325D0A765463419D6623C69961A0071EDA461E14C940326F1CA36339C946CD -007D6143BABAFFF19D77CC57E15AB4351C1D102856CB182F3F512EEFCD6FDF4F -CB97161DDE414D6D4D96FF726F73FF3AD0D71F9768EA6BBBFF08ABABB33A15B2 -A558FB601E42FAC986D0421446C7C898A9BDB0711FFB872B333CBEE9FC560DB9D7C790C502E59A29F493A2EC1EBA3FA5 -65E772E08F92E50C8151AA99FCA8D27F35D5F90C1CD45D098C5654C8046649F0 -DCB929C33CB3E4D28029D0E50C146074714CEFC765BE475B324F4D8DCBCDA931 -0ACC1EC04B63A689270904860E1EC3BF8E7F1DB1B18FBDD460AAE6148641894F -CE96406CECA957184499060DEF5FA7F0E956BC6B120B60DB1DCCB0F665F455E4 -D8C0B7CFDD3D20F58112660C08B236040242BCB1CF1FA5CFC66A6382282D2340 -D5E0F33DDD03D11AC90D33A230AA77A9ACB7C239520EE5A95587700CD87AF5C7 -D095F39B66EFAEECAAA2B9D4EC0AAEE6EA0749B2F12C17B38D96DC0197DECAD9 -E52D638ADD750B0231738F751EB97C2724877E184C365F9761F5995BCFD6F812 -EFA069F75B0A4B3FD6E6B8845E4A466BE092C746F6F574118AE435A32550464E -6FBFBD47F3EC4846E946121A54042E418C4A98E5EEF4F8D8C667EC2A774EBEA2 -0A73F468C6F8C4E8CF4934A28DF83972CCF41905562A2AEE79BCADD9CFC11F00 -73AD62A6660287252396902D6F80557772B64E4D6B16E1635489F985E54CFBED -942F89D0520D08B20973D8560F89C8DA8111842DB867EBC51B9F5451AC942EE7 -4FFA3EC48275D44C1A3FE528546FCA0D6E44262BADDA765B71E19863F0337C59 -484C420725B919EF3F2D3D9887175C3EE58CA17E8AD9588AC4EC241A7B91FB96 -39C3E86438AC72575B8BC7F9C2108D1C40AD56D920C0F820D6D92416AFB6244B -D0B3CD5D299820AF61BB4782746750056A7D212B9595424D6E50BFAEBCB089951090BD09D4C0B1F4D357C3FAFE6E73A9 -BB441902B1078F7F3D5E1F2BC5546E242C4E27B49149D3E1A54C20B6FD9EC56A -78C4CF85F6DB0CD63CB72A9B118C5DCE8EE7E6CC15A4312ACEC0B6503738325C -DE92516887651C73E89E2CE0D64DEE236E235C7CCBF0D14FE291D8793782616D -74F855306E36A0DA5B0FFF097CB69AAB34DEF3CF3D2DFFCF1A80447D6CC057A438AA4FBCB631F476FE568E9BA941ED2B +IV: 4F 77 4F 20 66 75 72 72 79 20 49 56 20 55 77 55 +1D0560740B25F58EE0E85BF949139971E5AA08C5499CC74B11992D124C281012 +C05E2D2C715D8E24C518EF2841DA02173C05DD5BA5310EE85D09709500DB1726 +9EA5721836369FF918859077F50E33100F7AC53E8E8F31E25296579F875359DF +D2A8AD1B65BC66B459525124CDC5011C79D98F542702FC69EABD64F908C0D80D +2FA5F078BEB59851D42BC7E4E331AE3A8C384892DF003238CDA82450A6CD02AC +E54ED5F49A093BC938521195C86FECF35FB6EC463C54C6E1609592DC5FA03CCB5E1EDA362FC9AB008C85E66B60147EBA +048F4A28B18496487D65A924F4E37766C3563F41090D442DE61D7A5DD82F5FF1 +DA876A11401727E5102B578F87CCF9596AB9D9925FC90CDF99C9DEC7261B2C8C +03D3842335D69A3AA42452274130B3FAAEE6087CB8D783B0E770062C034BB302 +7F50401E9FFAF10D1F61067C2E830EBBEC7C8B3B20F5C0AC2E10E68912BF2C82 +160BC0CA2FF01E076830F29846C1F6CCBAC7857F2043E8163449048BA8C99AA8 +09357F089CB148DDC578E0F11EC10659EF68A57440700F584922CB9842E2BF08AC977CCAA11355E89FA5C18113349F5E +910D166F40F264225BD4C8EB16C5CC6374F8F8E1202D5BF28FA2E8BA38E420A36E67611E6D151051F7C74843E4A72BBC +D9ACEBC528D7CA74B894A0378095E03C9BDBBE13DDA3FCD6D60CD3CAC49746B8 +90F94FD262E1859B7E5C08E7ED5B16CDB56D0E930034E315CD011DE3759150DA +6620E176FC61DF250EF2BBC2AB27E0DA45A6E1E27F4E94405EE01C36E892EFBF +7D6A062453236E4C353F19B875D079157D016B223B7D429C8F5BEA9D0F703EED +20631589CB541B32C23CA7EA93B12E2016B5A90A2C9CAA6F5849C0B67158EA635858F26A86282C124AEA3FD31B7FD365 +E6CF167CEA0639D1504E0BFC8BAAA7FC7FA36A2286CBBE1312803422018A9F00 +0EB81E23FF37366BA4890CBD46BC8AF5A2CD56E9802B8DF5CDDD5114F677CDF6 +62195292F6F920DAF91F812FC3B94E8539C157D35D3BC94F2FB7A8481406C655AC0F112C4E10AC36892D43D95827BC1D +65FB9BEBDB9BE975168D47B02CA8A2E0ADE2CD1949E90B06689B0475395663BD5AF3C8FEC42C4138CBBB8956AC55B475 +EF0A6961C754FCDBAE0222099DD8AA38DD6A92BCD53A576E105BC5BBD23400B7 +A608752C8602A5BD538441DE046DD7AE011FBA87210B57372BCBB471ECC2B720 +222C83DDC445F72152E563CD068851389364C1D83C9F7D6353325EFD553560B1 +96977544F2F821408C1A88FADB9B1E12D9CA97638A622190F83BC640508B6029 +B596A98BDDA5BD2FF1F812BE67FD00456D4D313E9497147E2439B51972B6B752 +FC276CAC90756F397C3BC616631CE8B9257E6C25D0DC15C5ED1CEB439ACF04D9 +383DD624B98E650E5B4BA28990B4D1912B785C689E6B6A05D77B47B6501CD98F +410814DC8B38DD6EF781B55CA02730092F252082A77400AD90F22BF45A41C849 +8DA240E13E8B512B50FF4504A61037D0A3920B00523D51EEF9996CC3907C175E +E655B7C31E346154C5EF7C59E3A710A2A2F145E7403E4ADB388B3A27D6FF59DE +E2FB7F96EA16B20589995E95D0959B4ECC1EDDF86E347EB85FD29D0D5933A2A1 +00D910F2B050900735A8446220FF7321813252862A69C05A7A534118E50E61DB +BA1B9E7E26E04542183F085060421553CDD3FD9034AAAFCB7EE980A68B98087E +216EBA33FCE4B834BF64621E557923D8AE41F5895266B7BBDFCA6EAF985F036E +2E9075A45ED6D86C172C9ADAAF5E991DA8DA9CBF2F24D746D22A331E236FBA4A +04E4B185C150AF45A67E15D68282C7558B13BFFB05BFCB71BCFD2B92DE5D9701 +1FDC4D759EA89681F76A8F7D336118FE6801EFD10D73925C2749775D9DFED282 +FFB32167FBF860418AAABF29B0D4FEF57BB07454ECF4BD2CF175D44E84C04CED +7C6E419658872D298F2E7B02568B9ED870FDFFE5082ED0BBE689FD04EFFFE7E7 +ADAB0F3108398C75ECC6D2E572960B5685C336DDF3D6F5B9C12D069F27BA15A8 +DAC772C1A81181738CDB8C0E89C2E5B7A57E2DA65CA15232DE96A3C4A599A0E9 +7F6204274D90E88B3F5D5AC86EEEE76C27C0D083E79ADA7BCF7D060FE6F05A3E +5BAB4CCB593418CD8965C09C0925EDB78BB4C8A10892F264DF12F50E532F006E +7C67525C921ABAEC4BFAA376162A7B2B2827AE4C9840DC37F067FE3B72BE7304B6EEB5FB1AD17CFF5F079EFECC04AD56 +94FF6DD4CE63381778E86E61423EDDDD9CC71C3462D66F1AD9A0AD5D378AECE2 +E9CA5BA5C6D6101EA3A51F28E48D49789D60273A9F70D56020D003265517AFA3 +EBF55649D226E9FDAAB57C2E1D75E3FD3A8D216488E97D00E932B3542E731D20 +2B576C3616DDAFEE23A8ECE24BBD89590C8C2D551F14D8EFA4DBB30216F89C31 +EE8D3CF3C503DE4FF368F23585F1A7017FF66A910696A6760AFD2B9822911960 +A32910F791C5EE9998DCE5371B3252427315C9D11AD506CE65760611D873C81D +740646D11A32C65A8549B3AEA8A499866C35D926B2BA21ED73934AA37ADCC1E6 +0E66EF4CA934A5D1ACED28CBEEAA3AF7941E10918DA79379090B6339F11E267E +D79D8666FD947B0D0D504FF10B048B147CB000AD8CDC1F0DEB395FB72B789963 +2F7BA07F18F4A91AEDC08867E9CC4B8689B0831A7CE0E0AEF3D92C0CA9BBC698 +1AB4351CFF02CC600C972CE87F69B23F8ECCC32A90BD5F429F8017A80306F23D +ED2AD447E7DF7A34D78A313395FA1C3AF63CE02B77A5B08CE19493CFA1173232 +C8C8DEAF10AA3994EE7D6DC8E1EB403042627E0F3524409F40C03A7C0C106A80 +5778B4A3E7BE82C07BA6A311A87649F3C7AE5107A89571E14AEF05B9E285C87A +30080347DB3B580B18E8EAC66E1B7227F791773F0342EE0DF8267EC993EC3F24 +2DB3B2A17C165B5C6A1D4944A5B595016588F028DD4F763C4ED6B7FE7849E918 +C1F0CF343B77F31D9A2E810821393EE9D1E0D4B54A87B2DD8CCFBB16FBD77A75B50A0E78D1E8A86310572443731B9DB5 +88EF373C37AADAE1155E7DBDBB7E0B048E3BFEFB412DC49EA8A48E1544B6DC87 +98694781F3EE698ABA8D2CDFFB1CA0425AA17BFE904FC7812E65A78DF1CA06C2 +6BBBCA6672311E1A3BF7001B3222890C8A68A8B7D87DE91624BB9D1FEC0E2728 +4550A44B654085C3A3620B5D4D2C6A7F962275BC5926B9B7E3A706F128BF6D6C967E2BF2ACD4DD000BDC8BDE69684F6F diff --git a/applications/main/subghz/scenes/subghz_scene_set_button.c b/applications/main/subghz/scenes/subghz_scene_set_button.c index baab8f095..e8914dbc5 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_button.c +++ b/applications/main/subghz/scenes/subghz_scene_set_button.c @@ -40,6 +40,10 @@ void subghz_scene_set_button_on_enter(void* context) { byte_ptr = &subghz->gen_info->kinggates_stylo_4k.btn; byte_count = sizeof(subghz->gen_info->kinggates_stylo_4k.btn); break; + case GenBenincaARC: + byte_ptr = &subghz->gen_info->beninca_arc.btn; + byte_count = sizeof(subghz->gen_info->beninca_arc.btn); + break; case GenNiceFlorS: byte_ptr = &subghz->gen_info->nice_flor_s.btn; byte_count = sizeof(subghz->gen_info->nice_flor_s.btn); @@ -87,6 +91,7 @@ bool subghz_scene_set_button_on_event(void* context, SceneManagerEvent event) { case GenAlutechAt4n: case GenSomfyTelis: case GenKingGatesStylo4k: + case GenBenincaARC: case GenNiceFlorS: case GenSecPlus2: scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCounter); diff --git a/applications/main/subghz/scenes/subghz_scene_set_counter.c b/applications/main/subghz/scenes/subghz_scene_set_counter.c index 42437fcbf..a58749256 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_counter.c +++ b/applications/main/subghz/scenes/subghz_scene_set_counter.c @@ -46,6 +46,10 @@ void subghz_scene_set_counter_on_enter(void* context) { byte_ptr = (uint8_t*)&subghz->gen_info->kinggates_stylo_4k.cnt; byte_count = sizeof(subghz->gen_info->kinggates_stylo_4k.cnt); break; + case GenBenincaARC: + byte_ptr = (uint8_t*)&subghz->gen_info->beninca_arc.cnt; + byte_count = sizeof(subghz->gen_info->beninca_arc.cnt); + break; case GenNiceFlorS: byte_ptr = (uint8_t*)&subghz->gen_info->nice_flor_s.cnt; byte_count = sizeof(subghz->gen_info->nice_flor_s.cnt); @@ -121,6 +125,9 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { subghz->gen_info->kinggates_stylo_4k.cnt = __bswap16(subghz->gen_info->kinggates_stylo_4k.cnt); break; + case GenBenincaARC: + subghz->gen_info->beninca_arc.cnt = __bswap32(subghz->gen_info->beninca_arc.cnt); + break; case GenNiceFlorS: subghz->gen_info->nice_flor_s.cnt = __bswap16(subghz->gen_info->nice_flor_s.cnt); break; @@ -188,6 +195,15 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { subghz->gen_info->kinggates_stylo_4k.btn, subghz->gen_info->kinggates_stylo_4k.cnt); break; + case GenBenincaARC: + generated_protocol = subghz_txrx_gen_beninca_arc_protocol( + subghz->txrx, + subghz->gen_info->mod, + subghz->gen_info->freq, + subghz->gen_info->beninca_arc.serial, + subghz->gen_info->beninca_arc.btn, + subghz->gen_info->beninca_arc.cnt); + break; case GenNiceFlorS: generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( subghz->txrx, diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed.c b/applications/main/subghz/scenes/subghz_scene_set_seed.c index b93203a17..648cfa1d3 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed.c @@ -31,6 +31,7 @@ void subghz_scene_set_seed_on_enter(void* context) { case GenAlutechAt4n: case GenSomfyTelis: case GenKingGatesStylo4k: + case GenBenincaARC: case GenNiceFlorS: case GenSecPlus2: case GenPhoenixV2: @@ -91,6 +92,7 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { case GenAlutechAt4n: case GenSomfyTelis: case GenKingGatesStylo4k: + case GenBenincaARC: case GenNiceFlorS: case GenSecPlus2: case GenPhoenixV2: diff --git a/applications/main/subghz/scenes/subghz_scene_set_serial.c b/applications/main/subghz/scenes/subghz_scene_set_serial.c index b11559b44..9219842e5 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_serial.c +++ b/applications/main/subghz/scenes/subghz_scene_set_serial.c @@ -46,6 +46,10 @@ void subghz_scene_set_serial_on_enter(void* context) { byte_ptr = (uint8_t*)&subghz->gen_info->kinggates_stylo_4k.serial; byte_count = sizeof(subghz->gen_info->kinggates_stylo_4k.serial); break; + case GenBenincaARC: + byte_ptr = (uint8_t*)&subghz->gen_info->beninca_arc.serial; + byte_count = sizeof(subghz->gen_info->beninca_arc.serial); + break; case GenNiceFlorS: byte_ptr = (uint8_t*)&subghz->gen_info->nice_flor_s.serial; byte_count = sizeof(subghz->gen_info->nice_flor_s.serial); @@ -118,6 +122,10 @@ bool subghz_scene_set_serial_on_event(void* context, SceneManagerEvent event) { subghz->gen_info->kinggates_stylo_4k.serial = __bswap32(subghz->gen_info->kinggates_stylo_4k.serial); break; + case GenBenincaARC: + subghz->gen_info->beninca_arc.serial = + __bswap32(subghz->gen_info->beninca_arc.serial); + break; case GenNiceFlorS: subghz->gen_info->nice_flor_s.serial = __bswap32(subghz->gen_info->nice_flor_s.serial); @@ -145,6 +153,7 @@ bool subghz_scene_set_serial_on_event(void* context, SceneManagerEvent event) { case GenAlutechAt4n: case GenSomfyTelis: case GenKingGatesStylo4k: + case GenBenincaARC: case GenNiceFlorS: case GenSecPlus2: scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetButton); diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index f21f73f38..28cd4bcf7 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -20,7 +20,8 @@ static const char* submenu_names[SetTypeMAX] = { [SetTypeAlutechAT4N] = "Alutech AT4N 433MHz", [SetTypeRoger_433] = "Roger 433MHz", [SetTypePhoenix_V2_433] = "V2 Phoenix 433MHz", - [SetTypeKingGatesStylo4k] = "KingGates Stylo4 433MHz", + [SetTypeKingGatesStylo4k] = "KingGates Stylo4k 433M.", + [SetTypeBenincaARC] = "Beninca ARC 433MHz", [SetTypeHCS101_433_92] = "KL: HCS101 433MHz", [SetTypeDoorHan_315_00] = "KL: DoorHan 315MHz", [SetTypeDoorHan_433_92] = "KL: DoorHan 433MHz", @@ -197,6 +198,15 @@ bool subghz_scene_set_type_generate_protocol_from_infos(SubGhz* subghz) { gen_info.kinggates_stylo_4k.btn, gen_info.kinggates_stylo_4k.cnt); break; + case GenBenincaARC: + generated_protocol = subghz_txrx_gen_beninca_arc_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.beninca_arc.serial, + gen_info.beninca_arc.btn, + gen_info.beninca_arc.cnt); + break; case GenNiceFlorS: generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( subghz->txrx, @@ -277,6 +287,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { case GenAlutechAt4n: // Serial (u32), Button (u8), Counter (u16) case GenSomfyTelis: // Serial (u32), Button (u8), Counter (u16) case GenKingGatesStylo4k: // Serial (u32), Button (u8), Counter (u16) + case GenBenincaARC: // Serial (u32), Button (u8), Counter (u32) case GenNiceFlorS: // Serial (u32), Button (u8), Counter (u16) case GenSecPlus2: // Serial (u32), Button (u8), Counter (u32) case GenPhoenixV2: // Serial (u32), Counter (u16) diff --git a/lib/subghz/protocols/aes_common.c b/lib/subghz/protocols/aes_common.c new file mode 100644 index 000000000..9e7d23a4f --- /dev/null +++ b/lib/subghz/protocols/aes_common.c @@ -0,0 +1,252 @@ +#include "aes_common.h" + +static const uint8_t aes_sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, + 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, + 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, + 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, + 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, + 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, + 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, + 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, + 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, + 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, + 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, + 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, + 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, + 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, + 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, + 0x16}; + +static const uint8_t aes_sbox_inv[256] = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, + 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, + 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, + 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, + 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, + 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, + 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, + 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, + 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, + 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, + 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, + 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, + 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, + 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, + 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, + 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, + 0x7d}; + +static const uint8_t aes_rcon[10] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36}; + +static uint8_t gf_mul2(uint8_t x) { + return ((x >> 7) * 0x1b) ^ (x << 1); +} + +static void aes_subbytes(uint8_t* state) { + for(uint8_t row = 0; row < 4; row++) { + for(uint8_t col = 0; col < 4; col++) { + state[row + col * 4] = aes_sbox[state[row + col * 4]]; + } + } +} + +static void aes_subbytes_inv(uint8_t* state) { + for(uint8_t row = 0; row < 4; row++) { + for(uint8_t col = 0; col < 4; col++) { + state[row + col * 4] = aes_sbox_inv[state[row + col * 4]]; + } + } +} + +static void aes_shiftrows(uint8_t* state) { + uint8_t temp; + + temp = state[1]; + state[1] = state[5]; + state[5] = state[9]; + state[9] = state[13]; + state[13] = temp; + + temp = state[2]; + state[2] = state[10]; + state[10] = temp; + temp = state[6]; + state[6] = state[14]; + state[14] = temp; + + temp = state[15]; + state[15] = state[11]; + state[11] = state[7]; + state[7] = state[3]; + state[3] = temp; +} + +static void aes_shiftrows_inv(uint8_t* state) { + uint8_t temp; + + temp = state[13]; + state[13] = state[9]; + state[9] = state[5]; + state[5] = state[1]; + state[1] = temp; + + temp = state[2]; + state[2] = state[10]; + state[10] = temp; + temp = state[6]; + state[6] = state[14]; + state[14] = temp; + + temp = state[3]; + state[3] = state[7]; + state[7] = state[11]; + state[11] = state[15]; + state[15] = temp; +} + +static void aes_mixcolumns(uint8_t* state) { + uint8_t a, b, c, d; + for(uint8_t i = 0; i < 4; i++) { + a = state[i * 4]; + b = state[i * 4 + 1]; + c = state[i * 4 + 2]; + d = state[i * 4 + 3]; + + uint8_t a2 = gf_mul2(a); + uint8_t b2 = gf_mul2(b); + uint8_t c2 = gf_mul2(c); + uint8_t d2 = gf_mul2(d); + + state[i * 4] = a2 ^ b2 ^ b ^ c ^ d; + state[i * 4 + 1] = a ^ b2 ^ c2 ^ c ^ d; + state[i * 4 + 2] = a ^ b ^ c2 ^ d2 ^ d; + state[i * 4 + 3] = a2 ^ a ^ b ^ c ^ d2; + } +} + +static void aes_mixcolumns_inv(uint8_t* state) { + uint8_t a, b, c, d; + for(uint8_t i = 0; i < 4; i++) { + a = state[i * 4]; + b = state[i * 4 + 1]; + c = state[i * 4 + 2]; + d = state[i * 4 + 3]; + + uint8_t a2 = gf_mul2(a); + uint8_t a4 = gf_mul2(a2); + uint8_t a8 = gf_mul2(a4); + uint8_t b2 = gf_mul2(b); + uint8_t b4 = gf_mul2(b2); + uint8_t b8 = gf_mul2(b4); + uint8_t c2 = gf_mul2(c); + uint8_t c4 = gf_mul2(c2); + uint8_t c8 = gf_mul2(c4); + uint8_t d2 = gf_mul2(d); + uint8_t d4 = gf_mul2(d2); + uint8_t d8 = gf_mul2(d4); + + state[i * 4] = (a8 ^ a4 ^ a2) ^ (b8 ^ b2 ^ b) ^ (c8 ^ c4 ^ c) ^ (d8 ^ d); + state[i * 4 + 1] = (a8 ^ a) ^ (b8 ^ b4 ^ b2) ^ (c8 ^ c2 ^ c) ^ (d8 ^ d4 ^ d); + state[i * 4 + 2] = (a8 ^ a4 ^ a) ^ (b8 ^ b) ^ (c8 ^ c4 ^ c2) ^ (d8 ^ d2 ^ d); + state[i * 4 + 3] = (a8 ^ a2 ^ a) ^ (b8 ^ b4 ^ b) ^ (c8 ^ c) ^ (d8 ^ d4 ^ d2); + } +} + +static void aes_addroundkey(uint8_t* state, const uint8_t* round_key) { + for(uint8_t col = 0; col < 4; col++) { + state[col * 4] ^= round_key[col * 4]; + state[col * 4 + 1] ^= round_key[col * 4 + 1]; + state[col * 4 + 2] ^= round_key[col * 4 + 2]; + state[col * 4 + 3] ^= round_key[col * 4 + 3]; + } +} + +void aes_key_expansion(const uint8_t* key, uint8_t* round_keys) { + for(uint8_t i = 0; i < 16; i++) { + round_keys[i] = key[i]; + } + + for(uint8_t i = 4; i < 44; i++) { + uint8_t prev_word_idx = (i - 1) * 4; + uint8_t b0 = round_keys[prev_word_idx]; + uint8_t b1 = round_keys[prev_word_idx + 1]; + uint8_t b2 = round_keys[prev_word_idx + 2]; + uint8_t b3 = round_keys[prev_word_idx + 3]; + + if((i % 4) == 0) { + uint8_t new_b0 = aes_sbox[b1] ^ aes_rcon[(i / 4) - 1]; + uint8_t new_b1 = aes_sbox[b2]; + uint8_t new_b2 = aes_sbox[b3]; + uint8_t new_b3 = aes_sbox[b0]; + b0 = new_b0; + b1 = new_b1; + b2 = new_b2; + b3 = new_b3; + } + + uint8_t back_word_idx = (i - 4) * 4; + b0 ^= round_keys[back_word_idx]; + b1 ^= round_keys[back_word_idx + 1]; + b2 ^= round_keys[back_word_idx + 2]; + b3 ^= round_keys[back_word_idx + 3]; + + uint8_t curr_word_idx = i * 4; + round_keys[curr_word_idx] = b0; + round_keys[curr_word_idx + 1] = b1; + round_keys[curr_word_idx + 2] = b2; + round_keys[curr_word_idx + 3] = b3; + } +} + +void aes128_encrypt(const uint8_t* expanded_key, uint8_t* data) { + uint8_t state[16]; + memcpy(state, data, 16); + + aes_addroundkey(state, &expanded_key[0]); + + for(uint8_t round = 1; round < 10; round++) { + aes_subbytes(state); + aes_shiftrows(state); + aes_mixcolumns(state); + aes_addroundkey(state, &expanded_key[round * 16]); + } + + aes_subbytes(state); + aes_shiftrows(state); + aes_addroundkey(state, &expanded_key[160]); + + memcpy(data, state, 16); +} + +void aes128_decrypt(const uint8_t* expanded_key, uint8_t* data) { + uint8_t state[16]; + memcpy(state, data, 16); + + aes_addroundkey(state, &expanded_key[160]); + + for(uint8_t round = 9; round > 0; round--) { + aes_shiftrows_inv(state); + aes_subbytes_inv(state); + aes_addroundkey(state, &expanded_key[round * 16]); + aes_mixcolumns_inv(state); + } + + aes_shiftrows_inv(state); + aes_subbytes_inv(state); + aes_addroundkey(state, &expanded_key[0]); + + memcpy(data, state, 16); +} + +void reverse_bits_in_bytes(uint8_t* data, uint8_t len) { + for(uint8_t i = 0; i < len; i++) { + uint8_t byte = data[i]; + uint8_t step1 = ((byte & 0x55) << 1) | ((byte >> 1) & 0x55); + uint8_t step2 = ((step1 & 0x33) << 2) | ((step1 >> 2) & 0x33); + data[i] = ((step2 & 0x0F) << 4) | (step2 >> 4); + } +} diff --git a/lib/subghz/protocols/aes_common.h b/lib/subghz/protocols/aes_common.h new file mode 100644 index 000000000..ba8168383 --- /dev/null +++ b/lib/subghz/protocols/aes_common.h @@ -0,0 +1,10 @@ +#pragma once + +#include "base.h" + +#include + +void reverse_bits_in_bytes(uint8_t* data, uint8_t len); +void aes128_decrypt(const uint8_t* expanded_key, uint8_t* data); +void aes128_encrypt(const uint8_t* expanded_key, uint8_t* data); +void aes_key_expansion(const uint8_t* key, uint8_t* round_keys); diff --git a/lib/subghz/protocols/beninca_arc.c b/lib/subghz/protocols/beninca_arc.c new file mode 100644 index 000000000..a77301fa3 --- /dev/null +++ b/lib/subghz/protocols/beninca_arc.c @@ -0,0 +1,679 @@ +#include "beninca_arc.h" +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" +#include "core/log.h" +#include +#include +#include "aes_common.h" + +#include "../blocks/custom_btn_i.h" + +#define TAG "BenincaARC" + +#define BENINCA_ARC_KEY_TYPE 9u + +static const SubGhzBlockConst subghz_protocol_beninca_arc_const = { + .te_short = 300, + .te_long = 600, + .te_delta = 155, + .min_count_bit_for_found = 128, +}; + +typedef enum { + BenincaARCDecoderStart = 0, + BenincaARCDecoderHighLevel, + BenincaARCDecoderLowLevel, +} BenincaARCDecoderState; + +struct SubGhzProtocolDecoderBenincaARC { + SubGhzProtocolDecoderBase base; + SubGhzBlockDecoder decoder; + + SubGhzBlockGeneric generic; + + SubGhzKeystore* keystore; +}; + +struct SubGhzProtocolEncoderBenincaARC { + SubGhzProtocolEncoderBase base; + SubGhzProtocolBlockEncoder encoder; + + SubGhzBlockGeneric generic; + + SubGhzKeystore* keystore; +}; + +const SubGhzProtocolDecoder subghz_protocol_beninca_arc_decoder = { + .alloc = subghz_protocol_decoder_beninca_arc_alloc, + .free = subghz_protocol_decoder_beninca_arc_free, + + .feed = subghz_protocol_decoder_beninca_arc_feed, + .reset = subghz_protocol_decoder_beninca_arc_reset, + + .get_hash_data = subghz_protocol_decoder_beninca_arc_get_hash_data, + .serialize = subghz_protocol_decoder_beninca_arc_serialize, + .deserialize = subghz_protocol_decoder_beninca_arc_deserialize, + .get_string = subghz_protocol_decoder_beninca_arc_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_beninca_arc_encoder = { + .alloc = subghz_protocol_encoder_beninca_arc_alloc, + .free = subghz_protocol_encoder_beninca_arc_free, + + .deserialize = subghz_protocol_encoder_beninca_arc_deserialize, + .stop = subghz_protocol_encoder_beninca_arc_stop, + .yield = subghz_protocol_encoder_beninca_arc_yield, +}; + +const SubGhzProtocol subghz_protocol_beninca_arc = { + .name = SUBGHZ_PROTOCOL_BENINCA_ARC_NAME, + .type = SubGhzProtocolTypeDynamic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_beninca_arc_decoder, + .encoder = &subghz_protocol_beninca_arc_encoder, +}; + +// Get custom button code +static uint8_t subghz_protocol_beninca_arc_get_btn_code(void) { + uint8_t custom_btn_id = subghz_custom_btn_get(); + uint8_t original_btn_code = subghz_custom_btn_get_original(); + uint8_t btn = original_btn_code; + + // Set custom button + if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) { + // Restore original button code + btn = original_btn_code; + } else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) { + switch(original_btn_code) { + case 0x02: + btn = 0x04; + break; + case 0x04: + btn = 0x02; + break; + case 0xFF: + btn = 0x04; + break; + + default: + break; + } + } else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) { + switch(original_btn_code) { + case 0x02: + btn = 0xFF; + break; + case 0x04: + btn = 0xFF; + break; + case 0xFF: + btn = 0x02; + break; + + default: + break; + } + } + + return btn; +} + +static void get_subghz_protocol_beninca_arc_aes_key(SubGhzKeystore* keystore, uint8_t* aes_key) { + uint64_t mfkey = 0; + for + M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) { + if(manufacture_code->type == BENINCA_ARC_KEY_TYPE) { + mfkey = manufacture_code->key; + break; + } + } + + uint32_t derived_lo = (uint32_t)(mfkey & 0xFFFFFFFF); + uint32_t derived_hi = (uint32_t)((mfkey >> 32) & 0xFFFFFFFF); + + uint64_t val64_a = ((uint64_t)derived_hi << 32) | derived_lo; + for(uint8_t i = 0; i < 8; i++) { + aes_key[i] = (val64_a >> (56 - i * 8)) & 0xFF; + } + + uint32_t new_lo = ((derived_hi >> 24) & 0xFF) | ((derived_hi >> 8) & 0xFF00) | + ((derived_hi << 8) & 0xFF0000) | ((derived_hi << 24) & 0xFF000000); + uint32_t new_hi = ((derived_lo >> 24) & 0xFF) | ((derived_lo >> 8) & 0xFF00) | + ((derived_lo << 8) & 0xFF0000) | ((derived_lo << 24) & 0xFF000000); + + uint64_t val64_b = ((uint64_t)new_hi << 32) | new_lo; + for(uint8_t i = 0; i < 8; i++) { + aes_key[i + 8] = (val64_b >> (56 - i * 8)) & 0xFF; + } +} + +static uint64_t + subghz_protocol_beninca_arc_decrypt(SubGhzBlockGeneric* generic, SubGhzKeystore* keystore) { + // Beninca ARC Decoder + // 01.2026 - @xMasterX (MMX) & @zero-mega + + // Decrypt data + uint8_t encrypted_data[16]; + + for(uint8_t i = 0; i < 8; i++) { + encrypted_data[i] = (generic->data >> (56 - i * 8)) & 0xFF; + encrypted_data[i + 8] = (generic->data_2 >> (56 - i * 8)) & 0xFF; + } + + reverse_bits_in_bytes(encrypted_data, 16); + + uint8_t aes_key[16]; + get_subghz_protocol_beninca_arc_aes_key(keystore, aes_key); + + uint8_t expanded_key[176]; + aes_key_expansion(aes_key, expanded_key); + + aes128_decrypt(expanded_key, encrypted_data); + + // Serial number of remote + generic->serial = ((uint32_t)encrypted_data[0] << 24) | ((uint32_t)encrypted_data[1] << 16) | + ((uint32_t)encrypted_data[2] << 8) | encrypted_data[3]; + + // Button code + generic->btn = encrypted_data[4]; + + // Middle bytes contains mini counter that is increased while button is held + // its value mostly stored in encrypted_data[9] but might be in other bytes as well + // In order to support all variants we read all middle bytes as uint64_t + // In case you have the remote with ARC rolling code please share RAW recording where you hold button for 15+ sec with us to improve this part! + uint64_t middle_bytes = 0; + middle_bytes = ((uint64_t)encrypted_data[5] << 32) | ((uint64_t)encrypted_data[6] << 24) | + ((uint64_t)encrypted_data[7] << 16) | ((uint64_t)encrypted_data[8] << 8) | + encrypted_data[9]; + + // 32-bit counter + generic->cnt = ((uint32_t)encrypted_data[10] << 24) | ((uint32_t)encrypted_data[11] << 16) | + ((uint32_t)encrypted_data[12] << 8) | encrypted_data[13]; + // Fixed constant value AA 55 + generic->seed = ((uint16_t)encrypted_data[14] << 8) | encrypted_data[15]; + + // Save original button for later use + if(subghz_custom_btn_get_original() == 0) { + subghz_custom_btn_set_original(generic->btn); + } + subghz_custom_btn_set_max(2); + + return middle_bytes; +} + +static void subghz_protocol_beninca_arc_encrypt( + SubGhzBlockGeneric* generic, + SubGhzKeystore* keystore, + uint64_t middle_bytes) { + // Beninca ARC Encoder + // 01.2026 - @xMasterX (MMX) & @zero-mega + // Encrypt data + uint8_t plaintext[16]; + + plaintext[0] = (generic->serial >> 24) & 0xFF; + plaintext[1] = (generic->serial >> 16) & 0xFF; + plaintext[2] = (generic->serial >> 8) & 0xFF; + plaintext[3] = generic->serial & 0xFF; + plaintext[4] = generic->btn; + plaintext[5] = (middle_bytes >> 32) & 0xFF; + plaintext[6] = (middle_bytes >> 24) & 0xFF; + plaintext[7] = (middle_bytes >> 16) & 0xFF; + plaintext[8] = (middle_bytes >> 8) & 0xFF; + plaintext[9] = middle_bytes & 0xFF; + plaintext[10] = (generic->cnt >> 24) & 0xFF; + plaintext[11] = (generic->cnt >> 16) & 0xFF; + plaintext[12] = (generic->cnt >> 8) & 0xFF; + plaintext[13] = generic->cnt & 0xFF; + plaintext[14] = (generic->seed >> 8) & 0xFF; + plaintext[15] = generic->seed & 0xFF; + + uint8_t aes_key[16]; + get_subghz_protocol_beninca_arc_aes_key(keystore, aes_key); + + uint8_t expanded_key[176]; + aes_key_expansion(aes_key, expanded_key); + + aes128_encrypt(expanded_key, plaintext); + + reverse_bits_in_bytes(plaintext, 16); + + for(uint8_t i = 0; i < 8; i++) { + generic->data = (generic->data << 8) | plaintext[i]; + generic->data_2 = (generic->data_2 << 8) | plaintext[i + 8]; + } + return; +} + +void* subghz_protocol_encoder_beninca_arc_alloc(SubGhzEnvironment* environment) { + SubGhzProtocolEncoderBenincaARC* instance = malloc(sizeof(SubGhzProtocolEncoderBenincaARC)); + + instance->base.protocol = &subghz_protocol_beninca_arc; + instance->generic.protocol_name = instance->base.protocol->name; + instance->keystore = subghz_environment_get_keystore(environment); + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 800; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + + return instance; +} + +void subghz_protocol_encoder_beninca_arc_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderBenincaARC* instance = context; + free(instance->encoder.upload); + free(instance); +} + +void subghz_protocol_encoder_beninca_arc_stop(void* context) { + furi_assert(context); + SubGhzProtocolEncoderBenincaARC* instance = context; + instance->encoder.is_running = false; +} + +static void subghz_protocol_beninca_arc_encoder_get_upload( + SubGhzProtocolEncoderBenincaARC* instance, + size_t* index) { + furi_assert(instance); + size_t index_local = *index; + + // First part of data 64 bits + for(uint8_t i = 64; i > 0; i--) { + if(bit_read(instance->generic.data, i - 1)) { + // Send bit 1 + instance->encoder.upload[index_local++] = + level_duration_make(true, (uint32_t)subghz_protocol_beninca_arc_const.te_short); + instance->encoder.upload[index_local++] = + level_duration_make(false, (uint32_t)subghz_protocol_beninca_arc_const.te_long); + } else { + // Send bit 0 + instance->encoder.upload[index_local++] = + level_duration_make(true, (uint32_t)subghz_protocol_beninca_arc_const.te_long); + instance->encoder.upload[index_local++] = + level_duration_make(false, (uint32_t)subghz_protocol_beninca_arc_const.te_short); + } + } + // Second part of data 64 bits - total 128bits data + for(uint8_t i = 64; i > 0; i--) { + if(bit_read(instance->generic.data_2, i - 1)) { + // Send bit 1 + instance->encoder.upload[index_local++] = + level_duration_make(true, (uint32_t)subghz_protocol_beninca_arc_const.te_short); + instance->encoder.upload[index_local++] = + level_duration_make(false, (uint32_t)subghz_protocol_beninca_arc_const.te_long); + } else { + // Send bit 0 + instance->encoder.upload[index_local++] = + level_duration_make(true, (uint32_t)subghz_protocol_beninca_arc_const.te_long); + instance->encoder.upload[index_local++] = + level_duration_make(false, (uint32_t)subghz_protocol_beninca_arc_const.te_short); + } + } + // Add stop bit + instance->encoder.upload[index_local++] = + level_duration_make(true, (uint32_t)subghz_protocol_beninca_arc_const.te_short); + // Add gap between packets + instance->encoder.upload[index_local++] = + level_duration_make(false, (uint32_t)subghz_protocol_beninca_arc_const.te_long * 15); + + *index = index_local; +} + +static void subghz_protocol_beninca_arc_encoder_prepare_packets( + SubGhzProtocolEncoderBenincaARC* instance) { + furi_assert(instance); + + // Counter increment + // check OFEX mode + if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFFFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } + } + } else { + // TODO: OFEX mode + instance->generic.cnt += 1; + } + // Index for upload array + size_t index = 0; + // Generate new key using custom or default button + instance->generic.btn = subghz_protocol_beninca_arc_get_btn_code(); + + // Make 3 packets with different mini counter values - 2, 4, 6 + for(uint8_t i = 0; i < 3; i++) { + subghz_protocol_beninca_arc_encrypt( + &instance->generic, instance->keystore, (uint64_t)((i + 1) * 2)); + subghz_protocol_beninca_arc_encoder_get_upload(instance, &index); + } + // Set final size of upload array + instance->encoder.size_upload = index; +} + +bool subghz_protocol_beninca_arc_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint32_t cnt, + SubGhzRadioPreset* preset) { + furi_assert(context); + // UwU + SubGhzProtocolEncoderBenincaARC* instance = context; + instance->generic.serial = serial; + instance->generic.btn = btn; // 02 / 04 + instance->generic.cnt = cnt; + instance->generic.seed = 0xAA55; // Fixed value constant + instance->generic.data_count_bit = 128; + + subghz_protocol_beninca_arc_encrypt(&instance->generic, instance->keystore, 0x1); + + SubGhzProtocolStatus res = + subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data_2 >> (i * 8)) & 0xFF; + } + + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + res = SubGhzProtocolStatusErrorParserOthers; + } + + if((res == SubGhzProtocolStatusOk) && + !flipper_format_insert_or_update_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to add Data2"); + res = SubGhzProtocolStatusErrorParserOthers; + } + + return res == SubGhzProtocolStatusOk; +} + +SubGhzProtocolStatus + subghz_protocol_encoder_beninca_arc_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderBenincaARC* instance = context; + SubGhzProtocolStatus res = SubGhzProtocolStatusError; + do { + if(SubGhzProtocolStatusOk != + subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + + uint8_t key_data[sizeof(uint64_t)] = {0}; + if(!flipper_format_read_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Missing Data"); + break; + } + + for(uint8_t i = 0; i < sizeof(uint64_t); i++) { + instance->generic.data_2 = instance->generic.data_2 << 8 | key_data[i]; + } + + // TODO: if minicounter having larger value use it instead of fixed values + subghz_protocol_beninca_arc_decrypt(&instance->generic, instance->keystore); + + subghz_protocol_beninca_arc_encoder_prepare_packets(instance); + + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data >> i * 8) & 0xFF; + } + if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to update Key"); + break; + } + + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data_2 >> i * 8) & 0xFF; + } + if(!flipper_format_update_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to update Data"); + break; + } + + instance->encoder.is_running = true; + + res = SubGhzProtocolStatusOk; + } while(false); + + return res; +} + +LevelDuration subghz_protocol_encoder_beninca_arc_yield(void* context) { + furi_assert(context); + SubGhzProtocolEncoderBenincaARC* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_beninca_arc_alloc(SubGhzEnvironment* environment) { + SubGhzProtocolDecoderBenincaARC* instance = malloc(sizeof(SubGhzProtocolDecoderBenincaARC)); + instance->base.protocol = &subghz_protocol_beninca_arc; + instance->generic.protocol_name = instance->base.protocol->name; + instance->keystore = subghz_environment_get_keystore(environment); + instance->decoder.parser_step = BenincaARCDecoderStart; + return instance; +} + +void subghz_protocol_decoder_beninca_arc_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderBenincaARC* instance = context; + free(instance); +} + +void subghz_protocol_decoder_beninca_arc_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderBenincaARC* instance = context; + instance->decoder.parser_step = BenincaARCDecoderStart; +} + +void subghz_protocol_decoder_beninca_arc_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderBenincaARC* instance = context; + + switch(instance->decoder.parser_step) { + case BenincaARCDecoderStart: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_beninca_arc_const.te_long * 16) < + subghz_protocol_beninca_arc_const.te_delta * 15)) { + // GAP (9300 +- 2325 us) found switch to next state + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + instance->decoder.parser_step = BenincaARCDecoderHighLevel; + break; + } + // No GAP so stay in current state + break; + case BenincaARCDecoderHighLevel: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = BenincaARCDecoderLowLevel; + // Check if we have collected enough bits + if((instance->decoder.decode_count_bit == + (subghz_protocol_beninca_arc_const.min_count_bit_for_found / 2)) && + (instance->decoder.decode_data != 0)) { + // Half data captured 64 bits + instance->generic.data = instance->decoder.decode_data; + instance->decoder.decode_data = 0; + } else if( + instance->decoder.decode_count_bit == + subghz_protocol_beninca_arc_const.min_count_bit_for_found) { + // Full data captured 128 bits + instance->generic.data_2 = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + instance->decoder.parser_step = BenincaARCDecoderStart; + + if(instance->base.callback) { + instance->base.callback(&instance->base, instance->base.context); + } + + break; + } + } else { + instance->decoder.parser_step = BenincaARCDecoderStart; + } + break; + case BenincaARCDecoderLowLevel: + if(!level) { + // Bit 1 is short and long timing = 300us HIGH (te_last) and 600us LOW + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_beninca_arc_const.te_short) < + subghz_protocol_beninca_arc_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_beninca_arc_const.te_long) < + subghz_protocol_beninca_arc_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = BenincaARCDecoderHighLevel; + // Bit 0 is long and short timing = 600us HIGH (te_last) and 300us LOW + } else if( + (DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_beninca_arc_const.te_long) < + subghz_protocol_beninca_arc_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_beninca_arc_const.te_short) < + subghz_protocol_beninca_arc_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = BenincaARCDecoderHighLevel; + } else { + instance->decoder.parser_step = BenincaARCDecoderStart; + } + break; + } else { + instance->decoder.parser_step = BenincaARCDecoderStart; + break; + } + } +} + +uint8_t subghz_protocol_decoder_beninca_arc_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderBenincaARC* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +SubGhzProtocolStatus subghz_protocol_decoder_beninca_arc_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolDecoderBenincaARC* instance = context; + SubGhzProtocolStatus ret = + subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data_2 >> (i * 8)) & 0xFF; + } + + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + ret = SubGhzProtocolStatusErrorParserOthers; + } + + if((ret == SubGhzProtocolStatusOk) && + !flipper_format_insert_or_update_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to add Data"); + ret = SubGhzProtocolStatusErrorParserOthers; + } + return ret; +} + +SubGhzProtocolStatus + subghz_protocol_decoder_beninca_arc_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderBenincaARC* instance = context; + + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; + do { + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_beninca_arc_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { + break; + } + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + ret = SubGhzProtocolStatusErrorParserOthers; + break; + } + uint8_t key_data[sizeof(uint64_t)] = {0}; + if(!flipper_format_read_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Missing Data"); + ret = SubGhzProtocolStatusErrorParserOthers; + break; + } + + for(uint8_t i = 0; i < sizeof(uint64_t); i++) { + instance->generic.data_2 = instance->generic.data_2 << 8 | key_data[i]; + } + } while(false); + return ret; +} + +void subghz_protocol_decoder_beninca_arc_get_string(void* context, FuriString* output) { + furi_assert(context); + SubGhzProtocolDecoderBenincaARC* instance = context; + + uint64_t middle_bytes_dec = + subghz_protocol_beninca_arc_decrypt(&instance->generic, instance->keystore); + + // push protocol data to global variable + subghz_block_generic_global.cnt_is_available = true; + subghz_block_generic_global.cnt_length_bit = 32; + subghz_block_generic_global.current_cnt = instance->generic.cnt; + + furi_string_printf( + output, + "%s %db\r\n" + "Key1:%08llX\r\n" + "Key2:%08llX\r\n" + "Sn:%08lX Btn:%02X\r\n" + "Mc:%0lX Cnt:%0lX\r\n" + "Fx:%04lX", + instance->base.protocol->name, + instance->generic.data_count_bit, + instance->generic.data, + instance->generic.data_2, + instance->generic.serial, + instance->generic.btn, + (uint32_t)(middle_bytes_dec & 0xFFFFFFFF), + instance->generic.cnt, + instance->generic.seed & 0xFFFF); +} diff --git a/lib/subghz/protocols/beninca_arc.h b/lib/subghz/protocols/beninca_arc.h new file mode 100644 index 000000000..d61617002 --- /dev/null +++ b/lib/subghz/protocols/beninca_arc.h @@ -0,0 +1,108 @@ +#pragma once +#include "base.h" + +#define SUBGHZ_PROTOCOL_BENINCA_ARC_NAME "Beninca ARC" + +typedef struct SubGhzProtocolDecoderBenincaARC SubGhzProtocolDecoderBenincaARC; +typedef struct SubGhzProtocolEncoderBenincaARC SubGhzProtocolEncoderBenincaARC; + +extern const SubGhzProtocolDecoder subghz_protocol_beninca_arc_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_beninca_arc_encoder; +extern const SubGhzProtocol subghz_protocol_beninca_arc; + +/** + * Allocate SubGhzProtocolEncoderBenincaARC. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderBenincaARC* pointer to a SubGhzProtocolEncoderBenincaARC instance + */ +void* subghz_protocol_encoder_beninca_arc_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderBenincaARC. + * @param context Pointer to a SubGhzProtocolEncoderBenincaARC instance + */ +void subghz_protocol_encoder_beninca_arc_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderBenincaARC instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +SubGhzProtocolStatus + subghz_protocol_encoder_beninca_arc_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderBenincaARC instance + */ +void subghz_protocol_encoder_beninca_arc_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderBenincaARC instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_beninca_arc_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderBenincaARC. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderBenincaARC* pointer to a SubGhzProtocolDecoderBenincaARC instance + */ +void* subghz_protocol_decoder_beninca_arc_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderBenincaARC. + * @param context Pointer to a SubGhzProtocolDecoderBenincaARC instance + */ +void subghz_protocol_decoder_beninca_arc_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderBenincaARC. + * @param context Pointer to a SubGhzProtocolDecoderBenincaARC instance + */ +void subghz_protocol_decoder_beninca_arc_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderBenincaARC instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_beninca_arc_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderBenincaARC instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_beninca_arc_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderBenincaARC. + * @param context Pointer to a SubGhzProtocolDecoderBenincaARC instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return status + */ +SubGhzProtocolStatus subghz_protocol_decoder_beninca_arc_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data SubGhzProtocolDecoderBenincaARC. + * @param context Pointer to a SubGhzProtocolDecoderBenincaARC instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return status + */ +SubGhzProtocolStatus + subghz_protocol_decoder_beninca_arc_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderBenincaARC instance + * @param output Resulting text + */ +void subghz_protocol_decoder_beninca_arc_get_string(void* context, FuriString* output); diff --git a/lib/subghz/protocols/keeloq_common.h b/lib/subghz/protocols/keeloq_common.h index c4af17f26..90c5ef6d7 100644 --- a/lib/subghz/protocols/keeloq_common.h +++ b/lib/subghz/protocols/keeloq_common.h @@ -25,6 +25,7 @@ #define KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_1 6u #define KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_2 7u #define KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_3 8u +// #define BENINCA_ARC_KEY_TYPE 9u -- RESERVED /** * Simple Learning Encrypt diff --git a/lib/subghz/protocols/protocol_items.c b/lib/subghz/protocols/protocol_items.c index 230b9a508..2c4054dd2 100644 --- a/lib/subghz/protocols/protocol_items.c +++ b/lib/subghz/protocols/protocol_items.c @@ -27,6 +27,7 @@ const SubGhzProtocol* const subghz_protocol_registry_items[] = { &subghz_protocol_hay21, &subghz_protocol_revers_rb2, &subghz_protocol_feron, &subghz_protocol_roger, &subghz_protocol_elplast, &subghz_protocol_treadmill37, + &subghz_protocol_beninca_arc, }; const SubGhzProtocolRegistry subghz_protocol_registry = { diff --git a/lib/subghz/protocols/protocol_items.h b/lib/subghz/protocols/protocol_items.h index 223dd1712..f61e71420 100644 --- a/lib/subghz/protocols/protocol_items.h +++ b/lib/subghz/protocols/protocol_items.h @@ -54,3 +54,4 @@ #include "roger.h" #include "elplast.h" #include "treadmill37.h" +#include "beninca_arc.h" diff --git a/lib/subghz/protocols/public_api.h b/lib/subghz/protocols/public_api.h index c9a866f2c..30b8212ce 100644 --- a/lib/subghz/protocols/public_api.h +++ b/lib/subghz/protocols/public_api.h @@ -213,6 +213,24 @@ bool subghz_protocol_kinggates_stylo_4k_create_data( uint16_t cnt, SubGhzRadioPreset* preset); +/** + * Key generation from simple data. + * @param context Pointer to a SubGhzProtocolEncoderBenincaARC instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param serial Serial number, 32 bit + * @param btn Button number, 8 bit + * @param cnt Counter value, 32 bit + * @param preset Modulation, SubGhzRadioPreset + * @return true On success + */ +bool subghz_protocol_beninca_arc_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint32_t cnt, + SubGhzRadioPreset* preset); + typedef struct SubGhzProtocolDecoderBinRAW SubGhzProtocolDecoderBinRAW; void subghz_protocol_decoder_bin_raw_data_input_rssi( diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 2e59c7d51..7e6190628 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,87.3,, +Version,+,87.4,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/applications.h,, Header,+,applications/services/bt/bt_service/bt.h,, @@ -3684,6 +3684,7 @@ Function,+,subghz_keystore_raw_get_data,_Bool,"const char*, size_t, uint8_t*, si Function,+,subghz_keystore_reset_kl,void,SubGhzKeystore* Function,+,subghz_keystore_save,_Bool,"SubGhzKeystore*, const char*, uint8_t*" Function,+,subghz_protocol_alutech_at_4n_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*" +Function,+,subghz_protocol_beninca_arc_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint32_t, SubGhzRadioPreset*" Function,+,subghz_protocol_blocks_add_bit,void,"SubGhzBlockDecoder*, uint8_t" Function,+,subghz_protocol_blocks_add_bytes,uint8_t,"const uint8_t[], size_t" Function,+,subghz_protocol_blocks_add_to_128_bit,void,"SubGhzBlockDecoder*, uint8_t, uint64_t*" From 5bf0a7dbc5be1bbc45abc1013cc6e6f20c61bb84 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 21 Jan 2026 07:59:05 +0300 Subject: [PATCH 039/160] subghz: smol fixes --- applications/main/subghz/scenes/subghz_scene_decode_raw.c | 8 ++++++++ lib/subghz/protocols/faac_slh.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index b6c57414f..17491d2b0 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -122,8 +122,16 @@ bool subghz_scene_decode_raw_next(SubGhz* subghz) { level_duration = subghz_file_encoder_worker_get_level_duration(subghz->decode_raw_file_worker_encoder); if(!level_duration_is_reset(level_duration)) { + if(level_duration_is_wait(level_duration)) { + FURI_LOG_W(TAG, "LD tells wait!"); + return true; + } bool level = level_duration_get_level(level_duration); uint32_t duration = level_duration_get_duration(level_duration); + if(duration > 1000000) { + FURI_LOG_E(TAG, "LD came with overflow: %ld", duration); + return true; + } subghz_receiver_decode(receiver, level, duration); } else { scene_manager_set_scene_state( diff --git a/lib/subghz/protocols/faac_slh.c b/lib/subghz/protocols/faac_slh.c index 7297a179d..f968f4926 100644 --- a/lib/subghz/protocols/faac_slh.c +++ b/lib/subghz/protocols/faac_slh.c @@ -153,7 +153,7 @@ static bool subghz_protocol_faac_slh_gen_data(SubGhzProtocolEncoderFaacSLH* inst } } } else { - // to do OFEX mode + // TODO: OFEX mode instance->generic.cnt += 1; } From 14cd98cbe3a78a9c28043b2009848254b3020c96 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 21 Jan 2026 08:05:58 +0300 Subject: [PATCH 040/160] subghz: remove data variable from niceflors [ci skip] --- lib/subghz/protocols/nice_flor_s.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index 0b5c39311..0f11b5645 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -35,7 +35,6 @@ struct SubGhzProtocolDecoderNiceFlorS { SubGhzBlockGeneric generic; const char* nice_flor_s_rainbow_table_file_name; - uint64_t data; }; struct SubGhzProtocolEncoderNiceFlorS { @@ -638,8 +637,8 @@ void subghz_protocol_decoder_nice_flor_s_feed(void* context, bool level, uint32_ if((instance->decoder.decode_count_bit == subghz_protocol_nice_flor_s_const.min_count_bit_for_found) || (instance->decoder.decode_count_bit == NICE_ONE_COUNT_BIT)) { - instance->generic.data = instance->data; - instance->data = instance->decoder.decode_data; + instance->generic.data = instance->generic.data_2; + instance->generic.data_2 = instance->decoder.decode_data; instance->decoder.decode_data = instance->generic.data; instance->generic.data_count_bit = instance->decoder.decode_count_bit; @@ -678,7 +677,7 @@ void subghz_protocol_decoder_nice_flor_s_feed(void* context, bool level, uint32_ } if(instance->decoder.decode_count_bit == subghz_protocol_nice_flor_s_const.min_count_bit_for_found) { - instance->data = instance->decoder.decode_data; + instance->generic.data_2 = instance->decoder.decode_data; instance->decoder.decode_data = 0; } break; @@ -774,7 +773,7 @@ SubGhzProtocolStatus subghz_protocol_decoder_nice_flor_s_serialize( } if((ret == SubGhzProtocolStatusOk) && !flipper_format_insert_or_update_uint32( - flipper_format, "Data", (uint32_t*)&instance->data, 1)) { + flipper_format, "Data", (uint32_t*)&instance->generic.data_2, 1)) { FURI_LOG_E(TAG, "Unable to add Data"); ret = SubGhzProtocolStatusErrorParserOthers; } @@ -811,7 +810,7 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorParserOthers; break; } - instance->data = (uint64_t)temp; + instance->generic.data_2 = (uint64_t)temp; } if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); @@ -948,7 +947,7 @@ void subghz_protocol_decoder_nice_flor_s_get_string(void* context, FuriString* o NICE_ONE_NAME, instance->generic.data_count_bit, instance->generic.data, - instance->data, + instance->generic.data_2, instance->generic.serial, instance->generic.cnt, instance->generic.btn); From 647fdace0e560b2861b0c784a98ebc4228990f3a Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 21 Jan 2026 08:35:51 +0300 Subject: [PATCH 041/160] fix typo --- lib/subghz/protocols/alutech_at_4n.c | 2 +- lib/subghz/protocols/ansonic.c | 2 +- lib/subghz/protocols/beninca_arc.c | 2 +- lib/subghz/protocols/bett.c | 2 +- lib/subghz/protocols/bin_raw.c | 4 ++-- lib/subghz/protocols/came.c | 2 +- lib/subghz/protocols/came_atomo.c | 2 +- lib/subghz/protocols/came_twee.c | 2 +- lib/subghz/protocols/chamberlain_code.c | 2 +- lib/subghz/protocols/clemsa.c | 2 +- lib/subghz/protocols/dickert_mahs.c | 2 +- lib/subghz/protocols/doitrand.c | 2 +- lib/subghz/protocols/dooya.c | 2 +- lib/subghz/protocols/elplast.c | 2 +- lib/subghz/protocols/faac_slh.c | 2 +- lib/subghz/protocols/feron.c | 2 +- lib/subghz/protocols/gangqi.c | 2 +- lib/subghz/protocols/gate_tx.c | 2 +- lib/subghz/protocols/hay21.c | 2 +- lib/subghz/protocols/hollarm.c | 2 +- lib/subghz/protocols/holtek.c | 2 +- lib/subghz/protocols/holtek_ht12x.c | 2 +- lib/subghz/protocols/honeywell.c | 2 +- lib/subghz/protocols/honeywell_wdb.c | 2 +- lib/subghz/protocols/hormann.c | 2 +- lib/subghz/protocols/intertechno_v3.c | 2 +- lib/subghz/protocols/keeloq.c | 2 +- lib/subghz/protocols/kinggates_stylo_4k.c | 2 +- lib/subghz/protocols/linear.c | 2 +- lib/subghz/protocols/linear_delta3.c | 2 +- lib/subghz/protocols/magellan.c | 2 +- lib/subghz/protocols/marantec.c | 2 +- lib/subghz/protocols/marantec24.c | 2 +- lib/subghz/protocols/mastercode.c | 2 +- lib/subghz/protocols/megacode.c | 2 +- lib/subghz/protocols/nero_radio.c | 2 +- lib/subghz/protocols/nero_sketch.c | 2 +- lib/subghz/protocols/nice_flo.c | 2 +- lib/subghz/protocols/nice_flor_s.c | 2 +- lib/subghz/protocols/phoenix_v2.c | 2 +- lib/subghz/protocols/power_smart.c | 2 +- lib/subghz/protocols/princeton.c | 2 +- lib/subghz/protocols/revers_rb2.c | 2 +- lib/subghz/protocols/roger.c | 2 +- lib/subghz/protocols/secplus_v1.c | 2 +- lib/subghz/protocols/secplus_v2.c | 2 +- lib/subghz/protocols/smc5326.c | 2 +- lib/subghz/protocols/somfy_keytis.c | 2 +- lib/subghz/protocols/somfy_telis.c | 2 +- lib/subghz/protocols/treadmill37.c | 2 +- 50 files changed, 51 insertions(+), 51 deletions(-) diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 9959e7cd2..8dff70dd1 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -483,7 +483,7 @@ SubGhzProtocolStatus subghz_protocol_encoder_alutech_at_4n_deserialize( break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/ansonic.c b/lib/subghz/protocols/ansonic.c index 9a122629b..75f803370 100644 --- a/lib/subghz/protocols/ansonic.c +++ b/lib/subghz/protocols/ansonic.c @@ -150,7 +150,7 @@ SubGhzProtocolStatus FURI_LOG_E(TAG, "Deserialize error"); break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/beninca_arc.c b/lib/subghz/protocols/beninca_arc.c index a77301fa3..62eb925f8 100644 --- a/lib/subghz/protocols/beninca_arc.c +++ b/lib/subghz/protocols/beninca_arc.c @@ -412,7 +412,7 @@ SubGhzProtocolStatus break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/bett.c b/lib/subghz/protocols/bett.c index 7fce94448..44946a2f6 100644 --- a/lib/subghz/protocols/bett.c +++ b/lib/subghz/protocols/bett.c @@ -169,7 +169,7 @@ SubGhzProtocolStatus FURI_LOG_E(TAG, "Deserialize error"); break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/bin_raw.c b/lib/subghz/protocols/bin_raw.c index 145aa5cee..f060f93bb 100644 --- a/lib/subghz/protocols/bin_raw.c +++ b/lib/subghz/protocols/bin_raw.c @@ -309,7 +309,7 @@ SubGhzProtocolStatus res = SubGhzProtocolStatusErrorParserOthers; break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); @@ -430,7 +430,7 @@ static bool } else if( DURATION_DIFF((float)(abs(instance->data_raw[i])), (classes[k].data)) < (classes[k].data / 4)) { //if the test value does not differ by more than 25% - classes[k].data += ((float)(abs(instance->data_raw[i])) - classes[k].data) * + classes[k].data += ((float)(abs(instance->data_raw[i]))-classes[k].data) * 0.05f; //running average k=0.05 classes[k].count++; break; diff --git a/lib/subghz/protocols/came.c b/lib/subghz/protocols/came.c index c3d9c8662..2762a2484 100644 --- a/lib/subghz/protocols/came.c +++ b/lib/subghz/protocols/came.c @@ -181,7 +181,7 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorValueBitCount; break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/came_atomo.c b/lib/subghz/protocols/came_atomo.c index 043736a34..f8ec7baa0 100644 --- a/lib/subghz/protocols/came_atomo.c +++ b/lib/subghz/protocols/came_atomo.c @@ -374,7 +374,7 @@ SubGhzProtocolStatus break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/came_twee.c b/lib/subghz/protocols/came_twee.c index 2369e854d..3bb909dc8 100644 --- a/lib/subghz/protocols/came_twee.c +++ b/lib/subghz/protocols/came_twee.c @@ -254,7 +254,7 @@ SubGhzProtocolStatus if(res != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/chamberlain_code.c b/lib/subghz/protocols/chamberlain_code.c index ea85fc0d9..fda224bb6 100644 --- a/lib/subghz/protocols/chamberlain_code.c +++ b/lib/subghz/protocols/chamberlain_code.c @@ -223,7 +223,7 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorValueBitCount; break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/clemsa.c b/lib/subghz/protocols/clemsa.c index 5cbffefed..672abcba3 100644 --- a/lib/subghz/protocols/clemsa.c +++ b/lib/subghz/protocols/clemsa.c @@ -168,7 +168,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/dickert_mahs.c b/lib/subghz/protocols/dickert_mahs.c index 3f614412b..65be6fd0c 100644 --- a/lib/subghz/protocols/dickert_mahs.c +++ b/lib/subghz/protocols/dickert_mahs.c @@ -207,7 +207,7 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorValueBitCount; break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/doitrand.c b/lib/subghz/protocols/doitrand.c index cf9618fcb..7c7946042 100644 --- a/lib/subghz/protocols/doitrand.c +++ b/lib/subghz/protocols/doitrand.c @@ -149,7 +149,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/dooya.c b/lib/subghz/protocols/dooya.c index 816847840..fd8645a0b 100644 --- a/lib/subghz/protocols/dooya.c +++ b/lib/subghz/protocols/dooya.c @@ -159,7 +159,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/elplast.c b/lib/subghz/protocols/elplast.c index c95eb84ba..18d6d07b4 100644 --- a/lib/subghz/protocols/elplast.c +++ b/lib/subghz/protocols/elplast.c @@ -141,7 +141,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/faac_slh.c b/lib/subghz/protocols/faac_slh.c index f968f4926..147e452eb 100644 --- a/lib/subghz/protocols/faac_slh.c +++ b/lib/subghz/protocols/faac_slh.c @@ -398,7 +398,7 @@ SubGhzProtocolStatus subghz_protocol_faac_slh_check_remote_controller( &instance->generic, instance->keystore, &instance->manufacture_name); - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/feron.c b/lib/subghz/protocols/feron.c index 0fcb14c1b..9591a4ebb 100644 --- a/lib/subghz/protocols/feron.c +++ b/lib/subghz/protocols/feron.c @@ -160,7 +160,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/gangqi.c b/lib/subghz/protocols/gangqi.c index 0d88f1f39..6b5542410 100644 --- a/lib/subghz/protocols/gangqi.c +++ b/lib/subghz/protocols/gangqi.c @@ -253,7 +253,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/gate_tx.c b/lib/subghz/protocols/gate_tx.c index d6a6bc7c9..608567626 100644 --- a/lib/subghz/protocols/gate_tx.c +++ b/lib/subghz/protocols/gate_tx.c @@ -142,7 +142,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/hay21.c b/lib/subghz/protocols/hay21.c index 382124ab6..ba6119dae 100644 --- a/lib/subghz/protocols/hay21.c +++ b/lib/subghz/protocols/hay21.c @@ -267,7 +267,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/hollarm.c b/lib/subghz/protocols/hollarm.c index 448fccdbe..9b2a53a05 100644 --- a/lib/subghz/protocols/hollarm.c +++ b/lib/subghz/protocols/hollarm.c @@ -254,7 +254,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/holtek.c b/lib/subghz/protocols/holtek.c index b4717f5c6..7ed5fc152 100644 --- a/lib/subghz/protocols/holtek.c +++ b/lib/subghz/protocols/holtek.c @@ -155,7 +155,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/holtek_ht12x.c b/lib/subghz/protocols/holtek_ht12x.c index be2dfd406..bf5e48adf 100644 --- a/lib/subghz/protocols/holtek_ht12x.c +++ b/lib/subghz/protocols/holtek_ht12x.c @@ -170,7 +170,7 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorParserTe; break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/honeywell.c b/lib/subghz/protocols/honeywell.c index f1ed6e4b8..1e3f231e8 100644 --- a/lib/subghz/protocols/honeywell.c +++ b/lib/subghz/protocols/honeywell.c @@ -211,7 +211,7 @@ SubGhzProtocolStatus break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/honeywell_wdb.c b/lib/subghz/protocols/honeywell_wdb.c index 16545b8a0..0b8f63a24 100644 --- a/lib/subghz/protocols/honeywell_wdb.c +++ b/lib/subghz/protocols/honeywell_wdb.c @@ -156,7 +156,7 @@ SubGhzProtocolStatus subghz_protocol_encoder_honeywell_wdb_deserialize( if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/hormann.c b/lib/subghz/protocols/hormann.c index 43a490ff9..f74a29fec 100644 --- a/lib/subghz/protocols/hormann.c +++ b/lib/subghz/protocols/hormann.c @@ -153,7 +153,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/intertechno_v3.c b/lib/subghz/protocols/intertechno_v3.c index da25e1e75..71513051b 100644 --- a/lib/subghz/protocols/intertechno_v3.c +++ b/lib/subghz/protocols/intertechno_v3.c @@ -176,7 +176,7 @@ SubGhzProtocolStatus subghz_protocol_encoder_intertechno_v3_deserialize( ret = SubGhzProtocolStatusErrorValueBitCount; break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index e0bfaef57..cd657f23f 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -667,7 +667,7 @@ SubGhzProtocolStatus subghz_protocol_keeloq_check_remote_controller( &instance->generic, instance->keystore, &instance->manufacture_name); - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/kinggates_stylo_4k.c b/lib/subghz/protocols/kinggates_stylo_4k.c index f46d07ccd..e23042b55 100644 --- a/lib/subghz/protocols/kinggates_stylo_4k.c +++ b/lib/subghz/protocols/kinggates_stylo_4k.c @@ -344,7 +344,7 @@ SubGhzProtocolStatus subghz_protocol_encoder_kinggates_stylo_4k_deserialize( break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/linear.c b/lib/subghz/protocols/linear.c index 7671dc428..f024316e9 100644 --- a/lib/subghz/protocols/linear.c +++ b/lib/subghz/protocols/linear.c @@ -160,7 +160,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/linear_delta3.c b/lib/subghz/protocols/linear_delta3.c index 321d25d41..c2f527ba8 100644 --- a/lib/subghz/protocols/linear_delta3.c +++ b/lib/subghz/protocols/linear_delta3.c @@ -164,7 +164,7 @@ SubGhzProtocolStatus subghz_protocol_encoder_linear_delta3_deserialize( if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/magellan.c b/lib/subghz/protocols/magellan.c index 209204817..55048ca61 100644 --- a/lib/subghz/protocols/magellan.c +++ b/lib/subghz/protocols/magellan.c @@ -164,7 +164,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/marantec.c b/lib/subghz/protocols/marantec.c index 658aac610..53e4d6895 100644 --- a/lib/subghz/protocols/marantec.c +++ b/lib/subghz/protocols/marantec.c @@ -213,7 +213,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/marantec24.c b/lib/subghz/protocols/marantec24.c index ac602fc96..6f636e8ab 100644 --- a/lib/subghz/protocols/marantec24.c +++ b/lib/subghz/protocols/marantec24.c @@ -155,7 +155,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/mastercode.c b/lib/subghz/protocols/mastercode.c index d4c549a42..e4fae40b3 100644 --- a/lib/subghz/protocols/mastercode.c +++ b/lib/subghz/protocols/mastercode.c @@ -168,7 +168,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/megacode.c b/lib/subghz/protocols/megacode.c index ba58bc445..2c4bf10a3 100644 --- a/lib/subghz/protocols/megacode.c +++ b/lib/subghz/protocols/megacode.c @@ -188,7 +188,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/nero_radio.c b/lib/subghz/protocols/nero_radio.c index d7822ac1c..da5497feb 100644 --- a/lib/subghz/protocols/nero_radio.c +++ b/lib/subghz/protocols/nero_radio.c @@ -180,7 +180,7 @@ SubGhzProtocolStatus break; } } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/nero_sketch.c b/lib/subghz/protocols/nero_sketch.c index 09cd0255a..64a75cfc0 100644 --- a/lib/subghz/protocols/nero_sketch.c +++ b/lib/subghz/protocols/nero_sketch.c @@ -161,7 +161,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/nice_flo.c b/lib/subghz/protocols/nice_flo.c index f60e07fb8..2e5fa96b5 100644 --- a/lib/subghz/protocols/nice_flo.c +++ b/lib/subghz/protocols/nice_flo.c @@ -147,7 +147,7 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorValueBitCount; break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index 0f11b5645..9085ee431 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -279,7 +279,7 @@ SubGhzProtocolStatus break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); // flipper_format_read_uint32( diff --git a/lib/subghz/protocols/phoenix_v2.c b/lib/subghz/protocols/phoenix_v2.c index b32c7fb60..1f2731f54 100644 --- a/lib/subghz/protocols/phoenix_v2.c +++ b/lib/subghz/protocols/phoenix_v2.c @@ -322,7 +322,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/power_smart.c b/lib/subghz/protocols/power_smart.c index 1359f416d..6449f720a 100644 --- a/lib/subghz/protocols/power_smart.c +++ b/lib/subghz/protocols/power_smart.c @@ -206,7 +206,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/princeton.c b/lib/subghz/protocols/princeton.c index 040ed8378..cce8a7a34 100644 --- a/lib/subghz/protocols/princeton.c +++ b/lib/subghz/protocols/princeton.c @@ -354,7 +354,7 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorParserTe; break; } - //optional parameter parameter + // Optional value if(!flipper_format_read_uint32( flipper_format, "Guard_time", (uint32_t*)&instance->guard_time, 1)) { instance->guard_time = PRINCETON_GUARD_TIME_DEFALUT; diff --git a/lib/subghz/protocols/revers_rb2.c b/lib/subghz/protocols/revers_rb2.c index 3d60a0730..941ff5c56 100644 --- a/lib/subghz/protocols/revers_rb2.c +++ b/lib/subghz/protocols/revers_rb2.c @@ -176,7 +176,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/roger.c b/lib/subghz/protocols/roger.c index 7b57cbab4..9c33b11ec 100644 --- a/lib/subghz/protocols/roger.c +++ b/lib/subghz/protocols/roger.c @@ -265,7 +265,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/secplus_v1.c b/lib/subghz/protocols/secplus_v1.c index c5690b910..13af0d302 100644 --- a/lib/subghz/protocols/secplus_v1.c +++ b/lib/subghz/protocols/secplus_v1.c @@ -298,7 +298,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/secplus_v2.c b/lib/subghz/protocols/secplus_v2.c index 9d24c1ae8..ad343968b 100644 --- a/lib/subghz/protocols/secplus_v2.c +++ b/lib/subghz/protocols/secplus_v2.c @@ -574,7 +574,7 @@ SubGhzProtocolStatus subghz_protocol_secplus_v2_remote_controller( &instance->generic, instance->secplus_packet_1); subghz_protocol_secplus_v2_encode(instance); - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); subghz_protocol_encoder_secplus_v2_get_upload(instance); diff --git a/lib/subghz/protocols/smc5326.c b/lib/subghz/protocols/smc5326.c index 0b9755b8c..217dbb780 100644 --- a/lib/subghz/protocols/smc5326.c +++ b/lib/subghz/protocols/smc5326.c @@ -178,7 +178,7 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorParserTe; break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/somfy_keytis.c b/lib/subghz/protocols/somfy_keytis.c index cb9af5bb6..c9f6f47bd 100644 --- a/lib/subghz/protocols/somfy_keytis.c +++ b/lib/subghz/protocols/somfy_keytis.c @@ -412,7 +412,7 @@ SubGhzProtocolStatus break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/somfy_telis.c b/lib/subghz/protocols/somfy_telis.c index 116e5e224..2be378b7d 100644 --- a/lib/subghz/protocols/somfy_telis.c +++ b/lib/subghz/protocols/somfy_telis.c @@ -341,7 +341,7 @@ SubGhzProtocolStatus break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/treadmill37.c b/lib/subghz/protocols/treadmill37.c index 215b48e71..e9915c296 100644 --- a/lib/subghz/protocols/treadmill37.c +++ b/lib/subghz/protocols/treadmill37.c @@ -151,7 +151,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - //optional parameter parameter + // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); From 579887ccc5649a9328c9e6eff63531b98d7cc5da Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 21 Jan 2026 08:58:09 +0300 Subject: [PATCH 042/160] upd changelog --- CHANGELOG.md | 14 ++++++++++---- documentation/SubGHzSupportedSystems.md | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a0ad81f0..a0ea760b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ ## Main changes -- Current API: 87.2 -* SubGHz: **Cardin S449 full support** (with Add manually, and all button codes) (**use FSK12K modulation to read the remote**) (closes issues #735 #908) (by @xMasterX and @zero-mega (thanks!)) -* SubGHz: Added **new modulation FSK with 12KHz deviation** +- Current API: 87.4 +* SubGHz: **Cardin S449 protocol full support** (64bit keeloq) (with Add manually, and all button codes) (**use FSK12K modulation to read the remote**) (closes issues #735 #908) (by @xMasterX and @zero-mega (thanks!)) +* SubGHz: **Beninca ARC AES128 protocol full support** (128bit dynamic) (with Add manually, and 2 button codes) (resolves issue #596) (by @xMasterX and @zero-mega) +* SubGHz: **Treadmill37 protocol support** (37bit static) (by @xMasterX) +* SubGHz: **New modulation FSK with 12KHz deviation** * SubGHz: **KingGates Stylo 4k - Add manually and button switch support** + refactoring of encoder * SubGHz: **Stilmatic - button 9 support** (two buttons hold simulation) (mapped on arrow keys) * SubGHz: **Counter editor refactoring** (PR #939 | by @Dmitry422) @@ -9,10 +11,14 @@ * SubGHz: **Sommer fm2 in Add manually now uses FM12K modulation** (Sommer without fm2 tag uses FM476) (try this if regular option doesn't work for you) * SubGHz: **Sommer - last button code 0x6 support** (mapped on arrow keys) * SubGHz: Add 390MHz, 430.5MHz to default hopper list (6 elements like in OFW) (works well with Hopper RSSI level set for your enviroment) +* SubGHz: Fixed button mapping for **FAAC RC/XT** * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * Archive: Allow folders to be pinned (by @WillyJL) -* Apps: Build tag (**9jan2026p2**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) +* Apps: Build tag (**21jan2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes +* SubGHz: Possible Sommer timings fix +* SubGHz: Various fixes +* SubGHz: Nice Flor S remove extra uint64 variable * SubGHz: Rename Sommer(fsk476) to Sommer (Sommer keeloq works better with FM12K) + added backwards compatibility with older saved files * Docs: Add full list of supported SubGHz protocols and their frequencies/modulations that can be used for reading remotes - [Docs Link](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSupportedSystems.md) * Desktop: Show debug status (D) if clock is enabled and debug flag is on (PR #942 | by @Dmitry422) diff --git a/documentation/SubGHzSupportedSystems.md b/documentation/SubGHzSupportedSystems.md index a30a9e475..d9269fbe9 100644 --- a/documentation/SubGHzSupportedSystems.md +++ b/documentation/SubGHzSupportedSystems.md @@ -20,6 +20,7 @@ That list is only for default SubGHz app, apps like *Weather Station* have their - AN-Motors (Alutech) AT4 `433.92MHz` `AM650` (64 bits, Pseudo-Dynamic, KeeLoq based) - Ansonic `433MHz` `FM` (12 bits, Static) - BETT `433.92MHz` `AM650` (18 bits, Static) +- Beninca ARC (TOGO2VA) `433.92MHz` `AM650` (128 bits, Dynamic AES) - BFT Mitto `433.92MHz` `AM650` (64 bits, Dynamic, KeeLoq based with Seed) - CAME Atomo `433.92MHz, 868MHz` `AM650` (62 bits, Dynamic) - CAME TWEE `433.92MHz` `AM650` (54 bits, Static) From 28bc7b056986b50de65bfd9287b11f719437d80f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 21 Jan 2026 09:12:04 +0300 Subject: [PATCH 043/160] fix slix unlock scene led not blinking --- CHANGELOG.md | 1 + applications/main/nfc/scenes/nfc_scene_slix_unlock.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0ea760b6..a83f7a68c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ * Archive: Allow folders to be pinned (by @WillyJL) * Apps: Build tag (**21jan2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes +* NFC: Fix LED not blinking at SLIX unlock (closes issue #945) * SubGHz: Possible Sommer timings fix * SubGHz: Various fixes * SubGHz: Nice Flor S remove extra uint64 variable diff --git a/applications/main/nfc/scenes/nfc_scene_slix_unlock.c b/applications/main/nfc/scenes/nfc_scene_slix_unlock.c index ae725ce67..f6e5a8f50 100644 --- a/applications/main/nfc/scenes/nfc_scene_slix_unlock.c +++ b/applications/main/nfc/scenes/nfc_scene_slix_unlock.c @@ -35,6 +35,8 @@ void nfc_scene_slix_unlock_on_enter(void* context) { instance->popup, "Hold card next\nto Flipper's back", 94, 27, AlignCenter, AlignTop); view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); + notification_message(instance->notifications, &sequence_blink_start_cyan); + instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolSlix); nfc_poller_start(instance->poller, nfc_scene_slix_unlock_worker_callback, instance); } @@ -67,4 +69,7 @@ void nfc_scene_slix_unlock_on_exit(void* context) { nfc_poller_free(instance->poller); popup_reset(instance->popup); + + // Stop notifications + nfc_blink_stop(instance); } From 5d4c1afcd07a307bc900ada810b681ed64c9e870 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 21 Jan 2026 09:32:21 +0300 Subject: [PATCH 044/160] oops add missing changelog [ci skip] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a83f7a68c..4ef922555 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ * Apps: Build tag (**21jan2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes * NFC: Fix LED not blinking at SLIX unlock (closes issue #945) +* SubGHz: Replaced Cars ignore option with Revers RB2 protocol ignore option +* SubGHz: Moved Starline, ScherKhan, Kia decoders into external app * SubGHz: Possible Sommer timings fix * SubGHz: Various fixes * SubGHz: Nice Flor S remove extra uint64 variable From 3f85bea80dad661f8d47f0715c36a11e5004d839 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 21 Jan 2026 19:55:15 +0300 Subject: [PATCH 045/160] fix slix unlock color --- applications/main/nfc/scenes/nfc_scene_slix_unlock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/nfc/scenes/nfc_scene_slix_unlock.c b/applications/main/nfc/scenes/nfc_scene_slix_unlock.c index f6e5a8f50..21305c58d 100644 --- a/applications/main/nfc/scenes/nfc_scene_slix_unlock.c +++ b/applications/main/nfc/scenes/nfc_scene_slix_unlock.c @@ -35,7 +35,7 @@ void nfc_scene_slix_unlock_on_enter(void* context) { instance->popup, "Hold card next\nto Flipper's back", 94, 27, AlignCenter, AlignTop); view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); - notification_message(instance->notifications, &sequence_blink_start_cyan); + notification_message(instance->notifications, &sequence_blink_start_yellow); instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolSlix); nfc_poller_start(instance->poller, nfc_scene_slix_unlock_worker_callback, instance); From d73d0f7fbd86613c5d2d8e300cecd476118fd6f8 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 21 Jan 2026 22:49:07 +0300 Subject: [PATCH 046/160] various ui/ux changes text spacing reduced from 4px to 3px some text was replaced --- .../main/nfc/helpers/protocol_support/felica/felica.c | 4 +--- applications/main/subghz/subghz_history.c | 2 +- applications/services/gui/elements.c | 8 ++++---- .../modules/widget_elements/widget_element_text_scroll.c | 2 +- lib/subghz/protocols/bin_raw.c | 2 +- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/felica/felica.c b/applications/main/nfc/helpers/protocol_support/felica/felica.c index 26dc86d41..0c98e7ffc 100644 --- a/applications/main/nfc/helpers/protocol_support/felica/felica.c +++ b/applications/main/nfc/helpers/protocol_support/felica/felica.c @@ -105,9 +105,7 @@ static void nfc_scene_read_success_on_enter_felica(NfcApp* instance) { if(data->workflow_type == FelicaLite) { bool all_unlocked = data->blocks_read == data->blocks_total; furi_string_cat_printf( - temp_str, - "\e#%s\n", - all_unlocked ? "All Blocks Are Unlocked" : "Some Blocks Are Locked"); + temp_str, "\e#%s\n", all_unlocked ? "All Blocks Unlocked" : "Some Blocks Locked"); nfc_render_felica_idm(data, NfcProtocolFormatTypeShort, temp_str); uint8_t* ck_data = instance->felica_auth->card_key.data; furi_string_cat_printf(temp_str, "Key:"); diff --git a/applications/main/subghz/subghz_history.c b/applications/main/subghz/subghz_history.c index d5dcee020..20d73feb0 100644 --- a/applications/main/subghz/subghz_history.c +++ b/applications/main/subghz/subghz_history.c @@ -153,7 +153,7 @@ FlipperFormat* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx bool subghz_history_get_text_space_left(SubGhzHistory* instance, FuriString* output) { furi_assert(instance); if(memmgr_get_free_heap() < SUBGHZ_HISTORY_FREE_HEAP) { - if(output != NULL) furi_string_printf(output, " Free heap LOW"); + if(output != NULL) furi_string_printf(output, " RAM almost FULL"); return true; } if(instance->last_index_write == SUBGHZ_HISTORY_MAX) { diff --git a/applications/services/gui/elements.c b/applications/services/gui/elements.c index 763c8b1b0..d32cbc8c9 100644 --- a/applications/services/gui/elements.c +++ b/applications/services/gui/elements.c @@ -339,7 +339,7 @@ void elements_multiline_text_aligned( furi_check(text); size_t lines_count = 0; - size_t font_height = canvas_current_font_height(canvas); + size_t font_height = canvas_current_font_height(canvas) - 1; FuriString* line; /* go through text line by line and count lines */ @@ -384,7 +384,7 @@ void elements_multiline_text(Canvas* canvas, int32_t x, int32_t y, const char* t furi_check(canvas); furi_check(text); - size_t font_height = canvas_current_font_height(canvas); + size_t font_height = canvas_current_font_height(canvas) - 1; FuriString* str; str = furi_string_alloc(); const char* start = text; @@ -407,7 +407,7 @@ void elements_multiline_text_framed(Canvas* canvas, int32_t x, int32_t y, const furi_check(canvas); furi_check(text); - size_t font_height = canvas_current_font_height(canvas); + size_t font_height = canvas_current_font_height(canvas) - 1; size_t str_width = canvas_string_width(canvas, text); // count \n's @@ -778,7 +778,7 @@ void elements_text_box( // Fill line parameters size_t line_leading_min = font_params->leading_min; size_t line_leading_default = font_params->leading_default; - size_t line_height = font_params->height; + size_t line_height = font_params->height - 1; size_t line_descender = font_params->descender; size_t line_num = 0; size_t line_width = 0; diff --git a/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c b/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c index 866aad815..ed4b19654 100644 --- a/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c +++ b/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c @@ -152,7 +152,7 @@ static void widget_element_text_scroll_draw(Canvas* canvas, WidgetElement* eleme } canvas_draw_str_aligned( canvas, x, y, line->horizontal, AlignTop, furi_string_get_cstr(line->text)); - y += params->leading_default; + y += params->leading_default - 1; } // Draw scroll bar if(model->scroll_pos_total > 1) { diff --git a/lib/subghz/protocols/bin_raw.c b/lib/subghz/protocols/bin_raw.c index f060f93bb..ca52cdd49 100644 --- a/lib/subghz/protocols/bin_raw.c +++ b/lib/subghz/protocols/bin_raw.c @@ -430,7 +430,7 @@ static bool } else if( DURATION_DIFF((float)(abs(instance->data_raw[i])), (classes[k].data)) < (classes[k].data / 4)) { //if the test value does not differ by more than 25% - classes[k].data += ((float)(abs(instance->data_raw[i]))-classes[k].data) * + classes[k].data += ((float)(abs(instance->data_raw[i])) - classes[k].data) * 0.05f; //running average k=0.05 classes[k].count++; break; From 7c27fe93591a98287bfe96db667e63f31d7d6ea4 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Wed, 21 Jan 2026 23:37:07 +0100 Subject: [PATCH 047/160] Sub-GHz: Disable X10 and Hormann Bisecur protocols --nobuild --- CHANGELOG.md | 4 +++- lib/subghz/protocols/protocol_items.c | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93e99ff77..b56b30a55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,4 +26,6 @@ - UL: NFC: Fix LED not blinking at SLIX unlock (by @xMasterX) ### Removed: -- SUb-GHz: Removed Starline, ScherKhan and Kia protocols from main Sub-GHz app, they can be decoded with `Apps > Sub-GHz > ProtoPirate` external app +- Sub-GHz: + - Removed Starline, ScherKhan and Kia protocols from main Sub-GHz app, they can be decoded with `Apps > Sub-GHz > ProtoPirate` external app + - Disabled X10 and Hormann Bisecur protocols due to flash space constraints and very limited usefulness, Momentum now has same protocol list as Unleashed diff --git a/lib/subghz/protocols/protocol_items.c b/lib/subghz/protocols/protocol_items.c index 4c1015029..d802e54b9 100644 --- a/lib/subghz/protocols/protocol_items.c +++ b/lib/subghz/protocols/protocol_items.c @@ -69,8 +69,8 @@ const SubGhzProtocol* const subghz_protocol_registry_items[] = { // &tpms_protocol_schrader_gg4, &subghz_protocol_bin_raw, &subghz_protocol_mastercode, - &subghz_protocol_x10, - &subghz_protocol_hormann_bisecur, + // &subghz_protocol_x10, + // &subghz_protocol_hormann_bisecur, &subghz_protocol_legrand, &subghz_protocol_dickert_mahs, &subghz_protocol_gangqi, From a1e01bc06d945e3ca045f3f1c526f4613544e2e2 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 22 Jan 2026 02:03:11 +0300 Subject: [PATCH 048/160] revert 4px to 3px change --- applications/services/gui/elements.c | 8 ++++---- .../modules/widget_elements/widget_element_text_scroll.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/applications/services/gui/elements.c b/applications/services/gui/elements.c index d32cbc8c9..763c8b1b0 100644 --- a/applications/services/gui/elements.c +++ b/applications/services/gui/elements.c @@ -339,7 +339,7 @@ void elements_multiline_text_aligned( furi_check(text); size_t lines_count = 0; - size_t font_height = canvas_current_font_height(canvas) - 1; + size_t font_height = canvas_current_font_height(canvas); FuriString* line; /* go through text line by line and count lines */ @@ -384,7 +384,7 @@ void elements_multiline_text(Canvas* canvas, int32_t x, int32_t y, const char* t furi_check(canvas); furi_check(text); - size_t font_height = canvas_current_font_height(canvas) - 1; + size_t font_height = canvas_current_font_height(canvas); FuriString* str; str = furi_string_alloc(); const char* start = text; @@ -407,7 +407,7 @@ void elements_multiline_text_framed(Canvas* canvas, int32_t x, int32_t y, const furi_check(canvas); furi_check(text); - size_t font_height = canvas_current_font_height(canvas) - 1; + size_t font_height = canvas_current_font_height(canvas); size_t str_width = canvas_string_width(canvas, text); // count \n's @@ -778,7 +778,7 @@ void elements_text_box( // Fill line parameters size_t line_leading_min = font_params->leading_min; size_t line_leading_default = font_params->leading_default; - size_t line_height = font_params->height - 1; + size_t line_height = font_params->height; size_t line_descender = font_params->descender; size_t line_num = 0; size_t line_width = 0; diff --git a/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c b/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c index ed4b19654..866aad815 100644 --- a/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c +++ b/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c @@ -152,7 +152,7 @@ static void widget_element_text_scroll_draw(Canvas* canvas, WidgetElement* eleme } canvas_draw_str_aligned( canvas, x, y, line->horizontal, AlignTop, furi_string_get_cstr(line->text)); - y += params->leading_default - 1; + y += params->leading_default; } // Draw scroll bar if(model->scroll_pos_total > 1) { From e76dedd825aabe2f8822809e7eb6432b844da6ad Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 22 Jan 2026 02:04:03 +0300 Subject: [PATCH 049/160] upd changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ef922555..8fdd5c190 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,8 +14,9 @@ * SubGHz: Fixed button mapping for **FAAC RC/XT** * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * Archive: Allow folders to be pinned (by @WillyJL) -* Apps: Build tag (**21jan2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) +* Apps: Build tag (**22jan2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes +* UI: Various small changes * NFC: Fix LED not blinking at SLIX unlock (closes issue #945) * SubGHz: Replaced Cars ignore option with Revers RB2 protocol ignore option * SubGHz: Moved Starline, ScherKhan, Kia decoders into external app From ef61941d458ae9835e4b9f1ae383e2168b6cf9e9 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Thu, 22 Jan 2026 00:12:26 +0100 Subject: [PATCH 050/160] Apps: Add ProtoPirate (by RocketGod-git & xMasterX & zero-mega et al.) --- CHANGELOG.md | 2 ++ applications/external | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b56b30a55..88e38d246 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ ### Added: +- Apps: + - Sub-GHz: ProtoPirate (by @RocketGod-git & @xMasterX & @zero-mega et al.) - Sub-GHz: - UL: Cardin S449 protocol full support (64bit keeloq) (with Add manually, and all button codes) (use FSK12K modulation to read the remote) (by @xMasterX & @zero-mega) - UL: Beninca ARC AES128 protocol full support (128bit dynamic) (with Add manually, and 2 button codes) (by @xMasterX & @zero-mega) diff --git a/applications/external b/applications/external index 85b0cdb4e..f10656c03 160000 --- a/applications/external +++ b/applications/external @@ -1 +1 @@ -Subproject commit 85b0cdb4e7dec08d16db6ceea3ec3fc5078bedb4 +Subproject commit f10656c036980e3bd70aa14f2634574157abfc9a From e0ebfa1506289e5cf0c48fa827d960161c7cf01c Mon Sep 17 00:00:00 2001 From: WillyJL Date: Thu, 22 Jan 2026 00:49:18 +0100 Subject: [PATCH 051/160] FBT: Fix duplicate order warning --- applications/system/findmy/application.fam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/system/findmy/application.fam b/applications/system/findmy/application.fam index 3edafeb62..e277c4f58 100644 --- a/applications/system/findmy/application.fam +++ b/applications/system/findmy/application.fam @@ -20,5 +20,5 @@ App( apptype=FlipperAppType.STARTUP, entry_point="findmy_startup", sources=["findmy_startup.c", "findmy_state.c"], - order=1000, + order=1210, ) From ee9f352ca66ad8d76e8f9b37294088c5a6b7fb31 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Thu, 22 Jan 2026 01:28:19 +0100 Subject: [PATCH 052/160] Apps: Update apps - CAN Tools: Parity with DBC format, support importing DBC files (by MatthewKuKanich) - ESP Flasher: Bump Marauder 1.9.1 (by justcallmekoko), Marauder 1.9.0 support (by H4W9) - FlipSocial: Autocomplete, keyboard improvements, bugfixes (by jblanked) - Geometry Dash: Major refactor, bugfixes and performance improvements, rename from Geometry Flip (by gooseprjkt) - HC-SR04 Distance Sensor: Option to change measure units (by Tyl3rA) - IconEdit: Save/Send animations, settings tab with canvas scale and cursor guides, bugfixes (by rdefeo) - NFC Login: Code refactor, bugfixes, renamed from NFC PC Login (by Play2BReal) - Seader: SAM ATR3 support, better IFSC/IFSD handling, various improvements (by bettse) - Seos Compatible: Seos write support, various improvements (by aaronjamt) - Sub-GHz Scheduler: Added new interval times, bugfixes and improvements (by shalebridge) - Unitemp: Numerous improvements from MLAB-project fork (by MLAB-project) - UL: Update Sub-GHz apps for FM12K modulation (by xMasterX) --- CHANGELOG.md | 13 +++++++++++++ applications/external | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88e38d246..1c50fc825 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,19 @@ - UL: Docs: Add [full list of supported SubGHz protocols](https://github.com/Next-Flip/Momentum-Firmware/blob/dev/documentation/SubGHzSupportedSystems.md) and their frequencies/modulations that can be used for reading remotes (by @xMasterX) ### Updated: +- Apps: + - CAN Tools: Parity with DBC format, support importing DBC files (by @MatthewKuKanich) + - ESP Flasher: Bump Marauder 1.9.1 (by @justcallmekoko), Marauder 1.9.0 support (by @H4W9) + - FlipSocial: Autocomplete, keyboard improvements, bugfixes (by @jblanked) + - Geometry Dash: Major refactor, bugfixes and performance improvements, rename from Geometry Flip (by @gooseprjkt) + - HC-SR04 Distance Sensor: Option to change measure units (by @Tyl3rA) + - IconEdit: Save/Send animations, settings tab with canvas scale and cursor guides, bugfixes (by @rdefeo) + - NFC Login: Code refactor, bugfixes, renamed from NFC PC Login (by @Play2BReal) + - Seader: SAM ATR3 support, better IFSC/IFSD handling, various improvements (by @bettse) + - Seos Compatible: Seos write support, various improvements (by @aaronjamt) + - Sub-GHz Scheduler: Added new interval times, bugfixes and improvements (by @shalebridge) + - Unitemp: Numerous improvements from @MLAB-project fork (by @MLAB-project) + - UL: Update Sub-GHz apps for FM12K modulation (by @xMasterX) - Sub-GHz: - UL: Counter editor refactoring (by @Dmitry422) - UL: Alutech AT-4N & Nice Flor S turbo speedup (by @Dmitry422) diff --git a/applications/external b/applications/external index f10656c03..d52c118c8 160000 --- a/applications/external +++ b/applications/external @@ -1 +1 @@ -Subproject commit f10656c036980e3bd70aa14f2634574157abfc9a +Subproject commit d52c118c825dd86c41c02943b34ae4529e4d3605 From 267140b161ea8f59db40baca409ccd21813ec00a Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Fri, 23 Jan 2026 18:59:14 +0700 Subject: [PATCH 053/160] work to home --- .../drivers/subghz/cc1101_ext/cc1101_ext.c | 19 +++-- .../main/subghz/helpers/subghz_txrx.c | 5 -- .../subghz/scenes/subghz_scene_transmitter.c | 67 ++++++++++----- applications/main/subghz/views/transmitter.c | 28 ++++--- lib/subghz/protocols/alutech_at_4n.c | 7 +- lib/subghz/protocols/ansonic.c | 5 +- lib/subghz/protocols/beninca_arc.c | 7 +- lib/subghz/protocols/bett.c | 5 +- lib/subghz/protocols/bin_raw.c | 7 +- lib/subghz/protocols/came.c | 7 +- lib/subghz/protocols/came_atomo.c | 7 +- lib/subghz/protocols/came_twee.c | 7 +- lib/subghz/protocols/chamberlain_code.c | 5 +- lib/subghz/protocols/clemsa.c | 5 +- lib/subghz/protocols/dickert_mahs.c | 7 +- lib/subghz/protocols/doitrand.c | 7 +- lib/subghz/protocols/dooya.c | 7 +- lib/subghz/protocols/elplast.c | 7 +- lib/subghz/protocols/faac_slh.c | 7 +- lib/subghz/protocols/feron.c | 7 +- lib/subghz/protocols/gangqi.c | 7 +- lib/subghz/protocols/gate_tx.c | 5 +- lib/subghz/protocols/hay21.c | 7 +- lib/subghz/protocols/hollarm.c | 7 +- lib/subghz/protocols/holtek.c | 7 +- lib/subghz/protocols/holtek_ht12x.c | 7 +- lib/subghz/protocols/honeywell.c | 7 +- lib/subghz/protocols/honeywell_wdb.c | 7 +- lib/subghz/protocols/hormann.c | 9 +-- lib/subghz/protocols/intertechno_v3.c | 7 +- lib/subghz/protocols/keeloq.c | 7 +- lib/subghz/protocols/kinggates_stylo_4k.c | 7 +- lib/subghz/protocols/linear.c | 5 +- lib/subghz/protocols/linear_delta3.c | 5 +- lib/subghz/protocols/magellan.c | 7 +- lib/subghz/protocols/marantec.c | 7 +- lib/subghz/protocols/marantec24.c | 7 +- lib/subghz/protocols/mastercode.c | 5 +- lib/subghz/protocols/megacode.c | 5 +- lib/subghz/protocols/nero_radio.c | 7 +- lib/subghz/protocols/nero_sketch.c | 7 +- lib/subghz/protocols/nice_flo.c | 5 +- lib/subghz/protocols/nice_flor_s.c | 7 +- lib/subghz/protocols/phoenix_v2.c | 7 +- lib/subghz/protocols/power_smart.c | 7 +- lib/subghz/protocols/revers_rb2.c | 7 +- lib/subghz/protocols/roger.c | 7 +- lib/subghz/protocols/secplus_v1.c | 7 +- lib/subghz/protocols/secplus_v2.c | 7 +- lib/subghz/protocols/smc5326.c | 7 +- lib/subghz/protocols/somfy_keytis.c | 7 +- lib/subghz/protocols/somfy_telis.c | 7 +- lib/subghz/protocols/treadmill37.c | 7 +- targets/f7/furi_hal/furi_hal_subghz.c | 81 ++++++++++++------- 54 files changed, 219 insertions(+), 306 deletions(-) diff --git a/applications/drivers/subghz/cc1101_ext/cc1101_ext.c b/applications/drivers/subghz/cc1101_ext/cc1101_ext.c index abca098eb..40cfe0d4a 100644 --- a/applications/drivers/subghz/cc1101_ext/cc1101_ext.c +++ b/applications/drivers/subghz/cc1101_ext/cc1101_ext.c @@ -98,6 +98,8 @@ typedef struct { static SubGhzDeviceCC1101Ext* subghz_device_cc1101_ext = NULL; +bool subghz_device_cc1101_ext_is_async_tx_complete(void); + static bool subghz_device_cc1101_ext_check_init(void) { furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateInit); subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle; @@ -794,15 +796,20 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb subghz_device_cc1101_ext->async_tx.buffer = malloc(SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t)); + // here we do the same things as in /unleashed-firmware/targets/f7/furi_hal/furi_hal_subghz.c + // use first DMA to update timer TIM17 durations, but TIM17 have not output chanel + // so we use second DMA to transfer data from gpio_tx_buff directly to gpio pin using BSSR. + // BSSR allow us tranfer data directly to pin in gpio port. + //Signal generation with mem-to-mem DMA furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false); furi_hal_gpio_init( subghz_device_cc1101_ext->g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); - // Configure DMA update timer + // Configure DMA to update timer TIM17 ARR by durations from buffer LL_DMA_SetMemoryAddress( SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t)subghz_device_cc1101_ext->async_tx.buffer); - LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t) & (TIM17->ARR)); + LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t)&(TIM17->ARR)); LL_DMA_ConfigTransfer( SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | @@ -821,7 +828,7 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb furi_hal_bus_enable(FuriHalBusTIM17); - // Configure TIM + // Configure TIM 17 // Set the timer resolution to 2 us LL_TIM_SetCounterMode(TIM17, LL_TIM_COUNTERMODE_UP); LL_TIM_SetClockDivision(TIM17, LL_TIM_CLOCKDIVISION_DIV1); @@ -835,7 +842,7 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb subghz_device_cc1101_ext_async_tx_refill( subghz_device_cc1101_ext->async_tx.buffer, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL); - // Configure tx gpio dma + // Configure DMA to transfer data from gpio_tx_buff directly to gpio pin using BSSR const GpioPin* gpio = subghz_device_cc1101_ext->g0_pin; subghz_device_cc1101_ext->async_tx.gpio_tx_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER; @@ -844,7 +851,7 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb LL_DMA_SetMemoryAddress( SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, (uint32_t)subghz_device_cc1101_ext->async_tx.gpio_tx_buff); - LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, (uint32_t) & (gpio->port->BSRR)); + LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, (uint32_t)&(gpio->port->BSRR)); LL_DMA_ConfigTransfer( SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | @@ -864,7 +871,7 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, (uint32_t)subghz_device_cc1101_ext->async_tx.debug_gpio_buff); LL_DMA_SetPeriphAddress( - SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, (uint32_t) & (gpio->port->BSRR)); + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, (uint32_t)&(gpio->port->BSRR)); LL_DMA_ConfigTransfer( SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index 8abf373f4..ca3f0b300 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -234,7 +234,6 @@ SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* SubGhzTxRxStartTxState ret = SubGhzTxRxStartTxStateErrorParserOthers; FuriString* temp_str = furi_string_alloc(); - uint32_t repeat = 200; do { if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); @@ -244,10 +243,6 @@ SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* FURI_LOG_E(TAG, "Missing Protocol"); break; } - if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { - FURI_LOG_E(TAG, "Unable Repeat"); - break; - } ret = SubGhzTxRxStartTxStateOk; SubGhzRadioPreset* preset = instance->preset; diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index ebd69059f..e7514ac92 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -3,7 +3,7 @@ #include #include - +#include #define TAG "SubGhzSceneTransmitter" void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) { @@ -72,25 +72,56 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { subghz->state_notifications = SubGhzNotificationStateTx; subghz_scene_transmitter_update_data_show(subghz); dolphin_deed(DolphinDeedSubGhzSend); + + // #subghz_one_press_send# - keyword to search changes + // #start insert# + + // TODO change while condition to subghz_devices_is_async_complete_tx(subghz->txrx->radio_device); + // while( + // !(furi_hal_subghz_is_async_tx_complete() && + // subghz_device_cc1101_ext_is_async_tx_complete())) { + // notification_message(subghz->notifications, &sequence_blink_magenta_10); + // } + + while(!furi_hal_subghz_is_async_tx_complete()) { + notification_message(subghz->notifications, &sequence_blink_magenta_10); + } + subghz->state_notifications = SubGhzNotificationStateIDLE; + subghz_txrx_stop(subghz->txrx); + if(subghz_custom_btn_get() != SUBGHZ_CUSTOM_BTN_OK) { + subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); + int32_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); + furi_hal_subghz_set_rolling_counter_mult(0); + // Calling restore! + subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); + subghz_txrx_stop(subghz->txrx); + // Calling restore 2nd time special for FAAC SLH! + // TODO: Find better way to restore after custom button is used!!! + subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); + subghz_txrx_stop(subghz->txrx); + furi_hal_subghz_set_rolling_counter_mult(tmp_counter); + } + // #end insert# } return true; - } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) { - subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz_txrx_stop(subghz->txrx); - if(subghz_custom_btn_get() != SUBGHZ_CUSTOM_BTN_OK) { - subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); - int32_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); - furi_hal_subghz_set_rolling_counter_mult(0); - // Calling restore! - subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); - subghz_txrx_stop(subghz->txrx); - // Calling restore 2nd time special for FAAC SLH! - // TODO: Find better way to restore after custom button is used!!! - subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); - subghz_txrx_stop(subghz->txrx); - furi_hal_subghz_set_rolling_counter_mult(tmp_counter); - } - return true; + // #subghz_one_press_send# - keyword to search changes + // } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) { + // subghz->state_notifications = SubGhzNotificationStateIDLE; + // subghz_txrx_stop(subghz->txrx); + // if(subghz_custom_btn_get() != SUBGHZ_CUSTOM_BTN_OK) { + // subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); + // int32_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); + // furi_hal_subghz_set_rolling_counter_mult(0); + // // Calling restore! + // subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); + // subghz_txrx_stop(subghz->txrx); + // // Calling restore 2nd time special for FAAC SLH! + // // TODO: Find better way to restore after custom button is used!!! + // subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); + // subghz_txrx_stop(subghz->txrx); + // furi_hal_subghz_set_rolling_counter_mult(tmp_counter); + // } + // return true; } else if(event.event == SubGhzCustomEventViewTransmitterBack) { subghz->state_notifications = SubGhzNotificationStateIDLE; scene_manager_search_and_switch_to_previous_scene( diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index 9faa703b6..455ab63a5 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -6,6 +6,9 @@ #include +#include +#include + struct SubGhzViewTransmitter { View* view; SubGhzViewTransmitterCallback callback; @@ -155,7 +158,10 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { true); if(can_be_sent) { - if(event->key == InputKeyOk && event->type == InputTypePress) { + // #subghz_one_press_send# - keyword to search changes + bool allow_events = furi_hal_subghz_is_async_tx_complete() && subghz_device_cc1101_ext_is_async_tx_complete (); + // # + if(event->key == InputKeyOk && event->type == InputTypePress && allow_events) { subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); with_view_model( subghz_transmitter->view, @@ -168,10 +174,11 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { subghz_transmitter->callback( SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); return true; - } else if(event->key == InputKeyOk && event->type == InputTypeRelease) { - subghz_transmitter->callback( - SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); - return true; + // #subghz_one_press_send# - keyword to search changes + // } else if(event->key == InputKeyOk && event->type == InputTypeRelease) { + // subghz_transmitter->callback( + // SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); + // return true; } // Finish "OK" key processing if(subghz_custom_btn_is_allowed()) { @@ -189,7 +196,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { return true; } - if(event->type == InputTypePress) { + if(event->type == InputTypePress && allow_events) { with_view_model( subghz_transmitter->view, SubGhzViewTransmitterModel * model, @@ -209,10 +216,11 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { subghz_transmitter->callback( SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); return true; - } else if(event->type == InputTypeRelease) { - subghz_transmitter->callback( - SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); - return true; + // #subghz_one_press_send# - keyword to search changes + // } else if(event->type == InputTypeRelease) { + // subghz_transmitter->callback( + // SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); + // return true; } } } diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 8dff70dd1..b442f61c9 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -95,7 +95,7 @@ void* subghz_protocol_encoder_alutech_at_4n_alloc(SubGhzEnvironment* environment instance->base.protocol = &subghz_protocol_alutech_at_4n; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 2; instance->encoder.size_upload = 512; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -483,10 +483,7 @@ SubGhzProtocolStatus subghz_protocol_encoder_alutech_at_4n_deserialize( break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); break; diff --git a/lib/subghz/protocols/ansonic.c b/lib/subghz/protocols/ansonic.c index 75f803370..7ad0732d6 100644 --- a/lib/subghz/protocols/ansonic.c +++ b/lib/subghz/protocols/ansonic.c @@ -150,10 +150,7 @@ SubGhzProtocolStatus FURI_LOG_E(TAG, "Deserialize error"); break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_ansonic_get_upload(instance)) { res = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/beninca_arc.c b/lib/subghz/protocols/beninca_arc.c index 62eb925f8..d269aaa47 100644 --- a/lib/subghz/protocols/beninca_arc.c +++ b/lib/subghz/protocols/beninca_arc.c @@ -256,7 +256,7 @@ void* subghz_protocol_encoder_beninca_arc_alloc(SubGhzEnvironment* environment) instance->generic.protocol_name = instance->base.protocol->name; instance->keystore = subghz_environment_get_keystore(environment); - instance->encoder.repeat = 10; + instance->encoder.repeat = 2; instance->encoder.size_upload = 800; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -412,10 +412,7 @@ SubGhzProtocolStatus break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); break; diff --git a/lib/subghz/protocols/bett.c b/lib/subghz/protocols/bett.c index 44946a2f6..173671aaa 100644 --- a/lib/subghz/protocols/bett.c +++ b/lib/subghz/protocols/bett.c @@ -169,10 +169,7 @@ SubGhzProtocolStatus FURI_LOG_E(TAG, "Deserialize error"); break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_bett_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/bin_raw.c b/lib/subghz/protocols/bin_raw.c index ca52cdd49..4753d467c 100644 --- a/lib/subghz/protocols/bin_raw.c +++ b/lib/subghz/protocols/bin_raw.c @@ -142,7 +142,7 @@ void* subghz_protocol_encoder_bin_raw_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_bin_raw; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 2; instance->encoder.size_upload = BIN_RAW_BUF_DATA_SIZE * 5; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->data = malloc(instance->encoder.size_upload * sizeof(uint8_t)); @@ -309,10 +309,7 @@ SubGhzProtocolStatus res = SubGhzProtocolStatusErrorParserOthers; break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_bin_raw_get_upload(instance)) { res = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/came.c b/lib/subghz/protocols/came.c index 2762a2484..5037f1a4b 100644 --- a/lib/subghz/protocols/came.c +++ b/lib/subghz/protocols/came.c @@ -90,7 +90,7 @@ void* subghz_protocol_encoder_came_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_came; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 5; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -181,10 +181,7 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorValueBitCount; break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_came_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/came_atomo.c b/lib/subghz/protocols/came_atomo.c index f8ec7baa0..60d1e93a5 100644 --- a/lib/subghz/protocols/came_atomo.c +++ b/lib/subghz/protocols/came_atomo.c @@ -89,7 +89,7 @@ void* subghz_protocol_encoder_came_atomo_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_came_atomo; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 2; instance->encoder.size_upload = 900; //actual size 766+ instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -374,10 +374,7 @@ SubGhzProtocolStatus break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); break; diff --git a/lib/subghz/protocols/came_twee.c b/lib/subghz/protocols/came_twee.c index 3bb909dc8..c2af278ea 100644 --- a/lib/subghz/protocols/came_twee.c +++ b/lib/subghz/protocols/came_twee.c @@ -109,7 +109,7 @@ void* subghz_protocol_encoder_came_twee_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_came_twee; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 1; instance->encoder.size_upload = 1536; //max upload 92*14 = 1288 !!!! instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -254,10 +254,7 @@ SubGhzProtocolStatus if(res != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + subghz_protocol_came_twee_remote_controller(&instance->generic); subghz_protocol_encoder_came_twee_get_upload(instance); instance->encoder.front = 0; // reset position before start diff --git a/lib/subghz/protocols/chamberlain_code.c b/lib/subghz/protocols/chamberlain_code.c index fda224bb6..d01c80c2e 100644 --- a/lib/subghz/protocols/chamberlain_code.c +++ b/lib/subghz/protocols/chamberlain_code.c @@ -223,10 +223,7 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorValueBitCount; break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_chamb_code_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/clemsa.c b/lib/subghz/protocols/clemsa.c index 672abcba3..fecbd4dfd 100644 --- a/lib/subghz/protocols/clemsa.c +++ b/lib/subghz/protocols/clemsa.c @@ -168,10 +168,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_clemsa_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/dickert_mahs.c b/lib/subghz/protocols/dickert_mahs.c index 65be6fd0c..ac00fd28a 100644 --- a/lib/subghz/protocols/dickert_mahs.c +++ b/lib/subghz/protocols/dickert_mahs.c @@ -132,7 +132,7 @@ void* subghz_protocol_encoder_dickert_mahs_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_dickert_mahs; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 5; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -207,10 +207,7 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorValueBitCount; break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_dickert_mahs_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/doitrand.c b/lib/subghz/protocols/doitrand.c index 7c7946042..ab700f5ad 100644 --- a/lib/subghz/protocols/doitrand.c +++ b/lib/subghz/protocols/doitrand.c @@ -82,7 +82,7 @@ void* subghz_protocol_encoder_doitrand_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_doitrand; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 5; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -149,10 +149,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_doitrand_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/dooya.c b/lib/subghz/protocols/dooya.c index fd8645a0b..76d2bac60 100644 --- a/lib/subghz/protocols/dooya.c +++ b/lib/subghz/protocols/dooya.c @@ -77,7 +77,7 @@ void* subghz_protocol_encoder_dooya_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_dooya; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 5; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -159,10 +159,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_dooya_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/elplast.c b/lib/subghz/protocols/elplast.c index 18d6d07b4..a9bd29562 100644 --- a/lib/subghz/protocols/elplast.c +++ b/lib/subghz/protocols/elplast.c @@ -73,7 +73,7 @@ void* subghz_protocol_encoder_elplast_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_elplast; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -141,10 +141,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + subghz_protocol_encoder_elplast_get_upload(instance); instance->encoder.is_running = true; } while(false); diff --git a/lib/subghz/protocols/faac_slh.c b/lib/subghz/protocols/faac_slh.c index 147e452eb..d0cfc721c 100644 --- a/lib/subghz/protocols/faac_slh.c +++ b/lib/subghz/protocols/faac_slh.c @@ -109,7 +109,7 @@ void* subghz_protocol_encoder_faac_slh_alloc(SubGhzEnvironment* environment) { instance->generic.protocol_name = instance->base.protocol->name; instance->keystore = subghz_environment_get_keystore(environment); - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -398,10 +398,7 @@ SubGhzProtocolStatus subghz_protocol_faac_slh_check_remote_controller( &instance->generic, instance->keystore, &instance->manufacture_name); - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + subghz_protocol_encoder_faac_slh_get_upload(instance); if(!flipper_format_rewind(flipper_format)) { diff --git a/lib/subghz/protocols/feron.c b/lib/subghz/protocols/feron.c index 9591a4ebb..f7d653f4c 100644 --- a/lib/subghz/protocols/feron.c +++ b/lib/subghz/protocols/feron.c @@ -74,7 +74,7 @@ void* subghz_protocol_encoder_feron_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_feron; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -160,10 +160,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + subghz_protocol_feron_check_remote_controller(&instance->generic); subghz_protocol_encoder_feron_get_upload(instance); instance->encoder.is_running = true; diff --git a/lib/subghz/protocols/gangqi.c b/lib/subghz/protocols/gangqi.c index 6b5542410..f78b37aac 100644 --- a/lib/subghz/protocols/gangqi.c +++ b/lib/subghz/protocols/gangqi.c @@ -76,7 +76,7 @@ void* subghz_protocol_encoder_gangqi_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_gangqi; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -253,10 +253,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + subghz_protocol_gangqi_remote_controller(&instance->generic); subghz_protocol_encoder_gangqi_get_upload(instance); diff --git a/lib/subghz/protocols/gate_tx.c b/lib/subghz/protocols/gate_tx.c index 608567626..08f6f3f41 100644 --- a/lib/subghz/protocols/gate_tx.c +++ b/lib/subghz/protocols/gate_tx.c @@ -142,10 +142,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_gate_tx_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/hay21.c b/lib/subghz/protocols/hay21.c index ba6119dae..8a0280168 100644 --- a/lib/subghz/protocols/hay21.c +++ b/lib/subghz/protocols/hay21.c @@ -75,7 +75,7 @@ void* subghz_protocol_encoder_hay21_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_hay21; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -267,10 +267,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + subghz_protocol_hay21_remote_controller(&instance->generic); subghz_protocol_encoder_hay21_get_upload(instance); diff --git a/lib/subghz/protocols/hollarm.c b/lib/subghz/protocols/hollarm.c index 9b2a53a05..b03de5b72 100644 --- a/lib/subghz/protocols/hollarm.c +++ b/lib/subghz/protocols/hollarm.c @@ -76,7 +76,7 @@ void* subghz_protocol_encoder_hollarm_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_hollarm; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -254,10 +254,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + subghz_protocol_hollarm_remote_controller(&instance->generic); subghz_protocol_encoder_hollarm_get_upload(instance); diff --git a/lib/subghz/protocols/holtek.c b/lib/subghz/protocols/holtek.c index 7ed5fc152..2735702c5 100644 --- a/lib/subghz/protocols/holtek.c +++ b/lib/subghz/protocols/holtek.c @@ -86,7 +86,7 @@ void* subghz_protocol_encoder_holtek_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_holtek; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 5; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -155,10 +155,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_holtek_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/holtek_ht12x.c b/lib/subghz/protocols/holtek_ht12x.c index bf5e48adf..bf4724130 100644 --- a/lib/subghz/protocols/holtek_ht12x.c +++ b/lib/subghz/protocols/holtek_ht12x.c @@ -94,7 +94,7 @@ void* subghz_protocol_encoder_holtek_th12x_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_holtek_th12x; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 5; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -170,10 +170,7 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorParserTe; break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_holtek_th12x_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/honeywell.c b/lib/subghz/protocols/honeywell.c index 1e3f231e8..7343648d7 100644 --- a/lib/subghz/protocols/honeywell.c +++ b/lib/subghz/protocols/honeywell.c @@ -98,7 +98,7 @@ void* subghz_protocol_encoder_honeywell_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_honeywell; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 4; + instance->encoder.repeat = 5; instance->encoder.size_upload = 64 * 2 + 10; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -211,10 +211,7 @@ SubGhzProtocolStatus break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + subghz_protocol_encoder_honeywell_get_upload(instance); if(!flipper_format_rewind(flipper_format)) { diff --git a/lib/subghz/protocols/honeywell_wdb.c b/lib/subghz/protocols/honeywell_wdb.c index 0b8f63a24..0a2cd53d6 100644 --- a/lib/subghz/protocols/honeywell_wdb.c +++ b/lib/subghz/protocols/honeywell_wdb.c @@ -88,7 +88,7 @@ void* subghz_protocol_encoder_honeywell_wdb_alloc(SubGhzEnvironment* environment instance->base.protocol = &subghz_protocol_honeywell_wdb; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 5; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -156,10 +156,7 @@ SubGhzProtocolStatus subghz_protocol_encoder_honeywell_wdb_deserialize( if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_honeywell_wdb_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/hormann.c b/lib/subghz/protocols/hormann.c index f74a29fec..1ac9f6b0d 100644 --- a/lib/subghz/protocols/hormann.c +++ b/lib/subghz/protocols/hormann.c @@ -80,7 +80,7 @@ void* subghz_protocol_encoder_hormann_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_hormann; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 2; instance->encoder.size_upload = 2048; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -110,7 +110,7 @@ static bool subghz_protocol_encoder_hormann_get_upload(SubGhzProtocolEncoderHorm } else { instance->encoder.size_upload = size_upload; } - instance->encoder.repeat = 10; //original remote does 10 repeats + instance->encoder.repeat = 3; //original remote does 10 repeats for(size_t repeat = 0; repeat < 20; repeat++) { //Send start bit @@ -153,10 +153,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_hormann_get_upload(instance)) { instance->encoder.front = 0; // reset position before start ret = SubGhzProtocolStatusErrorEncoderGetUpload; diff --git a/lib/subghz/protocols/intertechno_v3.c b/lib/subghz/protocols/intertechno_v3.c index 71513051b..85818763b 100644 --- a/lib/subghz/protocols/intertechno_v3.c +++ b/lib/subghz/protocols/intertechno_v3.c @@ -86,7 +86,7 @@ void* subghz_protocol_encoder_intertechno_v3_alloc(SubGhzEnvironment* environmen instance->base.protocol = &subghz_protocol_intertechno_v3; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -176,10 +176,7 @@ SubGhzProtocolStatus subghz_protocol_encoder_intertechno_v3_deserialize( ret = SubGhzProtocolStatusErrorValueBitCount; break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_intertechno_v3_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index cd657f23f..39f957e24 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -107,7 +107,7 @@ void* subghz_protocol_encoder_keeloq_alloc(SubGhzEnvironment* environment) { instance->generic.protocol_name = instance->base.protocol->name; instance->keystore = subghz_environment_get_keystore(environment); - instance->encoder.repeat = 100; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -667,10 +667,7 @@ SubGhzProtocolStatus subghz_protocol_keeloq_check_remote_controller( &instance->generic, instance->keystore, &instance->manufacture_name); - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_keeloq_get_upload(instance, instance->generic.btn)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/kinggates_stylo_4k.c b/lib/subghz/protocols/kinggates_stylo_4k.c index e23042b55..18fb91651 100644 --- a/lib/subghz/protocols/kinggates_stylo_4k.c +++ b/lib/subghz/protocols/kinggates_stylo_4k.c @@ -101,7 +101,7 @@ void* subghz_protocol_encoder_kinggates_stylo_4k_alloc(SubGhzEnvironment* enviro instance->generic.protocol_name = instance->base.protocol->name; instance->keystore = subghz_environment_get_keystore(environment); - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 512; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -344,10 +344,7 @@ SubGhzProtocolStatus subghz_protocol_encoder_kinggates_stylo_4k_deserialize( break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); break; diff --git a/lib/subghz/protocols/linear.c b/lib/subghz/protocols/linear.c index f024316e9..e170c90ee 100644 --- a/lib/subghz/protocols/linear.c +++ b/lib/subghz/protocols/linear.c @@ -160,10 +160,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_linear_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/linear_delta3.c b/lib/subghz/protocols/linear_delta3.c index c2f527ba8..b9b28c66a 100644 --- a/lib/subghz/protocols/linear_delta3.c +++ b/lib/subghz/protocols/linear_delta3.c @@ -164,10 +164,7 @@ SubGhzProtocolStatus subghz_protocol_encoder_linear_delta3_deserialize( if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_linear_delta3_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/magellan.c b/lib/subghz/protocols/magellan.c index 55048ca61..ef0c9d2ae 100644 --- a/lib/subghz/protocols/magellan.c +++ b/lib/subghz/protocols/magellan.c @@ -78,7 +78,7 @@ void* subghz_protocol_encoder_magellan_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_magellan; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -164,10 +164,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_magellan_get_upload(instance)) { instance->encoder.front = 0; // reset before start ret = SubGhzProtocolStatusErrorEncoderGetUpload; diff --git a/lib/subghz/protocols/marantec.c b/lib/subghz/protocols/marantec.c index 53e4d6895..02d6aa801 100644 --- a/lib/subghz/protocols/marantec.c +++ b/lib/subghz/protocols/marantec.c @@ -77,7 +77,7 @@ void* subghz_protocol_encoder_marantec_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_marantec; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -213,10 +213,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + subghz_protocol_marantec_remote_controller(&instance->generic); subghz_protocol_encoder_marantec_get_upload(instance); instance->encoder.front = 0; diff --git a/lib/subghz/protocols/marantec24.c b/lib/subghz/protocols/marantec24.c index 6f636e8ab..63d8e7be2 100644 --- a/lib/subghz/protocols/marantec24.c +++ b/lib/subghz/protocols/marantec24.c @@ -73,7 +73,7 @@ void* subghz_protocol_encoder_marantec24_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_marantec24; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -155,10 +155,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + subghz_protocol_marantec24_check_remote_controller(&instance->generic); subghz_protocol_encoder_marantec24_get_upload(instance); instance->encoder.is_running = true; diff --git a/lib/subghz/protocols/mastercode.c b/lib/subghz/protocols/mastercode.c index e4fae40b3..5a57d764e 100644 --- a/lib/subghz/protocols/mastercode.c +++ b/lib/subghz/protocols/mastercode.c @@ -168,10 +168,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_mastercode_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/megacode.c b/lib/subghz/protocols/megacode.c index 2c4bf10a3..13cc99436 100644 --- a/lib/subghz/protocols/megacode.c +++ b/lib/subghz/protocols/megacode.c @@ -188,10 +188,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_megacode_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/nero_radio.c b/lib/subghz/protocols/nero_radio.c index da5497feb..18fdfffa8 100644 --- a/lib/subghz/protocols/nero_radio.c +++ b/lib/subghz/protocols/nero_radio.c @@ -77,7 +77,7 @@ void* subghz_protocol_encoder_nero_radio_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_nero_radio; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -180,10 +180,7 @@ SubGhzProtocolStatus break; } } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_nero_radio_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/nero_sketch.c b/lib/subghz/protocols/nero_sketch.c index 64a75cfc0..0550cf801 100644 --- a/lib/subghz/protocols/nero_sketch.c +++ b/lib/subghz/protocols/nero_sketch.c @@ -76,7 +76,7 @@ void* subghz_protocol_encoder_nero_sketch_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_nero_sketch; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -161,10 +161,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_nero_sketch_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/nice_flo.c b/lib/subghz/protocols/nice_flo.c index 2e5fa96b5..dc423fe83 100644 --- a/lib/subghz/protocols/nice_flo.c +++ b/lib/subghz/protocols/nice_flo.c @@ -147,10 +147,7 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorValueBitCount; break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_nice_flo_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index 9085ee431..59cf4d2cc 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -104,7 +104,7 @@ void* subghz_protocol_encoder_nice_flor_s_alloc(SubGhzEnvironment* environment) FURI_LOG_D( TAG, "Loading rainbow table from %s", instance->nice_flor_s_rainbow_table_file_name); } - instance->encoder.repeat = 10; + instance->encoder.repeat = 1; instance->encoder.size_upload = 2400; //wrong!! upload 186*16 = 2976 - actual size about 1728 instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -279,10 +279,7 @@ SubGhzProtocolStatus break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - // flipper_format_read_uint32( + // flipper_format_read_uint32( // flipper_format, "Data", (uint32_t*)&instance->generic.data_2, 1); if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); diff --git a/lib/subghz/protocols/phoenix_v2.c b/lib/subghz/protocols/phoenix_v2.c index 1f2731f54..c70b4cb00 100644 --- a/lib/subghz/protocols/phoenix_v2.c +++ b/lib/subghz/protocols/phoenix_v2.c @@ -77,7 +77,7 @@ void* subghz_protocol_encoder_phoenix_v2_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_phoenix_v2; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 5; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -322,10 +322,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + subghz_protocol_phoenix_v2_check_remote_controller(&instance->generic); if(!subghz_protocol_encoder_phoenix_v2_get_upload(instance)) { diff --git a/lib/subghz/protocols/power_smart.c b/lib/subghz/protocols/power_smart.c index 6449f720a..ed237780e 100644 --- a/lib/subghz/protocols/power_smart.c +++ b/lib/subghz/protocols/power_smart.c @@ -85,7 +85,7 @@ void* subghz_protocol_encoder_power_smart_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_power_smart; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 2; instance->encoder.size_upload = 1024; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -206,10 +206,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + subghz_protocol_power_smart_remote_controller(&instance->generic); subghz_protocol_encoder_power_smart_get_upload(instance); instance->encoder.front = 0; // reset before start diff --git a/lib/subghz/protocols/revers_rb2.c b/lib/subghz/protocols/revers_rb2.c index 941ff5c56..2e9aee592 100644 --- a/lib/subghz/protocols/revers_rb2.c +++ b/lib/subghz/protocols/revers_rb2.c @@ -78,7 +78,7 @@ void* subghz_protocol_encoder_revers_rb2_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_revers_rb2; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 5; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -176,10 +176,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + subghz_protocol_revers_rb2_remote_controller(&instance->generic); subghz_protocol_encoder_revers_rb2_get_upload(instance); instance->encoder.is_running = true; diff --git a/lib/subghz/protocols/roger.c b/lib/subghz/protocols/roger.c index 9c33b11ec..30767db82 100644 --- a/lib/subghz/protocols/roger.c +++ b/lib/subghz/protocols/roger.c @@ -76,7 +76,7 @@ void* subghz_protocol_encoder_roger_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_roger; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -265,10 +265,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + subghz_protocol_roger_check_remote_controller(&instance->generic); subghz_protocol_encoder_roger_get_upload(instance); diff --git a/lib/subghz/protocols/secplus_v1.c b/lib/subghz/protocols/secplus_v1.c index 13af0d302..460ff766e 100644 --- a/lib/subghz/protocols/secplus_v1.c +++ b/lib/subghz/protocols/secplus_v1.c @@ -98,7 +98,7 @@ void* subghz_protocol_encoder_secplus_v1_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_secplus_v1; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 5; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -298,10 +298,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_secplus_v1_encode(instance)) { ret = SubGhzProtocolStatusErrorParserOthers; break; diff --git a/lib/subghz/protocols/secplus_v2.c b/lib/subghz/protocols/secplus_v2.c index ad343968b..bcbf3183a 100644 --- a/lib/subghz/protocols/secplus_v2.c +++ b/lib/subghz/protocols/secplus_v2.c @@ -92,7 +92,7 @@ void* subghz_protocol_encoder_secplus_v2_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_secplus_v2; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -574,10 +574,7 @@ SubGhzProtocolStatus subghz_protocol_secplus_v2_remote_controller( &instance->generic, instance->secplus_packet_1); subghz_protocol_secplus_v2_encode(instance); - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_secplus_v2_get_upload(instance); + subghz_protocol_encoder_secplus_v2_get_upload(instance); //update data for(size_t i = 0; i < sizeof(uint64_t); i++) { diff --git a/lib/subghz/protocols/smc5326.c b/lib/subghz/protocols/smc5326.c index 217dbb780..bf006e146 100644 --- a/lib/subghz/protocols/smc5326.c +++ b/lib/subghz/protocols/smc5326.c @@ -101,7 +101,7 @@ void* subghz_protocol_encoder_smc5326_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_smc5326; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 5; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -178,10 +178,7 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorParserTe; break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + if(!subghz_protocol_encoder_smc5326_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/somfy_keytis.c b/lib/subghz/protocols/somfy_keytis.c index c9f6f47bd..c462035c6 100644 --- a/lib/subghz/protocols/somfy_keytis.c +++ b/lib/subghz/protocols/somfy_keytis.c @@ -81,7 +81,7 @@ void* subghz_protocol_encoder_somfy_keytis_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_somfy_keytis; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 512; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -412,10 +412,7 @@ SubGhzProtocolStatus break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + subghz_protocol_encoder_somfy_keytis_get_upload(instance, instance->generic.btn); if(!flipper_format_rewind(flipper_format)) { diff --git a/lib/subghz/protocols/somfy_telis.c b/lib/subghz/protocols/somfy_telis.c index 2be378b7d..a4b756daa 100644 --- a/lib/subghz/protocols/somfy_telis.c +++ b/lib/subghz/protocols/somfy_telis.c @@ -82,7 +82,7 @@ void* subghz_protocol_encoder_somfy_telis_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_somfy_telis; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 512; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -341,10 +341,7 @@ SubGhzProtocolStatus break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + subghz_protocol_encoder_somfy_telis_get_upload(instance, instance->generic.btn); if(!flipper_format_rewind(flipper_format)) { diff --git a/lib/subghz/protocols/treadmill37.c b/lib/subghz/protocols/treadmill37.c index e9915c296..9784fe1e3 100644 --- a/lib/subghz/protocols/treadmill37.c +++ b/lib/subghz/protocols/treadmill37.c @@ -73,7 +73,7 @@ void* subghz_protocol_encoder_treadmill37_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_treadmill37; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -151,10 +151,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value - flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - + subghz_protocol_treadmill37_check_remote_controller(&instance->generic); subghz_protocol_encoder_treadmill37_get_upload(instance); instance->encoder.is_running = true; diff --git a/targets/f7/furi_hal/furi_hal_subghz.c b/targets/f7/furi_hal/furi_hal_subghz.c index dc6add277..0f8fa939c 100644 --- a/targets/f7/furi_hal/furi_hal_subghz.c +++ b/targets/f7/furi_hal/furi_hal_subghz.c @@ -684,6 +684,8 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { while(samples > 0) { volatile uint32_t duration = furi_hal_subghz_async_tx_middleware_get_duration( &furi_hal_subghz_async_tx.middleware, furi_hal_subghz_async_tx.callback); + // if duration == 0 then we stop DMA interrupt(that used to refill buffer) and write to buffer 0 as last element. + // later DMA write this 0 to ARR and timer TIM2 will be stopped. if(duration == 0) { *buffer = 0; buffer++; @@ -756,48 +758,64 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* furi_hal_subghz_async_tx.buffer = malloc(FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t)); - // Connect CC1101_GD0 to TIM2 as output + // Here we use TIM2_CH2 (Timer 2 Channel 2) to generate HI/LOW signals for C1101 with current durations. + // DMA update/rewrite TIM2 settings (ARR) with new duration each time TIM2 completes. + // Every time when timer counter exeed current TIM2-ARR (AutoReload Register) value timer generate event that call DMA + // DMA load next new value from buffer to TIM2-ARR and timer start count up from 0 to new value again + // Totally we have timer that generate events and update they settings with new durations by DMA action. + // When duration = 0 then DMA wirte 0 to ARR. So when we set ARR=0 - thats mean TIM2 stop counting. + + // Connect CC1101_GD0 to TIM2 as output (Pin B3 - GpioAltFn1TIM2 - TIM2, CH2) furi_hal_gpio_init_ex( &gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); - // Configure DMA - LL_DMA_InitTypeDef dma_config = {0}; - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); - dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_async_tx.buffer; - dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; - dma_config.Mode = LL_DMA_MODE_CIRCULAR; - dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; - dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; - dma_config.NbData = FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL; - dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + // Configure DMA to update TIM2->ARR + LL_DMA_InitTypeDef dma_config = {0}; // DMA settings structure + dma_config.PeriphOrM2MSrcAddress = (uint32_t)&(TIM2->ARR); // DMA destination TIM2->ARR + dma_config.MemoryOrM2MDstAddress = + (uint32_t)furi_hal_subghz_async_tx.buffer; // DMA buffer with signals durations + dma_config.Direction = + LL_DMA_DIRECTION_MEMORY_TO_PERIPH; // DMA direction from memory to periperhal + dma_config.Mode = LL_DMA_MODE_CIRCULAR; // DMA mode + dma_config.PeriphOrM2MSrcIncMode = + LL_DMA_PERIPH_NOINCREMENT; // DMA destination not changed - allways stay on ARR (AutoReload Register) + dma_config.MemoryOrM2MDstIncMode = + LL_DMA_MEMORY_INCREMENT; // DMA source increment - step by step on durations buffer + dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; // DMA source packet size + dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; // DMA destination packet size + dma_config.NbData = FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL; // DMA buffer size + dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; // DMA start by TIM2 event dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH; // Ensure that ARR is updated before anyone else try to check it - LL_DMA_Init(SUBGHZ_DMA_CH1_DEF, &dma_config); + LL_DMA_Init(SUBGHZ_DMA_CH1_DEF, &dma_config); // Setup DMA with settings structure + // setup interrupt for DMA. When DMA generate interrupt event we call furi_hal_subghz_async_tx_dma_isr furi_hal_interrupt_set_isr(SUBGHZ_DMA_CH1_IRQ, furi_hal_subghz_async_tx_dma_isr, NULL); - LL_DMA_EnableIT_TC(SUBGHZ_DMA_CH1_DEF); - LL_DMA_EnableIT_HT(SUBGHZ_DMA_CH1_DEF); - LL_DMA_EnableChannel(SUBGHZ_DMA_CH1_DEF); + LL_DMA_EnableIT_TC(SUBGHZ_DMA_CH1_DEF); // interrupt for full buffer sent + LL_DMA_EnableIT_HT(SUBGHZ_DMA_CH1_DEF); // interrupt for half buffer sent + LL_DMA_EnableChannel(SUBGHZ_DMA_CH1_DEF); // Enable - furi_hal_bus_enable(FuriHalBusTIM2); + furi_hal_bus_enable(FuriHalBusTIM2); // Enable TIM2 // Configure TIM2 - LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); + LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); // TIM2 set counter mode UP + // Set the division ratio between the timer clock and the sampling clock 1:1 LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); + LL_TIM_SetPrescaler(TIM2, 64 - 1); // Perscaler 64 Mghz/64 = 1 Mghz (1 000 000 tick/sec) + // AutoReload Register (ARR) 1000 ticks = 1/1000 Mghz = 1 millisecond, will be changed by DMA by new durations LL_TIM_SetAutoReload(TIM2, 1000); - LL_TIM_SetPrescaler(TIM2, 64 - 1); - LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); - LL_TIM_DisableARRPreload(TIM2); + LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); // ClockSource for TIM2 + LL_TIM_DisableARRPreload( + TIM2); // Change TIM2 setting immediately (dont wait when counter will be overload) // Configure TIM2 CH2 - LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0}; + LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0}; //Settings structure + // CH2 working mode - TOGGLE (swith between HI and LOW levels) TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_TOGGLE; TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE; TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE; - TIM_OC_InitStruct.CompareValue = 0; - TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH; - LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct); + TIM_OC_InitStruct.CompareValue = 0; // Counter value to generate events and TOGGLE output + TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH; // Initial CH2 state - HIGH level + LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct); // Apply settings to CH2 LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH2); LL_TIM_DisableMasterSlaveMode(TIM2); @@ -805,8 +823,8 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* furi_hal_subghz_async_tx_refill( furi_hal_subghz_async_tx.buffer, FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL); - LL_TIM_EnableDMAReq_UPDATE(TIM2); - LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); + LL_TIM_EnableDMAReq_UPDATE(TIM2); // Setup calling DMA by TIM2 events + LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); //Enable TIM2 CH2 // Start debug if(furi_hal_subghz_start_debug()) { @@ -820,7 +838,7 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* furi_hal_subghz_debug_gpio_buff[1] = (uint32_t)gpio->pin << GPIO_NUMBER; dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_debug_gpio_buff; - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->BSRR); + dma_config.PeriphOrM2MSrcAddress = (uint32_t)&(gpio->port->BSRR); dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; dma_config.Mode = LL_DMA_MODE_CIRCULAR; dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; @@ -841,14 +859,15 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* #endif furi_hal_subghz_tx(); - LL_TIM_SetCounter(TIM2, 0); - LL_TIM_EnableCounter(TIM2); + LL_TIM_SetCounter(TIM2, 0); // Reset TIM2 + LL_TIM_EnableCounter(TIM2); // Start TIM2 counting. return true; } bool furi_hal_subghz_is_async_tx_complete(void) { return (furi_hal_subghz.state == SubGhzStateAsyncTx) && (LL_TIM_GetAutoReload(TIM2) == 0); + FURI_LOG_I(TAG, "SubGhzStateAsyncTx %d , TIM2-ARR %ld",furi_hal_subghz.state,LL_TIM_GetAutoReload(TIM2)); } void furi_hal_subghz_stop_async_tx(void) { From bb9e6bd3ca929290d19991ecab484154cdf1624f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 23 Jan 2026 18:23:09 +0300 Subject: [PATCH 054/160] fix docs [ci skip] --- documentation/SubGHzSupportedSystems.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/SubGHzSupportedSystems.md b/documentation/SubGHzSupportedSystems.md index d9269fbe9..65e96225b 100644 --- a/documentation/SubGHzSupportedSystems.md +++ b/documentation/SubGHzSupportedSystems.md @@ -121,7 +121,7 @@ The following manufacturers have KeeLoq support in Unleashed firmware: - Nice Smilo - `433.92MHz` `AM650` (KeeLoq, 64 bits) (8bit serial part in Hop - simple learning) - Normstahl - `433.92MHz` `AM650` (KeeLoq, 64 bits) - Novoferm - `433.92MHz` `AM650` (KeeLoq, 64 bits) -- Sommer `434.42MHz, 868.80MHz` `FSK12K (or FSK476)` (KeeLoq, 64 bits) (normal learning) (TX03-868-4, Pearl, and maybe other models are supported (SOMloq2)) +- Sommer `434.42MHz, 868.80MHz` `FSK12K (or FSK476)` (KeeLoq, 64 bits) (normal learning) (TX03-868-4, Pearl, and maybe other models are supported (SOMloq)) - Steelmate - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) - Stilmatic - `433.92MHz` `AM650` (KeeLoq, 64 bits) (normal learning) From c2487a3761451c5f03197e3bd6acd0abddd3de64 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Fri, 23 Jan 2026 22:56:15 +0100 Subject: [PATCH 055/160] NFC: Fix sending 32+ byte ISO 15693-3 commands --- targets/f7/furi_hal/furi_hal_nfc_iso15693.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/targets/f7/furi_hal/furi_hal_nfc_iso15693.c b/targets/f7/furi_hal/furi_hal_nfc_iso15693.c index d35b160f4..1fafba6b2 100644 --- a/targets/f7/furi_hal/furi_hal_nfc_iso15693.c +++ b/targets/f7/furi_hal/furi_hal_nfc_iso15693.c @@ -8,6 +8,7 @@ #define FURI_HAL_NFC_ISO15693_MAX_FRAME_SIZE (1024U) #define FURI_HAL_NFC_ISO15693_POLLER_MAX_BUFFER_SIZE (64) +#define FURI_HAL_NFC_ISO15693_BIT_LEN (4) #define FURI_HAL_NFC_ISO15693_RESP_SOF_SIZE (5) #define FURI_HAL_NFC_ISO15693_RESP_EOF_SIZE (5) @@ -34,9 +35,9 @@ typedef struct { typedef struct { // 4 bits per data bit on transmit - uint8_t fifo_buf[FURI_HAL_NFC_ISO15693_POLLER_MAX_BUFFER_SIZE * 4]; + uint8_t fifo_buf[FURI_HAL_NFC_ISO15693_POLLER_MAX_BUFFER_SIZE * FURI_HAL_NFC_ISO15693_BIT_LEN]; size_t fifo_buf_bits; - uint8_t frame_buf[FURI_HAL_NFC_ISO15693_POLLER_MAX_BUFFER_SIZE * 2]; + uint8_t frame_buf[FURI_HAL_NFC_ISO15693_POLLER_MAX_BUFFER_SIZE * FURI_HAL_NFC_ISO15693_BIT_LEN]; size_t frame_buf_bits; } FuriHalNfcIso15693Poller; From 09076229c98c4d91e094c1afee1034c7d30aeee0 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 24 Jan 2026 17:59:10 +0300 Subject: [PATCH 056/160] NFC: Fix sending 32+ byte ISO 15693-3 commands ofw pr 4333 by WillyJL --- targets/f7/furi_hal/furi_hal_nfc_iso15693.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/targets/f7/furi_hal/furi_hal_nfc_iso15693.c b/targets/f7/furi_hal/furi_hal_nfc_iso15693.c index 028c60927..4c8639f08 100644 --- a/targets/f7/furi_hal/furi_hal_nfc_iso15693.c +++ b/targets/f7/furi_hal/furi_hal_nfc_iso15693.c @@ -8,6 +8,7 @@ #define FURI_HAL_NFC_ISO15693_MAX_FRAME_SIZE (1024U) #define FURI_HAL_NFC_ISO15693_POLLER_MAX_BUFFER_SIZE (64) +#define FURI_HAL_NFC_ISO15693_BIT_LEN (4) #define FURI_HAL_NFC_ISO15693_RESP_SOF_SIZE (5) #define FURI_HAL_NFC_ISO15693_RESP_EOF_SIZE (5) @@ -34,9 +35,9 @@ typedef struct { typedef struct { // 4 bits per data bit on transmit - uint8_t fifo_buf[FURI_HAL_NFC_ISO15693_POLLER_MAX_BUFFER_SIZE * 4]; + uint8_t fifo_buf[FURI_HAL_NFC_ISO15693_POLLER_MAX_BUFFER_SIZE * FURI_HAL_NFC_ISO15693_BIT_LEN]; size_t fifo_buf_bits; - uint8_t frame_buf[FURI_HAL_NFC_ISO15693_POLLER_MAX_BUFFER_SIZE * 2]; + uint8_t frame_buf[FURI_HAL_NFC_ISO15693_POLLER_MAX_BUFFER_SIZE * FURI_HAL_NFC_ISO15693_BIT_LEN]; size_t frame_buf_bits; } FuriHalNfcIso15693Poller; From 1bbdfc8b09fa75e2f5cdd52b579d65c2b886219f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 24 Jan 2026 18:00:18 +0300 Subject: [PATCH 057/160] upd changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fdd5c190..44063cb06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ * Apps: Build tag (**22jan2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes * UI: Various small changes +* OFW PR 4333: NFC: Fix sending 32+ byte ISO 15693-3 commands (by @WillyJL) * NFC: Fix LED not blinking at SLIX unlock (closes issue #945) * SubGHz: Replaced Cars ignore option with Revers RB2 protocol ignore option * SubGHz: Moved Starline, ScherKhan, Kia decoders into external app From 9a5ec93e9ce753dbd4f31c2db693d3a679dbfd7b Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 25 Jan 2026 06:19:20 +0300 Subject: [PATCH 058/160] subghz: fix beninca programming mode --- lib/subghz/protocols/beninca_arc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/subghz/protocols/beninca_arc.c b/lib/subghz/protocols/beninca_arc.c index 62eb925f8..83db66306 100644 --- a/lib/subghz/protocols/beninca_arc.c +++ b/lib/subghz/protocols/beninca_arc.c @@ -96,7 +96,7 @@ static uint8_t subghz_protocol_beninca_arc_get_btn_code(void) { case 0x04: btn = 0x02; break; - case 0xFF: + case 0x00: btn = 0x04; break; @@ -106,12 +106,12 @@ static uint8_t subghz_protocol_beninca_arc_get_btn_code(void) { } else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) { switch(original_btn_code) { case 0x02: - btn = 0xFF; + btn = 0x00; break; case 0x04: - btn = 0xFF; + btn = 0x00; break; - case 0xFF: + case 0x00: btn = 0x02; break; From c5ea6f79820ca5b712ade6a21eaa64dcd9fab122 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 25 Jan 2026 06:19:57 +0300 Subject: [PATCH 059/160] upd changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44063cb06..ff834aadf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ## Main changes - Current API: 87.4 * SubGHz: **Cardin S449 protocol full support** (64bit keeloq) (with Add manually, and all button codes) (**use FSK12K modulation to read the remote**) (closes issues #735 #908) (by @xMasterX and @zero-mega (thanks!)) -* SubGHz: **Beninca ARC AES128 protocol full support** (128bit dynamic) (with Add manually, and 2 button codes) (resolves issue #596) (by @xMasterX and @zero-mega) +* SubGHz: **Beninca ARC AES128 protocol full support** (128bit dynamic) (with Add manually, and 3 button codes) (resolves issue #596) (by @xMasterX and @zero-mega) * SubGHz: **Treadmill37 protocol support** (37bit static) (by @xMasterX) * SubGHz: **New modulation FSK with 12KHz deviation** * SubGHz: **KingGates Stylo 4k - Add manually and button switch support** + refactoring of encoder From 8a85ab88a767ab2777f171de2e45b47195f35b0a Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Sun, 25 Jan 2026 22:38:11 +0700 Subject: [PATCH 060/160] Home to work --- .../drivers/subghz/cc1101_ext/cc1101_ext.c | 2 - .../scenes/subghz_scene_receiver_info.c | 8 ++ .../subghz/scenes/subghz_scene_transmitter.c | 113 +++++++++++------- applications/main/subghz/views/transmitter.c | 28 ++--- 4 files changed, 85 insertions(+), 66 deletions(-) diff --git a/applications/drivers/subghz/cc1101_ext/cc1101_ext.c b/applications/drivers/subghz/cc1101_ext/cc1101_ext.c index 40cfe0d4a..adcf785f2 100644 --- a/applications/drivers/subghz/cc1101_ext/cc1101_ext.c +++ b/applications/drivers/subghz/cc1101_ext/cc1101_ext.c @@ -98,8 +98,6 @@ typedef struct { static SubGhzDeviceCC1101Ext* subghz_device_cc1101_ext = NULL; -bool subghz_device_cc1101_ext_is_async_tx_complete(void); - static bool subghz_device_cc1101_ext_check_init(void) { furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateInit); subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle; diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index e68b0203d..a34239f6b 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -2,6 +2,8 @@ #include +#include "applications/main/subghz/helpers/subghz_txrx_i.h" + #define TAG "SubGhzSceneReceiverInfo" void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, void* context) { @@ -138,6 +140,12 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) return true; } else if(event.event == SubGhzCustomEventSceneReceiverInfoTxStop) { //CC1101 Stop Tx -> Start RX + // #subghz_one_press_send# - keyword to search changes + // when user release OK button we wait until full data packed will send and later stop TX + while(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { + notification_message(subghz->notifications, &sequence_blink_magenta_10); + } + //# subghz->state_notifications = SubGhzNotificationStateIDLE; widget_reset(subghz->widget); diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index e7514ac92..65d0c7bc6 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -4,8 +4,13 @@ #include #include + +#include "applications/main/subghz/helpers/subghz_txrx_i.h" + #define TAG "SubGhzSceneTransmitter" +static bool tx_stop_called = false; + void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) { furi_assert(context); SubGhz* subghz = context; @@ -66,26 +71,63 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventViewTransmitterSendStart) { + // if we recieve event to start transmission (user press OK button) then start/restart TX subghz->state_notifications = SubGhzNotificationStateIDLE; if(subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { subghz->state_notifications = SubGhzNotificationStateTx; subghz_scene_transmitter_update_data_show(subghz); dolphin_deed(DolphinDeedSubGhzSend); - - // #subghz_one_press_send# - keyword to search changes - // #start insert# - - // TODO change while condition to subghz_devices_is_async_complete_tx(subghz->txrx->radio_device); - // while( - // !(furi_hal_subghz_is_async_tx_complete() && - // subghz_device_cc1101_ext_is_async_tx_complete())) { - // notification_message(subghz->notifications, &sequence_blink_magenta_10); - // } - - while(!furi_hal_subghz_is_async_tx_complete()) { - notification_message(subghz->notifications, &sequence_blink_magenta_10); - } + } + return true; + } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) { + // we recieve event to stop tranmission (user release OK button) but + // hardware TX still working now then set flag to stop it after hardware TX will be realy ended + if(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { + tx_stop_called = true; + return true; + } + // if hardware TX not working now so just stop TX correctly + subghz->state_notifications = SubGhzNotificationStateIDLE; + subghz_txrx_stop(subghz->txrx); + if(subghz_custom_btn_get() != SUBGHZ_CUSTOM_BTN_OK) { + subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); + int32_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); + furi_hal_subghz_set_rolling_counter_mult(0); + // Calling restore! + subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); + subghz_txrx_stop(subghz->txrx); + // Calling restore 2nd time special for FAAC SLH! + // TODO: Find better way to restore after custom button is used!!! + subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); + subghz_txrx_stop(subghz->txrx); + furi_hal_subghz_set_rolling_counter_mult(tmp_counter); + } + return true; + } else if(event.event == SubGhzCustomEventViewTransmitterBack) { + // if user press back button then force stop TX if they was active + if(subghz->state_notifications == SubGhzNotificationStateTx) { + subghz_txrx_stop(subghz->txrx); + } + subghz->state_notifications = SubGhzNotificationStateIDLE; + scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneStart); + return true; + } else if(event.event == SubGhzCustomEventViewTransmitterError) { + furi_string_set(subghz->error_str, "Protocol not\nfound!"); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); + } + } else if(event.type == SceneManagerEventTypeTick) { + if(subghz->state_notifications == SubGhzNotificationStateTx) { + // if hardware TX still working at this time so we just blink led and do nothing + if(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { + notification_message(subghz->notifications, &sequence_blink_magenta_10); + return true; + } + // if hardware TX not working now and tx_stop_called = true + // (mean user release OK button early than hardware TX was ended) then we stop TX + if(tx_stop_called) { + tx_stop_called = false; subghz->state_notifications = SubGhzNotificationStateIDLE; subghz_txrx_stop(subghz->txrx); if(subghz_custom_btn_get() != SUBGHZ_CUSTOM_BTN_OK) { @@ -101,39 +143,18 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { subghz_txrx_stop(subghz->txrx); furi_hal_subghz_set_rolling_counter_mult(tmp_counter); } - // #end insert# + return true; + } else { + // if state_notifications == SubGhzNotificationStateTx but hardware TX was ended + // and user still dont release OK button then we repeat transmission + subghz->state_notifications = SubGhzNotificationStateIDLE; + if(subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { + subghz->state_notifications = SubGhzNotificationStateTx; + subghz_scene_transmitter_update_data_show(subghz); + dolphin_deed(DolphinDeedSubGhzSend); + } + return true; } - return true; - // #subghz_one_press_send# - keyword to search changes - // } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) { - // subghz->state_notifications = SubGhzNotificationStateIDLE; - // subghz_txrx_stop(subghz->txrx); - // if(subghz_custom_btn_get() != SUBGHZ_CUSTOM_BTN_OK) { - // subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); - // int32_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); - // furi_hal_subghz_set_rolling_counter_mult(0); - // // Calling restore! - // subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); - // subghz_txrx_stop(subghz->txrx); - // // Calling restore 2nd time special for FAAC SLH! - // // TODO: Find better way to restore after custom button is used!!! - // subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); - // subghz_txrx_stop(subghz->txrx); - // furi_hal_subghz_set_rolling_counter_mult(tmp_counter); - // } - // return true; - } else if(event.event == SubGhzCustomEventViewTransmitterBack) { - subghz->state_notifications = SubGhzNotificationStateIDLE; - scene_manager_search_and_switch_to_previous_scene( - subghz->scene_manager, SubGhzSceneStart); - return true; - } else if(event.event == SubGhzCustomEventViewTransmitterError) { - furi_string_set(subghz->error_str, "Protocol not\nfound!"); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); - } - } else if(event.type == SceneManagerEventTypeTick) { - if(subghz->state_notifications == SubGhzNotificationStateTx) { - notification_message(subghz->notifications, &sequence_blink_magenta_10); } return true; } diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index 455ab63a5..9faa703b6 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -6,9 +6,6 @@ #include -#include -#include - struct SubGhzViewTransmitter { View* view; SubGhzViewTransmitterCallback callback; @@ -158,10 +155,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { true); if(can_be_sent) { - // #subghz_one_press_send# - keyword to search changes - bool allow_events = furi_hal_subghz_is_async_tx_complete() && subghz_device_cc1101_ext_is_async_tx_complete (); - // # - if(event->key == InputKeyOk && event->type == InputTypePress && allow_events) { + if(event->key == InputKeyOk && event->type == InputTypePress) { subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); with_view_model( subghz_transmitter->view, @@ -174,11 +168,10 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { subghz_transmitter->callback( SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); return true; - // #subghz_one_press_send# - keyword to search changes - // } else if(event->key == InputKeyOk && event->type == InputTypeRelease) { - // subghz_transmitter->callback( - // SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); - // return true; + } else if(event->key == InputKeyOk && event->type == InputTypeRelease) { + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); + return true; } // Finish "OK" key processing if(subghz_custom_btn_is_allowed()) { @@ -196,7 +189,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { return true; } - if(event->type == InputTypePress && allow_events) { + if(event->type == InputTypePress) { with_view_model( subghz_transmitter->view, SubGhzViewTransmitterModel * model, @@ -216,11 +209,10 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { subghz_transmitter->callback( SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); return true; - // #subghz_one_press_send# - keyword to search changes - // } else if(event->type == InputTypeRelease) { - // subghz_transmitter->callback( - // SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); - // return true; + } else if(event->type == InputTypeRelease) { + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); + return true; } } } From 72aa0372bec144792c7bb1d4620f98d197465584 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Sun, 25 Jan 2026 21:41:42 +0100 Subject: [PATCH 061/160] Update changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c50fc825..7668d7167 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,7 +38,9 @@ - UL: Possible Sommer timings fix (by @xMasterX) - UL: Various fixes (by @xMasterX) - UL: Nice Flor S remove extra uint64 variable (by @xMasterX) -- UL: NFC: Fix LED not blinking at SLIX unlock (by @xMasterX) +- NFC: + - Fix sending 32+ byte ISO 15693-3 commands (by @WillyJL) + - UL: Fix LED not blinking at SLIX unlock (by @xMasterX) ### Removed: - Sub-GHz: From 338240447abaab4456807982e748d324a0326470 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Sun, 25 Jan 2026 21:54:52 +0100 Subject: [PATCH 062/160] Update apps --nobuild --- applications/external | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/external b/applications/external index d52c118c8..7d9d6ada3 160000 --- a/applications/external +++ b/applications/external @@ -1 +1 @@ -Subproject commit d52c118c825dd86c41c02943b34ae4529e4d3605 +Subproject commit 7d9d6ada30d5d1f0fa0cea3242ea25eee1ec851b From 33321e532a4d846cc924edf67d6ed57b03ceee4e Mon Sep 17 00:00:00 2001 From: WillyJL Date: Sun, 25 Jan 2026 23:43:30 +0100 Subject: [PATCH 063/160] Apps: Add ISO 15693-3 NFC Writer (by ch4istO) --- CHANGELOG.md | 1 + applications/external | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c690ebe1..7ad2b4ac2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ### Added: - Apps: + - NFC: ISO 15693-3 NFC Writer (by @ch4istO) - Sub-GHz: ProtoPirate (by @RocketGod-git & @xMasterX & @zero-mega et al.) - Sub-GHz: - UL: Cardin S449 protocol full support (64bit keeloq) (with Add manually, and all button codes) (use FSK12K modulation to read the remote) (by @xMasterX & @zero-mega) diff --git a/applications/external b/applications/external index 7d9d6ada3..e9230bc08 160000 --- a/applications/external +++ b/applications/external @@ -1 +1 @@ -Subproject commit 7d9d6ada30d5d1f0fa0cea3242ea25eee1ec851b +Subproject commit e9230bc089ae26094a9cba4614815c36532fc964 From c94b5505b7fff741dcb89b08bc4fad4b3b2aa53a Mon Sep 17 00:00:00 2001 From: Leeroy <135471162+LeeroysHub@users.noreply.github.com> Date: Mon, 26 Jan 2026 09:46:52 +1100 Subject: [PATCH 064/160] Archive: Support opening and pinning ProtoPirate files from Archive (#510) * ProtoPirate added to known apps, can use browser and favorites to Open PSFs now. * Archive: Use protopirate icon for .psf files * Update changelog * Format --------- Co-authored-by: WillyJL --- CHANGELOG.md | 1 + .../main/archive/helpers/archive_browser.h | 1 + applications/main/archive/helpers/archive_files.h | 1 + .../main/archive/scenes/archive_scene_browser.c | 2 ++ .../main/archive/views/archive_browser_view.c | 1 + assets/icons/Archive/protopirate_10px.png | Bin 0 -> 96 bytes targets/f7/api_symbols.csv | 1 + 7 files changed, 7 insertions(+) create mode 100644 assets/icons/Archive/protopirate_10px.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ad2b4ac2..cc8ed1259 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ - UL: Alutech AT-4N & Nice Flor S turbo speedup (by @Dmitry422) - UL: Sommer fm2 in Add manually now uses FM12K modulation (Sommer without fm2 tag uses FM476) (try this if regular option doesn't work for you) (by @xMasterX) - UL: Replaced Cars ignore option with Revers RB2 protocol ignore option (by @xMasterX) +- Archive: Support opening and pinning ProtoPirate files from Archive (#510 by @LeeroysHub) ### Fixed: - Sub-GHz: diff --git a/applications/main/archive/helpers/archive_browser.h b/applications/main/archive/helpers/archive_browser.h index 2378c53b2..14bb8f76d 100644 --- a/applications/main/archive/helpers/archive_browser.h +++ b/applications/main/archive/helpers/archive_browser.h @@ -45,6 +45,7 @@ static const char* const known_ext[] = { [ArchiveFileTypeUpdateManifest] = ".fuf", [ArchiveFileTypeDiskImage] = ".img", [ArchiveFileTypeFolder] = "?", + [ArchiveFileTypeProtoPirate] = ".psf", [ArchiveFileTypeUnknown] = "*", [ArchiveFileTypeAppOrJs] = ".fap|.js", [ArchiveFileTypeSetting] = "?", diff --git a/applications/main/archive/helpers/archive_files.h b/applications/main/archive/helpers/archive_files.h index a33313284..c4837f426 100644 --- a/applications/main/archive/helpers/archive_files.h +++ b/applications/main/archive/helpers/archive_files.h @@ -31,6 +31,7 @@ typedef enum { ArchiveFileTypeDiskImage, ArchiveFileTypeFolder, ArchiveFileTypeSetting, + ArchiveFileTypeProtoPirate, ArchiveFileTypeUnknown, ArchiveFileTypeAppOrJs, ArchiveFileTypeLoading, diff --git a/applications/main/archive/scenes/archive_scene_browser.c b/applications/main/archive/scenes/archive_scene_browser.c index 6042c8f32..777fd471e 100644 --- a/applications/main/archive/scenes/archive_scene_browser.c +++ b/applications/main/archive/scenes/archive_scene_browser.c @@ -29,6 +29,8 @@ const char* archive_get_flipper_app_name(ArchiveFileTypeEnum file_type) { return EXT_PATH("apps/Sub-Ghz/subghz_playlist.fap"); case ArchiveFileTypeSubghzRemote: return EXT_PATH("apps/Sub-Ghz/subghz_remote.fap"); + case ArchiveFileTypeProtoPirate: + return EXT_PATH("apps/Sub-Ghz/proto_pirate.fap"); case ArchiveFileTypeInfraredRemote: return EXT_PATH("apps/Infrared/ir_remote.fap"); case ArchiveFileTypeBadUsb: diff --git a/applications/main/archive/views/archive_browser_view.c b/applications/main/archive/views/archive_browser_view.c index 98462d86a..1882d267a 100644 --- a/applications/main/archive/views/archive_browser_view.c +++ b/applications/main/archive/views/archive_browser_view.c @@ -45,6 +45,7 @@ static const Icon* ArchiveItemIcons[] = { [ArchiveFileTypeSearch] = &I_search_10px, [ArchiveFileTypeUpdateManifest] = &I_update_10px, [ArchiveFileTypeDiskImage] = &I_floppydisk_10px, + [ArchiveFileTypeProtoPirate] = &I_protopirate_10px, [ArchiveFileTypeFolder] = &I_dir_10px, [ArchiveFileTypeUnknown] = &I_unknown_10px, [ArchiveFileTypeLoading] = &I_loading_10px, diff --git a/assets/icons/Archive/protopirate_10px.png b/assets/icons/Archive/protopirate_10px.png new file mode 100644 index 0000000000000000000000000000000000000000..ba5e7ccbcb67934ce403eb929b6d3be67d7a8f72 GIT binary patch literal 96 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2xkYHHq`AGmsse8IOhE&W+w)r@zShG%z@6Xds)yz|gmY-QVkf(GQSTPgg&ebxsLQ017r4V*mgE literal 0 HcmV?d00001 diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 61c31facb..e578d5541 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -4319,6 +4319,7 @@ Variable,+,I_power_text_24x5,const Icon, Variable,+,I_prev_19x20,const Icon, Variable,+,I_prev_hover_19x20,const Icon, Variable,+,I_prev_text_19x5,const Icon, +Variable,+,I_protopirate_10px,const Icon, Variable,-,I_qr_benchmark_25x25,const Icon, Variable,+,I_red_19x20,const Icon, Variable,+,I_red_hover_19x20,const Icon, From c176524fca3d8ab3485fd5ef5220b8c7f3cdae2d Mon Sep 17 00:00:00 2001 From: Aaron Tulino Date: Sun, 25 Jan 2026 15:47:12 -0700 Subject: [PATCH 065/160] NFC: ISO 15693-3 emulation READ_MULTI and GET_BLOCK_SECURITY fixes (#501) * Fix ISO15693 crash (hopefully) * NFC: Fix off-by-one block count in ISO 15693-3 READ MULTI command * NFC: Handle 256 long BLOCK SECURITY response and too large READ MULTI response * Move the define so correlation is clearer * Oops * Change to no reply if too many blocks requested than can be handled * Update CHANGELOG.md --------- Co-authored-by: WillyJL --- CHANGELOG.md | 1 + .../presets/nfc/iso15693_signal.c | 6 +++++- .../iso15693_3/iso15693_3_listener.c | 2 -- .../iso15693_3/iso15693_3_listener_i.c | 20 ++++++++++++++++--- .../iso15693_3/iso15693_3_listener_i.h | 12 +++++++++++ 5 files changed, 35 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc8ed1259..5f94135d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ - UL: Nice Flor S remove extra uint64 variable (by @xMasterX) - NFC: - Fix sending 32+ byte ISO 15693-3 commands (by @WillyJL) + - Fixes to `READ_MULTI` and `GET_BLOCK_SECURITY` commands in ISO 15693-3 emulation (#501 by @WillyJL & aaronjamt) - UL: Fix LED not blinking at SLIX unlock (by @xMasterX) - UL: UI: Some small changes (by @xMasterX) diff --git a/lib/digital_signal/presets/nfc/iso15693_signal.c b/lib/digital_signal/presets/nfc/iso15693_signal.c index 43066b5bf..560a393a0 100644 --- a/lib/digital_signal/presets/nfc/iso15693_signal.c +++ b/lib/digital_signal/presets/nfc/iso15693_signal.c @@ -2,8 +2,12 @@ #include +#include + #define BITS_IN_BYTE (8U) +#define ISO15693_SIGNAL_BUFFER_SIZE (ISO15693_3_LISTENER_BUFFER_SIZE * BITS_IN_BYTE + 2) + #define ISO15693_SIGNAL_COEFF_HI (1U) #define ISO15693_SIGNAL_COEFF_LO (4U) @@ -151,7 +155,7 @@ Iso15693Signal* iso15693_signal_alloc(const GpioPin* pin) { Iso15693Signal* instance = malloc(sizeof(Iso15693Signal)); - instance->tx_sequence = digital_sequence_alloc(BITS_IN_BYTE * 255 + 2, pin); + instance->tx_sequence = digital_sequence_alloc(ISO15693_SIGNAL_BUFFER_SIZE, pin); for(uint32_t i = 0; i < Iso15693SignalDataRateNum; ++i) { iso15693_signal_bank_fill(instance, i); diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c b/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c index 151e4ae4a..2d1d053c3 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c @@ -8,8 +8,6 @@ #define TAG "Iso15693_3Listener" -#define ISO15693_3_LISTENER_BUFFER_SIZE (256U) - Iso15693_3Listener* iso15693_3_listener_alloc(Nfc* nfc, Iso15693_3Data* data) { furi_assert(nfc); diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c index 6132fbf47..1e0f65bfd 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c @@ -263,8 +263,9 @@ static Iso15693_3Error iso15693_3_listener_read_multi_blocks_handler( const uint32_t block_index_start = request->first_block_num; const uint32_t block_index_end = - MIN((block_index_start + request->block_count + 1), + MIN((block_index_start + request->block_count), ((uint32_t)instance->data->system_info.block_count - 1)); + const uint32_t block_count = block_index_end - block_index_start + 1; error = iso15693_3_listener_extension_handler( instance, @@ -273,8 +274,21 @@ static Iso15693_3Error iso15693_3_listener_read_multi_blocks_handler( (uint32_t)block_index_end); if(error != Iso15693_3ErrorNone) break; + const bool include_block_security = (flags & ISO15693_3_REQ_FLAG_T4_OPTION) != 0; + const uint8_t bytes_per_block = + (include_block_security ? 1 : 0) + instance->data->system_info.block_size; + const uint32_t response_data_max = + bit_buffer_get_capacity_bytes(instance->tx_buffer) - 1 - 2; // Flags and CRC + const uint32_t response_blocks_max = response_data_max / bytes_per_block; + if(block_count > response_blocks_max) { + // Tested on SLIX2, if asked for more blocks than supported at once there is no reply + // Let's do the same + error = Iso15693_3ErrorIgnore; + break; + } + for(uint32_t i = block_index_start; i <= block_index_end; ++i) { - if(flags & ISO15693_3_REQ_FLAG_T4_OPTION) { + if(include_block_security) { iso15693_3_append_block_security( instance->data, i, instance->tx_buffer); // Block security (optional) } @@ -341,7 +355,7 @@ static Iso15693_3Error iso15693_3_listener_write_multi_blocks_handler( if(error != Iso15693_3ErrorNone) break; - for(uint32_t i = block_index_start; i < block_count + request->first_block_num; ++i) { + for(uint32_t i = block_index_start; i <= block_index_end; ++i) { const uint8_t* block_data = &request->block_data[block_size * i]; iso15693_3_set_block_data(instance->data, i, block_data, block_size); } diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h index a9e0822bf..24a2d1cf0 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h @@ -10,6 +10,18 @@ extern "C" { #endif +// Based on GET_BLOCKS_SECURITY, one of the commands with lengthier responses: +// - 1 byte flags +// - 1 byte security status * 256 max block count +// - 2 byte crc +// for a response size of 259 bytes. +// There is also READ_MULTI_BLOCKS which has no explicit limit on requested block count +// and ISO 15693-3 also does not specify a maximum overall response length, so this command could +// theoretically result in a 8195 byte response (1 byte flags + 32 byte block * 256 blocks + 2 byte crc); +// for practicality we use a sufficient buffer for a full GET_BLOCKS_SECURITY and +// limit READ_MULTI_BLOCKS to how many blocks we can fit into that buffer size. +#define ISO15693_3_LISTENER_BUFFER_SIZE (259U) + typedef enum { Iso15693_3ListenerStateReady, Iso15693_3ListenerStateSelected, From 896a50066796e5d4ba1da09073fa65da9d6bb01c Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 26 Jan 2026 03:04:46 +0300 Subject: [PATCH 066/160] Fixes to READ_MULTI and GET_BLOCK_SECURITY commands in 15693-3 emu [ci skip] by WillyJL & aaronjamt --- .../presets/nfc/iso15693_signal.c | 6 +++++- .../iso15693_3/iso15693_3_listener.c | 2 -- .../iso15693_3/iso15693_3_listener_i.c | 20 ++++++++++++++++--- .../iso15693_3/iso15693_3_listener_i.h | 12 +++++++++++ 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/lib/digital_signal/presets/nfc/iso15693_signal.c b/lib/digital_signal/presets/nfc/iso15693_signal.c index 43066b5bf..560a393a0 100644 --- a/lib/digital_signal/presets/nfc/iso15693_signal.c +++ b/lib/digital_signal/presets/nfc/iso15693_signal.c @@ -2,8 +2,12 @@ #include +#include + #define BITS_IN_BYTE (8U) +#define ISO15693_SIGNAL_BUFFER_SIZE (ISO15693_3_LISTENER_BUFFER_SIZE * BITS_IN_BYTE + 2) + #define ISO15693_SIGNAL_COEFF_HI (1U) #define ISO15693_SIGNAL_COEFF_LO (4U) @@ -151,7 +155,7 @@ Iso15693Signal* iso15693_signal_alloc(const GpioPin* pin) { Iso15693Signal* instance = malloc(sizeof(Iso15693Signal)); - instance->tx_sequence = digital_sequence_alloc(BITS_IN_BYTE * 255 + 2, pin); + instance->tx_sequence = digital_sequence_alloc(ISO15693_SIGNAL_BUFFER_SIZE, pin); for(uint32_t i = 0; i < Iso15693SignalDataRateNum; ++i) { iso15693_signal_bank_fill(instance, i); diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c b/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c index 151e4ae4a..2d1d053c3 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c @@ -8,8 +8,6 @@ #define TAG "Iso15693_3Listener" -#define ISO15693_3_LISTENER_BUFFER_SIZE (256U) - Iso15693_3Listener* iso15693_3_listener_alloc(Nfc* nfc, Iso15693_3Data* data) { furi_assert(nfc); diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c index 6132fbf47..1e0f65bfd 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c @@ -263,8 +263,9 @@ static Iso15693_3Error iso15693_3_listener_read_multi_blocks_handler( const uint32_t block_index_start = request->first_block_num; const uint32_t block_index_end = - MIN((block_index_start + request->block_count + 1), + MIN((block_index_start + request->block_count), ((uint32_t)instance->data->system_info.block_count - 1)); + const uint32_t block_count = block_index_end - block_index_start + 1; error = iso15693_3_listener_extension_handler( instance, @@ -273,8 +274,21 @@ static Iso15693_3Error iso15693_3_listener_read_multi_blocks_handler( (uint32_t)block_index_end); if(error != Iso15693_3ErrorNone) break; + const bool include_block_security = (flags & ISO15693_3_REQ_FLAG_T4_OPTION) != 0; + const uint8_t bytes_per_block = + (include_block_security ? 1 : 0) + instance->data->system_info.block_size; + const uint32_t response_data_max = + bit_buffer_get_capacity_bytes(instance->tx_buffer) - 1 - 2; // Flags and CRC + const uint32_t response_blocks_max = response_data_max / bytes_per_block; + if(block_count > response_blocks_max) { + // Tested on SLIX2, if asked for more blocks than supported at once there is no reply + // Let's do the same + error = Iso15693_3ErrorIgnore; + break; + } + for(uint32_t i = block_index_start; i <= block_index_end; ++i) { - if(flags & ISO15693_3_REQ_FLAG_T4_OPTION) { + if(include_block_security) { iso15693_3_append_block_security( instance->data, i, instance->tx_buffer); // Block security (optional) } @@ -341,7 +355,7 @@ static Iso15693_3Error iso15693_3_listener_write_multi_blocks_handler( if(error != Iso15693_3ErrorNone) break; - for(uint32_t i = block_index_start; i < block_count + request->first_block_num; ++i) { + for(uint32_t i = block_index_start; i <= block_index_end; ++i) { const uint8_t* block_data = &request->block_data[block_size * i]; iso15693_3_set_block_data(instance->data, i, block_data, block_size); } diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h index a9e0822bf..24a2d1cf0 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h @@ -10,6 +10,18 @@ extern "C" { #endif +// Based on GET_BLOCKS_SECURITY, one of the commands with lengthier responses: +// - 1 byte flags +// - 1 byte security status * 256 max block count +// - 2 byte crc +// for a response size of 259 bytes. +// There is also READ_MULTI_BLOCKS which has no explicit limit on requested block count +// and ISO 15693-3 also does not specify a maximum overall response length, so this command could +// theoretically result in a 8195 byte response (1 byte flags + 32 byte block * 256 blocks + 2 byte crc); +// for practicality we use a sufficient buffer for a full GET_BLOCKS_SECURITY and +// limit READ_MULTI_BLOCKS to how many blocks we can fit into that buffer size. +#define ISO15693_3_LISTENER_BUFFER_SIZE (259U) + typedef enum { Iso15693_3ListenerStateReady, Iso15693_3ListenerStateSelected, From f0abf0f1342a9810de1a8d52db326121f231283c Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 26 Jan 2026 03:11:25 +0300 Subject: [PATCH 067/160] upd changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff834aadf..a6b678b3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * SubGHz: Add 390MHz, 430.5MHz to default hopper list (6 elements like in OFW) (works well with Hopper RSSI level set for your enviroment) * SubGHz: Fixed button mapping for **FAAC RC/XT** * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) +* NFC: Fixes to `READ_MULTI` and `GET_BLOCK_SECURITY` commands in ISO 15693-3 emulation (by @WillyJL & @aaronjamt) * Archive: Allow folders to be pinned (by @WillyJL) * Apps: Build tag (**22jan2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes From 209ae6f76f0901847b7a674addcae35e38ed811a Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 26 Jan 2026 03:11:50 +0300 Subject: [PATCH 068/160] bump apps tag --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6b678b3d..f5993e7c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * NFC: Fixes to `READ_MULTI` and `GET_BLOCK_SECURITY` commands in ISO 15693-3 emulation (by @WillyJL & @aaronjamt) * Archive: Allow folders to be pinned (by @WillyJL) -* Apps: Build tag (**22jan2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) +* Apps: Build tag (**26jan2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes * UI: Various small changes * OFW PR 4333: NFC: Fix sending 32+ byte ISO 15693-3 commands (by @WillyJL) From 3cc57f7b3e2a46d2e599091b079a65f8e938b417 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Mon, 26 Jan 2026 13:07:19 +0700 Subject: [PATCH 069/160] Subghz send by one touch --- .../scenes/subghz_scene_receiver_info.c | 67 +++++++++++++++++-- .../subghz/scenes/subghz_scene_transmitter.c | 6 +- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index a34239f6b..26b4d4600 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -6,6 +6,8 @@ #define TAG "SubGhzSceneReceiverInfo" +static bool tx_stop_called = false; + void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, void* context) { furi_assert(context); SubGhz* subghz = context; @@ -140,14 +142,17 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) return true; } else if(event.event == SubGhzCustomEventSceneReceiverInfoTxStop) { //CC1101 Stop Tx -> Start RX - // #subghz_one_press_send# - keyword to search changes - // when user release OK button we wait until full data packed will send and later stop TX - while(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { - notification_message(subghz->notifications, &sequence_blink_magenta_10); + + // if we recieve event to stop tranmission (user release OK button) but + // hardware TX still working now then set flag to stop it after hardware TX will be realy ended + // else stop TX correctly and start RX + if(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { + tx_stop_called = true; + return true; } - //# subghz->state_notifications = SubGhzNotificationStateIDLE; + //update screen data widget_reset(subghz->widget); subghz_scene_receiver_info_draw_widget(subghz); @@ -187,7 +192,57 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) } switch(subghz->state_notifications) { case SubGhzNotificationStateTx: - notification_message(subghz->notifications, &sequence_blink_magenta_10); + // if hardware TX still working at this time so we just blink led and do nothing + if(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { + notification_message(subghz->notifications, &sequence_blink_magenta_10); + return true; + } + // if hardware TX not working now and tx_stop_called = true + // (mean user release OK button early than hardware TX was ended) then we stop TX + if(tx_stop_called) { + tx_stop_called = false; + subghz->state_notifications = SubGhzNotificationStateIDLE; + + //update screen data + widget_reset(subghz->widget); + subghz_scene_receiver_info_draw_widget(subghz); + + subghz_txrx_stop(subghz->txrx); + + // Start RX + if(!scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneDecodeRAW)) { + subghz_txrx_rx_start(subghz->txrx); + + subghz_txrx_hopper_unpause(subghz->txrx); + if(!subghz_history_get_text_space_left(subghz->history, NULL)) { + subghz->state_notifications = SubGhzNotificationStateRx; + } + } + return true; + } else { + // if current state == SubGhzNotificationStateTx but hardware TX was ended + // and user still not release OK button then we repeat TX + + subghz->state_notifications = SubGhzNotificationStateIDLE; + + //update screen data + widget_reset(subghz->widget); + subghz_scene_receiver_info_draw_widget(subghz); + + //CC1101 Stop RX -> Start TX + subghz_txrx_hopper_pause(subghz->txrx); + if(!subghz_tx_start( + subghz, + subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen))) { + subghz_txrx_rx_start(subghz->txrx); + subghz_txrx_hopper_unpause(subghz->txrx); + subghz->state_notifications = SubGhzNotificationStateRx; + } else { + subghz->state_notifications = SubGhzNotificationStateTx; + } + + return true; + } break; case SubGhzNotificationStateRx: notification_message(subghz->notifications, &sequence_blink_cyan_10); diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 65d0c7bc6..bfb974417 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -81,7 +81,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { } return true; } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) { - // we recieve event to stop tranmission (user release OK button) but + // if we recieve event to stop tranmission (user release OK button) but // hardware TX still working now then set flag to stop it after hardware TX will be realy ended if(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { tx_stop_called = true; @@ -145,8 +145,8 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { } return true; } else { - // if state_notifications == SubGhzNotificationStateTx but hardware TX was ended - // and user still dont release OK button then we repeat transmission + // if current state == SubGhzNotificationStateTx but hardware TX was ended + // and user still not release OK button then we repeat transmission subghz->state_notifications = SubGhzNotificationStateIDLE; if(subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { subghz->state_notifications = SubGhzNotificationStateTx; From 271c65a969e20a7194b716b23d19fc23a9ce3fa0 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 26 Jan 2026 11:51:28 +0300 Subject: [PATCH 070/160] subghz: add jarolift protocol and various fixes --- .../main/subghz/helpers/subghz_custom_event.h | 1 + .../main/subghz/helpers/subghz_gen_info.c | 9 + .../main/subghz/helpers/subghz_gen_info.h | 6 + .../helpers/subghz_txrx_create_protocol_key.c | 30 + .../helpers/subghz_txrx_create_protocol_key.h | 8 + .../resources/subghz/assets/keeloq_mfcodes | 137 +-- .../subghz/scenes/subghz_scene_set_button.c | 5 + .../subghz/scenes/subghz_scene_set_counter.c | 16 + .../subghz/scenes/subghz_scene_set_seed.c | 2 + .../subghz/scenes/subghz_scene_set_serial.c | 8 + .../subghz/scenes/subghz_scene_set_type.c | 11 + lib/subghz/protocols/alutech_at_4n.c | 13 +- lib/subghz/protocols/jarolift.c | 777 ++++++++++++++++++ lib/subghz/protocols/jarolift.h | 108 +++ lib/subghz/protocols/keeloq_common.h | 2 + lib/subghz/protocols/kinggates_stylo_4k.c | 8 +- lib/subghz/protocols/protocol_items.c | 2 +- lib/subghz/protocols/protocol_items.h | 1 + lib/subghz/protocols/public_api.h | 18 + targets/f7/api_symbols.csv | 1 + 20 files changed, 1081 insertions(+), 82 deletions(-) create mode 100644 lib/subghz/protocols/jarolift.c create mode 100644 lib/subghz/protocols/jarolift.h diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index 4fb40f5c0..011b53025 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -72,6 +72,7 @@ typedef enum { SetTypeSomfyTelis, SetTypeKingGatesStylo4k, SetTypeBenincaARC, + SetTypeJarolift, SetTypeANMotorsAT4, SetTypeAlutechAT4N, SetTypePhoenix_V2_433, diff --git a/applications/main/subghz/helpers/subghz_gen_info.c b/applications/main/subghz/helpers/subghz_gen_info.c index a0f07a1d8..bfa609e32 100644 --- a/applications/main/subghz/helpers/subghz_gen_info.c +++ b/applications/main/subghz/helpers/subghz_gen_info.c @@ -541,6 +541,15 @@ void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType ty .beninca_arc.btn = 0x02, .beninca_arc.cnt = 0x03}; break; + case SetTypeJarolift: + gen_info = (GenInfo){ + .type = GenJarolift, + .mod = "AM650", + .freq = 433920000, + .jarolift.serial = key & 0xFFFFF00, + .jarolift.btn = 0x02, + .jarolift.cnt = 0x03}; + break; case SetTypeMotorline433: gen_info = (GenInfo){ .type = GenKeeloq, diff --git a/applications/main/subghz/helpers/subghz_gen_info.h b/applications/main/subghz/helpers/subghz_gen_info.h index e47c218d6..a680b7ba5 100644 --- a/applications/main/subghz/helpers/subghz_gen_info.h +++ b/applications/main/subghz/helpers/subghz_gen_info.h @@ -12,6 +12,7 @@ typedef enum { GenSomfyTelis, GenKingGatesStylo4k, GenBenincaARC, + GenJarolift, GenNiceFlorS, GenSecPlus1, GenSecPlus2, @@ -73,6 +74,11 @@ typedef struct { uint8_t btn; uint32_t cnt; } beninca_arc; + struct { + uint32_t serial; + uint8_t btn; + uint16_t cnt; + } jarolift; struct { uint32_t serial; uint8_t btn; diff --git a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c index 075720dfc..27fb71f5b 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c +++ b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c @@ -395,6 +395,36 @@ bool subghz_txrx_gen_beninca_arc_protocol( return res; } +bool subghz_txrx_gen_jarolift_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt) { + SubGhzTxRx* txrx = context; + + bool res = false; + + txrx->transmitter = + subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_JAROLIFT_NAME); + subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); + + if(txrx->transmitter && subghz_protocol_jarolift_create_data( + subghz_transmitter_get_protocol_instance(txrx->transmitter), + txrx->fff_data, + serial, + btn, + cnt, + txrx->preset)) { + res = true; + } + + subghz_transmitter_free(txrx->transmitter); + + return res; +} + bool subghz_txrx_gen_secplus_v2_protocol( SubGhzTxRx* instance, const char* name_preset, diff --git a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h index afc1059b5..285770975 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h +++ b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h @@ -124,6 +124,14 @@ bool subghz_txrx_gen_beninca_arc_protocol( uint8_t btn, uint32_t cnt); +bool subghz_txrx_gen_jarolift_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt); + bool subghz_txrx_gen_came_atomo_protocol( void* context, const char* preset_name, diff --git a/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes b/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes index b55548844..ae6315a2d 100644 --- a/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes +++ b/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes @@ -1,71 +1,72 @@ Filetype: Flipper SubGhz Keystore File Version: 0 Encryption: 1 -IV: 4F 77 4F 20 66 75 72 72 79 20 49 56 20 55 77 55 -1D0560740B25F58EE0E85BF949139971E5AA08C5499CC74B11992D124C281012 -C05E2D2C715D8E24C518EF2841DA02173C05DD5BA5310EE85D09709500DB1726 -9EA5721836369FF918859077F50E33100F7AC53E8E8F31E25296579F875359DF -D2A8AD1B65BC66B459525124CDC5011C79D98F542702FC69EABD64F908C0D80D -2FA5F078BEB59851D42BC7E4E331AE3A8C384892DF003238CDA82450A6CD02AC -E54ED5F49A093BC938521195C86FECF35FB6EC463C54C6E1609592DC5FA03CCB5E1EDA362FC9AB008C85E66B60147EBA -048F4A28B18496487D65A924F4E37766C3563F41090D442DE61D7A5DD82F5FF1 -DA876A11401727E5102B578F87CCF9596AB9D9925FC90CDF99C9DEC7261B2C8C -03D3842335D69A3AA42452274130B3FAAEE6087CB8D783B0E770062C034BB302 -7F50401E9FFAF10D1F61067C2E830EBBEC7C8B3B20F5C0AC2E10E68912BF2C82 -160BC0CA2FF01E076830F29846C1F6CCBAC7857F2043E8163449048BA8C99AA8 -09357F089CB148DDC578E0F11EC10659EF68A57440700F584922CB9842E2BF08AC977CCAA11355E89FA5C18113349F5E -910D166F40F264225BD4C8EB16C5CC6374F8F8E1202D5BF28FA2E8BA38E420A36E67611E6D151051F7C74843E4A72BBC -D9ACEBC528D7CA74B894A0378095E03C9BDBBE13DDA3FCD6D60CD3CAC49746B8 -90F94FD262E1859B7E5C08E7ED5B16CDB56D0E930034E315CD011DE3759150DA -6620E176FC61DF250EF2BBC2AB27E0DA45A6E1E27F4E94405EE01C36E892EFBF -7D6A062453236E4C353F19B875D079157D016B223B7D429C8F5BEA9D0F703EED -20631589CB541B32C23CA7EA93B12E2016B5A90A2C9CAA6F5849C0B67158EA635858F26A86282C124AEA3FD31B7FD365 -E6CF167CEA0639D1504E0BFC8BAAA7FC7FA36A2286CBBE1312803422018A9F00 -0EB81E23FF37366BA4890CBD46BC8AF5A2CD56E9802B8DF5CDDD5114F677CDF6 -62195292F6F920DAF91F812FC3B94E8539C157D35D3BC94F2FB7A8481406C655AC0F112C4E10AC36892D43D95827BC1D -65FB9BEBDB9BE975168D47B02CA8A2E0ADE2CD1949E90B06689B0475395663BD5AF3C8FEC42C4138CBBB8956AC55B475 -EF0A6961C754FCDBAE0222099DD8AA38DD6A92BCD53A576E105BC5BBD23400B7 -A608752C8602A5BD538441DE046DD7AE011FBA87210B57372BCBB471ECC2B720 -222C83DDC445F72152E563CD068851389364C1D83C9F7D6353325EFD553560B1 -96977544F2F821408C1A88FADB9B1E12D9CA97638A622190F83BC640508B6029 -B596A98BDDA5BD2FF1F812BE67FD00456D4D313E9497147E2439B51972B6B752 -FC276CAC90756F397C3BC616631CE8B9257E6C25D0DC15C5ED1CEB439ACF04D9 -383DD624B98E650E5B4BA28990B4D1912B785C689E6B6A05D77B47B6501CD98F -410814DC8B38DD6EF781B55CA02730092F252082A77400AD90F22BF45A41C849 -8DA240E13E8B512B50FF4504A61037D0A3920B00523D51EEF9996CC3907C175E -E655B7C31E346154C5EF7C59E3A710A2A2F145E7403E4ADB388B3A27D6FF59DE -E2FB7F96EA16B20589995E95D0959B4ECC1EDDF86E347EB85FD29D0D5933A2A1 -00D910F2B050900735A8446220FF7321813252862A69C05A7A534118E50E61DB -BA1B9E7E26E04542183F085060421553CDD3FD9034AAAFCB7EE980A68B98087E -216EBA33FCE4B834BF64621E557923D8AE41F5895266B7BBDFCA6EAF985F036E -2E9075A45ED6D86C172C9ADAAF5E991DA8DA9CBF2F24D746D22A331E236FBA4A -04E4B185C150AF45A67E15D68282C7558B13BFFB05BFCB71BCFD2B92DE5D9701 -1FDC4D759EA89681F76A8F7D336118FE6801EFD10D73925C2749775D9DFED282 -FFB32167FBF860418AAABF29B0D4FEF57BB07454ECF4BD2CF175D44E84C04CED -7C6E419658872D298F2E7B02568B9ED870FDFFE5082ED0BBE689FD04EFFFE7E7 -ADAB0F3108398C75ECC6D2E572960B5685C336DDF3D6F5B9C12D069F27BA15A8 -DAC772C1A81181738CDB8C0E89C2E5B7A57E2DA65CA15232DE96A3C4A599A0E9 -7F6204274D90E88B3F5D5AC86EEEE76C27C0D083E79ADA7BCF7D060FE6F05A3E -5BAB4CCB593418CD8965C09C0925EDB78BB4C8A10892F264DF12F50E532F006E -7C67525C921ABAEC4BFAA376162A7B2B2827AE4C9840DC37F067FE3B72BE7304B6EEB5FB1AD17CFF5F079EFECC04AD56 -94FF6DD4CE63381778E86E61423EDDDD9CC71C3462D66F1AD9A0AD5D378AECE2 -E9CA5BA5C6D6101EA3A51F28E48D49789D60273A9F70D56020D003265517AFA3 -EBF55649D226E9FDAAB57C2E1D75E3FD3A8D216488E97D00E932B3542E731D20 -2B576C3616DDAFEE23A8ECE24BBD89590C8C2D551F14D8EFA4DBB30216F89C31 -EE8D3CF3C503DE4FF368F23585F1A7017FF66A910696A6760AFD2B9822911960 -A32910F791C5EE9998DCE5371B3252427315C9D11AD506CE65760611D873C81D -740646D11A32C65A8549B3AEA8A499866C35D926B2BA21ED73934AA37ADCC1E6 -0E66EF4CA934A5D1ACED28CBEEAA3AF7941E10918DA79379090B6339F11E267E -D79D8666FD947B0D0D504FF10B048B147CB000AD8CDC1F0DEB395FB72B789963 -2F7BA07F18F4A91AEDC08867E9CC4B8689B0831A7CE0E0AEF3D92C0CA9BBC698 -1AB4351CFF02CC600C972CE87F69B23F8ECCC32A90BD5F429F8017A80306F23D -ED2AD447E7DF7A34D78A313395FA1C3AF63CE02B77A5B08CE19493CFA1173232 -C8C8DEAF10AA3994EE7D6DC8E1EB403042627E0F3524409F40C03A7C0C106A80 -5778B4A3E7BE82C07BA6A311A87649F3C7AE5107A89571E14AEF05B9E285C87A -30080347DB3B580B18E8EAC66E1B7227F791773F0342EE0DF8267EC993EC3F24 -2DB3B2A17C165B5C6A1D4944A5B595016588F028DD4F763C4ED6B7FE7849E918 -C1F0CF343B77F31D9A2E810821393EE9D1E0D4B54A87B2DD8CCFBB16FBD77A75B50A0E78D1E8A86310572443731B9DB5 -88EF373C37AADAE1155E7DBDBB7E0B048E3BFEFB412DC49EA8A48E1544B6DC87 -98694781F3EE698ABA8D2CDFFB1CA0425AA17BFE904FC7812E65A78DF1CA06C2 -6BBBCA6672311E1A3BF7001B3222890C8A68A8B7D87DE91624BB9D1FEC0E2728 -4550A44B654085C3A3620B5D4D2C6A7F962275BC5926B9B7E3A706F128BF6D6C967E2BF2ACD4DD000BDC8BDE69684F6F +IV: 6E 6F 74 69 63 65 73 20 62 75 6C 67 65 4F 77 4F +212F687B2D38E6E9066E95894E455A6AD3A8861CDDAFD09DBC2557506676332D +2CFF25E9743E4588820D24998B5047E8019C6E200922BCB66830C7F722822A79 +74AA0EF345C27F583042C4EDDBB83D5446387D4E5B31DFD3F7B9D09F0662A0AA95BEB40BF37678954CAE0200B2898D22 +6998443F71D17938425CD231B8500E769976601315D79D673AA37E4F9BDCE50B +3335691566FEDDDE5828BE0A5BBBD9AC013987A1134E68020D3F0F477E09BC71 +1B3A3CBB3D56783220BEAECEA15FFF5CD92AF44F63547F6F84F4533D2B3D820B +A1ECFE74E714D0E1514D0C18903598E7FB7E7AF5C0165DEDE85DFAE05B26C0EC +BA3F2EFBE7CB6671206EA90DA903FF48CCABEC9F393D55B9DB3B7E207A48C059 +CA91805C8ADF02501B41D6BF0C69D7C3DD6E218D4B4EB6BED2FDE1367256E544 +5465E78D877F2594AF40115723C8AC71D09F60ACCC8121CD3B6BA271BEA43B5C +BB1D3DE0A048694FC86CA8E79BB7BFBB1EF91515C44E917FD5017676EE5C4B13 +48C08D8B2B42D025D2557CC650EDA3C5CC301CD71169CFE0044C07A95224109B +3DAE6C5B94C237FF10CF82FAA58517DB4DD4E4D82FD81CFAAA4836C9B8460CE1 +645F8F5D213889BAB0F437497856A0CF402E3D4A3679258BB0BF2B768D1F1714 +AFC3C462698C795B1A407F27F499CD1757931BD676BA43E4B41E8EF2672EC4AE +5A19F0D1CD87C40883D7BE51377CDAD94C977B4F6CFCCECED91D56867C9EC211 +716645BD4F5B18002417A92D6A2BD29D18087F7ADB549A90A2661EB4163EF190 +54B83F7F7F50AD4C3DC3498822240AEB7D9A43728704F14691A39C79FAC9B6A3 +FFDDCEFAFF3ADA3616B388684B1AD4987B83E459BA5037E377FE17CC7EDAA430 +9CC98590A371E580B164A5F1369945A6DB653797331EC898755E84BE93EDF3EF +63697AD15064194A3986CC1F3111A09E3D86AC8D370A8EC4D22EDDA4B9661B63 +F7CE4FA63EA9D388AE4AB6A468768AE91E2E3CF6F1D9A5EA17845466A6801A8C +38B2DE32CF36D68842CB31FD97394892B76FB4E81FCFB33164676BAB354939DE +93192FA1D7E347AF9FC98EE49A8B02869527511D0B263FD3B08CCFE645A39F51 +3D5F832CF75D94B58B078B4EE0DFC1D987795CD49959517F391F9E9F09CA187C +6CBCCCE0F8E6A833D5CA18E09E821A7F93B9FD7D912632E277B1721985F4B701 +5896050E9F4950CD7061ED4DD3BA9FC6013CA52F5C1B0493110FA3934116AC66 +F0D3FF283FBD7CFBFE697DBE752EDD5A1F124DCCAE3B629A146E0E85A7ED4E06 +6B6C7C365A5CABA2F1023ED1F97D182F0B9D575C64393272E19B8B809DF3C329 +1AF30761D85AE1C6DD4D78D4ECE79983C7F58ECE859709570262811CFCA8C97F +FC86201D96F4AE36C63A1C00DA34AC14BFDE317383D19A534362E6149E860366 +54F55F34A27E1D690F56269D29C795105C8407A4E1A9ED431588F559948C115A +4DD62ECD2FE8CBB783E3D7F0B1D95496D585405DE5AEB07C8A4E053B3AAAD808 +EDB356AFA869EFB987F099239449D6B9F1469EA6D8C9F0A6B4171F685E2853A1 +03C058A2C0DB83179E520F035BBAAB01673EFE4FDE717A0F5D1AB6B81BC9D033 +D2F33C08136AB161EED6121E721F8C479CED5F26A1B7DEEDEA8580314C232C5E +51CB3275D6D7250CD88A446242590C3DFD36DF83F5E34379DE73601511CD24B9 +ED4EC928AC505CBEFA6ACB2901C8E2221FC5073624B0B78F8365DD0442EFBA10 +76F959BBF8A4EC4AC22F41F06719BCBA58F070CB65B282BFC2C99F6CC02E30DB +0A44A7C5D4ECF2F08CBDF3FE947D45C6AC586D4558DBFB36719927F58EBB525B +F096777DDC5BF671CBF1A9682EBEE8308AA1002F6CB6899D575A30CFACB30125C8378864C77922360ADD0AC486EFF7F4 +372863D5B6F6D7A671AB734A99403AF230DEBBBA435AB8F236B179960FAFDFC6 +6CC31C5E86CF6851D92FA973253B3B1FC9023B150980A216A63720CD74592EB7 +6643B2CA94415FE4A4E25A3086B8370172C53283360A7BD54B322BD889A5A831 +03209037BD7E96A16C69A4F0B6FEB3F2ABA1408353BE09C53485CB7C2362A490 +BE4619EC34F7FB8DFE53A8ABFDE6A831895B88D0AB1A9B4861BC7EC7F1121611 +41223F7AD8B0F28D08C1EEC2B96324F337F6428759032CAE58A04E8511BC4CBCE497EE1502F18BED5B5038E719F4F085 +1533D9B78F16803DFD8AC0C9C85ECEB6BABE9ADF83BF0B6692857BAA03843444064FCDBC89464D9E002AAFF53C65098B +466CC36F82D1AF9BA0704789B2F8B249E79D4964E7E5CB74917760E7D30AB7FA +E9673C0CF35137C179132DDCA57869E285FE6014BB32C5DD78E7549ED0076906 +A511A9999C777750FA348772A9E2881A75DEC94ED833AC282037B3E10913B150 +F20652B2CA0E0ADD34331D2462CD5AFACC4E01F24EF17C97CFF57089039AD7D8 +AFCB6518894626B9E8AFC7E7D9D0430D1D820969CE79B61B91E63D08D4995308D8403705AE4E25AB0F254D47FB03A1A2 +C43987548689A1DD9A65A3BE76F97A8470263ACAC0696B5882383AE97893B5D6 +7FB47AC9A16094C38D436F9932041A40F6B4644A633361B47C6F6E4A8F2E7C26 +BDD48C4689912872055999ECADCF93D152ACDEC34C6318F2FBBBA1A34C8CC166FCBA31AED11F95C973B21A646828CEEA +1582E265DF46C8A9A019AF338104C267873FD3C2C7AF290263FEF921CC9926E76F37FA31881307C675CF37F8A5A236D7 +790D8AF6D9F5B634F953F5751378BA5412425B950C696549902EB6A9383630D0 +6F44FF0DB55651218C81B41153C9D77B1911C5BFA70650FB9326DD6B8A1479EE +4B0891C1C24E004AB2869A858941C47346EF0789DFAEA1CD1B0E008A73AF2F7E +7E9F990652FD6632612866B6ECA726EAE2112234EBCA59D0C1BF220B94E1F472 +9C08E9DAE977DD30E61E6634F51BFD654330C34E9FB3AA2E8856B428141D7164 +7C0E756C593FFBBE2609F63D142A0D53F99772EB0722616DFC7B203BA70AA5AE +52C03D8984496DFF95503D843CA1980A6CA46AAE3390C6D4D38E277A0937429C185C118B98B6EBE0711F10F47F8D8F3F +DE8A5BFD2AB351BCAD1D7817737946EF2445E3C974C9E11BF7AD058463F0E437 +D09ABB320F59A75C4B2EE8B52E45D52C46226DD8BC8339F53229578733928F1F +C2E6F135E638C83363097EB79ED9A58E94A8E5F626E27083D1363E8BC61B55A4 +F06CC55446D0FCCCE5AD007949AE3FCA9C6FCB3C0CA1B5DE1BA65544B55326F1CF726E1F1E5CA90CA2B986930C9B9D83 diff --git a/applications/main/subghz/scenes/subghz_scene_set_button.c b/applications/main/subghz/scenes/subghz_scene_set_button.c index e8914dbc5..d2ef60a91 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_button.c +++ b/applications/main/subghz/scenes/subghz_scene_set_button.c @@ -44,6 +44,10 @@ void subghz_scene_set_button_on_enter(void* context) { byte_ptr = &subghz->gen_info->beninca_arc.btn; byte_count = sizeof(subghz->gen_info->beninca_arc.btn); break; + case GenJarolift: + byte_ptr = &subghz->gen_info->jarolift.btn; + byte_count = sizeof(subghz->gen_info->jarolift.btn); + break; case GenNiceFlorS: byte_ptr = &subghz->gen_info->nice_flor_s.btn; byte_count = sizeof(subghz->gen_info->nice_flor_s.btn); @@ -92,6 +96,7 @@ bool subghz_scene_set_button_on_event(void* context, SceneManagerEvent event) { case GenSomfyTelis: case GenKingGatesStylo4k: case GenBenincaARC: + case GenJarolift: case GenNiceFlorS: case GenSecPlus2: scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCounter); diff --git a/applications/main/subghz/scenes/subghz_scene_set_counter.c b/applications/main/subghz/scenes/subghz_scene_set_counter.c index a58749256..8510d4aca 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_counter.c +++ b/applications/main/subghz/scenes/subghz_scene_set_counter.c @@ -50,6 +50,10 @@ void subghz_scene_set_counter_on_enter(void* context) { byte_ptr = (uint8_t*)&subghz->gen_info->beninca_arc.cnt; byte_count = sizeof(subghz->gen_info->beninca_arc.cnt); break; + case GenJarolift: + byte_ptr = (uint8_t*)&subghz->gen_info->jarolift.cnt; + byte_count = sizeof(subghz->gen_info->jarolift.cnt); + break; case GenNiceFlorS: byte_ptr = (uint8_t*)&subghz->gen_info->nice_flor_s.cnt; byte_count = sizeof(subghz->gen_info->nice_flor_s.cnt); @@ -128,6 +132,9 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { case GenBenincaARC: subghz->gen_info->beninca_arc.cnt = __bswap32(subghz->gen_info->beninca_arc.cnt); break; + case GenJarolift: + subghz->gen_info->jarolift.cnt = __bswap16(subghz->gen_info->jarolift.cnt); + break; case GenNiceFlorS: subghz->gen_info->nice_flor_s.cnt = __bswap16(subghz->gen_info->nice_flor_s.cnt); break; @@ -204,6 +211,15 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { subghz->gen_info->beninca_arc.btn, subghz->gen_info->beninca_arc.cnt); break; + case GenJarolift: + generated_protocol = subghz_txrx_gen_jarolift_protocol( + subghz->txrx, + subghz->gen_info->mod, + subghz->gen_info->freq, + subghz->gen_info->jarolift.serial, + subghz->gen_info->jarolift.btn, + subghz->gen_info->jarolift.cnt); + break; case GenNiceFlorS: generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( subghz->txrx, diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed.c b/applications/main/subghz/scenes/subghz_scene_set_seed.c index 648cfa1d3..36307f11f 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed.c @@ -32,6 +32,7 @@ void subghz_scene_set_seed_on_enter(void* context) { case GenSomfyTelis: case GenKingGatesStylo4k: case GenBenincaARC: + case GenJarolift: case GenNiceFlorS: case GenSecPlus2: case GenPhoenixV2: @@ -93,6 +94,7 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { case GenSomfyTelis: case GenKingGatesStylo4k: case GenBenincaARC: + case GenJarolift: case GenNiceFlorS: case GenSecPlus2: case GenPhoenixV2: diff --git a/applications/main/subghz/scenes/subghz_scene_set_serial.c b/applications/main/subghz/scenes/subghz_scene_set_serial.c index 9219842e5..f30b1a4a5 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_serial.c +++ b/applications/main/subghz/scenes/subghz_scene_set_serial.c @@ -50,6 +50,10 @@ void subghz_scene_set_serial_on_enter(void* context) { byte_ptr = (uint8_t*)&subghz->gen_info->beninca_arc.serial; byte_count = sizeof(subghz->gen_info->beninca_arc.serial); break; + case GenJarolift: + byte_ptr = (uint8_t*)&subghz->gen_info->jarolift.serial; + byte_count = sizeof(subghz->gen_info->jarolift.serial); + break; case GenNiceFlorS: byte_ptr = (uint8_t*)&subghz->gen_info->nice_flor_s.serial; byte_count = sizeof(subghz->gen_info->nice_flor_s.serial); @@ -122,6 +126,9 @@ bool subghz_scene_set_serial_on_event(void* context, SceneManagerEvent event) { subghz->gen_info->kinggates_stylo_4k.serial = __bswap32(subghz->gen_info->kinggates_stylo_4k.serial); break; + case GenJarolift: + subghz->gen_info->jarolift.serial = __bswap32(subghz->gen_info->jarolift.serial); + break; case GenBenincaARC: subghz->gen_info->beninca_arc.serial = __bswap32(subghz->gen_info->beninca_arc.serial); @@ -154,6 +161,7 @@ bool subghz_scene_set_serial_on_event(void* context, SceneManagerEvent event) { case GenSomfyTelis: case GenKingGatesStylo4k: case GenBenincaARC: + case GenJarolift: case GenNiceFlorS: case GenSecPlus2: scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetButton); diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 28cd4bcf7..2be40602b 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -22,6 +22,7 @@ static const char* submenu_names[SetTypeMAX] = { [SetTypePhoenix_V2_433] = "V2 Phoenix 433MHz", [SetTypeKingGatesStylo4k] = "KingGates Stylo4k 433M.", [SetTypeBenincaARC] = "Beninca ARC 433MHz", + [SetTypeJarolift] = "Jarolift 433MHz", [SetTypeHCS101_433_92] = "KL: HCS101 433MHz", [SetTypeDoorHan_315_00] = "KL: DoorHan 315MHz", [SetTypeDoorHan_433_92] = "KL: DoorHan 433MHz", @@ -207,6 +208,15 @@ bool subghz_scene_set_type_generate_protocol_from_infos(SubGhz* subghz) { gen_info.beninca_arc.btn, gen_info.beninca_arc.cnt); break; + case GenJarolift: + generated_protocol = subghz_txrx_gen_jarolift_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.jarolift.serial, + gen_info.jarolift.btn, + gen_info.jarolift.cnt); + break; case GenNiceFlorS: generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( subghz->txrx, @@ -288,6 +298,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { case GenSomfyTelis: // Serial (u32), Button (u8), Counter (u16) case GenKingGatesStylo4k: // Serial (u32), Button (u8), Counter (u16) case GenBenincaARC: // Serial (u32), Button (u8), Counter (u32) + case GenJarolift: // Serial (u32), Button (u4), Counter (u16) case GenNiceFlorS: // Serial (u32), Button (u8), Counter (u16) case GenSecPlus2: // Serial (u32), Button (u8), Counter (u32) case GenPhoenixV2: // Serial (u32), Counter (u16) diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 8dff70dd1..687a1e930 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -25,7 +25,6 @@ struct SubGhzProtocolDecoderAlutech_at_4n { SubGhzBlockDecoder decoder; SubGhzBlockGeneric generic; - uint64_t data; uint32_t crc; uint16_t header_count; @@ -578,13 +577,12 @@ void subghz_protocol_decoder_alutech_at_4n_feed(void* context, bool level, uint3 instance->decoder.parser_step = Alutech_at_4nDecoderStepReset; break; } - if((instance->header_count > 2) && + if((instance->header_count > 9) && (DURATION_DIFF(duration, subghz_protocol_alutech_at_4n_const.te_short * 10) < subghz_protocol_alutech_at_4n_const.te_delta * 10)) { // Found header instance->decoder.parser_step = Alutech_at_4nDecoderStepSaveDuration; instance->decoder.decode_data = 0; - instance->data = 0; instance->decoder.decode_count_bit = 0; } else { instance->decoder.parser_step = Alutech_at_4nDecoderStepReset; @@ -617,8 +615,8 @@ void subghz_protocol_decoder_alutech_at_4n_feed(void* context, bool level, uint3 instance->decoder.parser_step = Alutech_at_4nDecoderStepReset; if(instance->decoder.decode_count_bit == subghz_protocol_alutech_at_4n_const.min_count_bit_for_found) { - if(instance->generic.data != instance->data) { - instance->generic.data = instance->data; + if(instance->generic.data != instance->generic.data_2) { + instance->generic.data = instance->generic.data_2; instance->generic.data_count_bit = instance->decoder.decode_count_bit; instance->crc = instance->decoder.decode_data; @@ -627,7 +625,6 @@ void subghz_protocol_decoder_alutech_at_4n_feed(void* context, bool level, uint3 instance->base.callback(&instance->base, instance->base.context); } instance->decoder.decode_data = 0; - instance->data = 0; instance->decoder.decode_count_bit = 0; instance->header_count = 0; } @@ -640,7 +637,7 @@ void subghz_protocol_decoder_alutech_at_4n_feed(void* context, bool level, uint3 subghz_protocol_alutech_at_4n_const.te_delta * 2)) { subghz_protocol_blocks_add_bit(&instance->decoder, 1); if(instance->decoder.decode_count_bit == 64) { - instance->data = instance->decoder.decode_data; + instance->generic.data_2 = instance->decoder.decode_data; instance->decoder.decode_data = 0; } instance->decoder.parser_step = Alutech_at_4nDecoderStepSaveDuration; @@ -652,7 +649,7 @@ void subghz_protocol_decoder_alutech_at_4n_feed(void* context, bool level, uint3 subghz_protocol_alutech_at_4n_const.te_delta)) { subghz_protocol_blocks_add_bit(&instance->decoder, 0); if(instance->decoder.decode_count_bit == 64) { - instance->data = instance->decoder.decode_data; + instance->generic.data_2 = instance->decoder.decode_data; instance->decoder.decode_data = 0; } instance->decoder.parser_step = Alutech_at_4nDecoderStepSaveDuration; diff --git a/lib/subghz/protocols/jarolift.c b/lib/subghz/protocols/jarolift.c new file mode 100644 index 000000000..9881b9892 --- /dev/null +++ b/lib/subghz/protocols/jarolift.c @@ -0,0 +1,777 @@ +#include "jarolift.h" +#include "core/log.h" +#include "keeloq_common.h" + +#include "../subghz_keystore.h" +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#include "../blocks/custom_btn_i.h" + +#define TAG "SubGhzProtocolJarolift" + +static const SubGhzBlockConst subghz_protocol_jarolift_const = { + .te_short = 400, + .te_long = 800, + .te_delta = 167, + .min_count_bit_for_found = 72, +}; + +struct SubGhzProtocolDecoderJarolift { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; + + uint16_t header_count; + SubGhzKeystore* keystore; +}; + +struct SubGhzProtocolEncoderJarolift { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; + SubGhzKeystore* keystore; +}; + +typedef enum { + JaroliftDecoderStepReset = 0, + JaroliftDecoderStepCheckPreambula, + JaroliftDecoderStepSaveDuration, + JaroliftDecoderStepCheckDuration, +} JaroliftDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_jarolift_decoder = { + .alloc = subghz_protocol_decoder_jarolift_alloc, + .free = subghz_protocol_decoder_jarolift_free, + + .feed = subghz_protocol_decoder_jarolift_feed, + .reset = subghz_protocol_decoder_jarolift_reset, + + .get_hash_data = subghz_protocol_decoder_jarolift_get_hash_data, + .serialize = subghz_protocol_decoder_jarolift_serialize, + .deserialize = subghz_protocol_decoder_jarolift_deserialize, + .get_string = subghz_protocol_decoder_jarolift_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_jarolift_encoder = { + .alloc = subghz_protocol_encoder_jarolift_alloc, + .free = subghz_protocol_encoder_jarolift_free, + + .deserialize = subghz_protocol_encoder_jarolift_deserialize, + .stop = subghz_protocol_encoder_jarolift_stop, + .yield = subghz_protocol_encoder_jarolift_yield, +}; + +const SubGhzProtocol subghz_protocol_jarolift = { + .name = SUBGHZ_PROTOCOL_JAROLIFT_NAME, + .type = SubGhzProtocolTypeDynamic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_jarolift_decoder, + .encoder = &subghz_protocol_jarolift_encoder, +}; + +// +// Encoder +// + +// Pre define function +static void subghz_protocol_jarolift_remote_controller( + SubGhzBlockGeneric* instance, + SubGhzKeystore* keystore); + +/** + * Defines the button value for the current btn_id + * Basic set | 0x1 | 0x2 | 0x4 | 0x8 | + * @return Button code + */ +static uint8_t subghz_protocol_jarolift_get_btn_code(void); + +void* subghz_protocol_encoder_jarolift_alloc(SubGhzEnvironment* environment) { + SubGhzProtocolEncoderJarolift* instance = malloc(sizeof(SubGhzProtocolEncoderJarolift)); + + instance->base.protocol = &subghz_protocol_jarolift; + instance->generic.protocol_name = instance->base.protocol->name; + instance->keystore = subghz_environment_get_keystore(environment); + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 256; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + + return instance; +} + +void subghz_protocol_encoder_jarolift_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderJarolift* instance = context; + free(instance->encoder.upload); + free(instance); +} + +void subghz_protocol_encoder_jarolift_stop(void* context) { + SubGhzProtocolEncoderJarolift* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_jarolift_yield(void* context) { + SubGhzProtocolEncoderJarolift* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +/** + * Key generation from simple data + * @param instance Pointer to a SubGhzProtocolEncoderJarolift* instance + * @param btn Button number, 4 bit + */ +static bool + subghz_protocol_jarolift_gen_data(SubGhzProtocolEncoderJarolift* instance, uint8_t btn) { + // Save original button for later use + if(subghz_custom_btn_get_original() == 0) { + subghz_custom_btn_set_original(btn); + } + + btn = subghz_protocol_jarolift_get_btn_code(); + + // Check for OFEX (overflow experimental) mode + if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } + } + } else { + if((instance->generic.cnt + 0x1) > 0xFFFF) { + instance->generic.cnt = 0; + } else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xFFFE) { + instance->generic.cnt = 0xFFFE; + } else { + instance->generic.cnt++; + } + } + + //(instance->generic.seed >> 8) = 8 bit grouping channel 0-7 + uint32_t hop_decrypted = (uint64_t)((instance->generic.seed >> 8) & 0xFF) << 24 | + ((instance->generic.serial & 0xFF) << 16) | + (instance->generic.cnt & 0xFFFF); + + uint64_t hop_encrypted = 0; + for + M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { + if(manufacture_code->type == KEELOQ_LEARNING_NORMAL_JAROLIFT) { + // Normal Learning + uint64_t man = subghz_protocol_keeloq_common_normal_learning( + instance->generic.serial, manufacture_code->key); + hop_encrypted = subghz_protocol_keeloq_common_encrypt(hop_decrypted, man); + break; + } + } + + // If we got some issue, return false + if(hop_encrypted == 0) { + return false; + } + uint64_t fix = (uint64_t)btn << 60 | ((uint64_t)(instance->generic.serial & 0xFFFFFFF) << 32) | + hop_encrypted; + + instance->generic.data = subghz_protocol_blocks_reverse_key(fix, 64); + //(instance->generic.seed & 0xFF) = 8 bit for grouping 8-16 + instance->generic.data_2 = + subghz_protocol_blocks_reverse_key((instance->generic.seed & 0xFF), 8); + + return true; +} + +bool subghz_protocol_jarolift_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolEncoderJarolift* instance = context; + instance->generic.serial = (serial & 0xFFFFF00); + instance->generic.cnt = cnt; + instance->generic.btn = btn; + instance->generic.seed = 0x0100; + instance->generic.data_count_bit = 72; + + // Encode data + + //(instance->generic.seed >> 8) = 8 bit grouping channel 0-7 + uint32_t hop_decrypted = (uint64_t)((instance->generic.seed >> 8) & 0xFF) << 24 | + ((instance->generic.serial & 0xFF) << 16) | + (instance->generic.cnt & 0xFFFF); + + uint64_t hop_encrypted = 0; + for + M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { + if(manufacture_code->type == KEELOQ_LEARNING_NORMAL_JAROLIFT) { + // Normal Learning + uint64_t man = subghz_protocol_keeloq_common_normal_learning( + instance->generic.serial, manufacture_code->key); + hop_encrypted = subghz_protocol_keeloq_common_encrypt(hop_decrypted, man); + break; + } + } + + uint64_t fix = (uint64_t)instance->generic.btn << 60 | + ((uint64_t)(instance->generic.serial & 0xFFFFFFF) << 32) | hop_encrypted; + + instance->generic.data = subghz_protocol_blocks_reverse_key(fix, 64); + //(instance->generic.seed & 0xFF) = 8 bit for grouping 8-16 + instance->generic.data_2 = + subghz_protocol_blocks_reverse_key((instance->generic.seed & 0xFF), 8); + + // Encode complete, now serialize + SubGhzProtocolStatus res = + subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data_2 >> (i * 8)) & 0xFF; + } + + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + res = SubGhzProtocolStatusErrorParserOthers; + } + + if((res == SubGhzProtocolStatusOk) && + !flipper_format_insert_or_update_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to add Data2"); + res = SubGhzProtocolStatusErrorParserOthers; + } + + return res == SubGhzProtocolStatusOk; +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderJarolift instance + * @return true On success + */ +static bool subghz_protocol_encoder_jarolift_get_upload( + SubGhzProtocolEncoderJarolift* instance, + uint8_t btn) { + furi_assert(instance); + + // Gen new key + if(!subghz_protocol_jarolift_gen_data(instance, btn)) { + return false; + } + + size_t index = 0; + + // Start 14k us delay + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_jarolift_const.te_long * 18); + + // First header bit + instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)1500); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_jarolift_const.te_short); + + // Finish header + for(uint8_t i = 8; i > 0; i--) { + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_jarolift_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_jarolift_const.te_short); + } + + // After header + instance->encoder.upload[index - 1].duration = (uint32_t)3800; // Adjust last low duration + + // Send key fix + for(uint8_t i = 64; i > 0; i--) { + if(bit_read(instance->generic.data, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_jarolift_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_jarolift_const.te_long); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_jarolift_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_jarolift_const.te_short); + } + } + + // Send grouping byte + for(uint8_t i = 8; i > 0; i--) { + if(bit_read(instance->generic.data_2, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_jarolift_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_jarolift_const.te_long); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_jarolift_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_jarolift_const.te_short); + } + } + + // Set upload size after generating upload, fix it later + instance->encoder.size_upload = index; + + return true; +} + +SubGhzProtocolStatus + subghz_protocol_encoder_jarolift_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderJarolift* instance = context; + SubGhzProtocolStatus res = SubGhzProtocolStatusError; + do { + if(SubGhzProtocolStatusOk != + subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + + uint8_t key_data[sizeof(uint64_t)] = {0}; + if(!flipper_format_read_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Missing Data"); + break; + } + + for(uint8_t i = 0; i < sizeof(uint64_t); i++) { + instance->generic.data_2 = instance->generic.data_2 << 8 | key_data[i]; + } + + subghz_protocol_jarolift_remote_controller(&instance->generic, instance->keystore); + + subghz_protocol_encoder_jarolift_get_upload(instance, instance->generic.btn); + + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data >> i * 8) & 0xFF; + } + if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to update Key"); + break; + } + + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data_2 >> i * 8) & 0xFF; + } + if(!flipper_format_update_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to update Data"); + break; + } + + instance->encoder.is_running = true; + + res = SubGhzProtocolStatusOk; + } while(false); + + return res; +} + +// +// Decoder +// +void* subghz_protocol_decoder_jarolift_alloc(SubGhzEnvironment* environment) { + SubGhzProtocolDecoderJarolift* instance = malloc(sizeof(SubGhzProtocolDecoderJarolift)); + instance->base.protocol = &subghz_protocol_jarolift; + instance->generic.protocol_name = instance->base.protocol->name; + instance->keystore = subghz_environment_get_keystore(environment); + return instance; +} + +void subghz_protocol_decoder_jarolift_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderJarolift* instance = context; + free(instance); +} + +void subghz_protocol_decoder_jarolift_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderJarolift* instance = context; + instance->decoder.parser_step = JaroliftDecoderStepReset; +} + +void subghz_protocol_decoder_jarolift_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderJarolift* instance = context; + + switch(instance->decoder.parser_step) { + case JaroliftDecoderStepReset: + if((level) && DURATION_DIFF(duration, subghz_protocol_jarolift_const.te_short) < + subghz_protocol_jarolift_const.te_delta) { + instance->decoder.parser_step = JaroliftDecoderStepCheckPreambula; + instance->header_count++; + } + break; + case JaroliftDecoderStepCheckPreambula: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_jarolift_const.te_short) < + subghz_protocol_jarolift_const.te_delta)) { + instance->decoder.parser_step = JaroliftDecoderStepReset; + break; + } + if((!level) && (instance->header_count == 8) && + (DURATION_DIFF(duration, subghz_protocol_jarolift_const.te_long * 5) < + subghz_protocol_jarolift_const.te_delta * 6)) { + // Found gap after header - 4000us +- 996us + instance->decoder.parser_step = JaroliftDecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + instance->header_count = 0; + break; + } else { + instance->decoder.parser_step = JaroliftDecoderStepReset; + instance->header_count = 0; + } + break; + case JaroliftDecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = JaroliftDecoderStepCheckDuration; + } else { + instance->header_count = 0; + instance->decoder.parser_step = JaroliftDecoderStepReset; + } + break; + case JaroliftDecoderStepCheckDuration: + if(!level) { + if(instance->decoder.decode_count_bit == 64) { + instance->generic.data = instance->decoder.decode_data; + instance->decoder.decode_data = 0; + } + if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_jarolift_const.te_short) < + subghz_protocol_jarolift_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_jarolift_const.te_long) < + subghz_protocol_jarolift_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = JaroliftDecoderStepSaveDuration; + } else if( + (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_jarolift_const.te_long) < + subghz_protocol_jarolift_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_jarolift_const.te_short) < + subghz_protocol_jarolift_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = JaroliftDecoderStepSaveDuration; + } else { + if(duration >= ((uint32_t)subghz_protocol_jarolift_const.te_long * 3)) { + // Add endbit + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_jarolift_const.te_long) < + subghz_protocol_jarolift_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + } else if((DURATION_DIFF( + instance->decoder.te_last, + subghz_protocol_jarolift_const.te_short) < + subghz_protocol_jarolift_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + } + if(instance->decoder.decode_count_bit == + subghz_protocol_jarolift_const.min_count_bit_for_found) { + instance->generic.data_2 = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + + instance->decoder.parser_step = JaroliftDecoderStepReset; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + instance->header_count = 0; + break; + } + instance->decoder.parser_step = JaroliftDecoderStepReset; + instance->header_count = 0; + } + } else { + instance->decoder.parser_step = JaroliftDecoderStepReset; + instance->header_count = 0; + } + break; + } +} + +/** + * Get button name. + * @param btn Button number, 4 bit + */ +static const char* subghz_protocol_jarolift_get_button_name(uint8_t btn) { + const char* btn_name; + switch(btn) { + case 0x1: + btn_name = "Learn"; + break; + case 0x2: + btn_name = "Down"; + break; + case 0x4: + btn_name = "Stop"; + break; + case 0x8: + btn_name = "Up"; + break; + default: + btn_name = "Unkn"; + break; + } + return btn_name; +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + * @param data Input encrypted data + * @param keystore Pointer to a SubGhzKeystore* instance + */ +static void subghz_protocol_jarolift_remote_controller( + SubGhzBlockGeneric* instance, + SubGhzKeystore* keystore) { + // Jarolift Decoder + // 01.2026 - @xMasterX (MMX) & d82k & Steffen (@bastelbudenbuben de) + + // Key samples (reversed) + // 0x821EB600EAC2EAD4 - Btn Up - cnt 0059 group 0100 + // 0x821EB6007D9BD66A - Btn Up - cnt 005A group 0100 + // 0x821EB600A029FA0E - Btn Up - cnt 005B group 0100 + + uint32_t group = subghz_protocol_blocks_reverse_key(instance->data_2, 8); + uint64_t key = subghz_protocol_blocks_reverse_key(instance->data, 64); + bool ret = false; + uint32_t decrypt = 0; + instance->serial = (key >> 32) & 0xFFFFFFF; + uint32_t hop = key & 0xFFFFFFFF; + + for + M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) { + if(manufacture_code->type == KEELOQ_LEARNING_NORMAL_JAROLIFT) { + uint64_t man = subghz_protocol_keeloq_common_normal_learning( + instance->serial, manufacture_code->key); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); + if(((decrypt >> 16) & 0xFF) == (instance->serial & 0xFF)) { + ret = true; + } + break; + } + } + if(ret) { + instance->btn = (key >> 60) & 0xF; + instance->seed = ((decrypt >> 24) << 8) | (group >> 8); + instance->cnt = decrypt & 0xFFFF; + // Save original button for later use + if(subghz_custom_btn_get_original() == 0) { + subghz_custom_btn_set_original(instance->btn); + } + subghz_custom_btn_set_max(3); + } else { + instance->btn = 0; + instance->serial = 0; + instance->cnt = 0; + instance->seed = 0; + } +} + +uint8_t subghz_protocol_decoder_jarolift_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderJarolift* instance = context; + uint8_t hash = 0; + uint8_t* p = (uint8_t*)&instance->generic.data; + for(size_t i = 0; i < 16; i++) { + hash ^= p[i]; + } + return hash; +} + +SubGhzProtocolStatus subghz_protocol_decoder_jarolift_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolDecoderJarolift* instance = context; + SubGhzProtocolStatus ret = + subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data_2 >> (i * 8)) & 0xFF; + } + + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + ret = SubGhzProtocolStatusErrorParserOthers; + } + + if((ret == SubGhzProtocolStatusOk) && + !flipper_format_insert_or_update_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to add Data"); + ret = SubGhzProtocolStatusErrorParserOthers; + } + return ret; +} + +SubGhzProtocolStatus + subghz_protocol_decoder_jarolift_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderJarolift* instance = context; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; + do { + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_jarolift_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { + break; + } + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + ret = SubGhzProtocolStatusErrorParserOthers; + break; + } + uint8_t key_data[sizeof(uint64_t)] = {0}; + if(!flipper_format_read_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Missing Data"); + ret = SubGhzProtocolStatusErrorParserOthers; + break; + } + + for(uint8_t i = 0; i < sizeof(uint64_t); i++) { + instance->generic.data_2 = instance->generic.data_2 << 8 | key_data[i]; + } + } while(false); + return ret; +} + +static uint8_t subghz_protocol_jarolift_get_btn_code(void) { + uint8_t custom_btn_id = subghz_custom_btn_get(); + uint8_t original_btn_code = subghz_custom_btn_get_original(); + uint8_t btn = original_btn_code; + + // Set custom button + if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) { + // Restore original button code + btn = original_btn_code; + } else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) { + switch(original_btn_code) { + case 0x1: + btn = 0x2; + break; + case 0x2: + btn = 0x1; + break; + case 0x4: + btn = 0x1; + break; + case 0x8: + btn = 0x1; + break; + + default: + break; + } + } else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) { + switch(original_btn_code) { + case 0x1: + btn = 0x4; + break; + case 0x2: + btn = 0x4; + break; + case 0x4: + btn = 0x2; + break; + case 0x8: + btn = 0x4; + break; + + default: + break; + } + } else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_LEFT) { + switch(original_btn_code) { + case 0x1: + btn = 0x8; + break; + case 0x2: + btn = 0x8; + break; + case 0x4: + btn = 0x8; + break; + case 0x8: + btn = 0x2; + break; + + default: + break; + } + } + + return btn; +} + +void subghz_protocol_decoder_jarolift_get_string(void* context, FuriString* output) { + furi_assert(context); + SubGhzProtocolDecoderJarolift* instance = context; + subghz_protocol_jarolift_remote_controller(&instance->generic, instance->keystore); + + // push protocol data to global variable + subghz_block_generic_global.cnt_is_available = true; + subghz_block_generic_global.cnt_length_bit = 16; + subghz_block_generic_global.current_cnt = instance->generic.cnt; + + furi_string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%0llX\r\n" + "Sn:%07lX Btn:%01X - %s\r\n" + "Cnt:%04lX Group:%04lX\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + instance->generic.data, + instance->generic.serial, + instance->generic.btn, + subghz_protocol_jarolift_get_button_name(instance->generic.btn), + instance->generic.cnt, + instance->generic.seed); +} diff --git a/lib/subghz/protocols/jarolift.h b/lib/subghz/protocols/jarolift.h new file mode 100644 index 000000000..0f666579e --- /dev/null +++ b/lib/subghz/protocols/jarolift.h @@ -0,0 +1,108 @@ +#pragma once +#include "base.h" + +#define SUBGHZ_PROTOCOL_JAROLIFT_NAME "Jarolift" + +typedef struct SubGhzProtocolDecoderJarolift SubGhzProtocolDecoderJarolift; +typedef struct SubGhzProtocolEncoderJarolift SubGhzProtocolEncoderJarolift; + +extern const SubGhzProtocolDecoder subghz_protocol_jarolift_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_jarolift_encoder; +extern const SubGhzProtocol subghz_protocol_jarolift; + +/** + * Allocate SubGhzProtocolEncoderJarolift. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderJarolift* pointer to a SubGhzProtocolEncoderJarolift instance + */ +void* subghz_protocol_encoder_jarolift_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderJarolift. + * @param context Pointer to a SubGhzProtocolEncoderJarolift instance + */ +void subghz_protocol_encoder_jarolift_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderJarolift instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +SubGhzProtocolStatus + subghz_protocol_encoder_jarolift_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderJarolift instance + */ +void subghz_protocol_encoder_jarolift_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderJarolift instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_jarolift_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderJarolift. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderJarolift* pointer to a SubGhzProtocolDecoderJarolift instance + */ +void* subghz_protocol_decoder_jarolift_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderJarolift. + * @param context Pointer to a SubGhzProtocolDecoderJarolift instance + */ +void subghz_protocol_decoder_jarolift_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderJarolift. + * @param context Pointer to a SubGhzProtocolDecoderJarolift instance + */ +void subghz_protocol_decoder_jarolift_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderJarolift instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_jarolift_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderJarolift instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_jarolift_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderJarolift. + * @param context Pointer to a SubGhzProtocolDecoderJarolift instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return status + */ +SubGhzProtocolStatus subghz_protocol_decoder_jarolift_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data SubGhzProtocolDecoderJarolift. + * @param context Pointer to a SubGhzProtocolDecoderJarolift instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return status + */ +SubGhzProtocolStatus + subghz_protocol_decoder_jarolift_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderJarolift instance + * @param output Resulting text + */ +void subghz_protocol_decoder_jarolift_get_string(void* context, FuriString* output); diff --git a/lib/subghz/protocols/keeloq_common.h b/lib/subghz/protocols/keeloq_common.h index 90c5ef6d7..1250cd2fc 100644 --- a/lib/subghz/protocols/keeloq_common.h +++ b/lib/subghz/protocols/keeloq_common.h @@ -26,6 +26,8 @@ #define KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_2 7u #define KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_3 8u // #define BENINCA_ARC_KEY_TYPE 9u -- RESERVED +#define KEELOQ_LEARNING_SIMPLE_KINGGATES 10u +#define KEELOQ_LEARNING_NORMAL_JAROLIFT 11u /** * Simple Learning Encrypt diff --git a/lib/subghz/protocols/kinggates_stylo_4k.c b/lib/subghz/protocols/kinggates_stylo_4k.c index e23042b55..9d7313559 100644 --- a/lib/subghz/protocols/kinggates_stylo_4k.c +++ b/lib/subghz/protocols/kinggates_stylo_4k.c @@ -187,7 +187,7 @@ static bool subghz_protocol_kinggates_stylo_4k_gen_data( uint64_t encrypt = 0; for M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { - if(strcmp(furi_string_get_cstr(manufacture_code->name), "Kingates_Stylo4k") == 0) { + if(manufacture_code->type == KEELOQ_LEARNING_SIMPLE_KINGGATES) { // Simple Learning encrypt = subghz_protocol_keeloq_common_encrypt(hop, manufacture_code->key); encrypt = subghz_protocol_blocks_reverse_key(encrypt, 32); @@ -220,7 +220,7 @@ bool subghz_protocol_kinggates_stylo_4k_create_data( uint64_t encrypt = 0; for M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { - if(strcmp(furi_string_get_cstr(manufacture_code->name), "Kingates_Stylo4k") == 0) { + if(manufacture_code->type == KEELOQ_LEARNING_SIMPLE_KINGGATES) { // Simple Learning encrypt = subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key); encrypt = subghz_protocol_blocks_reverse_key(encrypt, 32); @@ -456,7 +456,6 @@ void subghz_protocol_decoder_kinggates_stylo_4k_feed(void* context, bool level, subghz_protocol_kinggates_stylo_4k_const.te_delta * 2) { instance->decoder.parser_step = KingGates_stylo_4kDecoderStepSaveDuration; instance->decoder.decode_data = 0; - instance->generic.data_2 = 0; instance->decoder.decode_count_bit = 0; instance->header_count = 0; } @@ -476,7 +475,6 @@ void subghz_protocol_decoder_kinggates_stylo_4k_feed(void* context, bool level, instance->decoder.parser_step = KingGates_stylo_4kDecoderStepReset; instance->decoder.decode_data = 0; - instance->generic.data_2 = 0; instance->decoder.decode_count_bit = 0; instance->header_count = 0; break; @@ -561,7 +559,7 @@ static void subghz_protocol_kinggates_stylo_4k_remote_controller( for M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) { - if(manufacture_code->type == KEELOQ_LEARNING_SIMPLE) { + if(manufacture_code->type == KEELOQ_LEARNING_SIMPLE_KINGGATES) { decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); if(((decrypt >> 28) == instance->btn) && (((decrypt >> 24) & 0x0F) == 0x0C) && (((decrypt >> 16) & 0xFF) == (instance->serial & 0xFF))) { diff --git a/lib/subghz/protocols/protocol_items.c b/lib/subghz/protocols/protocol_items.c index 2c4054dd2..14d54b8d3 100644 --- a/lib/subghz/protocols/protocol_items.c +++ b/lib/subghz/protocols/protocol_items.c @@ -27,7 +27,7 @@ const SubGhzProtocol* const subghz_protocol_registry_items[] = { &subghz_protocol_hay21, &subghz_protocol_revers_rb2, &subghz_protocol_feron, &subghz_protocol_roger, &subghz_protocol_elplast, &subghz_protocol_treadmill37, - &subghz_protocol_beninca_arc, + &subghz_protocol_beninca_arc, &subghz_protocol_jarolift, }; const SubGhzProtocolRegistry subghz_protocol_registry = { diff --git a/lib/subghz/protocols/protocol_items.h b/lib/subghz/protocols/protocol_items.h index f61e71420..2c36260ed 100644 --- a/lib/subghz/protocols/protocol_items.h +++ b/lib/subghz/protocols/protocol_items.h @@ -55,3 +55,4 @@ #include "elplast.h" #include "treadmill37.h" #include "beninca_arc.h" +#include "jarolift.h" diff --git a/lib/subghz/protocols/public_api.h b/lib/subghz/protocols/public_api.h index 30b8212ce..7539352dc 100644 --- a/lib/subghz/protocols/public_api.h +++ b/lib/subghz/protocols/public_api.h @@ -231,6 +231,24 @@ bool subghz_protocol_beninca_arc_create_data( uint32_t cnt, SubGhzRadioPreset* preset); +/** + * Key generation from simple data. + * @param context Pointer to a SubGhzProtocolEncoderJarolift instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param serial Serial number, 24 bit + * @param btn Button number, 8 bit + * @param cnt Counter value, 16 bit + * @param preset Modulation, SubGhzRadioPreset + * @return true On success + */ +bool subghz_protocol_jarolift_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + SubGhzRadioPreset* preset); + typedef struct SubGhzProtocolDecoderBinRAW SubGhzProtocolDecoderBinRAW; void subghz_protocol_decoder_bin_raw_data_input_rssi( diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 7e6190628..1ad9bc413 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -3725,6 +3725,7 @@ Function,+,subghz_protocol_encoder_raw_free,void,void* Function,+,subghz_protocol_encoder_raw_stop,void,void* Function,+,subghz_protocol_encoder_raw_yield,LevelDuration,void* Function,+,subghz_protocol_faac_slh_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint32_t, uint32_t, const char*, SubGhzRadioPreset*" +Function,+,subghz_protocol_jarolift_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*" Function,+,subghz_protocol_keeloq_bft_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, uint32_t, const char*, SubGhzRadioPreset*" Function,+,subghz_protocol_keeloq_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, const char*, SubGhzRadioPreset*" Function,+,subghz_protocol_kinggates_stylo_4k_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*" From a8d5743cf64c3026a29c0b517c78f2feb14dc653 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 26 Jan 2026 12:05:03 +0300 Subject: [PATCH 071/160] upd changelog --- CHANGELOG.md | 3 +++ documentation/SubGHzSupportedSystems.md | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5993e7c3..8a6bc797f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ * SubGHz: **Cardin S449 protocol full support** (64bit keeloq) (with Add manually, and all button codes) (**use FSK12K modulation to read the remote**) (closes issues #735 #908) (by @xMasterX and @zero-mega (thanks!)) * SubGHz: **Beninca ARC AES128 protocol full support** (128bit dynamic) (with Add manually, and 3 button codes) (resolves issue #596) (by @xMasterX and @zero-mega) * SubGHz: **Treadmill37 protocol support** (37bit static) (by @xMasterX) +* SubGHz: **Jarolift protocol full support** (72bit dynamic) (with Add manually, and all button codes) (by @xMasterX & d82k & Steffen (bastelbudenbuben de)) * SubGHz: **New modulation FSK with 12KHz deviation** * SubGHz: **KingGates Stylo 4k - Add manually and button switch support** + refactoring of encoder * SubGHz: **Stilmatic - button 9 support** (two buttons hold simulation) (mapped on arrow keys) @@ -20,6 +21,8 @@ * UI: Various small changes * OFW PR 4333: NFC: Fix sending 32+ byte ISO 15693-3 commands (by @WillyJL) * NFC: Fix LED not blinking at SLIX unlock (closes issue #945) +* SubGHz: Fix Alutech AT4N false positives +* SubGHz: Cleanup of extra local variables * SubGHz: Replaced Cars ignore option with Revers RB2 protocol ignore option * SubGHz: Moved Starline, ScherKhan, Kia decoders into external app * SubGHz: Possible Sommer timings fix diff --git a/documentation/SubGHzSupportedSystems.md b/documentation/SubGHzSupportedSystems.md index 65e96225b..0cfcb8881 100644 --- a/documentation/SubGHzSupportedSystems.md +++ b/documentation/SubGHzSupportedSystems.md @@ -64,9 +64,10 @@ That list is only for default SubGHz app, apps like *Weather Station* have their - Legrand `AM650` (18 bits, Static) - Doorbells - Somfy Telis `433.92MHz` `AM650` (56 bits, Dynamic) - Feron `433.92MHz` `AM650` (32 bits, Static) - RGB LED remotes, other. -- Honeywell `AM650` (64 bits, Dynamic) - Alarm, Sensor -- Honeywell WDB `AM650` (48 bits, Dynamic) - Doorbell +- Honeywell `AM650` (64 bits, Static) - Alarm, Sensor +- Honeywell WDB `AM650` (48 bits, Static) - Doorbell - Magellan `433.92MHz` `AM650` (32 bits, Static) - Sensor, alarm +- Jarolift `433.92MHz` `AM650` (72 bits, Dynamic, KeeLoq based) - Automatic roller shutters ### Alarms - Hollarm `433.92MHz` `AM650` (42 bits, Static) - Bike alarms From d47bc0232635fd3b2d09225f1960037e8dd53f18 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Mon, 26 Jan 2026 16:15:22 +0700 Subject: [PATCH 072/160] Return protocols Repeat option (used by external apps) --- lib/subghz/protocols/alutech_at_4n.c | 5 ++++- lib/subghz/protocols/ansonic.c | 6 +++++- lib/subghz/protocols/beninca_arc.c | 5 ++++- lib/subghz/protocols/bett.c | 6 +++++- lib/subghz/protocols/bin_raw.c | 6 +++++- lib/subghz/protocols/came.c | 6 +++++- lib/subghz/protocols/came_atomo.c | 5 ++++- lib/subghz/protocols/came_twee.c | 6 +++++- lib/subghz/protocols/chamberlain_code.c | 6 +++++- lib/subghz/protocols/clemsa.c | 6 +++++- lib/subghz/protocols/dickert_mahs.c | 6 +++++- lib/subghz/protocols/doitrand.c | 6 +++++- lib/subghz/protocols/dooya.c | 6 +++++- lib/subghz/protocols/elplast.c | 6 +++++- lib/subghz/protocols/faac_slh.c | 5 ++++- lib/subghz/protocols/feron.c | 6 +++++- lib/subghz/protocols/gangqi.c | 6 +++++- lib/subghz/protocols/gate_tx.c | 6 +++++- lib/subghz/protocols/hay21.c | 6 +++++- lib/subghz/protocols/hollarm.c | 6 +++++- lib/subghz/protocols/holtek.c | 6 +++++- lib/subghz/protocols/holtek_ht12x.c | 6 +++++- lib/subghz/protocols/honeywell.c | 5 ++++- lib/subghz/protocols/honeywell_wdb.c | 6 +++++- lib/subghz/protocols/hormann.c | 6 +++++- lib/subghz/protocols/intertechno_v3.c | 6 +++++- lib/subghz/protocols/keeloq.c | 5 ++++- lib/subghz/protocols/kinggates_stylo_4k.c | 5 ++++- lib/subghz/protocols/legrand.c | 1 + lib/subghz/protocols/linear.c | 6 +++++- lib/subghz/protocols/linear_delta3.c | 6 +++++- lib/subghz/protocols/magellan.c | 6 +++++- lib/subghz/protocols/marantec.c | 6 +++++- lib/subghz/protocols/marantec24.c | 6 +++++- lib/subghz/protocols/mastercode.c | 6 +++++- lib/subghz/protocols/megacode.c | 6 +++++- lib/subghz/protocols/nero_radio.c | 6 +++++- lib/subghz/protocols/nero_sketch.c | 6 +++++- lib/subghz/protocols/nice_flo.c | 6 +++++- lib/subghz/protocols/nice_flor_s.c | 6 +++++- lib/subghz/protocols/phoenix_v2.c | 6 +++++- lib/subghz/protocols/power_smart.c | 6 +++++- lib/subghz/protocols/revers_rb2.c | 6 +++++- lib/subghz/protocols/roger.c | 6 +++++- lib/subghz/protocols/secplus_v1.c | 6 +++++- lib/subghz/protocols/secplus_v2.c | 7 ++++++- lib/subghz/protocols/smc5326.c | 6 +++++- lib/subghz/protocols/somfy_keytis.c | 5 ++++- lib/subghz/protocols/somfy_telis.c | 5 ++++- lib/subghz/protocols/treadmill37.c | 6 +++++- 50 files changed, 238 insertions(+), 49 deletions(-) diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 421a57b6a..71c8c4fb4 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -482,7 +482,10 @@ SubGhzProtocolStatus subghz_protocol_encoder_alutech_at_4n_deserialize( break; } - + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); break; diff --git a/lib/subghz/protocols/ansonic.c b/lib/subghz/protocols/ansonic.c index 7ad0732d6..176ebe0bc 100644 --- a/lib/subghz/protocols/ansonic.c +++ b/lib/subghz/protocols/ansonic.c @@ -150,7 +150,11 @@ SubGhzProtocolStatus FURI_LOG_E(TAG, "Deserialize error"); break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_ansonic_get_upload(instance)) { res = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/beninca_arc.c b/lib/subghz/protocols/beninca_arc.c index 210b8e0ad..1c2eb471e 100644 --- a/lib/subghz/protocols/beninca_arc.c +++ b/lib/subghz/protocols/beninca_arc.c @@ -412,7 +412,10 @@ SubGhzProtocolStatus break; } - + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); break; diff --git a/lib/subghz/protocols/bett.c b/lib/subghz/protocols/bett.c index 173671aaa..277d75bd0 100644 --- a/lib/subghz/protocols/bett.c +++ b/lib/subghz/protocols/bett.c @@ -169,7 +169,11 @@ SubGhzProtocolStatus FURI_LOG_E(TAG, "Deserialize error"); break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_bett_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/bin_raw.c b/lib/subghz/protocols/bin_raw.c index 4753d467c..8feb403ac 100644 --- a/lib/subghz/protocols/bin_raw.c +++ b/lib/subghz/protocols/bin_raw.c @@ -309,7 +309,11 @@ SubGhzProtocolStatus res = SubGhzProtocolStatusErrorParserOthers; break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_bin_raw_get_upload(instance)) { res = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/came.c b/lib/subghz/protocols/came.c index 5037f1a4b..7be07a476 100644 --- a/lib/subghz/protocols/came.c +++ b/lib/subghz/protocols/came.c @@ -181,7 +181,11 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorValueBitCount; break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_came_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/came_atomo.c b/lib/subghz/protocols/came_atomo.c index 60d1e93a5..c2f1afe9c 100644 --- a/lib/subghz/protocols/came_atomo.c +++ b/lib/subghz/protocols/came_atomo.c @@ -374,7 +374,10 @@ SubGhzProtocolStatus break; } - + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); break; diff --git a/lib/subghz/protocols/came_twee.c b/lib/subghz/protocols/came_twee.c index c2af278ea..1eb28d94f 100644 --- a/lib/subghz/protocols/came_twee.c +++ b/lib/subghz/protocols/came_twee.c @@ -254,7 +254,11 @@ SubGhzProtocolStatus if(res != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_came_twee_remote_controller(&instance->generic); subghz_protocol_encoder_came_twee_get_upload(instance); instance->encoder.front = 0; // reset position before start diff --git a/lib/subghz/protocols/chamberlain_code.c b/lib/subghz/protocols/chamberlain_code.c index d01c80c2e..61ef7747b 100644 --- a/lib/subghz/protocols/chamberlain_code.c +++ b/lib/subghz/protocols/chamberlain_code.c @@ -223,7 +223,11 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorValueBitCount; break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_chamb_code_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/clemsa.c b/lib/subghz/protocols/clemsa.c index fecbd4dfd..3d3ebe3d9 100644 --- a/lib/subghz/protocols/clemsa.c +++ b/lib/subghz/protocols/clemsa.c @@ -168,7 +168,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_clemsa_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/dickert_mahs.c b/lib/subghz/protocols/dickert_mahs.c index ac00fd28a..f5d710c79 100644 --- a/lib/subghz/protocols/dickert_mahs.c +++ b/lib/subghz/protocols/dickert_mahs.c @@ -207,7 +207,11 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorValueBitCount; break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_dickert_mahs_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/doitrand.c b/lib/subghz/protocols/doitrand.c index ab700f5ad..158f53169 100644 --- a/lib/subghz/protocols/doitrand.c +++ b/lib/subghz/protocols/doitrand.c @@ -149,7 +149,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_doitrand_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/dooya.c b/lib/subghz/protocols/dooya.c index 76d2bac60..b290da8e1 100644 --- a/lib/subghz/protocols/dooya.c +++ b/lib/subghz/protocols/dooya.c @@ -159,7 +159,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_dooya_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/elplast.c b/lib/subghz/protocols/elplast.c index a9bd29562..f95c937db 100644 --- a/lib/subghz/protocols/elplast.c +++ b/lib/subghz/protocols/elplast.c @@ -141,7 +141,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_encoder_elplast_get_upload(instance); instance->encoder.is_running = true; } while(false); diff --git a/lib/subghz/protocols/faac_slh.c b/lib/subghz/protocols/faac_slh.c index d0cfc721c..03e61d6f2 100644 --- a/lib/subghz/protocols/faac_slh.c +++ b/lib/subghz/protocols/faac_slh.c @@ -398,7 +398,10 @@ SubGhzProtocolStatus subghz_protocol_faac_slh_check_remote_controller( &instance->generic, instance->keystore, &instance->manufacture_name); - + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_encoder_faac_slh_get_upload(instance); if(!flipper_format_rewind(flipper_format)) { diff --git a/lib/subghz/protocols/feron.c b/lib/subghz/protocols/feron.c index f7d653f4c..d02258f04 100644 --- a/lib/subghz/protocols/feron.c +++ b/lib/subghz/protocols/feron.c @@ -160,7 +160,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_feron_check_remote_controller(&instance->generic); subghz_protocol_encoder_feron_get_upload(instance); instance->encoder.is_running = true; diff --git a/lib/subghz/protocols/gangqi.c b/lib/subghz/protocols/gangqi.c index f78b37aac..0cdb442d5 100644 --- a/lib/subghz/protocols/gangqi.c +++ b/lib/subghz/protocols/gangqi.c @@ -253,7 +253,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_gangqi_remote_controller(&instance->generic); subghz_protocol_encoder_gangqi_get_upload(instance); diff --git a/lib/subghz/protocols/gate_tx.c b/lib/subghz/protocols/gate_tx.c index 08f6f3f41..8572edd58 100644 --- a/lib/subghz/protocols/gate_tx.c +++ b/lib/subghz/protocols/gate_tx.c @@ -142,7 +142,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_gate_tx_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/hay21.c b/lib/subghz/protocols/hay21.c index 8a0280168..701e98659 100644 --- a/lib/subghz/protocols/hay21.c +++ b/lib/subghz/protocols/hay21.c @@ -267,7 +267,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_hay21_remote_controller(&instance->generic); subghz_protocol_encoder_hay21_get_upload(instance); diff --git a/lib/subghz/protocols/hollarm.c b/lib/subghz/protocols/hollarm.c index b03de5b72..da0dc97e1 100644 --- a/lib/subghz/protocols/hollarm.c +++ b/lib/subghz/protocols/hollarm.c @@ -254,7 +254,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_hollarm_remote_controller(&instance->generic); subghz_protocol_encoder_hollarm_get_upload(instance); diff --git a/lib/subghz/protocols/holtek.c b/lib/subghz/protocols/holtek.c index 2735702c5..4afe25070 100644 --- a/lib/subghz/protocols/holtek.c +++ b/lib/subghz/protocols/holtek.c @@ -155,7 +155,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_holtek_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/holtek_ht12x.c b/lib/subghz/protocols/holtek_ht12x.c index bf4724130..595237a1f 100644 --- a/lib/subghz/protocols/holtek_ht12x.c +++ b/lib/subghz/protocols/holtek_ht12x.c @@ -170,7 +170,11 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorParserTe; break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_holtek_th12x_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/honeywell.c b/lib/subghz/protocols/honeywell.c index 7343648d7..d8ce0d8eb 100644 --- a/lib/subghz/protocols/honeywell.c +++ b/lib/subghz/protocols/honeywell.c @@ -211,7 +211,10 @@ SubGhzProtocolStatus break; } - + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_encoder_honeywell_get_upload(instance); if(!flipper_format_rewind(flipper_format)) { diff --git a/lib/subghz/protocols/honeywell_wdb.c b/lib/subghz/protocols/honeywell_wdb.c index 0a2cd53d6..96f5f5e7f 100644 --- a/lib/subghz/protocols/honeywell_wdb.c +++ b/lib/subghz/protocols/honeywell_wdb.c @@ -156,7 +156,11 @@ SubGhzProtocolStatus subghz_protocol_encoder_honeywell_wdb_deserialize( if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_honeywell_wdb_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/hormann.c b/lib/subghz/protocols/hormann.c index 1ac9f6b0d..0d75c0c5f 100644 --- a/lib/subghz/protocols/hormann.c +++ b/lib/subghz/protocols/hormann.c @@ -153,7 +153,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_hormann_get_upload(instance)) { instance->encoder.front = 0; // reset position before start ret = SubGhzProtocolStatusErrorEncoderGetUpload; diff --git a/lib/subghz/protocols/intertechno_v3.c b/lib/subghz/protocols/intertechno_v3.c index 85818763b..7b9bfbf1a 100644 --- a/lib/subghz/protocols/intertechno_v3.c +++ b/lib/subghz/protocols/intertechno_v3.c @@ -176,7 +176,11 @@ SubGhzProtocolStatus subghz_protocol_encoder_intertechno_v3_deserialize( ret = SubGhzProtocolStatusErrorValueBitCount; break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_intertechno_v3_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 39f957e24..d5a8a9aa7 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -667,7 +667,10 @@ SubGhzProtocolStatus subghz_protocol_keeloq_check_remote_controller( &instance->generic, instance->keystore, &instance->manufacture_name); - + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_keeloq_get_upload(instance, instance->generic.btn)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/kinggates_stylo_4k.c b/lib/subghz/protocols/kinggates_stylo_4k.c index e6e9d6d38..6b8d0e428 100644 --- a/lib/subghz/protocols/kinggates_stylo_4k.c +++ b/lib/subghz/protocols/kinggates_stylo_4k.c @@ -344,7 +344,10 @@ SubGhzProtocolStatus subghz_protocol_encoder_kinggates_stylo_4k_deserialize( break; } - + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); break; diff --git a/lib/subghz/protocols/legrand.c b/lib/subghz/protocols/legrand.c index 94a45694c..45a46847c 100644 --- a/lib/subghz/protocols/legrand.c +++ b/lib/subghz/protocols/legrand.c @@ -155,6 +155,7 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorParserTe; break; } + // optional parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/linear.c b/lib/subghz/protocols/linear.c index e170c90ee..61a21ec05 100644 --- a/lib/subghz/protocols/linear.c +++ b/lib/subghz/protocols/linear.c @@ -160,7 +160,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_linear_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/linear_delta3.c b/lib/subghz/protocols/linear_delta3.c index b9b28c66a..515fc43a6 100644 --- a/lib/subghz/protocols/linear_delta3.c +++ b/lib/subghz/protocols/linear_delta3.c @@ -164,7 +164,11 @@ SubGhzProtocolStatus subghz_protocol_encoder_linear_delta3_deserialize( if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_linear_delta3_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/magellan.c b/lib/subghz/protocols/magellan.c index ef0c9d2ae..5fc003ab4 100644 --- a/lib/subghz/protocols/magellan.c +++ b/lib/subghz/protocols/magellan.c @@ -164,7 +164,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_magellan_get_upload(instance)) { instance->encoder.front = 0; // reset before start ret = SubGhzProtocolStatusErrorEncoderGetUpload; diff --git a/lib/subghz/protocols/marantec.c b/lib/subghz/protocols/marantec.c index 02d6aa801..d70c4eed2 100644 --- a/lib/subghz/protocols/marantec.c +++ b/lib/subghz/protocols/marantec.c @@ -213,7 +213,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_marantec_remote_controller(&instance->generic); subghz_protocol_encoder_marantec_get_upload(instance); instance->encoder.front = 0; diff --git a/lib/subghz/protocols/marantec24.c b/lib/subghz/protocols/marantec24.c index 63d8e7be2..fbd16ecbb 100644 --- a/lib/subghz/protocols/marantec24.c +++ b/lib/subghz/protocols/marantec24.c @@ -155,7 +155,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_marantec24_check_remote_controller(&instance->generic); subghz_protocol_encoder_marantec24_get_upload(instance); instance->encoder.is_running = true; diff --git a/lib/subghz/protocols/mastercode.c b/lib/subghz/protocols/mastercode.c index 5a57d764e..b0b7f789d 100644 --- a/lib/subghz/protocols/mastercode.c +++ b/lib/subghz/protocols/mastercode.c @@ -168,7 +168,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_mastercode_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/megacode.c b/lib/subghz/protocols/megacode.c index 13cc99436..22e57c364 100644 --- a/lib/subghz/protocols/megacode.c +++ b/lib/subghz/protocols/megacode.c @@ -188,7 +188,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_megacode_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/nero_radio.c b/lib/subghz/protocols/nero_radio.c index 18fdfffa8..d5c284693 100644 --- a/lib/subghz/protocols/nero_radio.c +++ b/lib/subghz/protocols/nero_radio.c @@ -180,7 +180,11 @@ SubGhzProtocolStatus break; } } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_nero_radio_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/nero_sketch.c b/lib/subghz/protocols/nero_sketch.c index 0550cf801..02682f4f1 100644 --- a/lib/subghz/protocols/nero_sketch.c +++ b/lib/subghz/protocols/nero_sketch.c @@ -161,7 +161,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_nero_sketch_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/nice_flo.c b/lib/subghz/protocols/nice_flo.c index dc423fe83..b47de0079 100644 --- a/lib/subghz/protocols/nice_flo.c +++ b/lib/subghz/protocols/nice_flo.c @@ -147,7 +147,11 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorValueBitCount; break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_nice_flo_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index 59cf4d2cc..67755c79f 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -279,7 +279,11 @@ SubGhzProtocolStatus break; } - // flipper_format_read_uint32( + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + // flipper_format_read_uint32( // flipper_format, "Data", (uint32_t*)&instance->generic.data_2, 1); if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); diff --git a/lib/subghz/protocols/phoenix_v2.c b/lib/subghz/protocols/phoenix_v2.c index c70b4cb00..9b97137f9 100644 --- a/lib/subghz/protocols/phoenix_v2.c +++ b/lib/subghz/protocols/phoenix_v2.c @@ -322,7 +322,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_phoenix_v2_check_remote_controller(&instance->generic); if(!subghz_protocol_encoder_phoenix_v2_get_upload(instance)) { diff --git a/lib/subghz/protocols/power_smart.c b/lib/subghz/protocols/power_smart.c index ed237780e..714232561 100644 --- a/lib/subghz/protocols/power_smart.c +++ b/lib/subghz/protocols/power_smart.c @@ -206,7 +206,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_power_smart_remote_controller(&instance->generic); subghz_protocol_encoder_power_smart_get_upload(instance); instance->encoder.front = 0; // reset before start diff --git a/lib/subghz/protocols/revers_rb2.c b/lib/subghz/protocols/revers_rb2.c index 2e9aee592..5e4ca97e8 100644 --- a/lib/subghz/protocols/revers_rb2.c +++ b/lib/subghz/protocols/revers_rb2.c @@ -176,7 +176,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_revers_rb2_remote_controller(&instance->generic); subghz_protocol_encoder_revers_rb2_get_upload(instance); instance->encoder.is_running = true; diff --git a/lib/subghz/protocols/roger.c b/lib/subghz/protocols/roger.c index 30767db82..62178981c 100644 --- a/lib/subghz/protocols/roger.c +++ b/lib/subghz/protocols/roger.c @@ -265,7 +265,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_roger_check_remote_controller(&instance->generic); subghz_protocol_encoder_roger_get_upload(instance); diff --git a/lib/subghz/protocols/secplus_v1.c b/lib/subghz/protocols/secplus_v1.c index 460ff766e..3d820b318 100644 --- a/lib/subghz/protocols/secplus_v1.c +++ b/lib/subghz/protocols/secplus_v1.c @@ -298,7 +298,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_secplus_v1_encode(instance)) { ret = SubGhzProtocolStatusErrorParserOthers; break; diff --git a/lib/subghz/protocols/secplus_v2.c b/lib/subghz/protocols/secplus_v2.c index bcbf3183a..902422148 100644 --- a/lib/subghz/protocols/secplus_v2.c +++ b/lib/subghz/protocols/secplus_v2.c @@ -574,7 +574,12 @@ SubGhzProtocolStatus subghz_protocol_secplus_v2_remote_controller( &instance->generic, instance->secplus_packet_1); subghz_protocol_secplus_v2_encode(instance); - subghz_protocol_encoder_secplus_v2_get_upload(instance); + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_encoder_secplus_v2_get_upload(instance); //update data for(size_t i = 0; i < sizeof(uint64_t); i++) { diff --git a/lib/subghz/protocols/smc5326.c b/lib/subghz/protocols/smc5326.c index bf006e146..201fcd9d7 100644 --- a/lib/subghz/protocols/smc5326.c +++ b/lib/subghz/protocols/smc5326.c @@ -178,7 +178,11 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorParserTe; break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!subghz_protocol_encoder_smc5326_get_upload(instance)) { ret = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/somfy_keytis.c b/lib/subghz/protocols/somfy_keytis.c index c462035c6..04dba4736 100644 --- a/lib/subghz/protocols/somfy_keytis.c +++ b/lib/subghz/protocols/somfy_keytis.c @@ -412,7 +412,10 @@ SubGhzProtocolStatus break; } - + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_encoder_somfy_keytis_get_upload(instance, instance->generic.btn); if(!flipper_format_rewind(flipper_format)) { diff --git a/lib/subghz/protocols/somfy_telis.c b/lib/subghz/protocols/somfy_telis.c index a4b756daa..4d4b128f1 100644 --- a/lib/subghz/protocols/somfy_telis.c +++ b/lib/subghz/protocols/somfy_telis.c @@ -341,7 +341,10 @@ SubGhzProtocolStatus break; } - + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_encoder_somfy_telis_get_upload(instance, instance->generic.btn); if(!flipper_format_rewind(flipper_format)) { diff --git a/lib/subghz/protocols/treadmill37.c b/lib/subghz/protocols/treadmill37.c index 9784fe1e3..8a7badb94 100644 --- a/lib/subghz/protocols/treadmill37.c +++ b/lib/subghz/protocols/treadmill37.c @@ -151,7 +151,11 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - + + // Optional value + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_treadmill37_check_remote_controller(&instance->generic); subghz_protocol_encoder_treadmill37_get_upload(instance); instance->encoder.is_running = true; From 14abc959cf0fb86d9a2904a5028e3196ff80fe31 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Mon, 26 Jan 2026 16:30:32 +0700 Subject: [PATCH 073/160] start working with subghz button editor --- .../scenes/subghz_scene_signal_settings.c | 40 ++++++++++++++++++- lib/subghz/blocks/generic.h | 5 +++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/applications/main/subghz/scenes/subghz_scene_signal_settings.c b/applications/main/subghz/scenes/subghz_scene_signal_settings.c index e74219a28..548516683 100644 --- a/applications/main/subghz/scenes/subghz_scene_signal_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_signal_settings.c @@ -14,6 +14,7 @@ static uint16_t counter16 = 0x0; static uint8_t byte_count = 0; static uint8_t* byte_ptr = NULL; static FuriString* byte_input_text; +static uint8_t button = 0x0; #define COUNTER_MODE_COUNT 7 static const char* const counter_mode_text[COUNTER_MODE_COUNT] = { @@ -74,6 +75,23 @@ void subghz_scene_signal_settings_variable_item_list_enter_callback(void* contex ByteInput* byte_input = subghz->byte_input; byte_input_set_header_text(byte_input, furi_string_get_cstr(byte_input_text)); + byte_input_set_result_callback( + byte_input, + subghz_scene_signal_settings_byte_input_callback, + NULL, + subghz, + byte_ptr, + byte_count); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); + } + // when we click OK on "Edit button" item + if(index == 2) { + furi_string_cat_str(byte_input_text, " button number in HEX"); + + // Setup byte_input view + ByteInput* byte_input = subghz->byte_input; + byte_input_set_header_text(byte_input, furi_string_get_cstr(byte_input_text)); + byte_input_set_result_callback( byte_input, subghz_scene_signal_settings_byte_input_callback, @@ -130,9 +148,10 @@ void subghz_scene_signal_settings_on_enter(void* context) { flipper_format_free(fff_data_file); furi_record_close(RECORD_STORAGE); - // ### Counter edit section ### byte_input_text = furi_string_alloc_set_str("Enter "); bool counter_not_available = true; + bool button_not_available = true; + SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(subghz->txrx); // deserialaze and decode loaded sugbhz file and push data to subghz_block_generic_global variable @@ -143,6 +162,8 @@ void subghz_scene_signal_settings_on_enter(void* context) { FURI_LOG_E(TAG, "Cant deserialize this subghz file"); } + // ### Counter edit section ### + if(!subghz_block_generic_global.cnt_is_available) { counter_mode = 0xff; FURI_LOG_D(TAG, "Counter mode and edit not available for this protocol"); @@ -166,6 +187,18 @@ void subghz_scene_signal_settings_on_enter(void* context) { } } + // ### Button edit section ### + + if(!subghz_block_generic_global.btn_is_available) { + FURI_LOG_D(TAG, "Button edit not available for this protocol"); + } else { + button_not_available = false; + button = subghz_block_generic_global.current_btn; + furi_string_printf(tmp_text, "%X", button); + byte_ptr = (uint8_t*)&button; + byte_count = 1; + } + furi_assert(byte_ptr); furi_assert(byte_count > 0); @@ -196,6 +229,11 @@ void subghz_scene_signal_settings_on_enter(void* context) { variable_item_set_current_value_text(item, furi_string_get_cstr(tmp_text)); variable_item_set_locked(item, (counter_not_available), "Not available\nfor this\nprotocol !"); + item = variable_item_list_add(variable_item_list, "Edit Button", 1, NULL, subghz); + variable_item_set_current_value_index(item, 0); + variable_item_set_current_value_text(item, furi_string_get_cstr(tmp_text)); + variable_item_set_locked(item, (button_not_available), "Not available\nfor this\nprotocol !"); + furi_string_free(tmp_text); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); diff --git a/lib/subghz/blocks/generic.h b/lib/subghz/blocks/generic.h index 1e72c5a5e..d3f7804dc 100644 --- a/lib/subghz/blocks/generic.h +++ b/lib/subghz/blocks/generic.h @@ -35,6 +35,11 @@ struct SubGhzBlockGenericGlobal { bool cnt_need_override; // flag for protocols to override signals counter inside of protocols uint8_t cnt_length_bit; // counter length in bytes (used in counter editor giu) bool cnt_is_available; // is there counter available for protocol (used in counter editor giu) + + uint8_t current_btn; // global counter value; + uint8_t new_btn; // global counter value; + bool btn_need_override; // flag for protocols to override signals counter inside of protocols + bool btn_is_available; // is there counter available for protocol (used in counter editor giu) }; extern SubGhzBlockGenericGlobal subghz_block_generic_global; //global structure for subghz From eb91b7a974f2ee6930635dfae6bbc67996d6ee1f Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Mon, 26 Jan 2026 16:41:57 +0700 Subject: [PATCH 074/160] Protocols repeat correction --- lib/subghz/protocols/alutech_at_4n.c | 2 +- lib/subghz/protocols/beninca_arc.c | 2 +- lib/subghz/protocols/bin_raw.c | 2 +- lib/subghz/protocols/came_atomo.c | 2 +- lib/subghz/protocols/hormann.c | 2 +- lib/subghz/protocols/jarolift.c | 2 +- lib/subghz/protocols/power_smart.c | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 71c8c4fb4..21ad71f01 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -94,7 +94,7 @@ void* subghz_protocol_encoder_alutech_at_4n_alloc(SubGhzEnvironment* environment instance->base.protocol = &subghz_protocol_alutech_at_4n; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 2; + instance->encoder.repeat = 3; instance->encoder.size_upload = 512; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; diff --git a/lib/subghz/protocols/beninca_arc.c b/lib/subghz/protocols/beninca_arc.c index 1c2eb471e..786de5fa8 100644 --- a/lib/subghz/protocols/beninca_arc.c +++ b/lib/subghz/protocols/beninca_arc.c @@ -256,7 +256,7 @@ void* subghz_protocol_encoder_beninca_arc_alloc(SubGhzEnvironment* environment) instance->generic.protocol_name = instance->base.protocol->name; instance->keystore = subghz_environment_get_keystore(environment); - instance->encoder.repeat = 2; + instance->encoder.repeat = 1; instance->encoder.size_upload = 800; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; diff --git a/lib/subghz/protocols/bin_raw.c b/lib/subghz/protocols/bin_raw.c index 8feb403ac..9ac339d79 100644 --- a/lib/subghz/protocols/bin_raw.c +++ b/lib/subghz/protocols/bin_raw.c @@ -142,7 +142,7 @@ void* subghz_protocol_encoder_bin_raw_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_bin_raw; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 2; + instance->encoder.repeat = 3; instance->encoder.size_upload = BIN_RAW_BUF_DATA_SIZE * 5; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->data = malloc(instance->encoder.size_upload * sizeof(uint8_t)); diff --git a/lib/subghz/protocols/came_atomo.c b/lib/subghz/protocols/came_atomo.c index c2f1afe9c..748d15af5 100644 --- a/lib/subghz/protocols/came_atomo.c +++ b/lib/subghz/protocols/came_atomo.c @@ -89,7 +89,7 @@ void* subghz_protocol_encoder_came_atomo_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_came_atomo; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 2; + instance->encoder.repeat = 1; instance->encoder.size_upload = 900; //actual size 766+ instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; diff --git a/lib/subghz/protocols/hormann.c b/lib/subghz/protocols/hormann.c index 0d75c0c5f..250ab4f62 100644 --- a/lib/subghz/protocols/hormann.c +++ b/lib/subghz/protocols/hormann.c @@ -80,7 +80,7 @@ void* subghz_protocol_encoder_hormann_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_hormann; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 2; + instance->encoder.repeat = 3; instance->encoder.size_upload = 2048; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; diff --git a/lib/subghz/protocols/jarolift.c b/lib/subghz/protocols/jarolift.c index 9881b9892..81eca4fde 100644 --- a/lib/subghz/protocols/jarolift.c +++ b/lib/subghz/protocols/jarolift.c @@ -100,7 +100,7 @@ void* subghz_protocol_encoder_jarolift_alloc(SubGhzEnvironment* environment) { instance->generic.protocol_name = instance->base.protocol->name; instance->keystore = subghz_environment_get_keystore(environment); - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; diff --git a/lib/subghz/protocols/power_smart.c b/lib/subghz/protocols/power_smart.c index 714232561..1e8f7098c 100644 --- a/lib/subghz/protocols/power_smart.c +++ b/lib/subghz/protocols/power_smart.c @@ -85,7 +85,7 @@ void* subghz_protocol_encoder_power_smart_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_power_smart; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 2; + instance->encoder.repeat = 3; instance->encoder.size_upload = 1024; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; From 7fa5624c509789adb2ad83a608537710ee68837a Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 26 Jan 2026 12:45:57 +0300 Subject: [PATCH 075/160] Revert "start working with subghz button editor" This reverts commit 14abc959cf0fb86d9a2904a5028e3196ff80fe31. --- .../scenes/subghz_scene_signal_settings.c | 40 +------------------ lib/subghz/blocks/generic.h | 5 --- 2 files changed, 1 insertion(+), 44 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_signal_settings.c b/applications/main/subghz/scenes/subghz_scene_signal_settings.c index 548516683..e74219a28 100644 --- a/applications/main/subghz/scenes/subghz_scene_signal_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_signal_settings.c @@ -14,7 +14,6 @@ static uint16_t counter16 = 0x0; static uint8_t byte_count = 0; static uint8_t* byte_ptr = NULL; static FuriString* byte_input_text; -static uint8_t button = 0x0; #define COUNTER_MODE_COUNT 7 static const char* const counter_mode_text[COUNTER_MODE_COUNT] = { @@ -75,23 +74,6 @@ void subghz_scene_signal_settings_variable_item_list_enter_callback(void* contex ByteInput* byte_input = subghz->byte_input; byte_input_set_header_text(byte_input, furi_string_get_cstr(byte_input_text)); - byte_input_set_result_callback( - byte_input, - subghz_scene_signal_settings_byte_input_callback, - NULL, - subghz, - byte_ptr, - byte_count); - view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); - } - // when we click OK on "Edit button" item - if(index == 2) { - furi_string_cat_str(byte_input_text, " button number in HEX"); - - // Setup byte_input view - ByteInput* byte_input = subghz->byte_input; - byte_input_set_header_text(byte_input, furi_string_get_cstr(byte_input_text)); - byte_input_set_result_callback( byte_input, subghz_scene_signal_settings_byte_input_callback, @@ -148,10 +130,9 @@ void subghz_scene_signal_settings_on_enter(void* context) { flipper_format_free(fff_data_file); furi_record_close(RECORD_STORAGE); + // ### Counter edit section ### byte_input_text = furi_string_alloc_set_str("Enter "); bool counter_not_available = true; - bool button_not_available = true; - SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(subghz->txrx); // deserialaze and decode loaded sugbhz file and push data to subghz_block_generic_global variable @@ -162,8 +143,6 @@ void subghz_scene_signal_settings_on_enter(void* context) { FURI_LOG_E(TAG, "Cant deserialize this subghz file"); } - // ### Counter edit section ### - if(!subghz_block_generic_global.cnt_is_available) { counter_mode = 0xff; FURI_LOG_D(TAG, "Counter mode and edit not available for this protocol"); @@ -187,18 +166,6 @@ void subghz_scene_signal_settings_on_enter(void* context) { } } - // ### Button edit section ### - - if(!subghz_block_generic_global.btn_is_available) { - FURI_LOG_D(TAG, "Button edit not available for this protocol"); - } else { - button_not_available = false; - button = subghz_block_generic_global.current_btn; - furi_string_printf(tmp_text, "%X", button); - byte_ptr = (uint8_t*)&button; - byte_count = 1; - } - furi_assert(byte_ptr); furi_assert(byte_count > 0); @@ -229,11 +196,6 @@ void subghz_scene_signal_settings_on_enter(void* context) { variable_item_set_current_value_text(item, furi_string_get_cstr(tmp_text)); variable_item_set_locked(item, (counter_not_available), "Not available\nfor this\nprotocol !"); - item = variable_item_list_add(variable_item_list, "Edit Button", 1, NULL, subghz); - variable_item_set_current_value_index(item, 0); - variable_item_set_current_value_text(item, furi_string_get_cstr(tmp_text)); - variable_item_set_locked(item, (button_not_available), "Not available\nfor this\nprotocol !"); - furi_string_free(tmp_text); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); diff --git a/lib/subghz/blocks/generic.h b/lib/subghz/blocks/generic.h index d3f7804dc..1e72c5a5e 100644 --- a/lib/subghz/blocks/generic.h +++ b/lib/subghz/blocks/generic.h @@ -35,11 +35,6 @@ struct SubGhzBlockGenericGlobal { bool cnt_need_override; // flag for protocols to override signals counter inside of protocols uint8_t cnt_length_bit; // counter length in bytes (used in counter editor giu) bool cnt_is_available; // is there counter available for protocol (used in counter editor giu) - - uint8_t current_btn; // global counter value; - uint8_t new_btn; // global counter value; - bool btn_need_override; // flag for protocols to override signals counter inside of protocols - bool btn_is_available; // is there counter available for protocol (used in counter editor giu) }; extern SubGhzBlockGenericGlobal subghz_block_generic_global; //global structure for subghz From 5564fe1f314f5f0cdf7069b579b6033bae5c1407 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 26 Jan 2026 12:46:30 +0300 Subject: [PATCH 076/160] fmt --- applications/drivers/subghz/cc1101_ext/cc1101_ext.c | 6 +++--- lib/subghz/protocols/legrand.c | 2 +- targets/f7/furi_hal/furi_hal_subghz.c | 12 ++++++++---- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/applications/drivers/subghz/cc1101_ext/cc1101_ext.c b/applications/drivers/subghz/cc1101_ext/cc1101_ext.c index adcf785f2..e24ed8f7a 100644 --- a/applications/drivers/subghz/cc1101_ext/cc1101_ext.c +++ b/applications/drivers/subghz/cc1101_ext/cc1101_ext.c @@ -807,7 +807,7 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb // Configure DMA to update timer TIM17 ARR by durations from buffer LL_DMA_SetMemoryAddress( SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t)subghz_device_cc1101_ext->async_tx.buffer); - LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t)&(TIM17->ARR)); + LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t) & (TIM17->ARR)); LL_DMA_ConfigTransfer( SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | @@ -849,7 +849,7 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb LL_DMA_SetMemoryAddress( SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, (uint32_t)subghz_device_cc1101_ext->async_tx.gpio_tx_buff); - LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, (uint32_t)&(gpio->port->BSRR)); + LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, (uint32_t) & (gpio->port->BSRR)); LL_DMA_ConfigTransfer( SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | @@ -869,7 +869,7 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, (uint32_t)subghz_device_cc1101_ext->async_tx.debug_gpio_buff); LL_DMA_SetPeriphAddress( - SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, (uint32_t)&(gpio->port->BSRR)); + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, (uint32_t) & (gpio->port->BSRR)); LL_DMA_ConfigTransfer( SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | diff --git a/lib/subghz/protocols/legrand.c b/lib/subghz/protocols/legrand.c index 45a46847c..7b8b70204 100644 --- a/lib/subghz/protocols/legrand.c +++ b/lib/subghz/protocols/legrand.c @@ -155,7 +155,7 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorParserTe; break; } - + // optional parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/targets/f7/furi_hal/furi_hal_subghz.c b/targets/f7/furi_hal/furi_hal_subghz.c index 0f8fa939c..b9723487e 100644 --- a/targets/f7/furi_hal/furi_hal_subghz.c +++ b/targets/f7/furi_hal/furi_hal_subghz.c @@ -684,7 +684,7 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { while(samples > 0) { volatile uint32_t duration = furi_hal_subghz_async_tx_middleware_get_duration( &furi_hal_subghz_async_tx.middleware, furi_hal_subghz_async_tx.callback); - // if duration == 0 then we stop DMA interrupt(that used to refill buffer) and write to buffer 0 as last element. + // if duration == 0 then we stop DMA interrupt(that used to refill buffer) and write to buffer 0 as last element. // later DMA write this 0 to ARR and timer TIM2 will be stopped. if(duration == 0) { *buffer = 0; @@ -771,7 +771,7 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* // Configure DMA to update TIM2->ARR LL_DMA_InitTypeDef dma_config = {0}; // DMA settings structure - dma_config.PeriphOrM2MSrcAddress = (uint32_t)&(TIM2->ARR); // DMA destination TIM2->ARR + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); // DMA destination TIM2->ARR dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_async_tx.buffer; // DMA buffer with signals durations dma_config.Direction = @@ -838,7 +838,7 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* furi_hal_subghz_debug_gpio_buff[1] = (uint32_t)gpio->pin << GPIO_NUMBER; dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_debug_gpio_buff; - dma_config.PeriphOrM2MSrcAddress = (uint32_t)&(gpio->port->BSRR); + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->BSRR); dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; dma_config.Mode = LL_DMA_MODE_CIRCULAR; dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; @@ -867,7 +867,11 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* bool furi_hal_subghz_is_async_tx_complete(void) { return (furi_hal_subghz.state == SubGhzStateAsyncTx) && (LL_TIM_GetAutoReload(TIM2) == 0); - FURI_LOG_I(TAG, "SubGhzStateAsyncTx %d , TIM2-ARR %ld",furi_hal_subghz.state,LL_TIM_GetAutoReload(TIM2)); + FURI_LOG_I( + TAG, + "SubGhzStateAsyncTx %d , TIM2-ARR %ld", + furi_hal_subghz.state, + LL_TIM_GetAutoReload(TIM2)); } void furi_hal_subghz_stop_async_tx(void) { From 5c7e48cf2f1e46580be55d278f80b4f0b2a3971f Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Mon, 26 Jan 2026 16:56:26 +0700 Subject: [PATCH 077/160] Remove Debug log --- targets/f7/furi_hal/furi_hal_subghz.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/targets/f7/furi_hal/furi_hal_subghz.c b/targets/f7/furi_hal/furi_hal_subghz.c index b9723487e..ece8dde2c 100644 --- a/targets/f7/furi_hal/furi_hal_subghz.c +++ b/targets/f7/furi_hal/furi_hal_subghz.c @@ -867,11 +867,6 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* bool furi_hal_subghz_is_async_tx_complete(void) { return (furi_hal_subghz.state == SubGhzStateAsyncTx) && (LL_TIM_GetAutoReload(TIM2) == 0); - FURI_LOG_I( - TAG, - "SubGhzStateAsyncTx %d , TIM2-ARR %ld", - furi_hal_subghz.state, - LL_TIM_GetAutoReload(TIM2)); } void furi_hal_subghz_stop_async_tx(void) { From 6789686e3f17f1cde950a13dbd55cea4d3a5cb16 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 26 Jan 2026 13:08:22 +0300 Subject: [PATCH 078/160] upd changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a6bc797f..edc777ae4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * SubGHz: **Beninca ARC AES128 protocol full support** (128bit dynamic) (with Add manually, and 3 button codes) (resolves issue #596) (by @xMasterX and @zero-mega) * SubGHz: **Treadmill37 protocol support** (37bit static) (by @xMasterX) * SubGHz: **Jarolift protocol full support** (72bit dynamic) (with Add manually, and all button codes) (by @xMasterX & d82k & Steffen (bastelbudenbuben de)) +* SubGHz: **Change key SEND action** (This changes solve problem when user press and release OK button too fast and signal was not fully sent) (PR #949 | by @Dmitry422) * SubGHz: **New modulation FSK with 12KHz deviation** * SubGHz: **KingGates Stylo 4k - Add manually and button switch support** + refactoring of encoder * SubGHz: **Stilmatic - button 9 support** (two buttons hold simulation) (mapped on arrow keys) From dfb17ab4288d1e316b7346b40c748dbdcd45b4a5 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 26 Jan 2026 14:14:06 +0300 Subject: [PATCH 079/160] Revert "Merge pull request #949 from Dmitry422/dev" This reverts commit ae1abd61393a7e46ee1c7d9c4f35c6dbc4c128eb, reversing changes made to a8d5743cf64c3026a29c0b517c78f2feb14dc653. --- .../drivers/subghz/cc1101_ext/cc1101_ext.c | 11 +-- .../main/subghz/helpers/subghz_txrx.c | 5 ++ .../scenes/subghz_scene_receiver_info.c | 65 +--------------- .../subghz/scenes/subghz_scene_transmitter.c | 54 +------------ lib/subghz/protocols/alutech_at_4n.c | 2 +- lib/subghz/protocols/ansonic.c | 1 - lib/subghz/protocols/beninca_arc.c | 2 +- lib/subghz/protocols/bett.c | 1 - lib/subghz/protocols/bin_raw.c | 3 +- lib/subghz/protocols/came.c | 3 +- lib/subghz/protocols/came_atomo.c | 2 +- lib/subghz/protocols/came_twee.c | 3 +- lib/subghz/protocols/chamberlain_code.c | 1 - lib/subghz/protocols/clemsa.c | 1 - lib/subghz/protocols/dickert_mahs.c | 3 +- lib/subghz/protocols/doitrand.c | 3 +- lib/subghz/protocols/dooya.c | 3 +- lib/subghz/protocols/elplast.c | 3 +- lib/subghz/protocols/faac_slh.c | 2 +- lib/subghz/protocols/feron.c | 3 +- lib/subghz/protocols/gangqi.c | 3 +- lib/subghz/protocols/gate_tx.c | 1 - lib/subghz/protocols/hay21.c | 3 +- lib/subghz/protocols/hollarm.c | 3 +- lib/subghz/protocols/holtek.c | 3 +- lib/subghz/protocols/holtek_ht12x.c | 3 +- lib/subghz/protocols/honeywell.c | 2 +- lib/subghz/protocols/honeywell_wdb.c | 3 +- lib/subghz/protocols/hormann.c | 5 +- lib/subghz/protocols/intertechno_v3.c | 3 +- lib/subghz/protocols/jarolift.c | 2 +- lib/subghz/protocols/keeloq.c | 2 +- lib/subghz/protocols/kinggates_stylo_4k.c | 2 +- lib/subghz/protocols/legrand.c | 1 - lib/subghz/protocols/linear.c | 1 - lib/subghz/protocols/linear_delta3.c | 1 - lib/subghz/protocols/magellan.c | 3 +- lib/subghz/protocols/marantec.c | 3 +- lib/subghz/protocols/marantec24.c | 3 +- lib/subghz/protocols/mastercode.c | 1 - lib/subghz/protocols/megacode.c | 1 - lib/subghz/protocols/nero_radio.c | 3 +- lib/subghz/protocols/nero_sketch.c | 3 +- lib/subghz/protocols/nice_flo.c | 1 - lib/subghz/protocols/nice_flor_s.c | 3 +- lib/subghz/protocols/phoenix_v2.c | 3 +- lib/subghz/protocols/power_smart.c | 3 +- lib/subghz/protocols/revers_rb2.c | 3 +- lib/subghz/protocols/roger.c | 3 +- lib/subghz/protocols/secplus_v1.c | 3 +- lib/subghz/protocols/secplus_v2.c | 4 +- lib/subghz/protocols/smc5326.c | 3 +- lib/subghz/protocols/somfy_keytis.c | 2 +- lib/subghz/protocols/somfy_telis.c | 2 +- lib/subghz/protocols/treadmill37.c | 3 +- targets/f7/furi_hal/furi_hal_subghz.c | 78 +++++++------------ 56 files changed, 81 insertions(+), 256 deletions(-) diff --git a/applications/drivers/subghz/cc1101_ext/cc1101_ext.c b/applications/drivers/subghz/cc1101_ext/cc1101_ext.c index e24ed8f7a..abca098eb 100644 --- a/applications/drivers/subghz/cc1101_ext/cc1101_ext.c +++ b/applications/drivers/subghz/cc1101_ext/cc1101_ext.c @@ -794,17 +794,12 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb subghz_device_cc1101_ext->async_tx.buffer = malloc(SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t)); - // here we do the same things as in /unleashed-firmware/targets/f7/furi_hal/furi_hal_subghz.c - // use first DMA to update timer TIM17 durations, but TIM17 have not output chanel - // so we use second DMA to transfer data from gpio_tx_buff directly to gpio pin using BSSR. - // BSSR allow us tranfer data directly to pin in gpio port. - //Signal generation with mem-to-mem DMA furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false); furi_hal_gpio_init( subghz_device_cc1101_ext->g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); - // Configure DMA to update timer TIM17 ARR by durations from buffer + // Configure DMA update timer LL_DMA_SetMemoryAddress( SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t)subghz_device_cc1101_ext->async_tx.buffer); LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t) & (TIM17->ARR)); @@ -826,7 +821,7 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb furi_hal_bus_enable(FuriHalBusTIM17); - // Configure TIM 17 + // Configure TIM // Set the timer resolution to 2 us LL_TIM_SetCounterMode(TIM17, LL_TIM_COUNTERMODE_UP); LL_TIM_SetClockDivision(TIM17, LL_TIM_CLOCKDIVISION_DIV1); @@ -840,7 +835,7 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb subghz_device_cc1101_ext_async_tx_refill( subghz_device_cc1101_ext->async_tx.buffer, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL); - // Configure DMA to transfer data from gpio_tx_buff directly to gpio pin using BSSR + // Configure tx gpio dma const GpioPin* gpio = subghz_device_cc1101_ext->g0_pin; subghz_device_cc1101_ext->async_tx.gpio_tx_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER; diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index ca3f0b300..8abf373f4 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -234,6 +234,7 @@ SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* SubGhzTxRxStartTxState ret = SubGhzTxRxStartTxStateErrorParserOthers; FuriString* temp_str = furi_string_alloc(); + uint32_t repeat = 200; do { if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); @@ -243,6 +244,10 @@ SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* FURI_LOG_E(TAG, "Missing Protocol"); break; } + if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { + FURI_LOG_E(TAG, "Unable Repeat"); + break; + } ret = SubGhzTxRxStartTxStateOk; SubGhzRadioPreset* preset = instance->preset; diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 26b4d4600..e68b0203d 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -2,12 +2,8 @@ #include -#include "applications/main/subghz/helpers/subghz_txrx_i.h" - #define TAG "SubGhzSceneReceiverInfo" -static bool tx_stop_called = false; - void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, void* context) { furi_assert(context); SubGhz* subghz = context; @@ -142,17 +138,8 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) return true; } else if(event.event == SubGhzCustomEventSceneReceiverInfoTxStop) { //CC1101 Stop Tx -> Start RX - - // if we recieve event to stop tranmission (user release OK button) but - // hardware TX still working now then set flag to stop it after hardware TX will be realy ended - // else stop TX correctly and start RX - if(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { - tx_stop_called = true; - return true; - } subghz->state_notifications = SubGhzNotificationStateIDLE; - //update screen data widget_reset(subghz->widget); subghz_scene_receiver_info_draw_widget(subghz); @@ -192,57 +179,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) } switch(subghz->state_notifications) { case SubGhzNotificationStateTx: - // if hardware TX still working at this time so we just blink led and do nothing - if(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { - notification_message(subghz->notifications, &sequence_blink_magenta_10); - return true; - } - // if hardware TX not working now and tx_stop_called = true - // (mean user release OK button early than hardware TX was ended) then we stop TX - if(tx_stop_called) { - tx_stop_called = false; - subghz->state_notifications = SubGhzNotificationStateIDLE; - - //update screen data - widget_reset(subghz->widget); - subghz_scene_receiver_info_draw_widget(subghz); - - subghz_txrx_stop(subghz->txrx); - - // Start RX - if(!scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneDecodeRAW)) { - subghz_txrx_rx_start(subghz->txrx); - - subghz_txrx_hopper_unpause(subghz->txrx); - if(!subghz_history_get_text_space_left(subghz->history, NULL)) { - subghz->state_notifications = SubGhzNotificationStateRx; - } - } - return true; - } else { - // if current state == SubGhzNotificationStateTx but hardware TX was ended - // and user still not release OK button then we repeat TX - - subghz->state_notifications = SubGhzNotificationStateIDLE; - - //update screen data - widget_reset(subghz->widget); - subghz_scene_receiver_info_draw_widget(subghz); - - //CC1101 Stop RX -> Start TX - subghz_txrx_hopper_pause(subghz->txrx); - if(!subghz_tx_start( - subghz, - subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen))) { - subghz_txrx_rx_start(subghz->txrx); - subghz_txrx_hopper_unpause(subghz->txrx); - subghz->state_notifications = SubGhzNotificationStateRx; - } else { - subghz->state_notifications = SubGhzNotificationStateTx; - } - - return true; - } + notification_message(subghz->notifications, &sequence_blink_magenta_10); break; case SubGhzNotificationStateRx: notification_message(subghz->notifications, &sequence_blink_cyan_10); diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index bfb974417..ebd69059f 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -3,14 +3,9 @@ #include #include -#include - -#include "applications/main/subghz/helpers/subghz_txrx_i.h" #define TAG "SubGhzSceneTransmitter" -static bool tx_stop_called = false; - void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) { furi_assert(context); SubGhz* subghz = context; @@ -71,7 +66,6 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventViewTransmitterSendStart) { - // if we recieve event to start transmission (user press OK button) then start/restart TX subghz->state_notifications = SubGhzNotificationStateIDLE; if(subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { @@ -81,13 +75,6 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { } return true; } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) { - // if we recieve event to stop tranmission (user release OK button) but - // hardware TX still working now then set flag to stop it after hardware TX will be realy ended - if(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { - tx_stop_called = true; - return true; - } - // if hardware TX not working now so just stop TX correctly subghz->state_notifications = SubGhzNotificationStateIDLE; subghz_txrx_stop(subghz->txrx); if(subghz_custom_btn_get() != SUBGHZ_CUSTOM_BTN_OK) { @@ -105,10 +92,6 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { } return true; } else if(event.event == SubGhzCustomEventViewTransmitterBack) { - // if user press back button then force stop TX if they was active - if(subghz->state_notifications == SubGhzNotificationStateTx) { - subghz_txrx_stop(subghz->txrx); - } subghz->state_notifications = SubGhzNotificationStateIDLE; scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); @@ -119,42 +102,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { } } else if(event.type == SceneManagerEventTypeTick) { if(subghz->state_notifications == SubGhzNotificationStateTx) { - // if hardware TX still working at this time so we just blink led and do nothing - if(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { - notification_message(subghz->notifications, &sequence_blink_magenta_10); - return true; - } - // if hardware TX not working now and tx_stop_called = true - // (mean user release OK button early than hardware TX was ended) then we stop TX - if(tx_stop_called) { - tx_stop_called = false; - subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz_txrx_stop(subghz->txrx); - if(subghz_custom_btn_get() != SUBGHZ_CUSTOM_BTN_OK) { - subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); - int32_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); - furi_hal_subghz_set_rolling_counter_mult(0); - // Calling restore! - subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); - subghz_txrx_stop(subghz->txrx); - // Calling restore 2nd time special for FAAC SLH! - // TODO: Find better way to restore after custom button is used!!! - subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); - subghz_txrx_stop(subghz->txrx); - furi_hal_subghz_set_rolling_counter_mult(tmp_counter); - } - return true; - } else { - // if current state == SubGhzNotificationStateTx but hardware TX was ended - // and user still not release OK button then we repeat transmission - subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { - subghz->state_notifications = SubGhzNotificationStateTx; - subghz_scene_transmitter_update_data_show(subghz); - dolphin_deed(DolphinDeedSubGhzSend); - } - return true; - } + notification_message(subghz->notifications, &sequence_blink_magenta_10); } return true; } diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 21ad71f01..687a1e930 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -94,7 +94,7 @@ void* subghz_protocol_encoder_alutech_at_4n_alloc(SubGhzEnvironment* environment instance->base.protocol = &subghz_protocol_alutech_at_4n; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 512; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; diff --git a/lib/subghz/protocols/ansonic.c b/lib/subghz/protocols/ansonic.c index 176ebe0bc..75f803370 100644 --- a/lib/subghz/protocols/ansonic.c +++ b/lib/subghz/protocols/ansonic.c @@ -150,7 +150,6 @@ SubGhzProtocolStatus FURI_LOG_E(TAG, "Deserialize error"); break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/beninca_arc.c b/lib/subghz/protocols/beninca_arc.c index 786de5fa8..83db66306 100644 --- a/lib/subghz/protocols/beninca_arc.c +++ b/lib/subghz/protocols/beninca_arc.c @@ -256,7 +256,7 @@ void* subghz_protocol_encoder_beninca_arc_alloc(SubGhzEnvironment* environment) instance->generic.protocol_name = instance->base.protocol->name; instance->keystore = subghz_environment_get_keystore(environment); - instance->encoder.repeat = 1; + instance->encoder.repeat = 10; instance->encoder.size_upload = 800; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; diff --git a/lib/subghz/protocols/bett.c b/lib/subghz/protocols/bett.c index 277d75bd0..44946a2f6 100644 --- a/lib/subghz/protocols/bett.c +++ b/lib/subghz/protocols/bett.c @@ -169,7 +169,6 @@ SubGhzProtocolStatus FURI_LOG_E(TAG, "Deserialize error"); break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/bin_raw.c b/lib/subghz/protocols/bin_raw.c index 9ac339d79..ca52cdd49 100644 --- a/lib/subghz/protocols/bin_raw.c +++ b/lib/subghz/protocols/bin_raw.c @@ -142,7 +142,7 @@ void* subghz_protocol_encoder_bin_raw_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_bin_raw; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = BIN_RAW_BUF_DATA_SIZE * 5; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->data = malloc(instance->encoder.size_upload * sizeof(uint8_t)); @@ -309,7 +309,6 @@ SubGhzProtocolStatus res = SubGhzProtocolStatusErrorParserOthers; break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/came.c b/lib/subghz/protocols/came.c index 7be07a476..2762a2484 100644 --- a/lib/subghz/protocols/came.c +++ b/lib/subghz/protocols/came.c @@ -90,7 +90,7 @@ void* subghz_protocol_encoder_came_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_came; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 5; + instance->encoder.repeat = 10; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -181,7 +181,6 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorValueBitCount; break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/came_atomo.c b/lib/subghz/protocols/came_atomo.c index 748d15af5..f8ec7baa0 100644 --- a/lib/subghz/protocols/came_atomo.c +++ b/lib/subghz/protocols/came_atomo.c @@ -89,7 +89,7 @@ void* subghz_protocol_encoder_came_atomo_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_came_atomo; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 1; + instance->encoder.repeat = 10; instance->encoder.size_upload = 900; //actual size 766+ instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; diff --git a/lib/subghz/protocols/came_twee.c b/lib/subghz/protocols/came_twee.c index 1eb28d94f..3bb909dc8 100644 --- a/lib/subghz/protocols/came_twee.c +++ b/lib/subghz/protocols/came_twee.c @@ -109,7 +109,7 @@ void* subghz_protocol_encoder_came_twee_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_came_twee; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 1; + instance->encoder.repeat = 10; instance->encoder.size_upload = 1536; //max upload 92*14 = 1288 !!!! instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -254,7 +254,6 @@ SubGhzProtocolStatus if(res != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/chamberlain_code.c b/lib/subghz/protocols/chamberlain_code.c index 61ef7747b..fda224bb6 100644 --- a/lib/subghz/protocols/chamberlain_code.c +++ b/lib/subghz/protocols/chamberlain_code.c @@ -223,7 +223,6 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorValueBitCount; break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/clemsa.c b/lib/subghz/protocols/clemsa.c index 3d3ebe3d9..672abcba3 100644 --- a/lib/subghz/protocols/clemsa.c +++ b/lib/subghz/protocols/clemsa.c @@ -168,7 +168,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/dickert_mahs.c b/lib/subghz/protocols/dickert_mahs.c index f5d710c79..65be6fd0c 100644 --- a/lib/subghz/protocols/dickert_mahs.c +++ b/lib/subghz/protocols/dickert_mahs.c @@ -132,7 +132,7 @@ void* subghz_protocol_encoder_dickert_mahs_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_dickert_mahs; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 5; + instance->encoder.repeat = 10; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -207,7 +207,6 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorValueBitCount; break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/doitrand.c b/lib/subghz/protocols/doitrand.c index 158f53169..7c7946042 100644 --- a/lib/subghz/protocols/doitrand.c +++ b/lib/subghz/protocols/doitrand.c @@ -82,7 +82,7 @@ void* subghz_protocol_encoder_doitrand_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_doitrand; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 5; + instance->encoder.repeat = 10; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -149,7 +149,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/dooya.c b/lib/subghz/protocols/dooya.c index b290da8e1..fd8645a0b 100644 --- a/lib/subghz/protocols/dooya.c +++ b/lib/subghz/protocols/dooya.c @@ -77,7 +77,7 @@ void* subghz_protocol_encoder_dooya_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_dooya; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 5; + instance->encoder.repeat = 10; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -159,7 +159,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/elplast.c b/lib/subghz/protocols/elplast.c index f95c937db..18d6d07b4 100644 --- a/lib/subghz/protocols/elplast.c +++ b/lib/subghz/protocols/elplast.c @@ -73,7 +73,7 @@ void* subghz_protocol_encoder_elplast_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_elplast; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -141,7 +141,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/faac_slh.c b/lib/subghz/protocols/faac_slh.c index 03e61d6f2..147e452eb 100644 --- a/lib/subghz/protocols/faac_slh.c +++ b/lib/subghz/protocols/faac_slh.c @@ -109,7 +109,7 @@ void* subghz_protocol_encoder_faac_slh_alloc(SubGhzEnvironment* environment) { instance->generic.protocol_name = instance->base.protocol->name; instance->keystore = subghz_environment_get_keystore(environment); - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; diff --git a/lib/subghz/protocols/feron.c b/lib/subghz/protocols/feron.c index d02258f04..9591a4ebb 100644 --- a/lib/subghz/protocols/feron.c +++ b/lib/subghz/protocols/feron.c @@ -74,7 +74,7 @@ void* subghz_protocol_encoder_feron_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_feron; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -160,7 +160,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/gangqi.c b/lib/subghz/protocols/gangqi.c index 0cdb442d5..6b5542410 100644 --- a/lib/subghz/protocols/gangqi.c +++ b/lib/subghz/protocols/gangqi.c @@ -76,7 +76,7 @@ void* subghz_protocol_encoder_gangqi_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_gangqi; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -253,7 +253,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/gate_tx.c b/lib/subghz/protocols/gate_tx.c index 8572edd58..608567626 100644 --- a/lib/subghz/protocols/gate_tx.c +++ b/lib/subghz/protocols/gate_tx.c @@ -142,7 +142,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/hay21.c b/lib/subghz/protocols/hay21.c index 701e98659..ba6119dae 100644 --- a/lib/subghz/protocols/hay21.c +++ b/lib/subghz/protocols/hay21.c @@ -75,7 +75,7 @@ void* subghz_protocol_encoder_hay21_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_hay21; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -267,7 +267,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/hollarm.c b/lib/subghz/protocols/hollarm.c index da0dc97e1..9b2a53a05 100644 --- a/lib/subghz/protocols/hollarm.c +++ b/lib/subghz/protocols/hollarm.c @@ -76,7 +76,7 @@ void* subghz_protocol_encoder_hollarm_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_hollarm; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -254,7 +254,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/holtek.c b/lib/subghz/protocols/holtek.c index 4afe25070..7ed5fc152 100644 --- a/lib/subghz/protocols/holtek.c +++ b/lib/subghz/protocols/holtek.c @@ -86,7 +86,7 @@ void* subghz_protocol_encoder_holtek_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_holtek; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 5; + instance->encoder.repeat = 10; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -155,7 +155,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/holtek_ht12x.c b/lib/subghz/protocols/holtek_ht12x.c index 595237a1f..bf5e48adf 100644 --- a/lib/subghz/protocols/holtek_ht12x.c +++ b/lib/subghz/protocols/holtek_ht12x.c @@ -94,7 +94,7 @@ void* subghz_protocol_encoder_holtek_th12x_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_holtek_th12x; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 5; + instance->encoder.repeat = 10; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -170,7 +170,6 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorParserTe; break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/honeywell.c b/lib/subghz/protocols/honeywell.c index d8ce0d8eb..1e3f231e8 100644 --- a/lib/subghz/protocols/honeywell.c +++ b/lib/subghz/protocols/honeywell.c @@ -98,7 +98,7 @@ void* subghz_protocol_encoder_honeywell_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_honeywell; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 5; + instance->encoder.repeat = 4; instance->encoder.size_upload = 64 * 2 + 10; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; diff --git a/lib/subghz/protocols/honeywell_wdb.c b/lib/subghz/protocols/honeywell_wdb.c index 96f5f5e7f..0b8f63a24 100644 --- a/lib/subghz/protocols/honeywell_wdb.c +++ b/lib/subghz/protocols/honeywell_wdb.c @@ -88,7 +88,7 @@ void* subghz_protocol_encoder_honeywell_wdb_alloc(SubGhzEnvironment* environment instance->base.protocol = &subghz_protocol_honeywell_wdb; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 5; + instance->encoder.repeat = 10; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -156,7 +156,6 @@ SubGhzProtocolStatus subghz_protocol_encoder_honeywell_wdb_deserialize( if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/hormann.c b/lib/subghz/protocols/hormann.c index 250ab4f62..f74a29fec 100644 --- a/lib/subghz/protocols/hormann.c +++ b/lib/subghz/protocols/hormann.c @@ -80,7 +80,7 @@ void* subghz_protocol_encoder_hormann_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_hormann; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 2048; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -110,7 +110,7 @@ static bool subghz_protocol_encoder_hormann_get_upload(SubGhzProtocolEncoderHorm } else { instance->encoder.size_upload = size_upload; } - instance->encoder.repeat = 3; //original remote does 10 repeats + instance->encoder.repeat = 10; //original remote does 10 repeats for(size_t repeat = 0; repeat < 20; repeat++) { //Send start bit @@ -153,7 +153,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/intertechno_v3.c b/lib/subghz/protocols/intertechno_v3.c index 7b9bfbf1a..71513051b 100644 --- a/lib/subghz/protocols/intertechno_v3.c +++ b/lib/subghz/protocols/intertechno_v3.c @@ -86,7 +86,7 @@ void* subghz_protocol_encoder_intertechno_v3_alloc(SubGhzEnvironment* environmen instance->base.protocol = &subghz_protocol_intertechno_v3; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -176,7 +176,6 @@ SubGhzProtocolStatus subghz_protocol_encoder_intertechno_v3_deserialize( ret = SubGhzProtocolStatusErrorValueBitCount; break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/jarolift.c b/lib/subghz/protocols/jarolift.c index 81eca4fde..9881b9892 100644 --- a/lib/subghz/protocols/jarolift.c +++ b/lib/subghz/protocols/jarolift.c @@ -100,7 +100,7 @@ void* subghz_protocol_encoder_jarolift_alloc(SubGhzEnvironment* environment) { instance->generic.protocol_name = instance->base.protocol->name; instance->keystore = subghz_environment_get_keystore(environment); - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index d5a8a9aa7..cd657f23f 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -107,7 +107,7 @@ void* subghz_protocol_encoder_keeloq_alloc(SubGhzEnvironment* environment) { instance->generic.protocol_name = instance->base.protocol->name; instance->keystore = subghz_environment_get_keystore(environment); - instance->encoder.repeat = 3; + instance->encoder.repeat = 100; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; diff --git a/lib/subghz/protocols/kinggates_stylo_4k.c b/lib/subghz/protocols/kinggates_stylo_4k.c index 6b8d0e428..9d7313559 100644 --- a/lib/subghz/protocols/kinggates_stylo_4k.c +++ b/lib/subghz/protocols/kinggates_stylo_4k.c @@ -101,7 +101,7 @@ void* subghz_protocol_encoder_kinggates_stylo_4k_alloc(SubGhzEnvironment* enviro instance->generic.protocol_name = instance->base.protocol->name; instance->keystore = subghz_environment_get_keystore(environment); - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 512; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; diff --git a/lib/subghz/protocols/legrand.c b/lib/subghz/protocols/legrand.c index 7b8b70204..94a45694c 100644 --- a/lib/subghz/protocols/legrand.c +++ b/lib/subghz/protocols/legrand.c @@ -155,7 +155,6 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorParserTe; break; } - // optional parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/linear.c b/lib/subghz/protocols/linear.c index 61a21ec05..f024316e9 100644 --- a/lib/subghz/protocols/linear.c +++ b/lib/subghz/protocols/linear.c @@ -160,7 +160,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/linear_delta3.c b/lib/subghz/protocols/linear_delta3.c index 515fc43a6..c2f527ba8 100644 --- a/lib/subghz/protocols/linear_delta3.c +++ b/lib/subghz/protocols/linear_delta3.c @@ -164,7 +164,6 @@ SubGhzProtocolStatus subghz_protocol_encoder_linear_delta3_deserialize( if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/magellan.c b/lib/subghz/protocols/magellan.c index 5fc003ab4..55048ca61 100644 --- a/lib/subghz/protocols/magellan.c +++ b/lib/subghz/protocols/magellan.c @@ -78,7 +78,7 @@ void* subghz_protocol_encoder_magellan_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_magellan; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -164,7 +164,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/marantec.c b/lib/subghz/protocols/marantec.c index d70c4eed2..53e4d6895 100644 --- a/lib/subghz/protocols/marantec.c +++ b/lib/subghz/protocols/marantec.c @@ -77,7 +77,7 @@ void* subghz_protocol_encoder_marantec_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_marantec; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -213,7 +213,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/marantec24.c b/lib/subghz/protocols/marantec24.c index fbd16ecbb..6f636e8ab 100644 --- a/lib/subghz/protocols/marantec24.c +++ b/lib/subghz/protocols/marantec24.c @@ -73,7 +73,7 @@ void* subghz_protocol_encoder_marantec24_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_marantec24; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -155,7 +155,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/mastercode.c b/lib/subghz/protocols/mastercode.c index b0b7f789d..e4fae40b3 100644 --- a/lib/subghz/protocols/mastercode.c +++ b/lib/subghz/protocols/mastercode.c @@ -168,7 +168,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/megacode.c b/lib/subghz/protocols/megacode.c index 22e57c364..2c4bf10a3 100644 --- a/lib/subghz/protocols/megacode.c +++ b/lib/subghz/protocols/megacode.c @@ -188,7 +188,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/nero_radio.c b/lib/subghz/protocols/nero_radio.c index d5c284693..da5497feb 100644 --- a/lib/subghz/protocols/nero_radio.c +++ b/lib/subghz/protocols/nero_radio.c @@ -77,7 +77,7 @@ void* subghz_protocol_encoder_nero_radio_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_nero_radio; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -180,7 +180,6 @@ SubGhzProtocolStatus break; } } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/nero_sketch.c b/lib/subghz/protocols/nero_sketch.c index 02682f4f1..64a75cfc0 100644 --- a/lib/subghz/protocols/nero_sketch.c +++ b/lib/subghz/protocols/nero_sketch.c @@ -76,7 +76,7 @@ void* subghz_protocol_encoder_nero_sketch_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_nero_sketch; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -161,7 +161,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/nice_flo.c b/lib/subghz/protocols/nice_flo.c index b47de0079..2e5fa96b5 100644 --- a/lib/subghz/protocols/nice_flo.c +++ b/lib/subghz/protocols/nice_flo.c @@ -147,7 +147,6 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorValueBitCount; break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index 67755c79f..9085ee431 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -104,7 +104,7 @@ void* subghz_protocol_encoder_nice_flor_s_alloc(SubGhzEnvironment* environment) FURI_LOG_D( TAG, "Loading rainbow table from %s", instance->nice_flor_s_rainbow_table_file_name); } - instance->encoder.repeat = 1; + instance->encoder.repeat = 10; instance->encoder.size_upload = 2400; //wrong!! upload 186*16 = 2976 - actual size about 1728 instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -282,7 +282,6 @@ SubGhzProtocolStatus // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - // flipper_format_read_uint32( // flipper_format, "Data", (uint32_t*)&instance->generic.data_2, 1); if(!flipper_format_rewind(flipper_format)) { diff --git a/lib/subghz/protocols/phoenix_v2.c b/lib/subghz/protocols/phoenix_v2.c index 9b97137f9..1f2731f54 100644 --- a/lib/subghz/protocols/phoenix_v2.c +++ b/lib/subghz/protocols/phoenix_v2.c @@ -77,7 +77,7 @@ void* subghz_protocol_encoder_phoenix_v2_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_phoenix_v2; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 5; + instance->encoder.repeat = 10; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -322,7 +322,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/power_smart.c b/lib/subghz/protocols/power_smart.c index 1e8f7098c..6449f720a 100644 --- a/lib/subghz/protocols/power_smart.c +++ b/lib/subghz/protocols/power_smart.c @@ -85,7 +85,7 @@ void* subghz_protocol_encoder_power_smart_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_power_smart; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 1024; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -206,7 +206,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/revers_rb2.c b/lib/subghz/protocols/revers_rb2.c index 5e4ca97e8..941ff5c56 100644 --- a/lib/subghz/protocols/revers_rb2.c +++ b/lib/subghz/protocols/revers_rb2.c @@ -78,7 +78,7 @@ void* subghz_protocol_encoder_revers_rb2_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_revers_rb2; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 5; + instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -176,7 +176,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/roger.c b/lib/subghz/protocols/roger.c index 62178981c..9c33b11ec 100644 --- a/lib/subghz/protocols/roger.c +++ b/lib/subghz/protocols/roger.c @@ -76,7 +76,7 @@ void* subghz_protocol_encoder_roger_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_roger; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -265,7 +265,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/secplus_v1.c b/lib/subghz/protocols/secplus_v1.c index 3d820b318..13af0d302 100644 --- a/lib/subghz/protocols/secplus_v1.c +++ b/lib/subghz/protocols/secplus_v1.c @@ -98,7 +98,7 @@ void* subghz_protocol_encoder_secplus_v1_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_secplus_v1; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 5; + instance->encoder.repeat = 10; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -298,7 +298,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/secplus_v2.c b/lib/subghz/protocols/secplus_v2.c index 902422148..ad343968b 100644 --- a/lib/subghz/protocols/secplus_v2.c +++ b/lib/subghz/protocols/secplus_v2.c @@ -92,7 +92,7 @@ void* subghz_protocol_encoder_secplus_v2_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_secplus_v2; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -574,11 +574,9 @@ SubGhzProtocolStatus subghz_protocol_secplus_v2_remote_controller( &instance->generic, instance->secplus_packet_1); subghz_protocol_secplus_v2_encode(instance); - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_secplus_v2_get_upload(instance); //update data diff --git a/lib/subghz/protocols/smc5326.c b/lib/subghz/protocols/smc5326.c index 201fcd9d7..217dbb780 100644 --- a/lib/subghz/protocols/smc5326.c +++ b/lib/subghz/protocols/smc5326.c @@ -101,7 +101,7 @@ void* subghz_protocol_encoder_smc5326_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_smc5326; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 5; + instance->encoder.repeat = 10; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -178,7 +178,6 @@ SubGhzProtocolStatus ret = SubGhzProtocolStatusErrorParserTe; break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/lib/subghz/protocols/somfy_keytis.c b/lib/subghz/protocols/somfy_keytis.c index 04dba4736..c9f6f47bd 100644 --- a/lib/subghz/protocols/somfy_keytis.c +++ b/lib/subghz/protocols/somfy_keytis.c @@ -81,7 +81,7 @@ void* subghz_protocol_encoder_somfy_keytis_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_somfy_keytis; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 512; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; diff --git a/lib/subghz/protocols/somfy_telis.c b/lib/subghz/protocols/somfy_telis.c index 4d4b128f1..2be378b7d 100644 --- a/lib/subghz/protocols/somfy_telis.c +++ b/lib/subghz/protocols/somfy_telis.c @@ -82,7 +82,7 @@ void* subghz_protocol_encoder_somfy_telis_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_somfy_telis; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 512; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; diff --git a/lib/subghz/protocols/treadmill37.c b/lib/subghz/protocols/treadmill37.c index 8a7badb94..e9915c296 100644 --- a/lib/subghz/protocols/treadmill37.c +++ b/lib/subghz/protocols/treadmill37.c @@ -73,7 +73,7 @@ void* subghz_protocol_encoder_treadmill37_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_treadmill37; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; + instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -151,7 +151,6 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - // Optional value flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); diff --git a/targets/f7/furi_hal/furi_hal_subghz.c b/targets/f7/furi_hal/furi_hal_subghz.c index ece8dde2c..dc6add277 100644 --- a/targets/f7/furi_hal/furi_hal_subghz.c +++ b/targets/f7/furi_hal/furi_hal_subghz.c @@ -684,8 +684,6 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { while(samples > 0) { volatile uint32_t duration = furi_hal_subghz_async_tx_middleware_get_duration( &furi_hal_subghz_async_tx.middleware, furi_hal_subghz_async_tx.callback); - // if duration == 0 then we stop DMA interrupt(that used to refill buffer) and write to buffer 0 as last element. - // later DMA write this 0 to ARR and timer TIM2 will be stopped. if(duration == 0) { *buffer = 0; buffer++; @@ -758,64 +756,48 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* furi_hal_subghz_async_tx.buffer = malloc(FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t)); - // Here we use TIM2_CH2 (Timer 2 Channel 2) to generate HI/LOW signals for C1101 with current durations. - // DMA update/rewrite TIM2 settings (ARR) with new duration each time TIM2 completes. - // Every time when timer counter exeed current TIM2-ARR (AutoReload Register) value timer generate event that call DMA - // DMA load next new value from buffer to TIM2-ARR and timer start count up from 0 to new value again - // Totally we have timer that generate events and update they settings with new durations by DMA action. - // When duration = 0 then DMA wirte 0 to ARR. So when we set ARR=0 - thats mean TIM2 stop counting. - - // Connect CC1101_GD0 to TIM2 as output (Pin B3 - GpioAltFn1TIM2 - TIM2, CH2) + // Connect CC1101_GD0 to TIM2 as output furi_hal_gpio_init_ex( &gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); - // Configure DMA to update TIM2->ARR - LL_DMA_InitTypeDef dma_config = {0}; // DMA settings structure - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); // DMA destination TIM2->ARR - dma_config.MemoryOrM2MDstAddress = - (uint32_t)furi_hal_subghz_async_tx.buffer; // DMA buffer with signals durations - dma_config.Direction = - LL_DMA_DIRECTION_MEMORY_TO_PERIPH; // DMA direction from memory to periperhal - dma_config.Mode = LL_DMA_MODE_CIRCULAR; // DMA mode - dma_config.PeriphOrM2MSrcIncMode = - LL_DMA_PERIPH_NOINCREMENT; // DMA destination not changed - allways stay on ARR (AutoReload Register) - dma_config.MemoryOrM2MDstIncMode = - LL_DMA_MEMORY_INCREMENT; // DMA source increment - step by step on durations buffer - dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; // DMA source packet size - dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; // DMA destination packet size - dma_config.NbData = FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL; // DMA buffer size - dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; // DMA start by TIM2 event + // Configure DMA + LL_DMA_InitTypeDef dma_config = {0}; + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); + dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_async_tx.buffer; + dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + dma_config.Mode = LL_DMA_MODE_CIRCULAR; + dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + dma_config.NbData = FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL; + dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH; // Ensure that ARR is updated before anyone else try to check it - LL_DMA_Init(SUBGHZ_DMA_CH1_DEF, &dma_config); // Setup DMA with settings structure - // setup interrupt for DMA. When DMA generate interrupt event we call furi_hal_subghz_async_tx_dma_isr + LL_DMA_Init(SUBGHZ_DMA_CH1_DEF, &dma_config); furi_hal_interrupt_set_isr(SUBGHZ_DMA_CH1_IRQ, furi_hal_subghz_async_tx_dma_isr, NULL); - LL_DMA_EnableIT_TC(SUBGHZ_DMA_CH1_DEF); // interrupt for full buffer sent - LL_DMA_EnableIT_HT(SUBGHZ_DMA_CH1_DEF); // interrupt for half buffer sent - LL_DMA_EnableChannel(SUBGHZ_DMA_CH1_DEF); // Enable + LL_DMA_EnableIT_TC(SUBGHZ_DMA_CH1_DEF); + LL_DMA_EnableIT_HT(SUBGHZ_DMA_CH1_DEF); + LL_DMA_EnableChannel(SUBGHZ_DMA_CH1_DEF); - furi_hal_bus_enable(FuriHalBusTIM2); // Enable TIM2 + furi_hal_bus_enable(FuriHalBusTIM2); // Configure TIM2 - LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); // TIM2 set counter mode UP - // Set the division ratio between the timer clock and the sampling clock 1:1 + LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); - LL_TIM_SetPrescaler(TIM2, 64 - 1); // Perscaler 64 Mghz/64 = 1 Mghz (1 000 000 tick/sec) - // AutoReload Register (ARR) 1000 ticks = 1/1000 Mghz = 1 millisecond, will be changed by DMA by new durations LL_TIM_SetAutoReload(TIM2, 1000); - LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); // ClockSource for TIM2 - LL_TIM_DisableARRPreload( - TIM2); // Change TIM2 setting immediately (dont wait when counter will be overload) + LL_TIM_SetPrescaler(TIM2, 64 - 1); + LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_DisableARRPreload(TIM2); // Configure TIM2 CH2 - LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0}; //Settings structure - // CH2 working mode - TOGGLE (swith between HI and LOW levels) + LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0}; TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_TOGGLE; TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE; TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE; - TIM_OC_InitStruct.CompareValue = 0; // Counter value to generate events and TOGGLE output - TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH; // Initial CH2 state - HIGH level - LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct); // Apply settings to CH2 + TIM_OC_InitStruct.CompareValue = 0; + TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH; + LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct); LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH2); LL_TIM_DisableMasterSlaveMode(TIM2); @@ -823,8 +805,8 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* furi_hal_subghz_async_tx_refill( furi_hal_subghz_async_tx.buffer, FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL); - LL_TIM_EnableDMAReq_UPDATE(TIM2); // Setup calling DMA by TIM2 events - LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); //Enable TIM2 CH2 + LL_TIM_EnableDMAReq_UPDATE(TIM2); + LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); // Start debug if(furi_hal_subghz_start_debug()) { @@ -859,8 +841,8 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* #endif furi_hal_subghz_tx(); - LL_TIM_SetCounter(TIM2, 0); // Reset TIM2 - LL_TIM_EnableCounter(TIM2); // Start TIM2 counting. + LL_TIM_SetCounter(TIM2, 0); + LL_TIM_EnableCounter(TIM2); return true; } From 7e851684959dda8d8c6059d01baf281d5897c961 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 26 Jan 2026 14:32:10 +0300 Subject: [PATCH 080/160] add comments back --- .../drivers/subghz/cc1101_ext/cc1101_ext.c | 11 ++- targets/f7/furi_hal/furi_hal_subghz.c | 78 ++++++++++++------- 2 files changed, 56 insertions(+), 33 deletions(-) diff --git a/applications/drivers/subghz/cc1101_ext/cc1101_ext.c b/applications/drivers/subghz/cc1101_ext/cc1101_ext.c index abca098eb..e24ed8f7a 100644 --- a/applications/drivers/subghz/cc1101_ext/cc1101_ext.c +++ b/applications/drivers/subghz/cc1101_ext/cc1101_ext.c @@ -794,12 +794,17 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb subghz_device_cc1101_ext->async_tx.buffer = malloc(SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t)); + // here we do the same things as in /unleashed-firmware/targets/f7/furi_hal/furi_hal_subghz.c + // use first DMA to update timer TIM17 durations, but TIM17 have not output chanel + // so we use second DMA to transfer data from gpio_tx_buff directly to gpio pin using BSSR. + // BSSR allow us tranfer data directly to pin in gpio port. + //Signal generation with mem-to-mem DMA furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false); furi_hal_gpio_init( subghz_device_cc1101_ext->g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); - // Configure DMA update timer + // Configure DMA to update timer TIM17 ARR by durations from buffer LL_DMA_SetMemoryAddress( SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t)subghz_device_cc1101_ext->async_tx.buffer); LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t) & (TIM17->ARR)); @@ -821,7 +826,7 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb furi_hal_bus_enable(FuriHalBusTIM17); - // Configure TIM + // Configure TIM 17 // Set the timer resolution to 2 us LL_TIM_SetCounterMode(TIM17, LL_TIM_COUNTERMODE_UP); LL_TIM_SetClockDivision(TIM17, LL_TIM_CLOCKDIVISION_DIV1); @@ -835,7 +840,7 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb subghz_device_cc1101_ext_async_tx_refill( subghz_device_cc1101_ext->async_tx.buffer, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL); - // Configure tx gpio dma + // Configure DMA to transfer data from gpio_tx_buff directly to gpio pin using BSSR const GpioPin* gpio = subghz_device_cc1101_ext->g0_pin; subghz_device_cc1101_ext->async_tx.gpio_tx_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER; diff --git a/targets/f7/furi_hal/furi_hal_subghz.c b/targets/f7/furi_hal/furi_hal_subghz.c index dc6add277..ece8dde2c 100644 --- a/targets/f7/furi_hal/furi_hal_subghz.c +++ b/targets/f7/furi_hal/furi_hal_subghz.c @@ -684,6 +684,8 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { while(samples > 0) { volatile uint32_t duration = furi_hal_subghz_async_tx_middleware_get_duration( &furi_hal_subghz_async_tx.middleware, furi_hal_subghz_async_tx.callback); + // if duration == 0 then we stop DMA interrupt(that used to refill buffer) and write to buffer 0 as last element. + // later DMA write this 0 to ARR and timer TIM2 will be stopped. if(duration == 0) { *buffer = 0; buffer++; @@ -756,48 +758,64 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* furi_hal_subghz_async_tx.buffer = malloc(FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t)); - // Connect CC1101_GD0 to TIM2 as output + // Here we use TIM2_CH2 (Timer 2 Channel 2) to generate HI/LOW signals for C1101 with current durations. + // DMA update/rewrite TIM2 settings (ARR) with new duration each time TIM2 completes. + // Every time when timer counter exeed current TIM2-ARR (AutoReload Register) value timer generate event that call DMA + // DMA load next new value from buffer to TIM2-ARR and timer start count up from 0 to new value again + // Totally we have timer that generate events and update they settings with new durations by DMA action. + // When duration = 0 then DMA wirte 0 to ARR. So when we set ARR=0 - thats mean TIM2 stop counting. + + // Connect CC1101_GD0 to TIM2 as output (Pin B3 - GpioAltFn1TIM2 - TIM2, CH2) furi_hal_gpio_init_ex( &gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); - // Configure DMA - LL_DMA_InitTypeDef dma_config = {0}; - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); - dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_async_tx.buffer; - dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; - dma_config.Mode = LL_DMA_MODE_CIRCULAR; - dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; - dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; - dma_config.NbData = FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL; - dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + // Configure DMA to update TIM2->ARR + LL_DMA_InitTypeDef dma_config = {0}; // DMA settings structure + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); // DMA destination TIM2->ARR + dma_config.MemoryOrM2MDstAddress = + (uint32_t)furi_hal_subghz_async_tx.buffer; // DMA buffer with signals durations + dma_config.Direction = + LL_DMA_DIRECTION_MEMORY_TO_PERIPH; // DMA direction from memory to periperhal + dma_config.Mode = LL_DMA_MODE_CIRCULAR; // DMA mode + dma_config.PeriphOrM2MSrcIncMode = + LL_DMA_PERIPH_NOINCREMENT; // DMA destination not changed - allways stay on ARR (AutoReload Register) + dma_config.MemoryOrM2MDstIncMode = + LL_DMA_MEMORY_INCREMENT; // DMA source increment - step by step on durations buffer + dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; // DMA source packet size + dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; // DMA destination packet size + dma_config.NbData = FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL; // DMA buffer size + dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; // DMA start by TIM2 event dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH; // Ensure that ARR is updated before anyone else try to check it - LL_DMA_Init(SUBGHZ_DMA_CH1_DEF, &dma_config); + LL_DMA_Init(SUBGHZ_DMA_CH1_DEF, &dma_config); // Setup DMA with settings structure + // setup interrupt for DMA. When DMA generate interrupt event we call furi_hal_subghz_async_tx_dma_isr furi_hal_interrupt_set_isr(SUBGHZ_DMA_CH1_IRQ, furi_hal_subghz_async_tx_dma_isr, NULL); - LL_DMA_EnableIT_TC(SUBGHZ_DMA_CH1_DEF); - LL_DMA_EnableIT_HT(SUBGHZ_DMA_CH1_DEF); - LL_DMA_EnableChannel(SUBGHZ_DMA_CH1_DEF); + LL_DMA_EnableIT_TC(SUBGHZ_DMA_CH1_DEF); // interrupt for full buffer sent + LL_DMA_EnableIT_HT(SUBGHZ_DMA_CH1_DEF); // interrupt for half buffer sent + LL_DMA_EnableChannel(SUBGHZ_DMA_CH1_DEF); // Enable - furi_hal_bus_enable(FuriHalBusTIM2); + furi_hal_bus_enable(FuriHalBusTIM2); // Enable TIM2 // Configure TIM2 - LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); + LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); // TIM2 set counter mode UP + // Set the division ratio between the timer clock and the sampling clock 1:1 LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); + LL_TIM_SetPrescaler(TIM2, 64 - 1); // Perscaler 64 Mghz/64 = 1 Mghz (1 000 000 tick/sec) + // AutoReload Register (ARR) 1000 ticks = 1/1000 Mghz = 1 millisecond, will be changed by DMA by new durations LL_TIM_SetAutoReload(TIM2, 1000); - LL_TIM_SetPrescaler(TIM2, 64 - 1); - LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); - LL_TIM_DisableARRPreload(TIM2); + LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); // ClockSource for TIM2 + LL_TIM_DisableARRPreload( + TIM2); // Change TIM2 setting immediately (dont wait when counter will be overload) // Configure TIM2 CH2 - LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0}; + LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0}; //Settings structure + // CH2 working mode - TOGGLE (swith between HI and LOW levels) TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_TOGGLE; TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE; TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE; - TIM_OC_InitStruct.CompareValue = 0; - TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH; - LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct); + TIM_OC_InitStruct.CompareValue = 0; // Counter value to generate events and TOGGLE output + TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH; // Initial CH2 state - HIGH level + LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct); // Apply settings to CH2 LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH2); LL_TIM_DisableMasterSlaveMode(TIM2); @@ -805,8 +823,8 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* furi_hal_subghz_async_tx_refill( furi_hal_subghz_async_tx.buffer, FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL); - LL_TIM_EnableDMAReq_UPDATE(TIM2); - LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); + LL_TIM_EnableDMAReq_UPDATE(TIM2); // Setup calling DMA by TIM2 events + LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); //Enable TIM2 CH2 // Start debug if(furi_hal_subghz_start_debug()) { @@ -841,8 +859,8 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* #endif furi_hal_subghz_tx(); - LL_TIM_SetCounter(TIM2, 0); - LL_TIM_EnableCounter(TIM2); + LL_TIM_SetCounter(TIM2, 0); // Reset TIM2 + LL_TIM_EnableCounter(TIM2); // Start TIM2 counting. return true; } From 914ca6f21d05f89b93069bb3f8b2edcbfc9cdc40 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 26 Jan 2026 14:36:06 +0300 Subject: [PATCH 081/160] Revert "enable winter anims" This reverts commit c8e756a3c52a615514c74951f9ec375b1f956223. --- .../L1_Happy_holidays_128x64/frame_0.png | Bin 858 -> 0 bytes .../L1_Happy_holidays_128x64/frame_1.png | Bin 855 -> 0 bytes .../L1_Happy_holidays_128x64/frame_10.png | Bin 872 -> 0 bytes .../L1_Happy_holidays_128x64/frame_11.png | Bin 861 -> 0 bytes .../L1_Happy_holidays_128x64/frame_12.png | Bin 853 -> 0 bytes .../L1_Happy_holidays_128x64/frame_2.png | Bin 851 -> 0 bytes .../L1_Happy_holidays_128x64/frame_3.png | Bin 852 -> 0 bytes .../L1_Happy_holidays_128x64/frame_4.png | Bin 856 -> 0 bytes .../L1_Happy_holidays_128x64/frame_5.png | Bin 850 -> 0 bytes .../L1_Happy_holidays_128x64/frame_6.png | Bin 851 -> 0 bytes .../L1_Happy_holidays_128x64/frame_7.png | Bin 860 -> 0 bytes .../L1_Happy_holidays_128x64/frame_8.png | Bin 857 -> 0 bytes .../L1_Happy_holidays_128x64/frame_9.png | Bin 863 -> 0 bytes .../L1_Happy_holidays_128x64/meta.txt | 23 ------------------ .../external/L1_New_year_128x64/frame_0.png | Bin 1740 -> 0 bytes .../external/L1_New_year_128x64/frame_1.png | Bin 1783 -> 0 bytes .../external/L1_New_year_128x64/frame_2.png | Bin 1754 -> 0 bytes .../external/L1_New_year_128x64/frame_3.png | Bin 1745 -> 0 bytes .../external/L1_New_year_128x64/meta.txt | 14 ----------- .../L1_Sleigh_ride_128x64/frame_0.png | Bin 820 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_1.png | Bin 881 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_10.png | Bin 788 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_11.png | Bin 816 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_12.png | Bin 864 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_13.png | Bin 798 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_14.png | Bin 813 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_15.png | Bin 879 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_16.png | Bin 855 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_17.png | Bin 772 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_18.png | Bin 817 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_19.png | Bin 867 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_2.png | Bin 866 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_20.png | Bin 809 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_21.png | Bin 795 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_22.png | Bin 870 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_23.png | Bin 852 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_24.png | Bin 805 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_25.png | Bin 858 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_26.png | Bin 830 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_27.png | Bin 828 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_28.png | Bin 585 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_29.png | Bin 431 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_3.png | Bin 812 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_30.png | Bin 281 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_31.png | Bin 270 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_32.png | Bin 236 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_33.png | Bin 485 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_34.png | Bin 771 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_35.png | Bin 887 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_36.png | Bin 809 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_4.png | Bin 890 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_5.png | Bin 819 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_6.png | Bin 799 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_7.png | Bin 817 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_8.png | Bin 875 -> 0 bytes .../L1_Sleigh_ride_128x64/frame_9.png | Bin 823 -> 0 bytes .../external/L1_Sleigh_ride_128x64/meta.txt | 23 ------------------ assets/dolphin/external/manifest.txt | 21 ---------------- 58 files changed, 81 deletions(-) delete mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_0.png delete mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_1.png delete mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_10.png delete mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_11.png delete mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_12.png delete mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_2.png delete mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_3.png delete mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_4.png delete mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_5.png delete mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_6.png delete mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_7.png delete mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_8.png delete mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_9.png delete mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/meta.txt delete mode 100644 assets/dolphin/external/L1_New_year_128x64/frame_0.png delete mode 100644 assets/dolphin/external/L1_New_year_128x64/frame_1.png delete mode 100644 assets/dolphin/external/L1_New_year_128x64/frame_2.png delete mode 100644 assets/dolphin/external/L1_New_year_128x64/frame_3.png delete mode 100644 assets/dolphin/external/L1_New_year_128x64/meta.txt delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_0.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_1.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_10.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_11.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_12.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_13.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_14.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_15.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_16.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_17.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_18.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_19.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_2.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_20.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_21.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_22.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_23.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_24.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_25.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_26.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_27.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_28.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_29.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_3.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_30.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_31.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_32.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_33.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_34.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_35.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_36.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_4.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_5.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_6.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_7.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_8.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_9.png delete mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/meta.txt diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_0.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_0.png deleted file mode 100755 index f1207ed14b35cd01eafa00342f2801d74b46c622..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 858 zcmV-g1Eu_lP)b3G}_zPLJOisK}_wXw<>5vl)fnyEcmLJ)0YM`-qsd9LG<*g zg3uHHfWB#8LN=zM6$A}^iEZj_uEAVvNj6Dq_mbTmAFd!cFTa@&W`4{t&64fs z1O6+|kM;zum_y0;LR;%E{4|RT5jh|65*n~`w!6HK#2L%5CukdP2q1}?sRvZR12EsS zP6BKKYE)f>e;Pi(R|nZq8>DGO9+1VXzqs;Y z>zzX{C5FwW0Jpr#S{j^JpU8;?=-uOueU6(!BS9RndoqvP1aOo&p}tH{j*$Y>F2CbY zJTRxpb}`rb=#NmV8-pBq^GnU*vUM}Lrs&3DVX2NWQRPbV9Eu_gHSp)RdG_xa2L$n& zAzo{&Ly7kt@}aaYyloeLFiehuLtK&CfvZv9i~0aRdxU@_`$?=4uDcSHyHB@B=3sjv z1Yp-C*-y?RIqd_Gb4_y*`NdA5GkU`(19o4%V_h1`c<^#Zb!*T(J_a>H!@b?Pw{we% z1dHI&$2X)22_qD0fIX;@)4QwO+?wU}hx4OTV?~Yn&m|Y9uV0s?!lVme6X@3g$i9tJ zAw<+xNi6@`UU{o9>1u#x3Q(N{@}pCiFtmK`&hbpo$P?pJF1bH9`LkVT#6U2cFbE**&wk(4~aXcues_UO>rxTx;jl=<04a40ce_veR#+-lBGlmLLRKtj8 k04biGE0u;J2K9h{0X->d_eOezlK=n!07*qoM6N<$g2W|{hX4Qo diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_1.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_1.png deleted file mode 100755 index 9d9012281f0193620bc458455f6a93538fad2e96..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 855 zcmV-d1E~CoP);NOWB)|bSkT1aRXRBA7yY|TxF{FSfXu8*lUk&&qCXhO8F)FkoA>H2*0;2g2fv& z(d#Xs;?yt-?E~*0`D{sLX^yAU0@$ekWb2zI3N8X{Fs83orr0sQ#X|guwcpNP1=Z{G zSdat3yA1rXr`2nki#Nt*x!NSyKj4u+UwHlRdp$A`_S7#~2^ znalc2P!kjpqG|x})i68iBGTxNe8ACYahNl>a$BAkJMa8EWISSW9x^|7!7He$DqzaK zHH~UJtLg*3q0pI4GT^O->aCwBq?&T_iw|3e_BWDe59<_EmFTb&R`!3M<{$oTix6M< z>)gGM21gU)@>GCLe`>uG{-^#CUE~ZdT5WwA&`g90koSOKH57+|(uvFv@ zu5jrw5_rGj>oQ@wX!V1Y;}RF$?qIcGbR!}y4R^HsbN*(0SXHAg%c)Z)Sl#Bty=5=L zsgMqRmyS4iNFy-1b&V$Edv0=qawEuV>%O>0>(QCF8Rm}903b;}$!G~1tcE58ti4NG z#Li1EDY$>yq#tK|B{A92+mN-R_2;-oJ?~InHFlt@zLj6-(yP6H#HwvaCccFQEMv5L zf=vPm?`HFc&NPYoHp(3VcND9qw+G8F!`Z&vP|e+|N$-{9)>3?5mJ2g}w){{ph6J4J z%MI1syar5eO=xJuFUo-&*Dz1D2A`uKvLp&GC&Xeh15D$Dcrr0Le)4jNZU3t?tW+aRjFfo7> hF5f7XLU{2m{sTJ-XIlu4y4L^z002ovPDHLkV1fh!ld%8* diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_10.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_10.png deleted file mode 100755 index cb8f173b0bdd8ae661a0e3c000fa88fe256b3a30..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 872 zcmV-u1DE`XP)?*-2wV(L$SR8{9F5vK7gWF*K9z%sdYhFTTrr?}P9A_;@_Xs~B$& zdb=C`2i$J}PvkF<5Lip!C9yJmJk zyD)1^<~b8;r*9}UQQZePJA_5QLN`m13s@3OkFb+2eNEr3q|e{3Do1W(`LOHQ*{Ccc zB5$Q4jUTjXj@h}Yt9&X@PQ4@to~kt#+CNgxBxB&i*V>Ql>6XdOn;M1U`%k`JdYzb# zxvXjd@yA2gSI!^4_f;b4ZVha>V{2(}QKcwlYoN5(9sVe;;QMGaV0UFMDS=xLDQI_k zl`c30L1j1u&AC6(zViz%&P+gL(A6Pd>t%<3qVh2Bofy|h5cY3#mMO5li|Y^PWBb5vv#*6Jr_FPc<~!% zzI?osA0I4#%i;aLLUqKAW@~uXa`(Ts#~MgIadhi(T6M8oL-0000;RtW zYC;GgHWEVi?&N>ACW2t*m9`GWO9_C1mL9w88*tuE7R2n%(<4e*f~ghW9``l2w{(Idzmy zutB!vuh7(q6FumKEzuwW3j>H)yTC$Q)<$cl-5z|y-D(1|M{-+S4~zn(Om^kCIMPHS9NRn-wo zb-G{73WfIdhPR*xoUE3%!LeNDq5+&-b6)u9wbmmCRLA3PDHsgjUH*FU4P5pLwkgFV zmxg|AeEVE-xl4Bs3UJRKUC+WFO%Y=k1n4^CS3kxxCIG~RLNWKb&+NDt@uDzso1(=) ziO{b`1j1wkskuLG`gr?8T!vo%MDt|Wxs$H6RMRzvDm|*B)6Vsz{HJQVCiK<`7I%66 zpD+s`5q~AZZ&Y`vK%F#^#?`Zh(igxfh#;bQczHYO!l%F7Qcd2Iw2#!O6k`4kFx=;dmqLL2aI=r`kQ=1B2Is`ynS&V z<-m2T+}iw1!W-ao64<|YDyCoJj>kKX`oA%;cSfI$NThnHV{pp1@th#<3}a7jmBu`P zDqsa5kKKJg0*?!;XMmeM@@8qw(-6&dL7+AUbPP_-V{~{se>K-hd3t2Z!}?=`PrJ;# zQnh39NRQzpt(~lq3*y4nYpOBlET<#Dr92W2XR56aRW)_yVsXJ!W4uiuWfyz#sBd~p naeM(t04ZO&R;l#2#RBjz<}zf`VzpON00000NkvXXu0mjf*Yuj_ diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_12.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_12.png deleted file mode 100755 index 5d4c7e7c55fb7012fa223c9084bfe754c5b50e4f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 853 zcmV-b1FHOqP)24#t z)$%{!Q45Ty-Up3=wft=c7FG4Oco@|*;BzJ3rR*z7I#_C0{0L^xB_+HdKGwmDt*hX6 zDH20Ibn!pi0Fyv8^LjZu2{ML(&ZIO+ZL(v#u~+Zi{QU%ZB`c)=A=;6(xnT!)w=IGt z=rYN(4d4fF8i~Na_14g#ID(kx5x^!L#~NS7XoQad>-6bk!-Etiv{*>*vHHuoDNw!k z6Bgu&=ryXNZat%G8DUk&U%K4Vh#e5;u5{tcO?gnuU;Vpo0uJJxMn=zn8dOzP6(9`7 zEDrjmYFK79AIVDKNJDk`d#Z&N9J_G3ad7`tJ->0As;ZJa<+8$t^j++69Ulc2wFZz}~l6 z2i~c<%n15&MiH}mc>V#t(I9v-Q%ybCJHJ&K+pAM;f5?b#dvfM$7{k&>F~d5MxP|iG zuzq5)*a~gZ@(lPVvHC{youmzh+FR<={yxpxF6ZCPB+GWTdbU|UpW2_RHsYTJ;tjyJJ$FNDVQx?~LS0I5z~ f@9uVx0t);KGZb(kKhPw)00000NkvXXu0mjfXi1u-?7W>nA=QF^N=Sn#Tt)k_1K?$nA#5M6H- z3SIFJs3+S?$SlbLxQwjlT}@4XMa_vL+g&bDiVrlO%h|I11tkAJR*h4?o`ocsAzjOk`v+05A z6S0AbLLD1$CbL%`nE^E%K>+(g<*^MDqF^JyR=fZHhu$#kT7e)w$r|myavG?9auyq; zKYZndksi}ZIGTPdw6*@?p1uO!w znz&u}0w4q@tEFA=Y*Y2x6`WjihCh3K<3L|C-CkX!q^iUR3udD4T<)wc*+BBe^$%O` z9DO;pT($(b6I9nTb45d9FA<=3UoiGLeh!Tk@xblL1OCRq3Fd|R3OxmeO3e8Dibr{1 zUeld&q4m*kk=8c%bL`D8HBUyJ+v!b3H;0AgI@Uyu>*@0-ig2hwxUj=>f6jU!NYIQ3 zT4Nn5ydO}Eq;>UexAYxw0t`u2rUq`rdtV~p$Dq)4{V=Ihabs3ZrTcVC0t^1*bx8)pZ36wySQ=&?|`G43`_qCmSb|uFJ9h)-AGPdfGG$gIuCG%s+c7RI1Xef zDMOT|0C&IEz1}^e&Fwi(K3p7`9xLnjeV5W}Gq-NZa%s{B7{ln-2ISGra}oGVt&uw6 z&4cn*Y0_7N<_b`o1d1cmKVj+UrGHN4dS0F!pY|#IzQs2U8)eLn$s>IRC)sFNgSj9c zT%A{qnQ&zVJj&x{G*jL9R6CvI^js_+_-a}HHpK^%`VRKOQ-O7;6vtCo$t)n{i}RJr dAS9px@GqP{Wg0BXhk5`2002ovPDHLkV1gwEk39eY diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_3.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_3.png deleted file mode 100755 index 3a47dfc170224127ad04528accd7b47104c33ae9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 852 zcmV-a1FQUrP)`u%7fF~_5srm=#DzMRcpHmH0U6ukyH3_+-tnN~JbCOQv8kQi2h4Vg#S0unXINGxg zZkHmf(E0H4f3_jULp=X_eme(@K&?>6D75yyarmQomH8?DIxB$n{l}YMtfCMgz$WARRBeK`i7Xb9N38#N{wk>6 zn8t$ai(jKW?KTqz)31beoqg$Au^EG>5F@0_K|5OoAV!jm2e98^DtSPu+D-&p6T7j? z22=T#GHT)qf}e{4E{@RF0Fg$IkAQ;u*%3|?$ZdIC>Ad>eun9>hhRF2Pg|Muus(`6R z)->i?xoVVmxigvOz>5vlTi;O5G~@UuZ#56>ZKQucT&Aq5_(KI(+xu}=dbnaMkX%?k zbML*uvD5@?3a}MTY;@e$8so!6fS&!)_@_xFgSiv|g03v0gM*XQC7OLe7Yx9Bg*ybo z<=>Gw{DDXpaM`TYH+n_1%^eCrrGy!?Ak{p{GzI z8~!pIEf6A&*y#3kR-v@#Cda7$LP?wVC3xSi3@2 z!A?tGJB8q9N&6|Bbg2;*OYx3%VpovwG3?>ipJCRCq5JN3X{KARhKwUBo|D-PFjKokHKSty^2^5?rk6=KdDEDqO$ zlE(C=O?Adb3-7cQG}Eo^pfh<6C=Srv}f|5b-c_7Lq9ky$8NSLWtCuN(*43ja_;nGG^5I8Gz^?q6nP)ZGpk{ZHis=6xRwwiRTHA8TKI}=fhUKOwbyp*p) z2p|>-q51KR|71-Kg38;iIutJ<0D2>80Fl&>=|L8@mlf0m2&d@4?5vamXlM>`E$uM& zLKMOdA7KG!y!qBs72u{$B7pt6@44MDK-D!^V87mRI{WLlLppT;;t_9C|0|_TN*h>^ zj^N5re|xwI8NVphb@q+h3wV$~8SxX!(74qyUqIrNE$9sE#={~=qPFP+W1vSt9(&E1 z0@w#M;|jvVascq_~JyI!tV!l;9SsuG>egr&l+Zp2-t5D{M= zxWD<`Yin~kj-C+Uz#rRbhI1ica{}Z${oyYtVl@D9A=jSz95#dEluuTe-J(51Z@~=S z7ayPQ^NX4scV{*~`TbBe`9Qia-9u8(wg>LXe{9TRN|XGS=5{@Zg<_dt<(Sv&+FJ*o ziN0^Nat=6q6b)+J;3_!3{A4WGN_o||LH+#NqgtL0dO9am(d!IKB4BSt_PHey6Isf7y-< z!wfa!9l9>;)g)X8pEG;~IUur8_8G`M#z14}0c@3I_-9^=i5){Fe2nIfdcshi9*ImQ~PmS^Z0g~t#yK>Pt#X=O#0ChmR iZ!Pxq^*{`ifqwzxpI*j|*hYB(00007mXC8pbK{fp*z8BBm>suB`z94 zFfN2z#O6;ZBKV8g7q#_QCCN@qXeOGrX(7q8#^xpS-n%X)ZoHd&?}2j;hXd^?#CwPA zZOi|FM=da>x(?a|HqzI5V_8*ymmEel_W3|*?omo@k`A{uEM5S!qfr}P5)T`~@!}eU zdlYFxI&$ehTOSiaaP7tRABvyQ0Q#b~$wP^DsbasocXJFd1{r#UZe(Mj5kjgVg2g{! zqNg^2ZK_BB-fyps9Bu~itIHvPje7exFE?RqvK{*YgMaUzt9`2BE?9`~vG&X8RZ#K) z7UV#1mhwdS08C|FSktM~pXWCN$lx48!Zft9CIB81XRJb3h^a7vAc@-4!PamLsmo(G z7;ooH(D5G)LNpx!ygxvW^j~~s^Wd{{%hC2_%Bo6qC>J(LcU4;-n|et6 z;lSJ~e$e#y#ZU2?PPWj?9s!L5~f{i={^$pKjX?pAQF9f0f{TU#lQ!M$*KdX4t-O&vGdPrS(ARtsZ%Cc+2!QQ{=VDb z$ZDTt^&CF36BRUR(S*Xj8=PdQQ7miHV(rM{c2K0j(_N#gNlTJmk~39ouyWD33IS_J z7XP|CXfrx*)k97CSv|YB^_+)F=h8LRI45=q`3b{5Jz4>f1FM)q(809%5-`|T2Vru@ zGKlX3frLxo*sC6#jq*=|cLuA^-vNb@?tE>=D{0cXn5jm8+S&5?R=a$R3xT(~^R*eT zpaBK_K|^ER?D>|0W*YN^<82^co0-IDeXEol(ku3ud+BR(w;t!C()#IT&PhZT>YIlj zV>2mDWvKY@{dLud2K0bP1Opc!9uJ{(@LR+Or^Zxv0OniRg=d^G^)Q+QXo8flT(4F` chyfh@3(5jmrgn0s#I%4<)Bp&osQ-~KgQQ%<@;Hi6Q z(k904#d!5(@qoOhMQKuPI7tL$L1LF^*jJ?G0dL=USP~QG@}2o6Gv9n?23nDej}kdT z%m0YSEikG2H%!)m?dFG!uBqxWM%Pu7wAs|rc~xB&@LEke)|w&YfSVIhi(VG60lZkK zLkJ)i38DG%)&FEo4TAZ%TXiUYLICte)Bqx>AJBu`+PbTtCO|kw2WESz9KfOG5zo>N zW6wt+Z1WKo$c;DOdU_tXrjrO@zvz3m5eBGw1`F)eJ08pa^3{+|?SlBkTh#wbsglwL z7NjG1bEv;P+<=TL33aW!apM*~Bv3_MLKP0Lx6BujIAs$$!@BXY2$HC6I$#WRKPX@? z=B5C40L^%U@TeL9Tz-aQyl;>-6FDHG4=Ro}JPG;MZ=V12InxGY0+11nx>Z$m^oHv9 zJ!00#x3=d1ACr6Z*?8-)XLd*YpYD=NHRbi`cN$$Ut<8r~2SrsSI*|#>#fGlOU8Wcj zUm3W!@y)9%vw8NP5@6SjZ8yW&5U_ax3Y~8Fb4pkZKs?B|r;dlspfu&k3YAUTGxQeC z;5~6Tx=$}?a?qXG_~f^Ts>ucEK6eL6ecK**NB^;2!IUTYHO)7Ch=o#>VCjI@>e^ce z$3)+kI)4&4u^$a;e8_u{`}qgpV!5CiA5uTPvR5nM=;@qLjSnR`MUv~wN8Fz_&NpST ztE3)r-lspDs^Lj;ii`tWV>=jR&xu_{?u0VL{y86*m5xnJE=-M|y$MLj$k!`-mlsi< zTxzKPaa_VxaGVFo0};g;Ab(sd-V^((KVFjIE7|@zXYq53SpZotj{5+^U>rC(`QTCw zd}g-JFvE8P_T8lqRy2G?Q;j+67zeWbbBh=q+%0OVSLKD#IiJk$J6tQSJ7w5Lq&0n+ zT-->gq=I;GdqFj#3?=X+f`LyVo(`eVbsO=(S7ZEtfFwG=E}eCzRE(k-pbkj)^@YB^ d9*BV|@Gpq#TX#gkE++s0002ovPDHLkV1lDnjsE}u diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_7.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_7.png deleted file mode 100755 index da3a78f4c7d2364f251efcf0d311cfeadf3693ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 860 zcmV-i1Ec(jP)HGw^KWKzD1O2?a4gD9ViVO(ALi=Ao3~!3nM+a`evB?;V{tr$^<9Ht z@Ozx-`5N$}TShE+x8EB(Sg}yy2m+X>`*`iE3Tp8XV3Q$zVtka;2@D3}hg5HzodeaM zuV6r)vTsm07j7o>+()SD%qy4MY8GPL03l%(8fhil9EnrbU|)z+i~uB2(+ps1v~_mb zU^43xhMmAih-NLo^Z-r$6p@vVC;(iIW>)CMlbf<#Y`*@W-|d2p} z`R|OgGP|3p27rY^b0W!r7i;O6Uw)vFYRd8R@6`71T~K%Z4h2;uI^c%mdrNwLec366 z#9s{jc5kkyehI4U0&E4N8_n>0h2Q;HfR25^&}VTGcrHNzuRRTD68cmrOE9xWI~;@g zRa*h!!Xw1`zY<8^2~%tI?Zu-K7rhR99V&Q&Uq>%2}c?`l}k+I{g3Ek&naV}M(`v%`QS-6Vs37`vu}7BFU+ zw1_z;d5(bhha}y&C&I*$mHU1m6Kn? z6o#RHp1Ib6S_zl4d*i*e8be^Bwr9Z`#3bzima(q3{<4?X#IMh*M(>-2!l_2~{L;4& z!N*-~{betw7I$4WbWE^ts-d8%#zHc2259RqPvK~3t8?OkUX;Tl>$Z m(G*Yzq;TDI@s{A_#w=kO&avP_}B;zHLpOl zBas;Lp^N{;2ABlG>9-nlBtgb7(4I6xQk!hsPVA5OZ~bv>g;d?_qHs8 zCFn58i#6aoZwd*)zy03OfjESiml41wZAWWg#%PF-0BiK>lf#1)##t<+_gVSn>=jVG z{sR`|nea`@qtRMM#}dMdj=y@fsTM+t=MXX`pxCl2s58CN>+<(53EMTR1?@1s!UhNz zA0T1yGfqsHXe9d1ERt5*nnQEm^aDj_SFZivmu{xz3DwlI96M&h#chtg~lh@tevO^(pN5SMgwUHpS{$p^2~#jlQbK(aQno=$AI7%fJCweu7e?5MO* zfPHAQHoOzFnGy80j3Q>`;M^m8qe1X&rkZ-Ndv3Edwp*{X{2?Q{<;lBW!5EfaifPse zC7K5Zz}oT2V$<2A=>_n6u=;lW{iFqkTAQj<{vOR*uI87flO;P-K3Q)(pW^Z8`A<00 z+EktLOB!;xepw@9-OS0lf);uk82K1zs!okzwEJFuxzGuDX<*9X{k6sy6*H-vkc1-A z4-Y&=ZNpqEPzm7r4b_BUlYaz4c_8Y}RcoQDmkiA$5`a@kJquYuQ+46qht*5 j04Y!0=|GNY91Bxel{hfU)#i;bjeXFf0r)cg|m z+s-(^7BF=7szJD24*=ER!!^!mfoCz4qOTO&dXl>^D)ywH&zYgxW*M#RUNTZ zr~AaLQfyyu=r(kNlhx8TIFjpJ)Q^*E&T}8W*1G?Y>Udn1qQUU(#jh9Nz-7N^o35DT z!r-rsZ=OjmcIw`J0^IUPH?!~uQ^MFq0Xh%+!yn-p69D2uv6TD#!|b>h@q#e1M#-YT zi_jmA2!zQ7QgeUW_VEscxD3AjvF6E;b0b}CsiqqYR=ZV4r=9tv@`q}=A@tM<7Wa7e z?=TA>5q~wpZw&8Jg*s^>jmvKpyS^|s#~^};=EKW7Q72{kDlOIIJxO~>ohqL9R~WaS zZiU>X=tpQTfTX=xKIz$j{av76>=oq4FoWFzCqO2oyoPZ?PlCeq8MbyKj(@ehbAG|7 zcWBPx*hDk(0RCt{2UE7WvI|y{I=Kp`W^N?6#XebJ7cRNX!w3;1X0AsGs>YSsscD6-0 z&u`MlajasswG2DsXC-l|Y^3<}JTDi;qPlMf>>&Hm7DfOD84o?rvozm%yxxDsUu6I< z=3{9JV8Et{7i;i%1bFc*9*+Pop2ceb1a_#_SK&2)0R8fJHiD5h`ZWLoI~S+&;wwh5 z)Br}k=1H%UZwK;y!IP2(*}LB`}3d6kQ}gYuuu1MGTK##)IXVJ=)&odxjVpiKSDoE|IiC z13-+cbI8jxU_FPC6B$8`V&!J5THmdO zTV1Cxki0+4B8yp+huQHymsJc~v+UZA&5%oacGa*xmUns3Au7uZ37Nfk6eT>mdd*Yc ztF5ty)TfuiylC0sMu44>H6YzRJpFxk$E6L*qi^ZxV{K&Gh^qHn0!OgqLiBdc{~EL8 zi!K}SDMbLU=$d(;h;Am7MisuMG5dSx%Xn!ORsn3`B5O;&1hT?Z5bl4sF57rhxo z5ri2-QHtR^0N!>h4dgA>J|shAq-=i90KKI^18(j5uYpYHK!SK-()-=on|V0$*6ohj z-e0K!s3I`yp%!%2j`l_!LzH56>G#ohdEQZYI?{7g1kmAv5z>ngtc6>76wT{3s0iEj z`zr5`XkQHFJkJwVkJ05K1F0H7h5jxV8-1VY{T{7M7f>>QtcU7#*&H6#Age0r-BHoW z#Q>V|4j>6Im&=Ce%9C*LmK7ReYJwsZy}RzX<9VHOqqgPyfCWl3%7nSy4}P9d_FC)8gmN z%X6S2ljYM|5CODMtc7VI!(P-lOf^De!XQ&6dvr(FW#JX$qY(f;1kEVYG8Y=KrclNHFc9WjG^|K@aotdb&;l1 zsVy}B%S#}-ApOF`GL80R4x`s0&*_DmRlv!8mWF)Hia zC_N*3>Hj`}o@eq@wFY23pP{o8GDa9VO|*v5!|+ouqx4Y&nFXdWx=W6zqlwaLBr9uZ zLk7SK5*^4hA~y6hbDpd-i>^B{>iHdM1IQLFOd&E_0A}Rzim1`=EPvMfqk>tVN$Upb zQ_h73a7T!ok-IZAbYbclSrn0&x?}~Av3L)Ao_;>;%h?QpJRHGVMEE?IOcJ_A*S}u8B>r*;hMc>iSm;9~0|J%6# z8DSgv;@`$s1n{0jt#Q=aWauDTRXP>Ea{g&OpmF8}G(-P5|BP0ZrUk1WDyw{5$W@gP iy>#AXgm)UP9RCFdzW|y^yUYy$0000Px*u}MThRCt{2UD0mjAPgkc{{JuM9!^xOV~@wiu!*`ORc#0ugN;3=+q4f}a)PXS-t3)>^W6Y*4%$>8e%4!ZFzCwRJZeAEG| z%fVGZT;=IJW~l=p<1!aKpLC9~^gPe=*U(5;`6Xpp&z}TU24?GUxp@(IL@glDF-sJ#Q7dL(4(MY|0d}qxyV^r;V zY||W3%8RVMuaOxioi9p^HLjuY5xM6bt^;Vs(I)raN#l;*m~||6qoR4*lZ)Pu#@C`6 z8t)mCg>+iv#3~2Sl-Cs9nTKU+(89LHUG7AKDV((OPRYN=3 z(f!{-0=w)ECND;a3>t&VI4@#&WnknPrNk_}>Z-p(d!PDsaMV#ECzas@o}o3_qg?Ab z+CTcN<@gFn16$Ei+oP8ZAB=Hly;s|C>z$<+8uOI=U!|Y67i?O%{5lvpfR!#7r$Hf5 zdpASq?(6_j!d8vT;cCuJpaiqIGYexvIf8a65_KlFD)RQtDg#$=E^pn|d>0ZZ7pYC+ zDWCCfW+O(qGbJdK>a>kx@~V{UrL)Q?pgEr>|H1*rK{MW|u}>@fMds;a8Dq?Z+0jUv z980cdU~~#s@Bk?nI&f>(kA%&p0IR?Ca};;Z@ex#W04AzTmx0+F&6Yr3XtqkKXg$vM zuX-Nmtaf0la+2?;2p~6jMoHGgvr)jyzo>N7=3ZrZZN62f-;;fDl=D1K=`ARqNU*0K zfhjvZ`HW$#b*+p5h%3y(I;4>*VA=sZVEmyjvNse6D?fK_g>^*B;AQVDqB z_34E0Q&6jb*5a2gY`YbjwEoQ89hMIAz0_gFcR6oGq+;$an0eF)fCRGnJsJ@h2lL=X zsfd16ST(OldfEMy{a_hbRSjt4D>eqnh^7>;eFm2EGm%nzk93xIEuI`00jx>n!mQlP zmOK_?UquXA_K)ONMMf6eBLK4yc0v|bUX6}t^^y5GQjTVIL!~Ry!RyCz4Yv#&g;nQj zONp#Zk7QP@XLY(jgtb3grSq%~FD*x~;htH*aa=#4f;`n@>#`q`!S=Vn?2GK{=@dc5 z!SgB<^)rET<1)Esb^+N_i%v~8ooM@F>5Ozj;~2e}Fz=-j8C{nB6EPKJj&TAM8L9|a zHrGeSMWdVM2yB!cp{4+BQdmlWHZ2@8V7(qWMYNofay-^+)rH)bM$MF_nz zhnWZ6CuG~0bw%^Ov`LqZqLT(W=kdQkAND*$X_INn%YI&JVHeM!GW1(IjcbbnIhHjC zQ>vROK!!*w#AS(~w+WtOp)xOP{PE|iwk%kuxtv~NUp4t7QXdM9mL1-h2)P`MZaF79 ziP17P(-uX9xJ9BKb6`~m@WN{({4y*#5&=*h$vXVhEQ92#L*eHDy$STqMcn0E0GZ2|8AU4Qkn=@r9i%K^rIZ0Kj- z{S`#^Aj|=@u*}q*EC-lL1I)rLqB#4^&d;8HtE97{1Y54lckaIt#4OTtge(V$fRQ1c zdemEUc#mWv2RRR0OBk&dh zyxTw2&fLt+$bW)9Px*lu1NERCt{2UG0wJFbGUmeg9X^{Wy6=$p8b`Nw&KqRc##`Fy_bTg^v%Bbd@gC2h|;jIfvUw)6~B84;Imz}5Oie&R> zA&e*@WxDI|r9ATaWksM=fGqgNXZdUhi`FB$7Qbj7;$<00HH|S*Pya4Z{cS+&6umU9 z&;ZyUG@@tPv!yjwuSL-TW{kw5QK>&Xph$ygq0iDmviz*~x49dr0i*!goF3)qt|yJp zC~WI_ReoK};JvDN-nMtS%r3w)1}2AFLd~i(v=Lai^8%;KJ6aDtI;q>R2wZV^9aycU zC7ajA-SvHj9%W9CIwG&g-H+oqSOY)=G6GlWRN71V>?sG2kd%8xgny z)*;HzZ2j^i%yOoPc6bq_iAR?RQBhWf7uGXj^QRcVswm*mJ*9vxc@t=XDOgZgvIMhu zMDtMSkGcaUf-qwdof&$zU^!)!icUqK-Xsf@Dp(6=`5_~!gnp(FLpnkGiHgya#~B7W z8}c5(!>I<4i?W7bZ8o!p;UOzvx57=NCa=a|zH6RdRABRS23|z<()6hYKtj$G>?A;e z&sFW{tPY5!-$kVcNc|QdJ&&EAox||Z)|~ZL_Pgb&Gw2T^)-TDAeQEjRdi`0$>;j^E z9_2o?#sbTO;rFC|KT0bz!SXp7%5j`8f|xdst;W$B>sg1#-3QBjXPn4;u3^<`nJ$1f z0L0MC#a?md&9Qi}ynYj+2+6F0_W+UrQ~0p$m}i+Rub+-pdo6cv8|VTCK}4)mfivFB ztY_y+SP^B#yXHG1LV0@2(1#Jgn!KtV>=;3X-{5%#R`Io>bhdWVdUyXS7(HXiCAj^2n`zG!bl5au;R$W!L1*X8&G?}&+@tvpX&)-ke5x~MoL;&b|g5buD-GwX)RV(LBDw8z|tp2t@n zihNn?kc`-PBt@j8_Ez%wH_*H>gYU^AgXOn}pL=1|3UyXnrq_8b>#VVr$V3|^YQLhxv^LEO!h~lg zMKI&6N323;kC{|p)k}zGB-hJg&K@iyc(n##JfETS1Tcq|DIl4{W%SU#3TBkvHIP|& zieYp+8s_lXXm`2^%p3+QNVW!$-~|l=smGcte>4yfR~5Sa|W~S0X#4?(A|a{mt*>K^nG=Ksrg#QVqM}{`guiy&j_hk z)Bsr;Y}AQxSIVh44VoLKfap?)U0cRTVg3&>=R*&hI#}CmM@`ryFtaBnNqE_7lWRRtCWhc?uTV<_hoZ2X; zt6&uR^u74q_W;@U)e7O&F2O_Bu=V$-141cV&lx&+O94^7vBo?wAv2@Qh(@-ko&6m_ z%O&@V-sJ&S^lhy}Px*i%CR5RCt{2T+x#3DhM=N^Z&o>eR9en4K#>J=AP-Qt(_PJRD{MkdydvxZ(oew zKg~am<0ebK6MuIq@4cTk@L$1G=6;C-poz|H)$)`FEexUHCZw0dz{U z4)K)we_$&K?7c6AxYhA1n00HPWq%3T?}@jT<~_jb1{}wcmf?+K7JLQBc4QNCiS>ky z)^N1ex-`^U{LDLcA?C%jbZGB)EV#63))5Ki^V(M1C}Hh`Y(IMMU2c4}1I+JR<2Fx* z-M7J{6ER_$k)O@i8QUws?7{s0G7>lx4+opswS3naUO-Lm3~ikCeS{42NM2;~&^!=O zg`tr|#u4S3q8};Cb%5*_HP*(=n>{|uehk>t8O_sLfA)I`xzLs~YhMhZ1A@j{TuA%< z(YFB(fQ&~*v+pXZfgy8FQ}0O_Y2(QR3?ajp=Kjo~m}RR~fMr1RUB#xH$O}oro>X&3 zu*yAHyqFr-!qq2DBdMD0RwTOXnY~NM5?-xxL49Erz#?Ms$|XpqyhLe3lXvy=Y+n^L z`5qyCNdk6t*}_2E#Q8JJU!H`jXloHcPtWNp*gB~wT|`*4hv+HN@GTCoD+*Y0Pbr{@ zDqtm4&p>ik^)ODLRSXspWg-aE=E?E;GxHkIHd~vwrtd@ok&+BpmLAdLI`i#pkmY2`iba>asmTF^W+M?@QJox+MVg=}FR z_{0H_krl>i$msFxtBhnj@dOS~`p?2GrXCsNZJ2k;tiFuSozFX}EHr<#HdF+#*nP$@ z231kuNgJ&_-;I-_^lpD0%!FHukRjz>-Rj9kI_}caPpXj?v!CiVi(#x)=>}QsNvKm;a4zx057d-hEpI~@K zh4VA1lF@}qJw{J!69>pH80z;H&eoy|V_qen7Fd?7wMQJKs-)f)0jgNKr7+@TLvPdx zA~_P}?1-+&oY3c}KGq(l-^a5o17~4Z#-@02^*`F5* zQ5LI?`BUsUhwP`%h?a0Y3pzvDFz~$I#p2SorFBBH#!l6D4vJ*h3*DCX@(}C<+ zC9u(c)|z=~DWX4O+XOeCbg z4rcO{RSvSoYH|@F^vWDYk5*x3)#(}I`mf@3RVVNS$dn!481KDw zLakk%2&qGkM=~qgEJSiYdnl|vo^wG5@N#~nc4fjdx-?-HJ98p-g58uVJuG3g4p!>_ z2gsIXmM)abwS4bYDp%)X7EuRe2zNG0jPWN2V9D70Ig-OQW3Je=yB&kAWW3OwsmL^( z93ZkttRYzrpt0=L-1vV$W(^Q$3X?#Mka@;LIDn?lYiI1yh~nxqt3MJ2tnqSA42P2M zj^pqhpyFa9$^kN9WN48@bLt4`+)Xg0Ud>swOFZo$zC6P#S*wN$4iJ@*i8=^(rJT&6 zL49A5%|RiM9lvr9z@WMUkn*&X#UPqC-JB6 z_OR;MOdE1CYwgE+h5onj+3O>omc0jvAnN&7RuU`D$)qaz-f~X4#?S$zr=!qUwb)We z77-a%2+vjt7AhkEQw2m0_{XMT-Wzn-^di{1jBS^dE`J&(Rfs3xo7-Ri> z*x#D|$D!;5GyPX_wZ12!VhxUdWdZxc%M8yPuSy|PSQv0oD1o%TPW{T%_G nU`(W4bAr3%RJ3cKck2BQ_h}N>mQy;y00000NkvXXu0mjf^7KZs diff --git a/assets/dolphin/external/L1_New_year_128x64/meta.txt b/assets/dolphin/external/L1_New_year_128x64/meta.txt deleted file mode 100644 index 06c2ee6a9..000000000 --- a/assets/dolphin/external/L1_New_year_128x64/meta.txt +++ /dev/null @@ -1,14 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 64 -Passive frames: 4 -Active frames: 0 -Frames order: 0 1 2 3 -Active cycles: 0 -Frame rate: 2 -Duration: 3600 -Active cooldown: 0 - -Bubble slots: 0 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_0.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_0.png deleted file mode 100755 index 0e86e6641ad50bc72708a7b895055522815e36d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 820 zcmV-41Izr0P)1v7=iJOBZEdWHjA-aY7b&xlmQc{Dndu)E{2@XnsnFVNDlS}PQBY`^8LX}% znuTQJqM~4B#zm-92_+Bf zi2p4g0OtWXwe8q|fXG%h&?xNYu0n&b4sL z^QO4X%7Pd6w}FAu%DJt*<9W?LZ}sJzDy)43;DZ5hUZWUqm44ih4)g{eVM}X9JCviI{E9d-bNa6iy*vm1^Sk%H{e(E@vBc# z-aP=|TlA@2q#79;JlIL1;H0w(ER>@j&yA3SNAp3&T#H2>$DO}UvOsY1@;7Fh)u(4; zt7iZxPyTM3-}yp`+0emQD`kSyQQMw0=@Wb0>0bbdoVK6z&aSpu)4j*~fWh82J(ahs zk^ZhEfYWDrc$Q;hgYH!iU><9-BSbx#yM_UN8nQ>e1vk4G9Zmr(R&7rJ9b9?yXnzv? z9;|Z+f{l5Tx$42x*?ZPK)0H*h3u1W~-EK=+bL4|;=wAanQcUf8|2Udo2oy+Cdv8L! zW>BpbXhV_;PA=Cmfr9i4`d*SM(!HKE(xp(jyCf-y=RThl2`wDk>F<@KOZp)req5=I zt7oqy&E?_}H9tt7zmbrnS|wGI<6b=68QGTva1ZnsG5TzOwD^4e+eWX)-a-qNT3C{T yjOM;xOQ2ei-mUtO+R?u!EKPKl0XTtM6#oJKCt7uy9%sA&0000O9aKtjFBFS<5rrbC%}m9M zUgRQo7XRX1b*D;^N?Ky=V?0!jd8EhM#x;n(iGKn8%i01^Q66Wj%mffr}U0-1Ob zAb^oTl>oMustNt26ldfm(WIn8cS^nw*cymV$9HzJdP{oZX z0DX}26@XXvB7mt|#QDeoiB>l%gnMp9<1RSsACR#L4*RrA4QTF}P@O3{P!=X&k|;Kw z{GG>YUjb)6wR^FoRzzG(K&R@4c1B+{Ck6u80E)uu#8e?{x_(D|nn3F|y%Owv`RPM< z0svYxdV1{gIr|r%6wR|rG z_Ipb9%K2T_WLJOdjU!Ia9LO0bFr9z*qjY7Kfbu;WBwM0Eytoa zv${bA+da&=CaBL3UV&D9ecr}20W+2Rq}Z_9H}LJJs7bb1)9v4MC!20Be7t`SouEjX zTsClwx2-l*f?XqA@%P8snc^`e*gjXTY;jv*Dp1Iz~P7fSP6>B%@=;M*NoN z&=$~kJR8Xvu~Q%XbJo)dAR^srD5aiZ-)UR74#8G8#=Rxu>vO8x(`%goMkdxKM;_5P zZ5{Tx07J%srCf@u9_7-oIH4>{e&LkJ13AL?UJoUdiY%}6iF|KsmFfb)$i%E)32)oT z?B9E2TqG~)Q3Yqo~o zxmYX{aZx*b>OB*Z?-*%R3J$iGAKipVIPm_Zv=l_ja&*?#pgOGkGbAD6?ryXZk;1r$ zgpSDY)KMFee7R0UWLTsi-{lZl4&zc)SuWa$RAgPDvy}TEA-!}aN+5?L00000NkvXX Hu0mjfdXb+( diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_10.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_10.png deleted file mode 100755 index 5459ae27c3e0b2d87cd3a2b68996ceda57cd6f41..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 788 zcmV+v1MB>WP)EtRqp8xfd%lOk=O*D>zE{8R{hs%EA5QbX z69Qmufyo`u1_Y$GvzL2?9p9?;NLR-=tK3H!AMk?h0wr)JIMuBH8gL~tfxn}}F~9Hl z<$3d+?Z7x3h(1Z$TV(8#I-a(CS;x3zBfP(Wy?+u2f9ZjcsCemK z<&Wal6rHP)KJnQ2Yvtay%j@gj8B=M*sn}#EX+NR&Um>=qX!_pf8Yg>hEzIEY$uM!~ zuUHdl*=yJLoQZl3Qs7L?KGb=y3kHxh*8cX{mbzm{kTmB!c5`-UTn&J< zi;4=Jp|JJtQ2@uGxF8J={k*IYuw2(H9Nf*1CmUz4QUwRhM%rSr=%v%@1-VHpG zX>Y!S*k6sK>@W1)wyDj22^axEz0^)k#2Eth(ON0dDZdreV{iwM$xVfJ3=R;nmUjlM zkIP-KkC1@=DueNqUDFnguRnB%j=2~?_}!KM4^rcK@M}knfZv+b-#PpJX`*(@2BJ)} zaNeHDRUsAFK-0he>Q9Cj2YSXfuX=A1S-C3gx@!a32OlmiuH_RBGzvD5ICz5x0uoat z{>dS!r6pY}w)Cs(4!d3ZqOY|2)f=COOUEq0l(VRO$UN>m{f%P*rjW;&`K2T7Tmw8Z6lW$uEFf_3*{&fP*BdvUl3oztSDYF#=e*{#<6Y z@2PT-f}$j~78AujRW#=~%x_4F-kx6gRJYs_*EOv~0=S@wNBws2I@rmXS`A)kr86X- z{0xjPjE+M4?q1+r4UAUOdqB_spqcWYb+E}M%Vo@AOo3b#kW`T*X<5;T>;4B1IZ1|x S#su9y zXzB&EP@D+}ih{(@X_M%bTA~QHMVd@Y+lgp0)1+x;&YU^F4|6efz3jcey;y7gKP>j} zzX$+u{sV*8eH#$awvz2^UTou3wn^%BjQ2M!)KLP8Whk`@B*5FwGi6BBK^~5Vrc%Bx z!!zfWgB5Ly#h+_Mtr*Q?Q|*O~S36pyZ&YD)F=)-@3=BUtO)xW*`MN8{(m6=&19!`NGz28WWYy2D z+1q#;8#7%4>R+{grs+~ag<|;qeU-2dT)UpNLrnkp%Qp?vkksdoM7O&2zCB2q^rAsE zNbCd5P9!bNM#nGd%QDb@1W7?6sy8)N0=&nOq>e}!Nh$?S`fDTL)RSjdZ#ZYc!?#qd zxhr<#Lh17CddFkQqNHjmoZb7Atjo}DRGw6jONIUf+tP50#f}GqIZXdUSuX>36-<}@nO@B3Kfof;!_8)rw+(TC;ykfz3 z+Zs!+ik#i9-MjZss&8!74os3!|1P@JqO^C)hRgXd3V3~VaW*aQ(dK( zBVB#P?3!PZr114b5K-1ir#FsS0MmVwb-Aa;(!pa$k_xATeam5Q`irBg?^UPoj(3>X zyvk%>=v;R5m{&()cOXqk3LlW9 u3nR;Mq(w=3Ly{^F&W|AlYDO5H8~Yc`rGxxvN7noR0000kltwRJ zHqlzsn8JD1t4U*p9c#2VF|pAm3NBb#Y=vFe5@y-ic^+mVzRUaPd*A#M}wUV0b+eehAL4h6(YK+)S~90XEeon$0@jRSee z1**;&2U2LCpW?xeSzJ_+`+MV|XB|L)n`aCBzmD9N9DuHZ(CO(LZ-gH-r2tr3l^L;t zh=jz-8J6!X#34GaY(O_2UWzjVn5E+Yni{+@Dhu{LyZNn9T?(s@Y97h_%fF3;*|l64 z4QBKGnSYn#VJt@ClE2XvRIamHipXqg_Ee4_ZP<)L#To26V6Da&ME`Geo*HOF!ECLr_vT<^KPyZ&y? zf)c1S`fIsY%e9pgb_i6X!JW^z8JU}?A3#?OD*E0FdvVCq0_AEJVIuEarTvP0NgR%&>G&UbFoz$}i=uVA#~b z@Jo4rqi^uVLmy*$I?%p8W;R6omrW~_o$vgsqp~|Tvx_aeVN(MJ(5tCT&tl7lb->bL z&s5C(Vk+OL&9>t;O9{dBF{%qaEO$IV zv>!x*Ga}WfB&%{VxnU`R>F;g-aq}-PM6T`+1B%6<^tj6iUP-m5bf9+=RR4pYg2rr{ zr37mC`h49p*P9mG&Y}c37`tV9rq~y6ndm7OrU1`WT}F2X?v_Q$YsH{bq_CcF994-# zsQJ&G+jo{N?>y+n71xansHHc-xMG2>;u-iTC;$NOo|M2iWDSBIL?2C`f~p6notk`0000R1tyh>M^I#_qv{QP$XrggLvOd7m!M?9MzFFYo`y^Z8emhj(nv z&MH@wAp>JwRUy-zK)tsfn@+-UZl|( zT7umoary&@;Oto&cW3Bxp*q?DA-WPrA>Hx(-0YX#T9+ErYr6N+8=_3c0}@aG`layq zN0$!)qX#{0U+lCF<*WJUhC+sxnbha4L=+=ZR}5>LR2JCsG3^VgcA{F1 zl`I{k9ksc1ZQRVK zs9{9@mEvq55&=BuE5Rz;SH`(93Ah+Q>i_(-uGBK1U6f$$-P@7 z(E61dDTey6mx6n*{JdiTU@i-Y$m03`yu#^%@1Mr^mB8YP>BfrpKk}dvmX*M-&%Chl z^X>1_z%FK#(CW1d&HkQIfJ|&a3Ab}S3uDRBV(L7#cer#4ps%S;ym8{*ajG1z0Yr|u z{Xpp)Y_$i+0q*3CF-`)`7eyD~@B#Cz2I%*C_Lm^JS}}PwK;(S(miZxq>)*I$GhQa# zoxo!sB6A1#DPd~L8DH6BTi&P74SqA!tz1T%l3RUw>0QI)JDF~1od#ln~EgM8``UT%NteSRUuc||C zBnU9%Ym+e8N}%_NW1xh^KT1|xb;RS-5DZ*8Rsxg*uV%r(BToac4{`w@QomVk$$b$K cTk!q=0mCXct2Z>fF#rGn07*qoM6N<$g2`}%OaK4? diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_14.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_14.png deleted file mode 100755 index a5d6c1a7a59b8116e393bfade90b5891981070b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 813 zcmV+|1JeA7P)1v7b7Rs(o7gnOg*DS66-E$$HkCr=ieeTj1et54L@9!bl#=W!D4i)HB3-mD zBK|A}E3_q3jZ`XySZ7>F0;NuAp%t~swa`vAaemsAnaSKauZzi~iDz@Z?>R3o@Aq*S z=YJ;zz_|-X*F75$(7BfFY8CFvt!#@leT=`rD(Wo(#p+rE5BxZLniW6*8EdNR6~6g% zU6f*RCS2RQZ?Wy0b&8$SvTJiO;lI}MFaX>rG!-oiw{H~M8ml10#-{6slXoSKdF6}U zzj|z0Wy%){3Wx>Gtr(Y0qc}Bo9ARYw*+gAcqm|aUnEQ9r;m&Er6R9{RyRj9f&4}QK ztYe+X#{l%Xz{2$p7vpS50&I2w9r`r-`sFNud7MylDk&`m0A0t8yl*#Mc-|xO$9I6g zOe|Mc?Dup=A>d3-ncTx&#%>q^(%`dfZg;_ro*&JK{&~PT!5#NrtgZLNIfm#<)8&E* zFAn(aFOoeu0sTg(_Rd%F);6L>F!u6u#~{8~orUv8Fm>_F7J$%2U%G&0>g%ntfW-- zec$&Vk}J=g8cHOS-9Et0s%s*2!V{5TuLt1}uGy0fVQ`ky0sQvnlH2_0r6`XaLVs`e z9athzww-R@e{A1pB}yHO`%?`mq5hGW?z`%Al-tgfY^~QLeQIyIH=w4criPVln^##{ z8ajX-yn47^O?;G>jZPlTh*-XmYuriYYEnwSB*aYZ)|G?ji}N<2Ym-sQ+3|VzCzWvm z<1sM&XaM&8L{W{63FTzBrKg3Yq8j_8+tS3Y{qxj%ic;ePrNV@+ovg&j-+C{jM#a8u rQ>r~%IE&P{qDHY?HF?>=f6x90pDlLgl6o*(00000NkvXXu0mjf1J{uq diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_15.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_15.png deleted file mode 100755 index 57b2c9bbee26fbc31ea9e384d8ca8c44936db89f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 879 zcmV-#1CacQP)~9or#-tqXwE=trZzs6*sn#Qc^H<9#z~Z znvGTpHdzRj*EHGvpJk|zVmyz3{er~ zRJ4A-qSzE22f*LtK!6Znr32yxpa5V8kOUDc9n>+g7yva{Xara*@Sg)>UsD<0H9F4%#7+c6@3i;;3lqVlFP?gN7EtTWC;%2# z#Rt^ml^V7kc?m2Jsjg(W_|fU|hYloy3n=+GP3T~(?GFi-licd6WZ5MW!Uk-bp0CnH zdV;G!!aw|$6jWZssSq8i``+Ff`{ua=Pdyq(|Kd!Z+7C|A0as;{qC>(E#(S*jb* zz%}pic+asr#b5aDQ=TphvIIU13}^V}&P1 z7AI2-Uz|81a{PEhru0d^T$|K(b8`s#qVomo%#_-Z(oa63UFf(JZk5-&^^##mem^L( zQkLlI9`QY+yJ@_a<)q6fgQ!Q1hAV%kJr^Dbe-7`Zln}2uGrz_1J!{)7|137+9bI#E zCp@g!Y1DQ{b8Xl6lSN-SjJjF%k+ErRSGv>zbOO`Mn$Eh=J2wY_`qSCMt47NYttvkR zpdL=MC505m65=&TyGYK@|CmHX65<^qCsLH7w@vUlBc2OY&dz#+Nb$0G;`s@YvCL6} z$U?t(;>nmuPA()h6rTVf4oyT-h~#c1JSmHa_=&s8e*u(ie_+i17}Nj&002ovPDHLk FV1imcqT>Jn diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_16.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_16.png deleted file mode 100755 index 4be832c648910992ec977cd567913fc99db14545..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 855 zcmV-d1E~CoP)KUdworlw-BFPg1P$sm6{!i*7qQZo8dHS0D;13N z$%nr9vh_vEth9X*1EygLLIXh(icMPr*-6mG{t20q(4A~%=lHOj&8na9}5Wptd<+DbzR3cxt*Ewh4m34o@}VAfhVy@PsMiN2QcLsHlbZ=iN@H^J-wY%Wz~Wu%moQnV?E zl&<|PvNT)+NkmHdy&`3)&FwM(`N?Hs)&)@e2xVUUoXm*_(C8r9Wtr}g<)JKd+m=go)IkZXy)*G?=PZEl_9=ml8wVe`O|AGu6;sJtb0sn3 zXD+({W}vAs*>m!ZR}VcC)`OK3@o2q4QWn6DvXY99$wCKH9)OqDB;-05bL=?}a6g5J zoDs=M=s1q!WE>5ca3Jk{Zb5kKsFLcrV3e8m_9+kUWYCB;27VWN&La=c3~G!tUWc2d z$>vVxHyepoh6`1ZoFx0QlC(8y)c2!})K!XaUMePSME>aSm3*uuk44sOTM5x87pvc! zgYB|EAD9>x3mDb(;WpHey}MZCMl|x#w|}jaqMR%`U5;ZMlw(ppg{Lf1z59wq9nZh^ z*74}6(^f0-y`z8>UYaXZzYtj!xnSEivQ(%JRL@Bv%*mqTIGQ#KpD$%{AWf~ULk_;(y4AEptLo<`ScaMvi$)DcMJ@lu9EEl#Kq`+yXr&IxC;l5FY?FvWz zxh=}_@^8V`xBid=!`l>x#>H&S#Wm-2#X|w`_fknwvCws=AQEnX0FxYFA8RG8|$;q6XG%r=c zSh^nM%kI`Ly9DYGnU(x~U!>GGVZmPJIuh?c$pEM(ME;TFoG+3E*zGC7D6=b#Ju?b8 zXh3q$f8Li0HCPTxFy^m=?SKysXi&jayj!K^n|jMBZ*FwqCPN5yJ}7~{caIKLwUIgI zQ34}VV-1@-1Pmj;K>M@8!?NPh>g<~?5a=>^_UZoWMv@upqFVwhC+@vd3$PdiL}YE^ zUpH|p;d!_4JSDKUV=}+v^Q$i8GifF8;LwrA8^)Qxgn+#_u-)cCD&`4+d7Q(9e}YfUK>b?o8c{&#~h1?Em)xqyb(Ibn|#eaqF=P7ftn__;9!x;sMT`- z>J#Un?;|s3`X$^euZYZh3D48)nY7`I%0ax<_tDf3jzV1+K-KG)K?!TWri^9OC70_N z(D3|n3Q#tjjDd#YTLAPx+y_K*^ZlW$i-?$n=e+=t8zr75sa7BfZXZXg8NeK5LsQ!P!!h0x$q9-Z^pKELh6!9z9p95xv#B_CqZ&{nIMI zj`RjmE?4}-CoxyOig9>&u(XuqnK9NkPzYV6zGK^i3acPu zp+)?B{7}3KVixL3k%|63wxj`C9Wd`lu6u`n^8w6m0_ls7!(GxGK;yVk(!cV=KW`EL z{UYF2NKEN={nW0k0>JUUG*g{TH`^22feg4*%-u$(VX5J3)2mzU&ga~-O%!OJALksR zB}1bT_nL#zozVmM-5#_V5i}JeeH+*4vfx}Ys~4c}uhJ#BVnq0NOwYFgfkmh7$sv|w zMo-5RzB8OwXe;F?$X^`vU|S|ESSdY_{-CbSP5Oj~#=o*#(>)?2lF0zwum5UFqc0am zE*1{I8)KQU@{&=w^2@-i)7%3iKKfK=02nL}U7#U15`T3N!0EI4^QVs3 z?o+h505>pejJ&DsllyfL;PQ3WLZ!6wtkmUsp0~GX&6c?&W*AP7L9h>_%KXGT#YgfZ z$G(NDZ(B=r;KTHL)2s3N3|eY+EoK0iySabsIj-(J*^QK2NEQ7(Qd@6A5Bz~tUdR@e zmwd zO=w(I7>1v7@43m%Pdnq!XvEY+Ce^{zI;~I}qs$a4wzv{|W6%gOq!B?hJ4LH=t)SvU zLZL3S+5`%XorN2PqQ;q(;zAwh!XFwk{Yg8f+L?6H%)QCX{aoBh?YBAbocBDOZ}Bq8 z#@OLe2f(-ij8OoBCQu+Z?xJC081MjeQziKg=}rLj(3K|#+@>d50m@#anMnd^jENBd z(y$MhhFlN{U+_kl_~hA}yyT%={!zS}{;Vgsd*DO800ZZU^j28o*FPpUTV` z+p?e<=X;h5X}i=>ZT$O;3kFeeeQ)*omd<*AHk;Lo!Y##eY|F_`-hK|yYTr-A$u7M< zG{not0JXdnKiB0)%b{6Lonlo^R4Q*R z1cP((gY$&tXp{B`nXL=k>Xo7sykP5=sRw~M^PbJScD#@6X)dNf-Ct{cwPZVhLHkx0 z>PBi(>;CN5S&j8)6i`z|lJicnR|)yO^}4QmAMM%hPyT(U5(?J`>)Nx7cgywkJBJae zo=MfDCaKyNv8Nl35*mN3C+v&eg@oNdoB$DdXh%8dmg>43NL_a{FzqMDE~MuIwkN)E z5Rq!7NaiZ0@xpmBC(vNX1= zNV`=hEsPys#*@zakEsOspa6_lxRos51<*!}LiPTXXO&<0MwoGb=;KSfO_gLWeeVTt zZ%dGg#fl3vYfCN>05mLaPNlLRR8ewkSbL|{LL<))Zudw;3lINOLC4&7sJZ)zqe~f? zEhl0i%cJkFisbrBAckyC&t^r|r8GBbV63}G9Ij6}0O}b7BRetY@Ko|LK$VFEnU%X+ zlJDyVFioV8srzb6?uZWk z`sZl*J$|J+N`YWAqW3kbfs+m48*L*15l=S^zPt9QR!0s$URnwL*@=z^yCXLvq-p$%Z*QysNn4?nzjye9?zUuU)P znq>vWJ1R5g!t{5h4u1iv@)JL_JcQi;Fs)U>vO-&m)P%`&>zIk;z6m4{nUq*}r^HNT zVg)WSa zJB>!GF_F9>tW+9W?b{e9F%c4DB_Wh2tx{T$!VJ!x`sN)MGt#-6d(W41zVCitjvDWJ z)k(8?^m}&uI_OR0=*`vNH!B6r>Oa4_9U~M(@&K4N@UO^Bo33?@h}i$TlK_8=kl(1<4*5_WLJlW{%hR8cAHq-F0tCAlWY!ftXQZrk%tLa767O)Eux&PC|SJHNv)xg;&YW>F+0s!@}Zo>SK zUP@=D0k#&9oOP;=r+1&o0~8A6&Tptle|$wEK>NNa^*e7lcZP?a2Y9xOs%}%)dvD*j zFes~g^eHgioPS6iJo2rFu&WG8IQwXl>A?YlVZW7aKM+3i0u;)C64nwI4m-^=&)u+< z7I4$a&lwqk$h1aQB#iDJ=$;SsL=lwm^?`HaYRmfptnCIR%a{7njh^IeDj**9F>Ihr z%_}`P1`NNLS8`?QoxLAD9v=RIb>a=zu*3WCcu3%V0^nLD)}5)mnO@?92imD?ybAL$ zG7fC58xqAK)PVJ73qY7MDE7cgv*eV4>wO0D-@tlpf8rD{@tP89%bDoUL(9D$M5jlU z&|I26X{`Hm2p2Obfx+aAYu!6z$l7Pz?1Zr{Ivp=Nw(5;}?LqsCG zZ|XCVK>L2yH-Ph)`s-yl*yL`xtOWQ)XX`!4K+(F86On3l@ra0gENqMkozM9HtZM>Pv%4_IT4XK?fbq_sS;#70QGtql&oyq-dfnH;!*_+I}^ns nfJ)I<216I^jeL^CZ$d11@;kWVw|A_%ItK^W7EB z2jgA3l%Z1jQH?Ge_7uDKzug6#rBm-o<-5Lk-#Z@2?=%7|twr@NBbLC+Rx;hHQD*uD ze|wjxIr5P{yUD$wxhVH7j_J5H_964YtMPjLiaJwT z*7BuKEV*h6#E=>zi_P3y?IG+yQY_t^y_0KI>_uwCYQaJfxd3JyX~TrEbGqdNY&(PI zHcxB)u-+U4@Sd}*?3>sOyv>c01;^{LKq~gcuB(@i0nZmVjOOF_r#PQU=w`oDVBM1X z=@2{|9YO3UvdxHdhkkPtE88iLo`pUm_FWh|A75&BJ7mGF`jx(cLiX>*MYv?a)nvbI z9xW1D^s&+PT5o@l)EAku^Lkz*Mr${E_f)g95^L}I(p_Si#fUT zpLd~H1V&H%ZWJDP$8A2gP)boH+IZHsesm_51t4+468n4!v$y`G4FQ7@t6n*@&D}15 zQ?T&I7+}8k0sg{>@<7Y&!lSBjCxNLXhV6eXKv@8UepLL-izjJl_~_k)&GfiYsYKKjefYg<<;ilyvRvkXk?o z(^{5-Ti!w&T+AqtqDP9;YVGErOHUs2a_KuCX-<-)Dd}3NoLUANfIZOAa`EHXP`8`Pm&ZK4P(h<0c%ii$YU%_p4?zWA_o8@|Yp zf>ie)v-71k0U3(S(Mq!y6%{KunKE4OgKf~dCT+UqCb_xChopF3J~-cx!^h#{Bu$yI z=CtRUgALhN00=iY5D*0-`4;g!-~%`do859zHX z01xIuqcI@iHwpXUb5v9+jdv zfJ667{=}xp!B#6++WM!CtT!AOYZ(`}Zylub_fsBpfI)A1k#eo$-iGpQ0c#n)Cyd2L zW*Qyg)pki2z8TeR*CkvSkZL!irJK_#WwR*t ztyFJUs{V$nYMYDXXH+i+^NkaGHT!AS0^?9B^lsYx;B4 z%D?)F(^6{XS%nQ3DY)j-F3qn@N&Q(Q?K@PsE|n`I(pRnnOxC;qfmq~c!rLyA%4^~A zjFg&D_?v5iSkyd{fbqaH6Rrb9hT1;+19k&5%MQQ?wmS)37oOSqTGFP0`}-D;fq5WL zXO8d6QV=B0N-BhvAF@;fNka)qs_N}UmoSr(zE4R~nE8Ay>zL#?>`4QdG6Qa~idZU6uP07*qoM6N<$g5|EIEdT%j diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_23.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_23.png deleted file mode 100755 index 639834612c846903283f6ed6628f2c79c3fd6a1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 852 zcmV-a1FQUrP)1v7=A^kbt&`HmrW%{6C=M}V3a-o|chR6ILKaRZph%VYN2(T;23%w=byKKd zK^HE>R7EJ0`cp*v12MOv(9&vybP;K2rms`?;8z^xJ(e?|IKT&-o4q z@B1c3g{)W9{bqnFuJ?MtHb&?TwN`-~Tpm1}h}In@`<0F(W5C#|5=)dO83VeSkwxA^ z0AiW}<|UY-O=<})WOKnap1A5&g#sq)@+CKCYL0#A??S}?XT0X{;fJXei5lZOM^By& z#Y^51^Z{EI@fD`7jJ$QLB!Sc}0{W@27@up!0|YR7%L7EYCF|A}SfnTUVqx=`zaA>b z{**6f)TH{{s<zCKn4VKM5y(OT z;I6!Z;83FYU-Ksy0iGE(QJ5U4l$I;y69#k!)pWjThm*S3onjO+pl$~Hv8-?{oD?9zJ?wvK{&E&bT;3D@~|Gk$L#P#-@&bh7VEWB6))9A3Gw6c&P(Z4Y0$ z6`co^HEq9~JYdTGU=3h2j(UB;%HAGd4||~EL*8^-_}q9Fm~R0U&!mEFpYCbz^nK#~ zJVqTw-97??gFx@|eM(L}Ev!8>eJLa)E<1)DAuyJ>asvPgl;H2N*4UK+fZ6Q^n$H2YDFZOPUkOWv{imJCxyJ>2qF)J> z$+fg|qwQh=CetW^F8y!lf!t+j>Fbe}3?gF7 zGV-~Iuk-niyb_?h;drT?;@vF2gc9Hn-LaZPI=#pN5s}5kYp#fl$ZwepA|lqde=s64 zlkdn^Gw8WqxYrh~e3 zL!wPgT(s%}oi=XVV72Mnn3h<@1W^)!4j@#mcBUP$@6pFQE?x^$@8yn@(@;@U~vu zl%z^!OIHK1$LMHl>~L-zE6H!jWk!7SMVMqa0=TghsMH|gY&$-vd+~{g3zMNL4XPR$ zSoLA&-D_G{sultYmE={7<$=NGPqy>)NrH7Now(ffW^24*jRLcmx6_x_2TGyUl|6K@ zVU$7(XD4yABcFh6&e%#VY>GyHaOs2EtM~lC&3^`MLYv#!;AHFb@B<;4nrMZ`~U>1I` ze7g(Z?fYeXoXDb&t^e@-l)kRb9W3}xv834O_1w$uY%V|o{a#5ksPu1 z$ovi$!1>%_=76cxnF_#ljF|2v$^`!&1vqoXLR+as6t#K)e*_k~vH+>qT!?xw;?A#+ zMK-eESKz{{)(9Ry7ug`Qauogfl4pU>+|w3XJud8iZy%ECXIE8~a{UEuxrC%>xf(wx z`A)gKa|%h?lRr_BmZh6LMI>p?H#I5lE`K^L3X8Ri+H#o%@!mnerWs~S<`tEcDn%Pjfu`Kw6H8mQar4y6RQOj#={92Rru`E jl;u7;lYj0beNp@eu20-ipVE6~Uf(?YKCPa%s!3ChnPn!ZgKpNQZ z0|#=Ra)E8K8KD^jI`URfrBJvs4Lm*JSHnEY!*2u6Hf%KZ%y)&qfdgY3&7ZMrPg=08 zq)-BIYqc=uK&SXgO*1yACa|ooO*Opaw^D?$U?xb$2V~AgHo^YTswC@5#0mRg;;bHZ z3FY5+0tsLJx+hr>(+Nid5K29C?!Iv<*S8_6RIaRC+Ou%tvagGQ2(9UseRnTU0}wY@ z^Lm|fW3k-{K-pNk#Co%5YzI)gjb_;+UGmy;WrZgFz1tz%8sSAt>xS+?ku1Rh1i{)6k?NHteb%0MqdDo_0wVf z`n=X!xvPt>{TZ&CXH!%5N*t6l|6YF}v7A`FQ*yi`8I+u8`f|42>8jkSS`_U=%5&Qz z-#lT@e7M&e!K;OpnCmyXRW)$)vvqfN(g(a0wM#DQUEQ6{A|g_~UTP)-KeX5?XDMO0d1lUP{Bp(GzWlHIs((L zt8l}X3p25r+G6!ud_LN&O{7kr+LAGlNV3Tny1V}DG(ZFjKtD=X*ZLx0bgQ}T;nYTl zh=lKFTD(n7E2W%sB4Fn_J13V)$I3Y6wX3v9H{k8w)@c=;W#}?(|1^S2w>W2rTw+{c-BToST=D=u-gmks;^vVo6_VwQX?N4{byAa!t7k%0PfPv$S+D+;X?zot z!aGEs^rz=s;O3gq-t%u>_zd;Hd!s-(Z&beX%uB7%zpV&d*@n!?xPBJKNk`G`n@B%QTE8I-EEN`PPPN8WjZck^Ke6Q^JaxEG%3 z_-PoOa^Y4F+Hu>8FIbC=iCjM>$+c)KUbNOKsb)<4#~ztYHMi!6KuJuByML8S`(`;F zfD&ASiw8?8(aep45-!qHow`RSn&qcK300GcYfU;b$R3aX0WNV?X=dOLZ2$lO07*qo IM6N<$f@c1SEdT%j diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_27.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_27.png deleted file mode 100755 index 962349bfdec5503429689825577af262921ac6c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 828 zcmV-C1H=4@P);MYf0)t1eLxntVNLyloX+DW?F4xn>Lx4kC|lVz2hP?>BPG^=lt&B&;Nhe z$Nydh0DT7xZunLpKw~}YuQjGxC8&`#9c5=&N6iIbu2e6O2D^vhwGJQ;rz2I`xM9`h z4OZsney!Bc=1tm9ZrFI?M~Uiv@ueNAX(#}uX4f`q5^7~o&di2&DB5-Eug~SqtX1DP z_x?f9>aIt8y%2v0r+v736~o;DEi^xOh-v}}MRKyT9$ND;fSLNc>P3gEkVkZT&0JYT zM56wYHIUNPsBVi}1ts_tc>iJmpgIjuT269gUOB)ft8$JgKlS47!h_?0g`9*kG0=KK zDuDJpm2)Cp87qz(e6XN$&Y7-CY44@1+-%XKU?6$C>!-d;eF*pXpmNUCzFW^uFOL#* zdw|Lnw*J5;@+}xLYJiw^qRKm&Htcw_)b33 zUNqEb3X6BW3)_NBrX2OtSTd4OJrK_;W?Lp)P+=G^$00KuI7fbI-c;0)xY~v9)6S5* zXSZ8bRxvLAY@zUQF?w^c$I(=<;fF$we>%ki@tEa4`EDLf|WcomHtkl$Pt=2S9cG-e) z5_8wBH44S%G)78~Q10~6%8j{+4DxU($qj3*IpoZ5j|~@^Ui)`TxV0C|wSjr>!qu-y zZkvx?IS1WaHM2&Rw-*#8yCq(l6|wakAriAN@4v~-jJ0000C6`P9 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_28.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_28.png deleted file mode 100755 index 2eb4456cc780a288fda6b71ff3ca99b931c51b2d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 585 zcmV-P0=E5$P)>Nh!OB=PyYTx622!q|kdqdsU?O6C zY`-77ka~b3JP3L3LgIs!0Zd;Hk+vjd7p0MO?%AFTaRBBC085+0@+}?!{nZ#{lBAI| zk}kVDr6OOCFON@Iau4&u`Bx3c7{kY_)lM4#Ej_Q+6-Yh8Z=k>B*GUKAX*Ese$ICP0 z8L+!^i5ZYC-uYR90EnFzb<-`4*OguP)Ht&3V|Fb%C>5PO>Cx+2p|}NS-`J?gV=)ir zz70x62H<0TQ-CQh41ETce^co0FIr!Wq z)xD}&RR9ok+5ix`BC#9JkkfQycE+FiSLaaE>t?%f+t<`R>!|U-2%8EfD`o&RA>zGy z-TmLTSAiX{>=J&-=7C$F==OWd64&-!+h`ToJoNh)^6=0kLjn7IB#T*5XBMEG*2HBJ~;}B+3L_Rues8tiw8w|~g@?NH`D5Z=;plA# Z{Rey_OQicOEv5hf002ovPDHLkV1i=g!{7h_ diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_3.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_3.png deleted file mode 100755 index e5772a672f9a63d511a03cd14cba48df73df3662..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 812 zcmV+{1JnG8P)Nkl)On1-IBH1q<;PWKD5!)^K#Gm-NXO<@41Ze zzwiNY{sXUWyEY)8t(lEB61#OO-ymB$!zBLg?gY45Y!*ns=rxXRW&kDlp=4^?JLamh z+pLsx{?psQ;nd2H&9$@0>|@QooFtWY03Qs1^AczMhH1c3pIA$Wnni;CTdm=A6HvBD zGSA)yb9kU=Vo_p8H@9Leot2K0zwqQFTQ5l6j6QXzX0%lrC%R+u;nrjJ>a~VMdA&GS z4(?H~2|`92GnJ8N11I`10J~7|-FPYNg|#{NK?{Ww{z7T#*F1oE#NjSICp*rq_k97d za|n?Nb}N4A-5~(?5K6>r4=ISt2ORHP%UI$1<@7syMgR_H)=m8Lea!rPr*}v=q>$rkwl*0<*&ZC zU?yImHA4m%OwQOyZvL-(F;7H0sSqT)ZQ<>F^-XwX41l(z{m9Jo9PDVVMF`%KQW{s)bzRqu$o?Gz2qm&E!1bC94yDt;WaxMT`~j@f z9R;OVIa7k-8>=Q5U;fO!(|0web&Z8)^pVL4F?q0000P43(XaExcZC)XO5g_}>Ap4BQE&%nc>iptZDLR|u?6uJVm%UC@+kLF@2I$vP@~#&R zxZV{tB$?U`%t5S1;qJ5m9kDuJM}JpjA48EIcNKk+9(EOFv?MK_o~iwzsEP7#?DW_H f$=?+J;Lm^?$5Vh#T320I00000NkvXXu0mjfxI%Y8 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_31.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_31.png deleted file mode 100755 index ec47b899c994843115098e2b481d4be9e3545bd9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 270 zcmV+p0rCEcP)g#Y&IE8RMH&I=ZT-N9#$G7Z;2?CV z!MD6x1bD!iYcNdCSF^9tY4hauHh`CC?40-Z-=cvn*3{YeK2>8 ze+2U>lk@GCfAh=B#t>UH24K-BvC9r%eZAQz=j37B8kTNI77Uy6BwY4=Pwc+n50F}o UZhAxmRsaA107*qoM6N<$g4SGi=l}o! diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_32.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_32.png deleted file mode 100755 index 3f345b563e9eeed887691ea64fd476c58e9eade1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 236 zcmVukXtLRdY<7&Yil?6l5smS!)4=ixyV{H|i zEVZ~qQTSxJvPvwAS+^ZYlHpRc4b{SFksE~%lY85BfJbk@bKKYrf4%(Tbt~+$){Jx@>H0 z9v!U*E>kPOV&QLk{US7P`x)X2@FjRl)L3A-;}s^}z6-}5I>m6R*COBYii7&ERd`uB zg+3&W`T8Obyggs*z8c*$1-S7%TAE9JE`yu<`gW@2bNRjVnA)?Z&*lEIf=!Xm246;w!wPWp`HmW)LcC6j8v((m0$X#-)(gTGH^FsQna8H2~_{aHwIgSCq bjE?>S{e=)!nb_>V00000NkvXXu0mjfi(20( diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_34.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_34.png deleted file mode 100755 index 44c4d0d498b2ebfd6caf104f011430dfe5b1d362..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 771 zcmV+e1N{7nP)-)V`@Jcg?b! z8h15C(1l>d;+xnmB8bn0s0B?%Nll~j^76-I($3t^#mqxoUG9(XoO|xacaS8dU}7Ul zvH+yz0pJ4=0SEvKI~0J8h$~QMwbUk6iDv-FZCWX+W})l<4*=N!%mPs`Nk=`_H&U(RQN03dn~zOR4?0F^bcZ+3Jd|f@+2ZE!M+C?0$2hh zw{b3pwgYGh$>~DExEw%JKEP9k2~3drd00M~y~*R%-#{v~l9@dz#;0AHy!)E}^O+Rx z94I<&WVukn2$BWI?n_UP21jE!C^3x zDZI1qZ-3U!AASDMd$7RXZN&e z0fPM>xds;872w$+fB2Cr%~H`{g2wRTyVJ=QSO^(AJ6nsq`o(wFD^F{B%*=)68BWF} zXvTF8XWqhPlMHg|MfEYgan$}7+&OQ0>r%*vAZ@7aw5@LMqSO@9nv+wm?Y$}K6O~oM zi|WC5xD2E}p3qgPtJartKM85w>$fDS`}vAa$%oo~qjz(2j6=ZJSTHBHSJMXE^+B4= zU?IC%uSc~Qb0kp_Bdvd-<4w&=Yi?5=q~4jgms(nr_H|mausIPt6w!cMd<>9Q)~-r& zZE1c*ve0jw1WX8%DOgyo1(dtlNXk_={mO$H@Gr*&ZJJBPG>ZTL002ovPDHLkV1id3 BYq9_U diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_35.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_35.png deleted file mode 100755 index f70ecb3abe0a34f98debe1b004eb08b12c98673b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 887 zcmV--1Bm>IP)I|X#-uh;n6?-_SZ&e{l2{{$MlW29fAFB}G}ef6 z^We24CdMpP8)HLjLOaozka(ay2$(iyAm9RpvIS%ZcJ_NcEbH}`=Y5{{AKi!E42k#v zphU=jbn`Zm>HmS%9n|H~b!8xcSy~v6Rp-lqj970})rLVV1{%PFlE?{~Lcju=gp(qd z*%bni;C>+|5^&gTdAuyV+9n|%4%uZeCHnQFxLmLD%HZub4lT)5>VmBj+N=Ys2_K~^ zV1&lW)zNY+0M!g#3me@gLq(%!W}f@y-)j(p62OXcD-EhLnzo)IU-P&fxLXyWwT&xb z|HtPlrdaioIrn2=-l|Ag9$u{a^!EC)Ppq60V{voLo_a4%xm$}zC)9i+&-Yb4NaVNu zT}A86)|x5aNgZC!$fT(ViYpi2T@%Uml)-}(Hzy{iL<&;QO|N1JE$x+v{x@M(!=v#?_jqm~nttmr=t z7iljxDh0nY&TkKQ|yw=xuTui4JdN{KB-Euw&K_M zu{BbrM#JrEfIY|m{;WB-CK-FYS(nvM?GAtt1i*TU3t>YvU|1~Pc4N&XpYNDWq}(Rp z%1DKNpNATlm3g=#xh%PX6<18Wv~9zwZ|N?vGQrSH_Q|xNkpJuzI{_f%wM-vl7TrJv3XRa0I{>wWXqt=#1!scW6rfAj(5QHzka zQyVTW<<9`DcMJh@nWN{PdHpKD^JPY&Lac7bwMEwITfBfU#P$ zpzZ?at5EsKk!a|~d!n)&`)d%L`FKEdSYMII!X7zGr3=u>>pS#Q)ytacEojC;7Z+o- zf~u--d0yT_qhcE=ol>1wU2q&x&iL;z`(Ogy;s!}joq9G5+oR*Er}dKKpt^WLd)oE1 z>NPL#d7`Mhy!(hh-O5rh2nM8MqRZx9h;M!aL}7YtJLn0QcYQGMO@3zpl7-zF5M|-c ndusK)F7<&Z%d5Xbx48TZM|mrzzUzGF00000NkvXXu0mjf3B8d` diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_4.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_4.png deleted file mode 100755 index 7d970234f57cdecc7e45bf765ed313ad92c3161b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 890 zcmV-=1BLvFP)6U8pcMp@S4V4`@4ocyo`72k70Lo9~?a<@?V4 z7-HkNVF>`RHUVn@0J9D#kj-8!oah5e0M0sEsTMByP~%y4 zifHE_S9;&`9T#56Ak&f!I@>Q6lLt#!o~PvQmWV0$Q@q{!jiW({!Iqm>)!xxJ?AFuZ zU`dwo>wNprw)yQDKtzs+Bql2VEZ#_Xp67&V7#vKE*?+fZ!Vmso8&H_w08_NvAH?=jCdf)!o1&-%i|OKByIox zqfF}OBHD?>C(oWM%kkR4&uP=|I_j5b%BsXW8h&_k_ouieho*b(@fTn6Bc%mb16K9q z*3XMWKdF`T9i{?#J9BX{Js+F+dx0w|yy5+vx-q!{q<+4=$2V`|kdXo3F66A36uoXB} z6B%s-2h^jkvB2)S^h~NLg^1+yYf==Mu3qsHo)V~txG|rV+P@lK2N5wJ)=f>1h#6iy z<#|>LREs*&0;(mlE0f{!s>rQ;P#O`*uOvKAm2H~}_jk`hrE~}|BS|sCby*QHA9$YU zsQ3v~3!Q-4l>sFSHQSiqlS7WB^FM<_LnNJkFb*ot#_xYEA|jF(lkmKM0Xq7HHc@&K QWdHyG07*qoM6N<$g4?&KI{*Lx diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_5.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_5.png deleted file mode 100755 index 70eab1f3e8c945560bd8aac429f4ae7e15401456..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 819 zcmV-31I+x1P) zUuYav6vlt|=B93H!FAKbeW-EU1Z_*GEfkSfldZI*f?}ae8v4g9A}AVcAQbvgb_ad1 z_+L=a2Qj|sjFwP*$U~(g*ir=9^q~+?$RMFRB|@f9lG)Ad93N&k+xu|ge4Ou`?|%0j zHPQd_kqn)qmV5r}K8jA-fW8>+@Sz(>OpOMw#lnx|~>+7u6}GfM*!KBRqQW$9C?c4A!&7q&C) zZR#>l`I#;9n;`}zfIja1F(kDxeFzxcYip8?Y`a8Eaw+*|eJ)F*YtkW27#2cQ3fD9xxO7i8G3U60x|3hHSFj?51%w@g*Fe6W3Pen(-lWthqH zIKkiFo>@#YdUcaWUK;ygeb245ZyzF3y)D)2H^w|bSsEA$o9Abri#(vmLPTOE(QB~) zSe5~l5WL-02egF&)bGsRKK>VQ(gpckWJY9Pc_ctPj$;TQ18@D9pQ6_VgMkYJ99z_qrZHz^_5-O!*)p0$SA@8>``u9&5i?P zA|=hi@vU}}3!lBz`j-#=wU1y@SuW7CZiv^m0KM@Q0KcH*jeYOjEG9ac0J!&rVWd>M zTm-QI%2S3C^+SMqw+Qi_2_+D0d{@?S)rZC17$6rG63sIoBP%l{B_LDHuT0c^g~i>i z$@@l4X0l=b;Z?7{h=@pS`7uw#(~h&(K}4h;O*1O@MIKm|5nrOJfLwFl+f(jocm#${{bV`LSb#O+VcPa002ovPDHLkV1lqyd=>xz diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_6.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_6.png deleted file mode 100755 index 8169e0766fd617850ef249e6919e2c7715e8cd9e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 799 zcmV+)1K|9LP)@2%14c(S3tq0sqQ7jEH5Dt=*W+!+tAtp8Hr$`!T0+9nA>H+_Nu>*%{ z!r3O^VVig%GbQn&7sQSz>BdX-(8LRNqlAUFbXQ8s>@Yj8hn=OZ-{pJr``+()pXX(q z|D6y3V*`wCc~&4mdNX^kU6}DLUYoRZlwRfq%GQCJzgfTnJ;GS40;s@jr2P7p4z2EO z`BkgUH8%sL>5Hx;%?&bmOPV#=@MWC5ermDatP_F);K8ay`L*yx0CU$U5dPW*AyM(x z^U`0%jVUtakvX+@=#1S?TU}kPT~eh=ycLt~QG(ax)Axz(Ni^|%eTCC)w+3qW$n?oI2)|Li?GX$SGl8*dSc?ud<`f8{IV6KN8%j`Qq+U;K{fgcF08uYQ&u>V>*Dtc2!ZX}?$gX!6H# zq9Cn==(qf}v5Vg(raVadCdiQojiEb=w{x+vg#B^nIU=LSh3(Hwpb#Cg{#fZvXs8rS zpx-R8%_ni*;!%$Q97uyP7Vy2+OWFi7VFxK|`I`@}h6^VQKwSwCd!Kq$AG)axK=pN@ z)ZD^x=k{?|2~f>$uM}>t@@GFFBGOowS((iZ7bT}nfaD|=o_p+uo70GhNU3w8F8_)= z)mjO_!)u>sms1C9KaF7lba$l=XVnG0*L9g&6OrikiTN+(Z)d=9R3ni9re$PLJ@C(h znY`?I@Kz&}CAt4AP%?e+AOz1kfhiA^Jk0C_dGjZ^Z2waRlkTK#qmH2p^tdhSB@q#k dszd{h^B;3hM?PLq!U_NY002ovPDHLkV1lI=dW!%6 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_7.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_7.png deleted file mode 100755 index adee1a63dac8b87d57862f233107c1f961f39cac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 817 zcmV-11J3-3P)RhGNuC&1^3lbT18NI;gl(OH8CIa|J4-6 z(9S=ILoqD~ih^##tZOy%4^>3nkhO7aYed^*?YbskzI=}tNn_`GbI$pl!}Gk)3x{3& zuL1y^|G>Z{*9HW%EN2fcZERyzc8Sz=jQclD6e|J6GL)JEDR8&*NEuRfkcY2BQz>8a z!ZoKBgJrhG;k3$Z5YIixT?A2j=N`iCBxBp4$A1Hidih4IN`Gk{$) z08G7~Xn=q)d8oQ~xAB^ZOz%*CwyJlUMANgg7yseme0?g$(l$VCe`M3^GyRY*IssWhRbTRzmwo2GAv1_?vkjcY8eA*Zql6w4+_~uC6_XZ@5yYZkJ zq@DvzFOud8@ndK8K^bWM5J^EQt`{{?0^IwMq*yeJrsaW?`NRnL@qv@8)}6B8;#(@# z+?ZG~S2|Z%>$ogflvd5d*|{gpnqgXv%Hs-hUg(dpH3L^!?6F`Vhv~a3>kdP=Q7sal z+%a0YJGrx*gI|q6zmGkh+uTcF(E%j+XHF=YZ_SK!XFi^>K()=g_RFq6cF{f@p10sT zky|(I&Ck1peII>hq4v@}eWf8H!?1Pm7bD8w_(u0hj%`@qWPBZb26TCpn%6&SC_-{V4gwZyxYn-U8Fd&v>xl0)?^# zuHM(>!OCF>?!W@(WZ7Za!0EEuiE^`mY8|g zU7rO>QutJQ;uW3FbW3%h_uie0s&d|)QeA^W<+}BGZFnta8^B+T0{cf3+mI$Cg?CEQ v>5;|Tk>(}o1xc!GnLUCOXsN>Z%vb*cYgu*d%gmGW00000NkvXXu0mjfmz0(k diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_8.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_8.png deleted file mode 100755 index db6e667fb77d119f4150c6a1ec875be023846c19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 875 zcmV-x1C;!UP)~KgG zR}iEKYkd&s5>XHzgbo{2);@?U76v}7jm|c0SDM(WxlQlAUmue0ynNw%zURyLoI^kL zGTAy>AJ&1*viblBH+3K&3PcJG#WBDGup1&ZI*~%d$8{V4nu?GFD0|!@zybGp`T!?U z0Vu+FXuJxL@-`K&x$fN}fO2^v@PK`OBbv*7;lLJ~Gm(Khvu{j6SulUGk@WbdCub`` z#Z=lc0L-r_Os)Cmk-CR%xAg-4&)Qm_@CkdyHb!T9$TTis^htr($(@hgP-8ijR#wVq z%mpcm4H(sWsqG$YTgG7ffWpkif6KfeWw8MZbNlgLKhph95n^DFO6A(*_O}BS*bbHr zEidX={A}`M!Uli0op_nh zy7S_t!gp1q>P8?#z*R_CPxQ`+cX9UxkHv&I6 zXB;Pcc;Wu^DaQzc_;96iITfyx{hJFr)~AcC`;s&|vYODkUY~ObGd+?@ML(r5^Yv=ZHt8XtwHhg6(hr?2qSD`z z!Y34FRMNLOi`H#fFb6PcT4~E8X;k$v3Nx#@{{d={ku%1$CRzXh002ovPDHLkV1k;- BrV{`F diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_9.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_9.png deleted file mode 100755 index a6a37fe29c7f17cec2d4824961e1acfe37f0d353..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 823 zcmV-71IYY|P)de9(=SZW1EY1mdVOhDM_c6MG5vwyzZ`^%H}ee=A}$LQ95 zF=jyHg=34CF#l@Q#%R2kI}nFKWUgz1neW&VR+pM! zBwEhe<@Uy2y7&2nVtj@elmP1LJezOG3#aM=kNA}QW9}aFhB*PvWR_uB5A7lEkYhOWwzPxbk_-U#y zg(S~e8g@uwO?$n#9ByJQ zGvG#6dKXzeCxaQ8l3B+|Bi?fK&dC{e`mUQ!fzM=bPgsdwY<$iqS6e%2d0>LNqEgNQ z9~D6fzibBC`8{xD4m8{csK)>{_^E|vBliO?{{st?Q~gh3V Date: Tue, 27 Jan 2026 04:28:32 +0300 Subject: [PATCH 082/160] upd changelog and readme --- CHANGELOG.md | 5 ++-- ReadMe.md | 67 +++------------------------------------------------- 2 files changed, 6 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index edc777ae4..f87d730fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,6 @@ * SubGHz: **Beninca ARC AES128 protocol full support** (128bit dynamic) (with Add manually, and 3 button codes) (resolves issue #596) (by @xMasterX and @zero-mega) * SubGHz: **Treadmill37 protocol support** (37bit static) (by @xMasterX) * SubGHz: **Jarolift protocol full support** (72bit dynamic) (with Add manually, and all button codes) (by @xMasterX & d82k & Steffen (bastelbudenbuben de)) -* SubGHz: **Change key SEND action** (This changes solve problem when user press and release OK button too fast and signal was not fully sent) (PR #949 | by @Dmitry422) * SubGHz: **New modulation FSK with 12KHz deviation** * SubGHz: **KingGates Stylo 4k - Add manually and button switch support** + refactoring of encoder * SubGHz: **Stilmatic - button 9 support** (two buttons hold simulation) (mapped on arrow keys) @@ -17,11 +16,13 @@ * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * NFC: Fixes to `READ_MULTI` and `GET_BLOCK_SECURITY` commands in ISO 15693-3 emulation (by @WillyJL & @aaronjamt) * Archive: Allow folders to be pinned (by @WillyJL) -* Apps: Build tag (**26jan2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) +* Apps: Build tag (**27jan2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes * UI: Various small changes +* Desktop: Disable winter holidays anims * OFW PR 4333: NFC: Fix sending 32+ byte ISO 15693-3 commands (by @WillyJL) * NFC: Fix LED not blinking at SLIX unlock (closes issue #945) +* SubGHz: Improve docs on low level code (PR #949 | by @Dmitry422) * SubGHz: Fix Alutech AT4N false positives * SubGHz: Cleanup of extra local variables * SubGHz: Replaced Cars ignore option with Revers RB2 protocol ignore option diff --git a/ReadMe.md b/ReadMe.md index 891fe9b8f..35f8759e6 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -141,75 +141,14 @@ Before getting started: Also check the [changelog in releases](https://github.com/DarkFlippers/unleashed-firmware/releases) for latest updates! ### Current modified and new Sub-GHz protocols list: -Thanks to Official team (to their SubGHz Developer, Skorp) for implementing support (decoder + encoder / or decode only) for these protocols in OFW. [Full list of supported protocols and their frequencies/modulations (to use in Read mode)](/documentation/SubGHzSupportedSystems.md) -> [!NOTE] -> Not all Keeloq systems are supported for decoding or emulation! ->
    -> Supported Keeloq manufacturers include ->
    -> -> | Column 1 | Column 2 | Column 3 | Column 4 | Column 5 | -> |-------------------|--------------|------------------|-------------------|------------------------| -> | Alligator | Comunello | GSN | Magic_4 | SL_A2-A4 | -> | Alligator_S-275 | Dea_Mio | Guard_RF-311A | Mongoose | SL_A6-A9/Tomahawk_9010 | -> | APS-1100_APS-2550 | DTM_Neo | Harpoon | Mutanco_Mutancode | SL_B6,B9_dop | -> | Aprimatic | DoorHan | IronLogic | NICE_MHOUSE | Sommer | -> | Beninca | EcoStar | JCM_Tech | NICE_Smilo | Stilmatic | -> | BFT | Elmes_Poland | KEY | Normstahl | Teco | -> | Came_Space | FAAC_RC,XT | Kingates_Stylo4k | Pantera | Tomahawk_TZ-9030 | -> | Cenmax | FAAC_SLH | KGB/Subaru | Pantera_CLK | Tomahawk_Z,X_3-5 | -> | Cenmax_St-5 | Faraon | Leopard | Pantera_XS/Jaguar | ZX-730-750-1055 | -> | Cenmax_St-7 | Genius_Bravo | Magic_1 | Partisan_RX | IL-100(Smart) | -> | Centurion | Gibidi | Magic_2 | Reff | Merlin | -> | Monarch | Jolly Motors | Magic_3 | Sheriff | Steelmate | -> | Motorline | Rosh | Pecinin | Rossi | Cardin S449 | ->
    -
    +Thanks to Official team (to their SubGHz Developer, Skorp) for implementing support (decoder + encoder / or decode only) for most protocols in OFW. -
    -Decoders/Encoders or emulation (+ programming mode) support made by @xMasterX -
    +And thanks to our contributors who took part in SubGHz improvements and making of new features: -- Elplast/P-11B/3BK/E.C.A (static 18 bit) -- Roger (static 28 bit) with add manually support (thanks @mishamyte) -- V2 Phoenix (Phox) (dynamic 52 bit) (thanks @RocketGod-git) -- Marantec (static 49 bit) (add manually support and CRC verify) (thanks @li0ard) -- Feron (static 32 bit) -- ReversRB2 / RB2M (static 64 bit) with add manually support -- Marantec24 (static 24 bit) with add manually support -- GangQi (static 34 bit) with button parsing and add manually support (thanks to @mishamyte for captures and testing, thanks @Skorpionm for help) -- Hollarm (static 42 bit) with button parsing and add manually support (thanks to @mishamyte for captures, thanks @Skorpionm for help) -- Hay21 (dynamic 21 bit) with button parsing -- Nero Radio 57bit (+ 56bit support) -- CAME 12bit/24bit encoder fixes (Fixes are now merged in OFW) -- Keeloq: Dea Mio, Genius Bravo, GSN, HCS101, AN-Motors, JCM Tech, MHouse, Nice Smilo, DTM Neo, FAAC RC,XT, Mutancode, Normstahl, Beninca + Allmatic, Stilmatic, CAME Space, Aprimatic (model TR and similar), Centurion Nova (thanks Carlos !), Hormann EcoStar, Novoferm, Sommer, Monarch (thanks @ashphx !), Jolly Motors (thanks @pkooiman !), IL-100(Smart) (thx Vitaly for RAWs), Motorline (with add manually support), Rosh, Pecinin, Rossi, Merlin, Steelmate (thanks @RocketGod-git), Cardin S449 (thanks @zero-mega) -
    - -
    -Protocols support made by Skorp (original implementation) and @xMasterX (current version) -
    - -- CAME Atomo → Update! check out new [instructions](/documentation/SubGHzRemoteProg.md) -- Nice Flor S → How to create new remote - [instructions](/documentation/SubGHzRemoteProg.md) -- FAAC SLH (Spa) → Update!!! (Programming mode!) Check out new [instructions](/documentation/SubGHzRemoteProg.md) -- Keeloq: BFT Mitto → Update! Check out new [instructions](/documentation/SubGHzRemoteProg.md) -- Star Line -- Security+ v1 & v2 -
    - -
    -Encoders made by @assasinfil and @xMasterX -
    - -- Somfy Telis → How to create new remote - [instructions](/documentation/SubGHzRemoteProg.md) -- Somfy Keytis -- KingGates Stylo 4k (UPD: Add manually and all buttons support) -- Alutech AT-4N → How to create new remote - [instructions](/documentation/SubGHzRemoteProg.md) -- Nice ON2E (Nice One) → How to create new remote - [instructions](/documentation/SubGHzRemoteProg.md) -
    +`@RocketGod-git, @zero-mega, @ashphx, @pkooiman, Vitaly, Carlos, @li0ard, @mishamyte, d82k, Steffen (bastelbudenbuben de), @assasinfil, @gid9798` ## ❤️ Please support development of the project From 84f580d1684ad6ad1b830b5fb310bebd504badb1 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 29 Jan 2026 03:17:41 +0300 Subject: [PATCH 083/160] subghz: fix stilmatic keeloq support, display decr. hop feature --- CHANGELOG.md | 3 +- documentation/SubGHzSupportedSystems.md | 2 +- lib/subghz/protocols/keeloq.c | 63 ++++++++++++++----------- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f87d730fd..4f37e21aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,13 +6,14 @@ * SubGHz: **Jarolift protocol full support** (72bit dynamic) (with Add manually, and all button codes) (by @xMasterX & d82k & Steffen (bastelbudenbuben de)) * SubGHz: **New modulation FSK with 12KHz deviation** * SubGHz: **KingGates Stylo 4k - Add manually and button switch support** + refactoring of encoder -* SubGHz: **Stilmatic - button 9 support** (two buttons hold simulation) (mapped on arrow keys) +* SubGHz: **Stilmatic (R-Tech) - 12bit discr. fix & button 9 support** (two buttons hold simulation) (mapped on arrow keys) * SubGHz: **Counter editor refactoring** (PR #939 | by @Dmitry422) * SubGHz: **Alutech AT-4N & Nice Flor S turbo speedup** (PR #942 | by @Dmitry422) * SubGHz: **Sommer fm2 in Add manually now uses FM12K modulation** (Sommer without fm2 tag uses FM476) (try this if regular option doesn't work for you) * SubGHz: **Sommer - last button code 0x6 support** (mapped on arrow keys) * SubGHz: Add 390MHz, 430.5MHz to default hopper list (6 elements like in OFW) (works well with Hopper RSSI level set for your enviroment) * SubGHz: Fixed button mapping for **FAAC RC/XT** +* SubGHz: KeeLoq display decrypted hop in `Hop` instead of showing encrypted as is (encrypted non byte reversed hop is still displayed in `Key` field) * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * NFC: Fixes to `READ_MULTI` and `GET_BLOCK_SECURITY` commands in ISO 15693-3 emulation (by @WillyJL & @aaronjamt) * Archive: Allow folders to be pinned (by @WillyJL) diff --git a/documentation/SubGHzSupportedSystems.md b/documentation/SubGHzSupportedSystems.md index 0cfcb8881..33e2d1cb2 100644 --- a/documentation/SubGHzSupportedSystems.md +++ b/documentation/SubGHzSupportedSystems.md @@ -124,7 +124,7 @@ The following manufacturers have KeeLoq support in Unleashed firmware: - Novoferm - `433.92MHz` `AM650` (KeeLoq, 64 bits) - Sommer `434.42MHz, 868.80MHz` `FSK12K (or FSK476)` (KeeLoq, 64 bits) (normal learning) (TX03-868-4, Pearl, and maybe other models are supported (SOMloq)) - Steelmate - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) -- Stilmatic - `433.92MHz` `AM650` (KeeLoq, 64 bits) (normal learning) +- Stilmatic (R-Tech) - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) ### Alarms, unknown origin, etc. - APS-1100/APS-2550 (KeeLoq, 64 bits) diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index cd657f23f..837ae038e 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -95,7 +95,7 @@ const SubGhzProtocol subghz_protocol_keeloq = { * @param keystore Pointer to a SubGhzKeystore* instance * @param manufacture_name */ -static void subghz_protocol_keeloq_check_remote_controller( +static uint32_t subghz_protocol_keeloq_check_remote_controller( SubGhzBlockGeneric* instance, SubGhzKeystore* keystore, const char** manufacture_name); @@ -305,12 +305,14 @@ static bool subghz_protocol_keeloq_gen_data( (strcmp(instance->manufacture_name, "Rossi") == 0) || (strcmp(instance->manufacture_name, "Pecinin") == 0) || (strcmp(instance->manufacture_name, "Steelmate") == 0) || - (strcmp(instance->manufacture_name, "Cardin_S449") == 0)) { + (strcmp(instance->manufacture_name, "Cardin_S449") == 0) || + (strcmp(instance->manufacture_name, "Stilmatic") == 0)) { // DTM Neo, Came_Space uses 12bit serial -> simple learning // FAAC_RC,XT , Mutanco_Mutancode, Genius_Bravo, GSN 12bit serial -> normal learning // Rosh, Rossi, Pecinin -> 12bit serial - simple learning // Steelmate -> 12bit serial - normal learning // Cardin_S449 -> 12bit serial - normal learning + // Stilmatic (r-tech) -> 12bit serial - normal learning decrypt = btn << 28 | (instance->generic.serial & 0xFFF) << 16 | instance->generic.cnt; } else if( @@ -899,9 +901,9 @@ static inline bool subghz_protocol_keeloq_check_decrypt_centurion( * @param hop Hop encrypted part of the parcel * @param keystore Pointer to a SubGhzKeystore* instance * @param manufacture_name - * @return true on successful search - */ -static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( + * @return uint32_t decrypt data */ + +static uint32_t subghz_protocol_keeloq_check_remote_controller_selector( SubGhzBlockGeneric* instance, uint32_t fix, uint32_t hop, @@ -924,7 +926,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( const char* mfname = keystore->mfname; if(strcmp(mfname, "Unknown") == 0) { - return 1; + return 0; } else if(strcmp(mfname, "") == 0) { mf_not_set = true; } @@ -938,7 +940,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); keystore->mfname = *manufacture_name; - return 1; + return decrypt; } break; case KEELOQ_LEARNING_NORMAL: @@ -951,14 +953,14 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( if(subghz_protocol_keeloq_check_decrypt_centurion(instance, decrypt, btn)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); keystore->mfname = *manufacture_name; - return 1; + return decrypt; } } else { if(subghz_protocol_keeloq_check_decrypt( instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); keystore->mfname = *manufacture_name; - return 1; + return decrypt; } } break; @@ -976,7 +978,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); keystore->mfname = *manufacture_name; - return 1; + return decrypt; } else { if(reset_seed_back) instance->seed = 0; } @@ -988,7 +990,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); keystore->mfname = *manufacture_name; - return 1; + return decrypt; } break; case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_1: @@ -998,7 +1000,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); keystore->mfname = *manufacture_name; - return 1; + return decrypt; } break; case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_2: @@ -1008,7 +1010,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); keystore->mfname = *manufacture_name; - return 1; + return decrypt; } break; case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_3: @@ -1018,7 +1020,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); keystore->mfname = *manufacture_name; - return 1; + return decrypt; } break; case KEELOQ_LEARNING_UNKNOWN: @@ -1028,7 +1030,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( *manufacture_name = furi_string_get_cstr(manufacture_code->name); keystore->mfname = *manufacture_name; keystore->kl_type = 1; - return 1; + return decrypt; } // Check for mirrored man @@ -1044,7 +1046,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( *manufacture_name = furi_string_get_cstr(manufacture_code->name); keystore->mfname = *manufacture_name; keystore->kl_type = 1; - return 1; + return decrypt; } //########################### @@ -1057,7 +1059,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( *manufacture_name = furi_string_get_cstr(manufacture_code->name); keystore->mfname = *manufacture_name; keystore->kl_type = 2; - return 1; + return decrypt; } // Check for mirrored man @@ -1067,7 +1069,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( *manufacture_name = furi_string_get_cstr(manufacture_code->name); keystore->mfname = *manufacture_name; keystore->kl_type = 2; - return 1; + return decrypt; } // Secure Learning @@ -1078,7 +1080,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( *manufacture_name = furi_string_get_cstr(manufacture_code->name); keystore->mfname = *manufacture_name; keystore->kl_type = 3; - return 1; + return decrypt; } // Check for mirrored man @@ -1089,7 +1091,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( *manufacture_name = furi_string_get_cstr(manufacture_code->name); keystore->mfname = *manufacture_name; keystore->kl_type = 3; - return 1; + return decrypt; } // Magic xor type1 learning @@ -1100,7 +1102,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( *manufacture_name = furi_string_get_cstr(manufacture_code->name); keystore->mfname = *manufacture_name; keystore->kl_type = 4; - return 1; + return decrypt; } // Check for mirrored man @@ -1110,7 +1112,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( *manufacture_name = furi_string_get_cstr(manufacture_code->name); keystore->mfname = *manufacture_name; keystore->kl_type = 4; - return 1; + return decrypt; } break; @@ -1126,7 +1128,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( return 0; } -static void subghz_protocol_keeloq_check_remote_controller( +static uint32_t subghz_protocol_keeloq_check_remote_controller( SubGhzBlockGeneric* instance, SubGhzKeystore* keystore, const char** manufacture_name) { @@ -1135,6 +1137,7 @@ static void subghz_protocol_keeloq_check_remote_controller( uint32_t key_fix = key >> 32; uint32_t key_hop = key & 0x00000000ffffffff; static uint16_t temp_counter = 0; // Be careful with prog_mode + uint32_t resdecrypt = 0; // If we are in BFT / Aprimatic / Dea_Mio programming mode we will set previous remembered counter and skip mf keys check ProgMode prog_mode = subghz_custom_btn_get_prog_mode(); @@ -1159,7 +1162,7 @@ static void subghz_protocol_keeloq_check_remote_controller( keystore->mfname = *manufacture_name; instance->cnt = key_hop >> 16; } else { - subghz_protocol_keeloq_check_remote_controller_selector( + resdecrypt = subghz_protocol_keeloq_check_remote_controller_selector( instance, key_fix, key_hop, keystore, manufacture_name); } } else { @@ -1176,7 +1179,7 @@ static void subghz_protocol_keeloq_check_remote_controller( instance->cnt = key_hop >> 16; } else { // Else we have mfname that is not AN-Motors or HCS101 we should check it via default selector - subghz_protocol_keeloq_check_remote_controller_selector( + resdecrypt = subghz_protocol_keeloq_check_remote_controller_selector( instance, key_fix, key_hop, keystore, manufacture_name); } } @@ -1213,6 +1216,8 @@ static void subghz_protocol_keeloq_check_remote_controller( } // Set max custom buttons subghz_custom_btn_set_max(4); + + return resdecrypt; } uint8_t subghz_protocol_decoder_keeloq_get_hash_data(void* context) { @@ -1483,7 +1488,9 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output furi_assert(context); SubGhzProtocolDecoderKeeloq* instance = context; - subghz_protocol_keeloq_check_remote_controller( + uint32_t hopdecrypt = 0; + + hopdecrypt = subghz_protocol_keeloq_check_remote_controller( &instance->generic, instance->keystore, &instance->manufacture_name); uint32_t code_found_hi = instance->generic.data >> 32; @@ -1511,7 +1518,7 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output code_found_lo, code_found_reverse_hi, instance->generic.cnt, - code_found_reverse_lo, + hopdecrypt, instance->generic.btn, instance->manufacture_name, instance->generic.seed); @@ -1549,7 +1556,7 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output code_found_lo, code_found_reverse_hi, instance->generic.cnt, - code_found_reverse_lo, + hopdecrypt, instance->generic.btn, instance->manufacture_name); } From c05ef82b11b93b35ff150b111859276782dafa2e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 29 Jan 2026 04:52:02 +0300 Subject: [PATCH 084/160] try to decode bft with zero seed ?! --- lib/subghz/protocols/keeloq.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 837ae038e..500ea6459 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -981,6 +981,16 @@ static uint32_t subghz_protocol_keeloq_check_remote_controller_selector( return decrypt; } else { if(reset_seed_back) instance->seed = 0; + // Try with zero seed (some strange remotes have been reported to use 0 seed) + man = subghz_protocol_keeloq_common_secure_learning( + fix, instance->seed, manufacture_code->key); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); + if(subghz_protocol_keeloq_check_decrypt( + instance, decrypt, btn, end_serial)) { + *manufacture_name = furi_string_get_cstr(manufacture_code->name); + keystore->mfname = *manufacture_name; + return decrypt; + } } break; case KEELOQ_LEARNING_MAGIC_XOR_TYPE_1: From 523a3723cf9ec475c2904603b422c55802120519 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 29 Jan 2026 06:10:45 +0300 Subject: [PATCH 085/160] upd changelog and faq --- CHANGELOG.md | 3 ++- documentation/FAQ.md | 28 ++++++++++++++-------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f37e21aa..f8564a535 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,8 @@ * SubGHz: **Sommer - last button code 0x6 support** (mapped on arrow keys) * SubGHz: Add 390MHz, 430.5MHz to default hopper list (6 elements like in OFW) (works well with Hopper RSSI level set for your enviroment) * SubGHz: Fixed button mapping for **FAAC RC/XT** -* SubGHz: KeeLoq display decrypted hop in `Hop` instead of showing encrypted as is (encrypted non byte reversed hop is still displayed in `Key` field) +* SubGHz: KeeLoq **display decrypted hop** in `Hop` instead of showing encrypted as is (encrypted non byte reversed hop is still displayed in `Key` field) +* SubGHz: **BFT KeeLoq** try decoding with **zero seed** too * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * NFC: Fixes to `READ_MULTI` and `GET_BLOCK_SECURITY` commands in ISO 15693-3 emulation (by @WillyJL & @aaronjamt) * Archive: Allow folders to be pinned (by @WillyJL) diff --git a/documentation/FAQ.md b/documentation/FAQ.md index cd38ad7a8..25f19e30f 100644 --- a/documentation/FAQ.md +++ b/documentation/FAQ.md @@ -44,21 +44,21 @@ Here - [link](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/docume ## I want to request or make new SubGHz protocol, my remote (is not car keyfob) and is not supported, how to record RAW signal properly? -1. Open SubGHz app, (if you know the frequency skip that step and go to Read) select Frequency analyzer, press and hold button on your remote and place it near IR window on flipper -You will find a approx. frequency that remote uses, release button on the remote and wait until frequency will be placed in history list -Hold OK on flipper to jump into Read mode, now try pressing your remote couple times holding it for at least 2 seconds -Try different modulations, AM650/FM238/FM476/FM12K - nothing works? Lets make RAW recording for analysis -2. Knowing the frequency open Read RAW and set it here in config page -Make sure RSSI Threshold is set to (----) -You need to make 1 RAW for each modulation AM650/FM238/FM476/FM12K -Press REC and on your remote press 1 button 5 times holding it for 1-2 seconds - then 5 times holding it for 5 seconds each time -If your remote has more than 1 button - record each button in similar way +1. Open SubGHz app, (if you know the frequency skip that step and go to Read) select Frequency analyzer, press and hold button on your remote and place it near IR window on flipper
    +You will find a approx. frequency that remote uses, release button on the remote and wait until frequency will be placed in history list
    +Hold OK on flipper to jump into Read mode, now try pressing your remote couple times holding it for at least 2 seconds
    +Try different modulations, AM650/FM238/FM476/FM12K - nothing works? Lets make RAW recording for analysis
    +2. Knowing the frequency open Read RAW and set it here in config page
    +Make sure RSSI Threshold is set to (----)
    +You need to make 1 RAW for each modulation AM650/FM238/FM476/FM12K
    +Press REC and on your remote press 1 button 5 times holding it for 1-2 seconds - then 5 times holding it for 5 seconds each time
    +If your remote has more than 1 button - record each button in similar way
    Label each raw - what button you recorded -3. Copy all that RAW files to PC and create issue in firmware repo, attach raw's in archive -Provide high quality photos of the remote, if possible - photos of disassembled remote too -Its model, manufacturer, any known information -If you have access to receiver board, add a photo too -Done! If your remote appears not to be encrypted and very unique, it might be added soon +3. Copy all that RAW files to PC and create issue in firmware repo, attach raw's in archive
    +Provide high quality photos of the remote, if possible - photos of disassembled remote too
    +Its model, manufacturer, any known information
    +If you have access to receiver board, add a photo too
    +Done! If your remote appears not to be encrypted and very unique, it might be added soon
    In case if you want to help us or analyze that signals youself there's a great online tool - https://lab.flipper.net/pulse-plotter ## How to build (compile) the firmware? From 2469206cc8b549f35d4c7fcbcd70d4986966ad60 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 29 Jan 2026 06:18:41 +0300 Subject: [PATCH 086/160] subghz fix and show prog mode bft --- CHANGELOG.md | 1 + lib/subghz/protocols/keeloq.c | 55 ++++++++++++++++++++++++----------- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8564a535..da9bbee95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ * SubGHz: Fixed button mapping for **FAAC RC/XT** * SubGHz: KeeLoq **display decrypted hop** in `Hop` instead of showing encrypted as is (encrypted non byte reversed hop is still displayed in `Key` field) * SubGHz: **BFT KeeLoq** try decoding with **zero seed** too +* SubGHz: KeeLoq **display BFT programming mode TX** (when arrow button is held) * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * NFC: Fixes to `READ_MULTI` and `GET_BLOCK_SECURITY` commands in ISO 15693-3 emulation (by @WillyJL & @aaronjamt) * Archive: Allow folders to be pinned (by @WillyJL) diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 500ea6459..ca0db9f7b 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -1515,23 +1515,44 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output subghz_block_generic_global.cnt_is_available = true; subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; - furi_string_cat_printf( - output, - "%s %dbit\r\n" - "Key:%08lX%08lX\r\n" - "Fix:0x%08lX Cnt:%04lX\r\n" - "Hop:0x%08lX Btn:%01X\r\n" - "MF:%s Sd:%08lX", - instance->generic.protocol_name, - instance->generic.data_count_bit, - code_found_hi, - code_found_lo, - code_found_reverse_hi, - instance->generic.cnt, - hopdecrypt, - instance->generic.btn, - instance->manufacture_name, - instance->generic.seed); + ProgMode prog_mode = subghz_custom_btn_get_prog_mode(); + if(prog_mode == PROG_MODE_KEELOQ_BFT) { + furi_string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%08lX%08lX\r\n" + "Fix:0x%08lX Cnt:%04lX\r\n" + "Hop:0x%08lX Btn:%01X\r\n" + "MF:%s PRG Sd:%08lX", + instance->generic.protocol_name, + instance->generic.data_count_bit, + code_found_hi, + code_found_lo, + code_found_reverse_hi, + instance->generic.cnt, + code_found_reverse_lo, + instance->generic.btn, + instance->manufacture_name, + instance->generic.seed); + } else { + furi_string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%08lX%08lX\r\n" + "Fix:0x%08lX Cnt:%04lX\r\n" + "Hop:0x%08lX Btn:%01X\r\n" + "MF:%s Sd:%08lX", + instance->generic.protocol_name, + instance->generic.data_count_bit, + code_found_hi, + code_found_lo, + code_found_reverse_hi, + instance->generic.cnt, + hopdecrypt, + instance->generic.btn, + instance->manufacture_name, + instance->generic.seed); + } } else if(strcmp(instance->manufacture_name, "Unknown") == 0) { instance->generic.cnt = 0x0; furi_string_cat_printf( From 1d734948d9592d3aa3339eb0e6bf633718510af3 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 29 Jan 2026 07:36:42 +0300 Subject: [PATCH 087/160] fix about screen define --- applications/settings/about/about.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/settings/about/about.c b/applications/settings/about/about.c index d9fbca87a..efd53f210 100644 --- a/applications/settings/about/about.c +++ b/applications/settings/about/about.c @@ -156,9 +156,9 @@ static DialogMessageButton fw_version_screen(DialogsApp* dialogs, DialogMessage* buffer = furi_string_alloc(); const Version* ver = furi_hal_version_get_firmware_version(); const BleGlueC2Info* c2_ver = NULL; -#ifdef SRV_BT + //#ifdef SRV_BT c2_ver = ble_glue_get_c2_info(); -#endif + //#endif if(!ver) { //-V1051 furi_string_cat_printf(buffer, "No info\n"); From 0eae6030b0f173ec1e8edc06ce0f7abef06d0bcd Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Fri, 30 Jan 2026 21:43:05 +0700 Subject: [PATCH 088/160] work to home --- .../scenes/subghz_scene_signal_settings.c | 66 +++++++++++++++---- .../subghz/scenes/subghz_scene_transmitter.c | 61 ++++++++++++++++- lib/subghz/blocks/generic.h | 7 ++ lib/subghz/protocols/alutech_at_4n.c | 2 +- lib/subghz/protocols/ansonic.c | 4 +- 5 files changed, 124 insertions(+), 16 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_signal_settings.c b/applications/main/subghz/scenes/subghz_scene_signal_settings.c index e74219a28..c8a0cf2a6 100644 --- a/applications/main/subghz/scenes/subghz_scene_signal_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_signal_settings.c @@ -11,10 +11,15 @@ static uint32_t counter_mode = 0xff; static uint32_t counter32 = 0x0; static uint16_t counter16 = 0x0; -static uint8_t byte_count = 0; -static uint8_t* byte_ptr = NULL; +static uint8_t cnt_byte_count = 0; +static uint8_t* cnt_byte_ptr = NULL; + static FuriString* byte_input_text; +static uint8_t button = 0x0; +static uint8_t btn_byte_count = 1; +static uint8_t* btn_byte_ptr = NULL; + #define COUNTER_MODE_COUNT 7 static const char* const counter_mode_text[COUNTER_MODE_COUNT] = { "System", @@ -79,8 +84,25 @@ void subghz_scene_signal_settings_variable_item_list_enter_callback(void* contex subghz_scene_signal_settings_byte_input_callback, NULL, subghz, - byte_ptr, - byte_count); + cnt_byte_ptr, + cnt_byte_count); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); + } + // when we click OK on "Edit button" item + if(index == 2) { + furi_string_cat_str(byte_input_text, " button number in HEX"); + + // Setup byte_input view + ByteInput* byte_input = subghz->byte_input; + byte_input_set_header_text(byte_input, furi_string_get_cstr(byte_input_text)); + + byte_input_set_result_callback( + byte_input, + subghz_scene_signal_settings_byte_input_callback, + NULL, + subghz, + btn_byte_ptr, + btn_byte_count); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); } } @@ -130,9 +152,10 @@ void subghz_scene_signal_settings_on_enter(void* context) { flipper_format_free(fff_data_file); furi_record_close(RECORD_STORAGE); - // ### Counter edit section ### byte_input_text = furi_string_alloc_set_str("Enter "); bool counter_not_available = true; + bool button_not_available = true; + SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(subghz->txrx); // deserialaze and decode loaded sugbhz file and push data to subghz_block_generic_global variable @@ -143,6 +166,8 @@ void subghz_scene_signal_settings_on_enter(void* context) { FURI_LOG_E(TAG, "Cant deserialize this subghz file"); } + // ### Counter edit section ### + if(!subghz_block_generic_global.cnt_is_available) { counter_mode = 0xff; FURI_LOG_D(TAG, "Counter mode and edit not available for this protocol"); @@ -155,19 +180,31 @@ void subghz_scene_signal_settings_on_enter(void* context) { counter32 = subghz_block_generic_global.current_cnt; furi_string_printf(tmp_text, "%lX", counter32); counter32 = __bswap32(counter32); - byte_ptr = (uint8_t*)&counter32; - byte_count = 4; + cnt_byte_ptr = (uint8_t*)&counter32; + cnt_byte_count = 4; } else { counter16 = subghz_block_generic_global.current_cnt; furi_string_printf(tmp_text, "%X", counter16); counter16 = __bswap16(counter16); - byte_ptr = (uint8_t*)&counter16; - byte_count = 2; + cnt_byte_ptr = (uint8_t*)&counter16; + cnt_byte_count = 2; } } - furi_assert(byte_ptr); - furi_assert(byte_count > 0); + // ### Button edit section ### + + if(!subghz_block_generic_global.btn_is_available) { + FURI_LOG_D(TAG, "Button edit not available for this protocol"); + } else { + button_not_available = false; + button = subghz_block_generic_global.current_btn; + furi_string_printf(tmp_text, "%X", button); + btn_byte_ptr = (uint8_t*)&button; + } + + furi_assert(cnt_byte_ptr); + furi_assert(cnt_byte_count > 0); + furi_assert(btn_byte_ptr); //Create and Enable/Disable variable_item_list depending on current values VariableItemList* variable_item_list = subghz->variable_item_list; @@ -196,6 +233,11 @@ void subghz_scene_signal_settings_on_enter(void* context) { variable_item_set_current_value_text(item, furi_string_get_cstr(tmp_text)); variable_item_set_locked(item, (counter_not_available), "Not available\nfor this\nprotocol !"); + item = variable_item_list_add(variable_item_list, "Edit Button", 1, NULL, subghz); + variable_item_set_current_value_index(item, 0); + variable_item_set_current_value_text(item, furi_string_get_cstr(tmp_text)); + variable_item_set_locked(item, (button_not_available), "Not available\nfor this\nprotocol !"); + furi_string_free(tmp_text); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); @@ -206,7 +248,7 @@ bool subghz_scene_signal_settings_on_event(void* context, SceneManagerEvent even if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventByteInputDone) { - switch(byte_count) { + switch(cnt_byte_count) { case 2: // set new cnt value and override_flag to global variable and call transmit to generate and save subghz signal counter16 = __bswap16(counter16); diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index ebd69059f..b27d88da0 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -3,7 +3,14 @@ #include #include +<<<<<<< HEAD +======= +#include + +#include "applications/main/subghz/helpers/subghz_txrx_i.h" +#include "lib/subghz/blocks/generic.h" +>>>>>>> cf35909c8 (work to home) #define TAG "SubGhzSceneTransmitter" void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) { @@ -67,7 +74,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventViewTransmitterSendStart) { subghz->state_notifications = SubGhzNotificationStateIDLE; - + FURI_LOG_D("000000", "PRESS"); if(subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { subghz->state_notifications = SubGhzNotificationStateTx; subghz_scene_transmitter_update_data_show(subghz); @@ -75,8 +82,23 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { } return true; } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) { +<<<<<<< HEAD +======= + FURI_LOG_D("111111", "RELEASE"); + + // if we recieve event to stop tranmission (user release OK button) but + // hardware TX still working now then set flag to stop it after hardware TX will be realy ended + if(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { + subghz_block_generic_global.endless_tx = true; + tx_stop_called = true; + FURI_LOG_D("111111", "STOP CALLED"); + return true; + } + // if hardware TX not working now so just stop TX correctly +>>>>>>> cf35909c8 (work to home) subghz->state_notifications = SubGhzNotificationStateIDLE; subghz_txrx_stop(subghz->txrx); + subghz_block_generic_global.endless_tx = false; if(subghz_custom_btn_get() != SUBGHZ_CUSTOM_BTN_OK) { subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); int32_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); @@ -90,6 +112,8 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { subghz_txrx_stop(subghz->txrx); furi_hal_subghz_set_rolling_counter_mult(tmp_counter); } + FURI_LOG_D("111111", "JUST STOP"); + return true; } else if(event.event == SubGhzCustomEventViewTransmitterBack) { subghz->state_notifications = SubGhzNotificationStateIDLE; @@ -102,7 +126,42 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { } } else if(event.type == SceneManagerEventTypeTick) { if(subghz->state_notifications == SubGhzNotificationStateTx) { +<<<<<<< HEAD notification_message(subghz->notifications, &sequence_blink_magenta_10); +======= + // if hardware TX still working at this time so we just blink led and do nothing + if(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { + notification_message(subghz->notifications, &sequence_blink_magenta_10); + return true; + + // if hardware TX not working now and tx_stop_called = true + // (mean user release OK button early than hardware TX was ended) then we stop TX + if(tx_stop_called) { + FURI_LOG_D("22222222", "STOP BY CALL"); + + // tx_stop_called = false; + // subghz->state_notifications = SubGhzNotificationStateIDLE; + // subghz_txrx_stop(subghz->txrx); + // // subghz_block_generic_global.endless_tx = false; + // if(subghz_custom_btn_get() != SUBGHZ_CUSTOM_BTN_OK) { + // subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); + // int32_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); + // furi_hal_subghz_set_rolling_counter_mult(0); + // // Calling restore! + // subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); + // subghz_txrx_stop(subghz->txrx); + // // Calling restore 2nd time special for FAAC SLH! + // // TODO: Find better way to restore after custom button is used!!! + // subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); + // subghz_txrx_stop(subghz->txrx); + // furi_hal_subghz_set_rolling_counter_mult(tmp_counter); + //} + return true; + } + subghz_block_generic_global.endless_tx = true; + FURI_LOG_D("22222222", "ENDELSS TX ON"); + } +>>>>>>> cf35909c8 (work to home) } return true; } diff --git a/lib/subghz/blocks/generic.h b/lib/subghz/blocks/generic.h index 1e72c5a5e..daed68b07 100644 --- a/lib/subghz/blocks/generic.h +++ b/lib/subghz/blocks/generic.h @@ -35,6 +35,13 @@ struct SubGhzBlockGenericGlobal { bool cnt_need_override; // flag for protocols to override signals counter inside of protocols uint8_t cnt_length_bit; // counter length in bytes (used in counter editor giu) bool cnt_is_available; // is there counter available for protocol (used in counter editor giu) + + uint8_t current_btn; // global counter value; + uint8_t new_btn; // global counter value; + bool btn_need_override; // flag for protocols to override signals counter inside of protocols + bool btn_is_available; // is there counter available for protocol (used in counter editor giu) + + bool endless_tx; // used for endless/breakless transmission in subghz protols (when user not release OK button) }; extern SubGhzBlockGenericGlobal subghz_block_generic_global; //global structure for subghz diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 687a1e930..5ebe1eb43 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -135,7 +135,7 @@ LevelDuration subghz_protocol_encoder_alutech_at_4n_yield(void* context) { instance->encoder.repeat--; instance->encoder.front = 0; } - + FURI_LOG_D("ALLLLLLL", "REPEAT - %i ", instance->encoder.repeat); return ret; } diff --git a/lib/subghz/protocols/ansonic.c b/lib/subghz/protocols/ansonic.c index 75f803370..1a9a69828 100644 --- a/lib/subghz/protocols/ansonic.c +++ b/lib/subghz/protocols/ansonic.c @@ -82,7 +82,7 @@ void* subghz_protocol_encoder_ansonic_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_ansonic; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 30; instance->encoder.size_upload = 52; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -183,7 +183,7 @@ LevelDuration subghz_protocol_encoder_ansonic_yield(void* context) { instance->encoder.repeat--; instance->encoder.front = 0; } - +FURI_LOG_D("ANNNN", "REPEAT - %i ",instance->encoder.repeat); return ret; } From 4800039d64b181e112eaf545295d226b00662584 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 31 Jan 2026 17:00:11 +0300 Subject: [PATCH 089/160] add info about stilmatic and cardin receivers --- documentation/SubGHzSupportedSystems.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/SubGHzSupportedSystems.md b/documentation/SubGHzSupportedSystems.md index 33e2d1cb2..faa42e9e1 100644 --- a/documentation/SubGHzSupportedSystems.md +++ b/documentation/SubGHzSupportedSystems.md @@ -98,7 +98,7 @@ The following manufacturers have KeeLoq support in Unleashed firmware: - Aprimatic - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial number art in Hop + 2bit "parity" in front of it replacing first 2 bits of serial) - Beninca - `433.92MHz, 868MHz` `AM650` (KeeLoq, 64 bits) (no serial part in Hop - magic XOR) - CAME Space - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - simple learning) -- Cardin S449 - `433.92MHz` `FSK12K` (KeeLoq, 64 bits) (12bit (original remotes) or 10bit (chinese remotes) serial part in Hop - normal learning) +- Cardin S449 - `433.92MHz` `FSK12K` (KeeLoq, 64 bits) (12bit (original remotes) or 10bit (chinese remotes) serial part in Hop - normal learning) (receiver checks for 10bit only (unverified)) - Centurion - `433.92MHz` `AM650` (KeeLoq, 64 bits) (no serial in Hop, uses fixed value 0x1CE - normal learning) - Comunello - `433.92MHz, 868MHz` `AM650` (KeeLoq, 64 bits) (normal learning) - DEA Mio - `433.92MHz` `AM650` (KeeLoq, 64 bits) (modified serial in Hop, uses last 3 digits modifying first one (example - 419 -> C19) - simple learning) @@ -124,7 +124,7 @@ The following manufacturers have KeeLoq support in Unleashed firmware: - Novoferm - `433.92MHz` `AM650` (KeeLoq, 64 bits) - Sommer `434.42MHz, 868.80MHz` `FSK12K (or FSK476)` (KeeLoq, 64 bits) (normal learning) (TX03-868-4, Pearl, and maybe other models are supported (SOMloq)) - Steelmate - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) -- Stilmatic (R-Tech) - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) +- Stilmatic (R-Tech) - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) (receiver checks for 10bit only (unverified)) ### Alarms, unknown origin, etc. - APS-1100/APS-2550 (KeeLoq, 64 bits) From 95dd537bf81ee445b1fb71aa60431cb62080333d Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 1 Feb 2026 05:51:09 +0300 Subject: [PATCH 090/160] add v2 phox counter modes support --- CHANGELOG.md | 1 + .../scenes/subghz_scene_signal_settings.c | 1 + documentation/SubGHzCounterMode.md | 18 +++++ documentation/SubGHzSupportedSystems.md | 4 +- lib/subghz/protocols/phoenix_v2.c | 72 ++++++++++++++++--- 5 files changed, 85 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da9bbee95..fea108a20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ * SubGHz: **Alutech AT-4N & Nice Flor S turbo speedup** (PR #942 | by @Dmitry422) * SubGHz: **Sommer fm2 in Add manually now uses FM12K modulation** (Sommer without fm2 tag uses FM476) (try this if regular option doesn't work for you) * SubGHz: **Sommer - last button code 0x6 support** (mapped on arrow keys) +* SubGHz: **V2 Phoenix (Phox) added 2 counter modes support** (docs updated) * SubGHz: Add 390MHz, 430.5MHz to default hopper list (6 elements like in OFW) (works well with Hopper RSSI level set for your enviroment) * SubGHz: Fixed button mapping for **FAAC RC/XT** * SubGHz: KeeLoq **display decrypted hop** in `Hop` instead of showing encrypted as is (encrypted non byte reversed hop is still displayed in `Key` field) diff --git a/applications/main/subghz/scenes/subghz_scene_signal_settings.c b/applications/main/subghz/scenes/subghz_scene_signal_settings.c index e74219a28..13c8234e2 100644 --- a/applications/main/subghz/scenes/subghz_scene_signal_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_signal_settings.c @@ -47,6 +47,7 @@ static Protocols protocols[] = { {"CAME Atomo", 4}, {"Alutech AT-4N", 3}, {"KeeLoq", 7}, + {"Phoenix_V2", 3}, }; #define PROTOCOLS_COUNT (sizeof(protocols) / sizeof(Protocols)); diff --git a/documentation/SubGHzCounterMode.md b/documentation/SubGHzCounterMode.md index 54fd0e24e..76eac58e4 100644 --- a/documentation/SubGHzCounterMode.md +++ b/documentation/SubGHzCounterMode.md @@ -129,6 +129,24 @@ CounterMode: 1 --- +### 5. V2 Phoenix (Phox) + +**Mode 0 (Default):** +- Standard - acts like regular remote +- Uses rolling counter multiplier from global settings (default +1) +- Counter increments based on the multiplier value (default +1) +- Resets to 0 when overflow occurs (> 0xFFFF) + +**Mode 1 (ofex like):** +- Counter sequence: `0x0000 / 0x0001 / 0xFFFE / 0xFFFF` +- Verified as working + +**Mode 2 (0 - 4):** +- Counter sequence: `0x0000 / 0x0001 / 0x0002 / 0x0003 / 0x0004` +- Might work (let us know!) + +--- + ## Notes and Warnings ### Important Considerations: diff --git a/documentation/SubGHzSupportedSystems.md b/documentation/SubGHzSupportedSystems.md index faa42e9e1..eed5ee420 100644 --- a/documentation/SubGHzSupportedSystems.md +++ b/documentation/SubGHzSupportedSystems.md @@ -20,7 +20,7 @@ That list is only for default SubGHz app, apps like *Weather Station* have their - AN-Motors (Alutech) AT4 `433.92MHz` `AM650` (64 bits, Pseudo-Dynamic, KeeLoq based) - Ansonic `433MHz` `FM` (12 bits, Static) - BETT `433.92MHz` `AM650` (18 bits, Static) -- Beninca ARC (TOGO2VA) `433.92MHz` `AM650` (128 bits, Dynamic AES) +- Beninca ARC (TOGO2VA) `433.92MHz` `AM650` (128 bits, Dynamic AES) (button code `0` emulates `hidden button` option on the remote) - BFT Mitto `433.92MHz` `AM650` (64 bits, Dynamic, KeeLoq based with Seed) - CAME Atomo `433.92MHz, 868MHz` `AM650` (62 bits, Dynamic) - CAME TWEE `433.92MHz` `AM650` (54 bits, Static) @@ -46,7 +46,7 @@ That list is only for default SubGHz app, apps like *Weather Station* have their - Nice One `433.92MHz` `AM650` (72 bits, Dynamic) - Revers RB2 (Реверс РБ-2 (М)) `433.92MHz` `AM650` (64 bits, Static) - Roger `433.92MHz` `AM650` (28 bits, Static) -- V2 Phoenix (Phox) `433.92MHz` `AM650` (52 bits, Dynamic) +- V2 Phoenix (Phox) `433.92MHz` `AM650` (52 bits, Dynamic) (receivers have option to enable Static mode, making them ignore rolling part of the key) - Marantec `433.92MHz, 868MHz` `AM650` (49 bits, Static) - Marantec24 `868MHz` `AM650` (24 bits, Static) - Somfy Keytis `433.92MHz, 868MHz` `AM650` (80 bits, Dynamic) diff --git a/lib/subghz/protocols/phoenix_v2.c b/lib/subghz/protocols/phoenix_v2.c index 1f2731f54..e6d5d6710 100644 --- a/lib/subghz/protocols/phoenix_v2.c +++ b/lib/subghz/protocols/phoenix_v2.c @@ -91,6 +91,8 @@ void subghz_protocol_encoder_phoenix_v2_free(void* context) { free(instance); } +static uint8_t v2_phoenix_counter_mode = 0; + // Pre define functions static uint16_t subghz_protocol_phoenix_v2_encrypt_counter(uint64_t full_key, uint16_t counter); static void subghz_protocol_phoenix_v2_check_remote_controller(SubGhzBlockGeneric* instance); @@ -252,18 +254,30 @@ static bool btn = subghz_protocol_phoenix_v2_get_btn_code(); // Reconstruction of the data - // Check for OFEX (overflow experimental) mode - if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { - // standart counter mode. PULL data from subghz_block_generic_global variables - if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { - // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value - if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { + if(v2_phoenix_counter_mode == 0) { + // Check for OFEX (overflow experimental) mode + if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } + } + } else { + if((instance->generic.cnt + 0x1) > 0xFFFF) { instance->generic.cnt = 0; + } else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xFFFE) { + instance->generic.cnt = 0xFFFE; } else { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + instance->generic.cnt++; } } - } else { + } else if(v2_phoenix_counter_mode == 1) { + // Mode 1 (ofex like) + // 0000 / 0001 / FFFE / FFFF if((instance->generic.cnt + 0x1) > 0xFFFF) { instance->generic.cnt = 0; } else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xFFFE) { @@ -271,6 +285,14 @@ static bool } else { instance->generic.cnt++; } + } else { + // Mode 2 (0 to 4) + // 0x0000 / 0x0001 / 0x0002 / 0x0003 / 0x0004 + if(instance->generic.cnt >= 0x0004) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt++; + } } uint64_t local_data_rev = subghz_protocol_blocks_reverse_key( @@ -326,6 +348,18 @@ SubGhzProtocolStatus flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + + uint32_t tmp_counter_mode; + if(flipper_format_read_uint32(flipper_format, "CounterMode", &tmp_counter_mode, 1)) { + v2_phoenix_counter_mode = (uint8_t)tmp_counter_mode; + } else { + v2_phoenix_counter_mode = 0; + } + subghz_protocol_phoenix_v2_check_remote_controller(&instance->generic); if(!subghz_protocol_encoder_phoenix_v2_get_upload(instance)) { @@ -333,6 +367,11 @@ SubGhzProtocolStatus break; } + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + uint8_t key_data[sizeof(uint64_t)] = {0}; for(size_t i = 0; i < sizeof(uint64_t); i++) { key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data >> i * 8) & 0xFF; @@ -582,10 +621,25 @@ SubGhzProtocolStatus subghz_protocol_decoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderPhoenix_V2* instance = context; - return subghz_block_generic_deserialize_check_count_bit( + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; + + ret = subghz_block_generic_deserialize_check_count_bit( &instance->generic, flipper_format, subghz_protocol_phoenix_v2_const.min_count_bit_for_found); + + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + return SubGhzProtocolStatusError; + } + + uint32_t tmp_counter_mode; + if(flipper_format_read_uint32(flipper_format, "CounterMode", &tmp_counter_mode, 1)) { + v2_phoenix_counter_mode = (uint8_t)tmp_counter_mode; + } else { + v2_phoenix_counter_mode = 0; + } + return ret; } void subghz_protocol_decoder_phoenix_v2_get_string(void* context, FuriString* output) { From 3872c7a73d85ae0b7c0658c691098d0fea8e4ced Mon Sep 17 00:00:00 2001 From: Luis Mayo Valbuena Date: Sun, 1 Feb 2026 14:31:31 +0100 Subject: [PATCH 091/160] feat: add IR capabilities to the JS engine --- applications/system/js_app/application.fam | 8 ++ .../apps/Scripts/js_examples/infrared-send.js | 47 +++++++ applications/system/js_app/js_modules.c | 1 + .../js_app/modules/js_infrared/js_infrared.c | 129 ++++++++++++++++++ .../packages/fz-sdk/infrared/index.d.ts | 41 ++++++ 5 files changed, 226 insertions(+) create mode 100644 applications/system/js_app/examples/apps/Scripts/js_examples/infrared-send.js create mode 100644 applications/system/js_app/modules/js_infrared/js_infrared.c create mode 100644 applications/system/js_app/packages/fz-sdk/infrared/index.d.ts diff --git a/applications/system/js_app/application.fam b/applications/system/js_app/application.fam index abafb6ea0..baef951e8 100644 --- a/applications/system/js_app/application.fam +++ b/applications/system/js_app/application.fam @@ -240,6 +240,14 @@ App( sources=["modules/js_subghz/*.c"], ) +App( + appid="js_infrared", + apptype=FlipperAppType.PLUGIN, + entry_point="js_infrared_ep", + requires=["js_app"], + sources=["modules/js_infrared/*.c"], +) + App( appid="js_blebeacon", apptype=FlipperAppType.PLUGIN, diff --git a/applications/system/js_app/examples/apps/Scripts/js_examples/infrared-send.js b/applications/system/js_app/examples/apps/Scripts/js_examples/infrared-send.js new file mode 100644 index 000000000..6606ef5f8 --- /dev/null +++ b/applications/system/js_app/examples/apps/Scripts/js_examples/infrared-send.js @@ -0,0 +1,47 @@ +checkSdkFeatures(["infrared-send"]); +let infrared = require("infrared"); + +print("Sending Samsung32 signal (lowers volume)..."); +infrared.sendSignal("Samsung32", 0x00000007, 0x0000000b); +delay(1000); +print("Sending raw signal... (Fujitsu AC)"); +infrared.sendRawSignal( + [ + 3298, 1571, 442, 368, 442, 367, 443, 1180, 442, 370, 440, 1181, 442, 368, + 442, 367, 442, 368, 442, 1180, 443, 1180, 442, 368, 441, 367, 442, 369, 441, + 1180, 442, 1180, 443, 368, 442, 369, 441, 368, 442, 368, 442, 368, 442, 368, + 441, 368, 441, 368, 442, 368, 442, 368, 442, 367, 442, 368, 442, 366, 444, + 1181, 442, 368, 441, 367, 442, 368, 442, 367, 442, 369, 441, 367, 443, 367, + 442, 1180, 442, 368, 442, 368, 442, 368, 441, 368, 441, 1180, 442, 1180, + 442, 1181, 442, 1181, 441, 1181, 442, 1181, 442, 1181, 442, 1181, 442, 369, + 441, 368, 441, 1182, 442, 367, 443, 367, 443, 367, 442, 368, 442, 1181, 441, + 369, 441, 369, 441, 369, 441, 1180, 442, 1181, 441, 369, 442, 368, 442, 367, + 442, 368, 441, 1181, 441, 1183, 440, 368, 442, 368, 441, 369, 441, 1181, + 442, 368, 442, 367, 443, 1181, 442, 368, 442, 369, 441, 368, 441, 369, 440, + 368, 442, 367, 443, 367, 442, 367, 442, 367, 442, 368, 442, 369, 441, 369, + 441, 368, 442, 369, 441, 368, 441, 367, 443, 368, 442, 367, 442, 369, 441, + 369, 441, 368, 441, 367, 442, 367, 442, 368, 442, 368, 441, 368, 442, 368, + 442, 368, 441, 367, 442, 367, 442, 368, 442, 368, 441, 368, 442, 369, 441, + 368, 441, 367, 442, 368, 441, 368, 442, 368, 442, 368, 442, 368, 442, 367, + 442, 1181, 442, 367, 442, 368, 441, 1181, 442, 1182, 441, 1181, 442, 1181, + 442, 1181, 441, 368, 442, 368, 442, 369, 441, + ], + true, + { frequency: 38000, dutyCycle: 0.33 }, +); +delay(1000); +print( + "Sending raw signal... (Fujitsu AC) with default frequency and duty cycle", +); +infrared.sendRawSignal([ + 3300, 1596, 416, 362, 448, 363, 446, 1177, 445, 363, 446, 1177, 445, 362, 448, + 362, 448, 364, 446, 1178, 444, 1207, 415, 362, 448, 362, 448, 363, 447, 1177, + 445, 1177, 446, 362, 448, 362, 447, 362, 447, 362, 448, 363, 447, 362, 447, + 363, 447, 363, 447, 363, 446, 363, 446, 362, 447, 362, 447, 363, 446, 1177, + 445, 363, 447, 364, 446, 362, 448, 363, 447, 363, 446, 362, 447, 362, 448, + 1175, 447, 363, 447, 364, 446, 362, 448, 362, 448, 1176, 446, 362, 448, 362, + 448, 363, 446, 362, 448, 362, 448, 363, 447, 1175, 446, 394, 415, 1176, 446, + 1178, 444, 1174, 449, 1177, 445, 1180, 443, 1179, 443, +]); + +print("Success"); diff --git a/applications/system/js_app/js_modules.c b/applications/system/js_app/js_modules.c index 93c8b4af8..845a596ab 100644 --- a/applications/system/js_app/js_modules.c +++ b/applications/system/js_app/js_modules.c @@ -281,6 +281,7 @@ static const char* extra_features[] = { "blebeacon", "i2c", "spi", + "infrared-send", "subghz", "usbdisk", "vgm", diff --git a/applications/system/js_app/modules/js_infrared/js_infrared.c b/applications/system/js_app/modules/js_infrared/js_infrared.c new file mode 100644 index 000000000..9015a98ea --- /dev/null +++ b/applications/system/js_app/modules/js_infrared/js_infrared.c @@ -0,0 +1,129 @@ +#include "../../js_modules.h" +#include +#include +#include + +#define TAG "JsMath" + +static void ret_bad_args(struct mjs* mjs, const char* error) { + mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "%s", error); + mjs_return(mjs, MJS_UNDEFINED); +} + +void js_send_protocol_signal(struct mjs* mjs) { + size_t num_args = mjs_nargs(mjs); + if(num_args < 3 || num_args > 4) { + ret_bad_args(mjs, "Wrong argument count"); + return; + } + if(!mjs_is_string(mjs_arg(mjs, 0)) || !mjs_is_number(mjs_arg(mjs, 1)) || + !mjs_is_number(mjs_arg(mjs, 2)) || (num_args == 4 && !mjs_is_object(mjs_arg(mjs, 3)))) { + ret_bad_args(mjs, "Wrong argument type"); + return; + } + bool repeat = false; + int times = 1; + if(num_args == 4) { + mjs_val_t options_obj = mjs_arg(mjs, 3); + + mjs_val_t repeat_val = mjs_get(mjs, options_obj, "repeat", ~0); + if(mjs_is_boolean(repeat_val)) { + repeat = mjs_get_bool(mjs, repeat_val); + } else if(!mjs_is_undefined(repeat_val)) { + ret_bad_args(mjs, "Wrong 'repeat' option type"); + return; + } + + mjs_val_t times_val = mjs_get(mjs, options_obj, "times", ~0); + if(mjs_is_number(times_val)) { + times = mjs_get_int(mjs, times_val); + } else if(!mjs_is_undefined(times_val)) { + ret_bad_args(mjs, "Wrong 'times' option type"); + return; + } + } + + InfraredMessage message; + message.repeat = repeat; + mjs_val_t protocol_arg = mjs_arg(mjs, 0); + message.protocol = infrared_get_protocol_by_name(mjs_get_cstring(mjs, &protocol_arg)); + message.address = mjs_get_int(mjs, mjs_arg(mjs, 1)); + message.command = mjs_get_int(mjs, mjs_arg(mjs, 2)); + infrared_send(&message, times); +} + +void js_send_raw_signal(struct mjs* mjs) { + size_t num_args = mjs_nargs(mjs); + if(num_args < 1 || num_args > 3) { + ret_bad_args(mjs, "Wrong argument count"); + return; + } + if(!mjs_is_array(mjs_arg(mjs, 0)) || (num_args > 1 && !mjs_is_boolean(mjs_arg(mjs, 1))) || + (num_args > 2 && !mjs_is_object(mjs_arg(mjs, 2)))) { + ret_bad_args(mjs, "Wrong argument type"); + return; + } + int array_length = mjs_array_length(mjs, mjs_arg(mjs, 0)); + uint32_t timings[array_length]; + for(int i = 0; i < array_length; i++) { + mjs_val_t elem = mjs_array_get(mjs, mjs_arg(mjs, 0), i); + if(!mjs_is_number(elem)) { + ret_bad_args(mjs, "Timings array must contain only numbers"); + return; + } + timings[i] = mjs_get_int(mjs, elem); + } + + bool start_from_mark = true; + if(num_args > 1) { + start_from_mark = mjs_get_bool(mjs, mjs_arg(mjs, 1)); + } + + if(num_args > 2) { + mjs_val_t options_obj = mjs_arg(mjs, 2); + + mjs_val_t frequency_val = mjs_get(mjs, options_obj, "frequency", ~0); + if(!mjs_is_number(frequency_val)) { + ret_bad_args(mjs, "Wrong 'frequency' option type"); + return; + } + + mjs_val_t duty_val = mjs_get(mjs, options_obj, "dutyCycle", ~0); + if(!mjs_is_number(duty_val)) { + ret_bad_args(mjs, "Wrong 'dutyCycle' option type"); + return; + } + uint32_t frequency = mjs_get_int(mjs, frequency_val); + float duty_cycle = mjs_get_double(mjs, duty_val); + infrared_send_raw_ext(timings, array_length, start_from_mark, frequency, duty_cycle); + } else { + infrared_send_raw(timings, array_length, start_from_mark); + } + return; +} + +static void* js_infrared_create(struct mjs* mjs, mjs_val_t* object, JsModules* modules) { + UNUSED(modules); + mjs_val_t infrared_object = mjs_mk_object(mjs); + mjs_set(mjs, infrared_object, "sendSignal", ~0, MJS_MK_FN(js_send_protocol_signal)); + mjs_set(mjs, infrared_object, "sendRawSignal", ~0, MJS_MK_FN(js_send_raw_signal)); + *object = infrared_object; + return (void*)1; +} + +static const JsModuleDescriptor js_infrared_desc = { + "infrared", + js_infrared_create, + NULL, + NULL, +}; + +static const FlipperAppPluginDescriptor plugin_descriptor = { + .appid = PLUGIN_APP_ID, + .ep_api_version = PLUGIN_API_VERSION, + .entry_point = &js_infrared_desc, +}; + +const FlipperAppPluginDescriptor* js_infrared_ep(void) { + return &plugin_descriptor; +} diff --git a/applications/system/js_app/packages/fz-sdk/infrared/index.d.ts b/applications/system/js_app/packages/fz-sdk/infrared/index.d.ts new file mode 100644 index 000000000..4767167f1 --- /dev/null +++ b/applications/system/js_app/packages/fz-sdk/infrared/index.d.ts @@ -0,0 +1,41 @@ +/** + * Module for using Infrared blaster/receptor + * @version Available with JS feature `infrared-send` + * @module + */ + +/** + * Sends an IR signal using a known protocol by Flipper Firmware + * @param address Note that the address expects a number. If you're reading from Flipper's IR files, the address is usually in little-endian hex format. Javascript numbers are defined as big endian by default. + * @param command Note that the command expects a number. If you're reading from Flipper's IR files, the command is usually in little-endian hex format. Javascript numbers are defined as big endian by default. + * @param options Repeat marks the signal as a repeat signal, times indicates how many times to send the signal + */ +export declare function sendSignal( + protocol: + | "NEC" + | "NECext" + | "NEC42" + | "NEC42ext" + | "Samsung32" + | "RC6" + | "RC5" + | "RC5X" + | "SIRC" + | "SIRC15" + | "SIRC20" + | "Kaseikyo" + | "RCA", + address: number, + command: number, + options?: { repeat?: boolean; times?: number }, +): void; + +/** + * Sends a signal from an unknown protocol + * @param startFromMark defaults to true + */ +export declare function sendRawSignal( + timings: number[], + startFromMark?: boolean, + advancedSettings?: { frequency: number; dutyCycle: number }, +): void; From 1d32d1de5cd116dadb4f3f73a5c6d59c545afaad Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Mon, 2 Feb 2026 01:22:39 +0700 Subject: [PATCH 092/160] btn_is_available = true --- .../main/subghz/helpers/subghz_txrx.c | 5 - .../scenes/subghz_scene_receiver_info.c | 45 +++-- .../scenes/subghz_scene_signal_settings.c | 112 ++++++----- .../subghz/scenes/subghz_scene_transmitter.c | 95 +++------- lib/subghz/blocks/generic.c | 23 ++- lib/subghz/blocks/generic.h | 34 +++- lib/subghz/protocols/alutech_at_4n.c | 14 +- lib/subghz/protocols/ansonic.c | 13 +- lib/subghz/protocols/beninca_arc.c | 13 +- lib/subghz/protocols/bett.c | 4 +- lib/subghz/protocols/bin_raw.c | 4 +- lib/subghz/protocols/came.c | 4 +- lib/subghz/protocols/came_atomo.c | 13 +- lib/subghz/protocols/came_twee.c | 10 +- lib/subghz/protocols/chamberlain_code.c | 4 +- lib/subghz/protocols/clemsa.c | 13 +- lib/subghz/protocols/dickert_mahs.c | 4 +- lib/subghz/protocols/doitrand.c | 11 +- lib/subghz/protocols/dooya.c | 13 +- lib/subghz/protocols/elplast.c | 4 +- lib/subghz/protocols/faac_slh.c | 176 ++++++++++-------- lib/subghz/protocols/feron.c | 4 +- lib/subghz/protocols/gangqi.c | 14 +- lib/subghz/protocols/gate_tx.c | 11 +- lib/subghz/protocols/hay21.c | 13 +- lib/subghz/protocols/hollarm.c | 14 +- lib/subghz/protocols/holtek.c | 10 +- lib/subghz/protocols/holtek_ht12x.c | 10 +- lib/subghz/protocols/honeywell.c | 2 +- lib/subghz/protocols/honeywell_wdb.c | 4 +- lib/subghz/protocols/hormann.c | 12 +- lib/subghz/protocols/ido.c | 6 + lib/subghz/protocols/intertechno_v3.c | 14 +- lib/subghz/protocols/jarolift.c | 13 +- lib/subghz/protocols/keeloq.c | 17 ++ lib/subghz/protocols/kinggates_stylo_4k.c | 13 +- lib/subghz/protocols/legrand.c | 4 +- lib/subghz/protocols/linear.c | 4 +- lib/subghz/protocols/linear_delta3.c | 4 +- lib/subghz/protocols/magellan.c | 11 +- lib/subghz/protocols/marantec.c | 10 +- lib/subghz/protocols/marantec24.c | 10 +- lib/subghz/protocols/mastercode.c | 13 +- lib/subghz/protocols/megacode.c | 10 +- lib/subghz/protocols/nero_radio.c | 10 +- lib/subghz/protocols/nero_sketch.c | 4 +- lib/subghz/protocols/nice_flo.c | 4 +- lib/subghz/protocols/nice_flor_s.c | 13 +- lib/subghz/protocols/phoenix_v2.c | 13 +- lib/subghz/protocols/power_smart.c | 10 +- lib/subghz/protocols/princeton.c | 15 +- lib/subghz/protocols/revers_rb2.c | 4 +- lib/subghz/protocols/roger.c | 14 +- lib/subghz/protocols/secplus_v1.c | 9 +- lib/subghz/protocols/secplus_v2.c | 13 +- lib/subghz/protocols/smc5326.c | 4 +- lib/subghz/protocols/somfy_keytis.c | 16 +- lib/subghz/protocols/somfy_telis.c | 16 +- lib/subghz/protocols/treadmill37.c | 11 +- targets/f7/api_symbols.csv | 4 +- targets/f7/furi_hal/furi_hal_subghz.c | 10 +- 61 files changed, 675 insertions(+), 332 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index 8abf373f4..ca3f0b300 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -234,7 +234,6 @@ SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* SubGhzTxRxStartTxState ret = SubGhzTxRxStartTxStateErrorParserOthers; FuriString* temp_str = furi_string_alloc(); - uint32_t repeat = 200; do { if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); @@ -244,10 +243,6 @@ SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* FURI_LOG_E(TAG, "Missing Protocol"); break; } - if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { - FURI_LOG_E(TAG, "Unable Repeat"); - break; - } ret = SubGhzTxRxStartTxStateOk; SubGhzRadioPreset* preset = instance->preset; diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index e68b0203d..f2970d343 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -2,6 +2,9 @@ #include +#include "applications/main/subghz/helpers/subghz_txrx_i.h" +#include + #define TAG "SubGhzSceneReceiverInfo" void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, void* context) { @@ -133,25 +136,22 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) subghz_txrx_hopper_unpause(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateRx; } else { + // key concept: we start endless TX until user release OK button, and after this we send last + // protocols repeats - this guarantee that one press OK will + // be guarantee send the required minimum protocol data packets + // for all of this we use subghz_block_generic_global.endless_tx in protocols _yield function. subghz->state_notifications = SubGhzNotificationStateTx; + subghz_block_generic_global.endless_tx = true; } return true; } else if(event.event == SubGhzCustomEventSceneReceiverInfoTxStop) { - //CC1101 Stop Tx -> Start RX + //CC1101 Stop Tx -> next tick event Start RX + // user release OK + // we switch off endless_tx - that mean protocols yield finish endless transmission, + // send upload "repeat=xx" times, and after will be stoped by the tick event down in this code subghz->state_notifications = SubGhzNotificationStateIDLE; + subghz_block_generic_global.endless_tx = false; - widget_reset(subghz->widget); - subghz_scene_receiver_info_draw_widget(subghz); - - subghz_txrx_stop(subghz->txrx); - if(!scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneDecodeRAW)) { - subghz_txrx_rx_start(subghz->txrx); - - subghz_txrx_hopper_unpause(subghz->txrx); - if(!subghz_history_get_text_space_left(subghz->history, NULL)) { - subghz->state_notifications = SubGhzNotificationStateRx; - } - } return true; } else if(event.event == SubGhzCustomEventSceneReceiverInfoSave) { //CC1101 Stop RX -> Save @@ -188,6 +188,25 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) notification_message(subghz->notifications, &sequence_blink_green_100); subghz->state_notifications = SubGhzNotificationStateRx; break; + case SubGhzNotificationStateIDLE: + // we wait until hardware TX finished and after stop TX and start RX, else just blink led + if(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { + notification_message(subghz->notifications, &sequence_blink_magenta_10); + } else { + subghz_txrx_stop(subghz->txrx); + // update screen + widget_reset(subghz->widget); + subghz_scene_receiver_info_draw_widget(subghz); + + if(!scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneDecodeRAW)) { + subghz_txrx_rx_start(subghz->txrx); + subghz_txrx_hopper_unpause(subghz->txrx); + if(!subghz_history_get_text_space_left(subghz->history, NULL)) { + subghz->state_notifications = SubGhzNotificationStateRx; + } + } + } + break; default: break; } diff --git a/applications/main/subghz/scenes/subghz_scene_signal_settings.c b/applications/main/subghz/scenes/subghz_scene_signal_settings.c index c8a0cf2a6..06fe5bc39 100644 --- a/applications/main/subghz/scenes/subghz_scene_signal_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_signal_settings.c @@ -20,6 +20,8 @@ static uint8_t button = 0x0; static uint8_t btn_byte_count = 1; static uint8_t* btn_byte_ptr = NULL; +static uint8_t submenu_called = 0; + #define COUNTER_MODE_COUNT 7 static const char* const counter_mode_text[COUNTER_MODE_COUNT] = { "System", @@ -72,6 +74,7 @@ void subghz_scene_signal_settings_variable_item_list_enter_callback(void* contex // when we click OK on "Edit counter" item if(index == 1) { + submenu_called = 1; furi_string_cat_printf(byte_input_text, "%i", subghz_block_generic_global.cnt_length_bit); furi_string_cat_str(byte_input_text, "-bits counter in HEX"); @@ -90,7 +93,9 @@ void subghz_scene_signal_settings_variable_item_list_enter_callback(void* contex } // when we click OK on "Edit button" item if(index == 2) { - furi_string_cat_str(byte_input_text, " button number in HEX"); + submenu_called = 2; + furi_string_cat_printf(byte_input_text, "%i", subghz_block_generic_global.btn_length_bit); + furi_string_cat_str(byte_input_text, "-bits button in HEX"); // Setup byte_input view ByteInput* byte_input = subghz->byte_input; @@ -156,6 +161,28 @@ void subghz_scene_signal_settings_on_enter(void* context) { bool counter_not_available = true; bool button_not_available = true; + //Create and Enable/Disable variable_item_list depending on current values + VariableItemList* variable_item_list = subghz->variable_item_list; + int32_t value_index; + VariableItem* item; + + variable_item_list_set_enter_callback( + variable_item_list, + subghz_scene_signal_settings_variable_item_list_enter_callback, + subghz); + + item = variable_item_list_add( + variable_item_list, + "Counter Mode", + mode_count, + subghz_scene_signal_settings_counter_mode_changed, + subghz); + value_index = value_index_int32(counter_mode, counter_mode_value, mode_count); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, counter_mode_text[value_index]); + variable_item_set_locked(item, (counter_mode == 0xff), "Not available\nfor this\nprotocol !"); + // + SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(subghz->txrx); // deserialaze and decode loaded sugbhz file and push data to subghz_block_generic_global variable @@ -191,6 +218,12 @@ void subghz_scene_signal_settings_on_enter(void* context) { } } + item = variable_item_list_add(variable_item_list, "Edit Counter", 1, NULL, subghz); + variable_item_set_current_value_index(item, 0); + variable_item_set_current_value_text(item, furi_string_get_cstr(tmp_text)); + variable_item_set_locked(item, (counter_not_available), "Not available\nfor this\nprotocol !"); + // + // ### Button edit section ### if(!subghz_block_generic_global.btn_is_available) { @@ -202,41 +235,15 @@ void subghz_scene_signal_settings_on_enter(void* context) { btn_byte_ptr = (uint8_t*)&button; } - furi_assert(cnt_byte_ptr); - furi_assert(cnt_byte_count > 0); - furi_assert(btn_byte_ptr); - - //Create and Enable/Disable variable_item_list depending on current values - VariableItemList* variable_item_list = subghz->variable_item_list; - int32_t value_index; - VariableItem* item; - - variable_item_list_set_enter_callback( - variable_item_list, - subghz_scene_signal_settings_variable_item_list_enter_callback, - subghz); - - item = variable_item_list_add( - variable_item_list, - "Counter Mode", - mode_count, - subghz_scene_signal_settings_counter_mode_changed, - subghz); - value_index = value_index_int32(counter_mode, counter_mode_value, mode_count); - - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, counter_mode_text[value_index]); - variable_item_set_locked(item, (counter_mode == 0xff), "Not available\nfor this\nprotocol !"); - - item = variable_item_list_add(variable_item_list, "Edit Counter", 1, NULL, subghz); - variable_item_set_current_value_index(item, 0); - variable_item_set_current_value_text(item, furi_string_get_cstr(tmp_text)); - variable_item_set_locked(item, (counter_not_available), "Not available\nfor this\nprotocol !"); - item = variable_item_list_add(variable_item_list, "Edit Button", 1, NULL, subghz); variable_item_set_current_value_index(item, 0); variable_item_set_current_value_text(item, furi_string_get_cstr(tmp_text)); variable_item_set_locked(item, (button_not_available), "Not available\nfor this\nprotocol !"); + // + + furi_assert(cnt_byte_ptr); + furi_assert(cnt_byte_count > 0); + furi_assert(btn_byte_ptr); furi_string_free(tmp_text); @@ -248,21 +255,40 @@ bool subghz_scene_signal_settings_on_event(void* context, SceneManagerEvent even if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventByteInputDone) { - switch(cnt_byte_count) { + switch(submenu_called) { + // edit counter + case 1: + switch(cnt_byte_count) { + case 2: + // set new cnt value and override_flag to global variable and call transmit to generate and save subghz signal + counter16 = __bswap16(counter16); + subghz_block_generic_global_counter_override_set(counter16); + subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); + subghz_txrx_stop(subghz->txrx); + break; + case 4: + // the same for 32 bit Counter + counter32 = __bswap32(counter32); + subghz_block_generic_global_counter_override_set(counter32); + subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); + subghz_txrx_stop(subghz->txrx); + break; + default: + break; + } + break; + // edit button case 2: - // set new cnt value and override_flag to global variable and call transmit to generate and save subghz signal - counter16 = __bswap16(counter16); - subghz_block_generic_global_counter_override_set(counter16); - subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); - subghz_txrx_stop(subghz->txrx); - break; - case 4: - // the same for 32 bit Counter - counter32 = __bswap32(counter32); - subghz_block_generic_global_counter_override_set(counter32); + subghz_block_generic_global_button_override_set(button); + // save counter mult to rewrite subghz singnal without changing counter + int32_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); + furi_hal_subghz_set_rolling_counter_mult(0); subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); subghz_txrx_stop(subghz->txrx); + // restore counter mult + furi_hal_subghz_set_rolling_counter_mult(tmp_counter); break; + default: break; } diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index b27d88da0..ed2f04389 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -3,14 +3,11 @@ #include #include -<<<<<<< HEAD -======= #include - #include "applications/main/subghz/helpers/subghz_txrx_i.h" #include "lib/subghz/blocks/generic.h" ->>>>>>> cf35909c8 (work to home) + #define TAG "SubGhzSceneTransmitter" void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) { @@ -70,11 +67,16 @@ void subghz_scene_transmitter_on_enter(void* context) { } bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { + // key concept: we start endless TX until user release OK button, and after this we send last + // protocols repeats - this guarantee that one press OK will + // be guarantee send the required minimum protocol data packets + // for all of this we use subghz_block_generic_global.endless_tx in protocols _yield function. SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventViewTransmitterSendStart) { + // user press OK - start endless TX subghz->state_notifications = SubGhzNotificationStateIDLE; - FURI_LOG_D("000000", "PRESS"); + subghz_block_generic_global.endless_tx = true; if(subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { subghz->state_notifications = SubGhzNotificationStateTx; subghz_scene_transmitter_update_data_show(subghz); @@ -82,41 +84,12 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { } return true; } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) { -<<<<<<< HEAD -======= - FURI_LOG_D("111111", "RELEASE"); - - // if we recieve event to stop tranmission (user release OK button) but - // hardware TX still working now then set flag to stop it after hardware TX will be realy ended - if(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { - subghz_block_generic_global.endless_tx = true; - tx_stop_called = true; - FURI_LOG_D("111111", "STOP CALLED"); - return true; - } - // if hardware TX not working now so just stop TX correctly ->>>>>>> cf35909c8 (work to home) - subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz_txrx_stop(subghz->txrx); + // user release OK + // we switch off endless_tx - that mean protocols yield finish endless transmission, + // send upload "repeat=xx" times, and after will be stoped by tick event down this code. subghz_block_generic_global.endless_tx = false; - if(subghz_custom_btn_get() != SUBGHZ_CUSTOM_BTN_OK) { - subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); - int32_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); - furi_hal_subghz_set_rolling_counter_mult(0); - // Calling restore! - subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); - subghz_txrx_stop(subghz->txrx); - // Calling restore 2nd time special for FAAC SLH! - // TODO: Find better way to restore after custom button is used!!! - subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); - subghz_txrx_stop(subghz->txrx); - furi_hal_subghz_set_rolling_counter_mult(tmp_counter); - } - FURI_LOG_D("111111", "JUST STOP"); - return true; } else if(event.event == SubGhzCustomEventViewTransmitterBack) { - subghz->state_notifications = SubGhzNotificationStateIDLE; scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); return true; @@ -126,42 +99,28 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { } } else if(event.type == SceneManagerEventTypeTick) { if(subghz->state_notifications == SubGhzNotificationStateTx) { -<<<<<<< HEAD - notification_message(subghz->notifications, &sequence_blink_magenta_10); -======= - // if hardware TX still working at this time so we just blink led and do nothing + // if hardware TX still working at this time so we just blink led and return if(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { notification_message(subghz->notifications, &sequence_blink_magenta_10); return true; - - // if hardware TX not working now and tx_stop_called = true - // (mean user release OK button early than hardware TX was ended) then we stop TX - if(tx_stop_called) { - FURI_LOG_D("22222222", "STOP BY CALL"); - - // tx_stop_called = false; - // subghz->state_notifications = SubGhzNotificationStateIDLE; - // subghz_txrx_stop(subghz->txrx); - // // subghz_block_generic_global.endless_tx = false; - // if(subghz_custom_btn_get() != SUBGHZ_CUSTOM_BTN_OK) { - // subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); - // int32_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); - // furi_hal_subghz_set_rolling_counter_mult(0); - // // Calling restore! - // subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); - // subghz_txrx_stop(subghz->txrx); - // // Calling restore 2nd time special for FAAC SLH! - // // TODO: Find better way to restore after custom button is used!!! - // subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); - // subghz_txrx_stop(subghz->txrx); - // furi_hal_subghz_set_rolling_counter_mult(tmp_counter); - //} - return true; + // if hardware TX was stoped so we stop TX correctly + } else { + subghz->state_notifications = SubGhzNotificationStateIDLE; + subghz_txrx_stop(subghz->txrx); + if(subghz_custom_btn_get() != SUBGHZ_CUSTOM_BTN_OK) { + subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); + int32_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); + furi_hal_subghz_set_rolling_counter_mult(0); + // Calling restore! + subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); + subghz_txrx_stop(subghz->txrx); + // Calling restore 2nd time special for FAAC SLH! + // TODO: Find better way to restore after custom button is used!!! + subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); + subghz_txrx_stop(subghz->txrx); + furi_hal_subghz_set_rolling_counter_mult(tmp_counter); } - subghz_block_generic_global.endless_tx = true; - FURI_LOG_D("22222222", "ENDELSS TX ON"); } ->>>>>>> cf35909c8 (work to home) } return true; } diff --git a/lib/subghz/blocks/generic.c b/lib/subghz/blocks/generic.c index f5974ffaa..82fbc03c7 100644 --- a/lib/subghz/blocks/generic.c +++ b/lib/subghz/blocks/generic.c @@ -17,7 +17,7 @@ void subghz_block_generic_global_counter_override_set(uint32_t counter) { bool subghz_block_generic_global_counter_override_get(uint32_t* counter) { // if override flag was enabled then return succes TRUE and return overrided counter, else return success = FALSE - // we cut counter bit length to available protocol bits length by the logical AND function + // we cut counter bits length to available protocol bits length by the logical AND function if(subghz_block_generic_global.cnt_need_override) { *counter = subghz_block_generic_global.new_cnt & ((0xFFFFFFFF >> (32 - subghz_block_generic_global.cnt_length_bit))); @@ -28,9 +28,30 @@ bool subghz_block_generic_global_counter_override_get(uint32_t* counter) { } } +void subghz_block_generic_global_button_override_set(uint8_t button) { + subghz_block_generic_global.new_btn = button; // set global variable + subghz_block_generic_global.btn_need_override = true; // set flag for protocols +} + +bool subghz_block_generic_global_button_override_get(uint8_t* button) { + // if override flag was enabled then return succes TRUE and return overrided button, else return success = FALSE + // we cut button bits length to available protocol bits length by the logical AND function + if(subghz_block_generic_global.btn_need_override) { + *button = subghz_block_generic_global.new_btn & + ((0xFF >> (8 - subghz_block_generic_global.btn_length_bit))); + subghz_block_generic_global.btn_need_override = false; + return true; + } else { + return false; + } +} + void subghz_block_generic_global_reset(void* p) { UNUSED(p); + // dont reset endless_tx, its used in protocols yield function to undless TX + bool tmp = subghz_block_generic_global.endless_tx; memset(&subghz_block_generic_global, 0, sizeof(subghz_block_generic_global)); + subghz_block_generic_global.endless_tx = tmp; } void subghz_block_generic_get_preset_name(const char* preset_name, FuriString* preset_str) { diff --git a/lib/subghz/blocks/generic.h b/lib/subghz/blocks/generic.h index daed68b07..788467a79 100644 --- a/lib/subghz/blocks/generic.h +++ b/lib/subghz/blocks/generic.h @@ -30,35 +30,49 @@ struct SubGhzBlockGeneric { typedef struct SubGhzBlockGenericGlobal SubGhzBlockGenericGlobal; struct SubGhzBlockGenericGlobal { - uint32_t current_cnt; // global counter value; - uint32_t new_cnt; // global counter value; + uint32_t current_cnt; // current counter value; + uint32_t new_cnt; // new counter value; bool cnt_need_override; // flag for protocols to override signals counter inside of protocols - uint8_t cnt_length_bit; // counter length in bytes (used in counter editor giu) + uint8_t cnt_length_bit; // counter length in bits (used in counter editor giu) bool cnt_is_available; // is there counter available for protocol (used in counter editor giu) - uint8_t current_btn; // global counter value; - uint8_t new_btn; // global counter value; - bool btn_need_override; // flag for protocols to override signals counter inside of protocols - bool btn_is_available; // is there counter available for protocol (used in counter editor giu) + uint8_t current_btn; // current button value; + uint8_t new_btn; // new button value; + bool btn_need_override; // flag for protocols to override button inside of protocols + uint8_t btn_length_bit; // button length in bits (used in counter editor giu) + bool btn_is_available; // is there button available for protocol (used in button editor giu) - bool endless_tx; // used for endless/breakless transmission in subghz protols (when user not release OK button) + bool endless_tx; // used for endless/breakless transmission in subghz protols yield function (when user hold OK button) }; extern SubGhzBlockGenericGlobal subghz_block_generic_global; //global structure for subghz /** - * Setup SubGhzBlockGenericGlobal.cnt and cnt_need_override flag to be used in protocols; + * Setup new_cnt and cnt_need_override flag to be used in protocols; * @param counter new counter value; */ void subghz_block_generic_global_counter_override_set(uint32_t counter); /** - * Return true if incomming variable was overrided by SubGhzBlockGenericGlobal.cnt + * Return true if incomming variable was overrided by new_cnt * else return false and not change incomming variable * @param counter pointer to counter variable that must be changed */ bool subghz_block_generic_global_counter_override_get(uint32_t* counter); +/** + * Setup new_btn and btn_need_override flag to be used in protocols; + * @param button new button value; + */ +void subghz_block_generic_global_button_override_set(uint8_t button); + +/** + * Return true if incomming variable was overrided by new_btn + * else return false and not change incomming variable + * @param button pointer to counter variable that must be changed + */ +bool subghz_block_generic_global_button_override_get(uint8_t* button); + /** * Reset subghz_block_generic global structure; */ diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 5ebe1eb43..186d5fd25 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -94,7 +94,7 @@ void* subghz_protocol_encoder_alutech_at_4n_alloc(SubGhzEnvironment* environment instance->base.protocol = &subghz_protocol_alutech_at_4n; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 512; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -132,10 +132,10 @@ LevelDuration subghz_protocol_encoder_alutech_at_4n_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } - FURI_LOG_D("ALLLLLLL", "REPEAT - %i ", instance->encoder.repeat); + return ret; } @@ -400,6 +400,10 @@ static bool subghz_protocol_encoder_alutech_at_4n_get_upload( btn = subghz_protocol_alutech_at_4n_get_btn_code(); + // override button if we change it with signal settings button editor + if(subghz_block_generic_global_button_override_get(&btn)) + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", btn); + // Gen new key if(!subghz_protocol_alutech_at_4n_gen_data(instance, btn)) { return false; @@ -895,6 +899,10 @@ void subghz_protocol_decoder_alutech_at_4n_get_string(void* context, FuriString* subghz_block_generic_global.cnt_is_available = true; subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; + + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 8; // furi_string_cat_printf( diff --git a/lib/subghz/protocols/ansonic.c b/lib/subghz/protocols/ansonic.c index 1a9a69828..692e4aea5 100644 --- a/lib/subghz/protocols/ansonic.c +++ b/lib/subghz/protocols/ansonic.c @@ -82,7 +82,7 @@ void* subghz_protocol_encoder_ansonic_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_ansonic; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 30; + instance->encoder.repeat = 3; instance->encoder.size_upload = 52; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -180,10 +180,10 @@ LevelDuration subghz_protocol_encoder_ansonic_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } -FURI_LOG_D("ANNNN", "REPEAT - %i ",instance->encoder.repeat); + return ret; } @@ -323,6 +323,13 @@ void subghz_protocol_decoder_ansonic_get_string(void* context, FuriString* outpu furi_assert(context); SubGhzProtocolDecoderAnsonic* instance = context; subghz_protocol_ansonic_check_remote_controller(&instance->generic); + + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 2; + // + furi_string_cat_printf( output, "%s %dbit\r\n" diff --git a/lib/subghz/protocols/beninca_arc.c b/lib/subghz/protocols/beninca_arc.c index 83db66306..308989d61 100644 --- a/lib/subghz/protocols/beninca_arc.c +++ b/lib/subghz/protocols/beninca_arc.c @@ -256,7 +256,7 @@ void* subghz_protocol_encoder_beninca_arc_alloc(SubGhzEnvironment* environment) instance->generic.protocol_name = instance->base.protocol->name; instance->keystore = subghz_environment_get_keystore(environment); - instance->encoder.repeat = 10; + instance->encoder.repeat = 1; instance->encoder.size_upload = 800; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -350,6 +350,10 @@ static void subghz_protocol_beninca_arc_encoder_prepare_packets( // Generate new key using custom or default button instance->generic.btn = subghz_protocol_beninca_arc_get_btn_code(); + // override button if we change it with signal settings button editor + if(subghz_block_generic_global_button_override_get(&instance->generic.btn)) + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", instance->generic.btn); + // Make 3 packets with different mini counter values - 2, 4, 6 for(uint8_t i = 0; i < 3; i++) { subghz_protocol_beninca_arc_encrypt( @@ -477,7 +481,7 @@ LevelDuration subghz_protocol_encoder_beninca_arc_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -659,6 +663,11 @@ void subghz_protocol_decoder_beninca_arc_get_string(void* context, FuriString* o subghz_block_generic_global.cnt_length_bit = 32; subghz_block_generic_global.current_cnt = instance->generic.cnt; + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 8; + // + furi_string_printf( output, "%s %db\r\n" diff --git a/lib/subghz/protocols/bett.c b/lib/subghz/protocols/bett.c index 44946a2f6..2d61e33a8 100644 --- a/lib/subghz/protocols/bett.c +++ b/lib/subghz/protocols/bett.c @@ -91,7 +91,7 @@ void* subghz_protocol_encoder_bett_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_bett; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 52; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -199,7 +199,7 @@ LevelDuration subghz_protocol_encoder_bett_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } diff --git a/lib/subghz/protocols/bin_raw.c b/lib/subghz/protocols/bin_raw.c index ca52cdd49..b3959363a 100644 --- a/lib/subghz/protocols/bin_raw.c +++ b/lib/subghz/protocols/bin_raw.c @@ -142,7 +142,7 @@ void* subghz_protocol_encoder_bin_raw_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_bin_raw; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = BIN_RAW_BUF_DATA_SIZE * 5; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->data = malloc(instance->encoder.size_upload * sizeof(uint8_t)); @@ -342,7 +342,7 @@ LevelDuration subghz_protocol_encoder_bin_raw_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } diff --git a/lib/subghz/protocols/came.c b/lib/subghz/protocols/came.c index 2762a2484..04ea1767f 100644 --- a/lib/subghz/protocols/came.c +++ b/lib/subghz/protocols/came.c @@ -90,7 +90,7 @@ void* subghz_protocol_encoder_came_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_came; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -211,7 +211,7 @@ LevelDuration subghz_protocol_encoder_came_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } diff --git a/lib/subghz/protocols/came_atomo.c b/lib/subghz/protocols/came_atomo.c index f8ec7baa0..f46b90b2d 100644 --- a/lib/subghz/protocols/came_atomo.c +++ b/lib/subghz/protocols/came_atomo.c @@ -89,7 +89,7 @@ void* subghz_protocol_encoder_came_atomo_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_came_atomo; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 1; instance->encoder.size_upload = 900; //actual size 766+ instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -251,6 +251,10 @@ static void subghz_protocol_encoder_came_atomo_get_upload( btn = 0x6; } + // override button if we change it with signal settings button editor + if(subghz_block_generic_global_button_override_get(&btn)) + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", btn); + //Send header instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)subghz_protocol_came_atomo_const.te_long * 15); @@ -430,7 +434,7 @@ LevelDuration subghz_protocol_encoder_came_atomo_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -829,6 +833,11 @@ void subghz_protocol_decoder_came_atomo_get_string(void* context, FuriString* ou subghz_block_generic_global.cnt_is_available = true; subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; + + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // furi_string_cat_printf( diff --git a/lib/subghz/protocols/came_twee.c b/lib/subghz/protocols/came_twee.c index 3bb909dc8..20a4c5cc3 100644 --- a/lib/subghz/protocols/came_twee.c +++ b/lib/subghz/protocols/came_twee.c @@ -109,7 +109,7 @@ void* subghz_protocol_encoder_came_twee_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_came_twee; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 1536; //max upload 92*14 = 1288 !!!! instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -284,7 +284,7 @@ LevelDuration subghz_protocol_encoder_came_twee_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -444,6 +444,12 @@ void subghz_protocol_decoder_came_twee_get_string(void* context, FuriString* out uint32_t code_found_hi = instance->generic.data >> 32; uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + furi_string_cat_printf( output, "%s %db\r\n" diff --git a/lib/subghz/protocols/chamberlain_code.c b/lib/subghz/protocols/chamberlain_code.c index fda224bb6..3e003d4b6 100644 --- a/lib/subghz/protocols/chamberlain_code.c +++ b/lib/subghz/protocols/chamberlain_code.c @@ -105,7 +105,7 @@ void* subghz_protocol_encoder_chamb_code_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_chamb_code; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 24; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -254,7 +254,7 @@ LevelDuration subghz_protocol_encoder_chamb_code_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } diff --git a/lib/subghz/protocols/clemsa.c b/lib/subghz/protocols/clemsa.c index 672abcba3..27c2e26c5 100644 --- a/lib/subghz/protocols/clemsa.c +++ b/lib/subghz/protocols/clemsa.c @@ -90,7 +90,7 @@ void* subghz_protocol_encoder_clemsa_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_clemsa; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 52; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -199,7 +199,7 @@ LevelDuration subghz_protocol_encoder_clemsa_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -338,10 +338,17 @@ void subghz_protocol_decoder_clemsa_get_string(void* context, FuriString* output SubGhzProtocolDecoderClemsa* instance = context; subghz_protocol_clemsa_check_remote_controller(&instance->generic); //uint32_t data = (uint32_t)(instance->generic.data & 0xFFFFFF); + + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 2; + // + furi_string_cat_printf( output, "%s %dbit\r\n" - "Key:%05lX Btn %X\r\n" + "Key:%05lX Btn:%X\r\n" " +: " DIP_PATTERN "\r\n" " o: " DIP_PATTERN "\r\n" " -: " DIP_PATTERN "\r\n", diff --git a/lib/subghz/protocols/dickert_mahs.c b/lib/subghz/protocols/dickert_mahs.c index 65be6fd0c..4d8ad3606 100644 --- a/lib/subghz/protocols/dickert_mahs.c +++ b/lib/subghz/protocols/dickert_mahs.c @@ -132,7 +132,7 @@ void* subghz_protocol_encoder_dickert_mahs_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_dickert_mahs; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -237,7 +237,7 @@ LevelDuration subghz_protocol_encoder_dickert_mahs_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } diff --git a/lib/subghz/protocols/doitrand.c b/lib/subghz/protocols/doitrand.c index 7c7946042..1853bd16f 100644 --- a/lib/subghz/protocols/doitrand.c +++ b/lib/subghz/protocols/doitrand.c @@ -82,7 +82,7 @@ void* subghz_protocol_encoder_doitrand_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_doitrand; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -179,7 +179,7 @@ LevelDuration subghz_protocol_encoder_doitrand_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -333,6 +333,13 @@ void subghz_protocol_decoder_doitrand_get_string(void* context, FuriString* outp furi_assert(context); SubGhzProtocolDecoderDoitrand* instance = context; subghz_protocol_doitrand_check_remote_controller(&instance->generic); + + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 2; + // + furi_string_cat_printf( output, "%s %dbit\r\n" diff --git a/lib/subghz/protocols/dooya.c b/lib/subghz/protocols/dooya.c index fd8645a0b..07dec5346 100644 --- a/lib/subghz/protocols/dooya.c +++ b/lib/subghz/protocols/dooya.c @@ -77,7 +77,7 @@ void* subghz_protocol_encoder_dooya_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_dooya; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -189,7 +189,7 @@ LevelDuration subghz_protocol_encoder_dooya_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -418,16 +418,23 @@ void subghz_protocol_decoder_dooya_get_string(void* context, FuriString* output) subghz_protocol_dooya_check_remote_controller(&instance->generic); + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 8; + // + furi_string_cat_printf( output, "%s %dbit\r\n" "Key:0x%010llX\r\n" "Sn:0x%08lX\r\n" - "Btn:%s\r\n", + "Btn:%X - %s\r\n", instance->generic.protocol_name, instance->generic.data_count_bit, instance->generic.data, instance->generic.serial, + instance->generic.btn, subghz_protocol_dooya_get_name_button(instance->generic.btn)); if(instance->generic.cnt == DOYA_SINGLE_CHANNEL) { furi_string_cat_printf(output, "Ch:Single\r\n"); diff --git a/lib/subghz/protocols/elplast.c b/lib/subghz/protocols/elplast.c index 18d6d07b4..909689830 100644 --- a/lib/subghz/protocols/elplast.c +++ b/lib/subghz/protocols/elplast.c @@ -73,7 +73,7 @@ void* subghz_protocol_encoder_elplast_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_elplast; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -168,7 +168,7 @@ LevelDuration subghz_protocol_encoder_elplast_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } diff --git a/lib/subghz/protocols/faac_slh.c b/lib/subghz/protocols/faac_slh.c index 147e452eb..fb82b1379 100644 --- a/lib/subghz/protocols/faac_slh.c +++ b/lib/subghz/protocols/faac_slh.c @@ -109,7 +109,7 @@ void* subghz_protocol_encoder_faac_slh_alloc(SubGhzEnvironment* environment) { instance->generic.protocol_name = instance->base.protocol->name; instance->keystore = subghz_environment_get_keystore(environment); - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -124,108 +124,115 @@ void subghz_protocol_encoder_faac_slh_free(void* context) { } static bool subghz_protocol_faac_slh_gen_data(SubGhzProtocolEncoderFaacSLH* instance) { - // TODO: Stupid bypass for custom button, remake later - if(subghz_custom_btn_get_original() == 0) { - subghz_custom_btn_set_original(0xF); - } + // override button if we change it with signal settings button editor + // else work as standart + if(subghz_block_generic_global_button_override_get(&instance->generic.btn)) { + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", instance->generic.btn); + } else { + // TODO: Stupid bypass for custom button, remake later + if(subghz_custom_btn_get_original() == 0) { + subghz_custom_btn_set_original(0xF); + } - uint8_t custom_btn_id = subghz_custom_btn_get(); + uint8_t custom_btn_id = subghz_custom_btn_get(); - // If we are using UP button - generate programming mode key and send it, otherwise - send regular key if possible - if((custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) && - !(!allow_zero_seed && (instance->generic.seed == 0x0))) { - uint8_t data_tmp = 0; - uint8_t data_prg[8]; + // If we are using UP button - generate programming mode key and send it, otherwise - send regular key if possible + if((custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) && + !(!allow_zero_seed && (instance->generic.seed == 0x0))) { + uint8_t data_tmp = 0; + uint8_t data_prg[8]; - data_prg[0] = 0x00; + data_prg[0] = 0x00; - if(allow_zero_seed || (instance->generic.seed != 0x0)) { - // check OFEX mode - if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { - // standart counter mode. PULL data from subghz_block_generic_global variables - if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { - // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value - if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > - 0xFFFFF) { - instance->generic.cnt = 0; - } else { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); - } - } - } else { - // TODO: OFEX mode - instance->generic.cnt += 1; - } - - if(temp_counter_backup != 0x0) { + if(allow_zero_seed || (instance->generic.seed != 0x0)) { // check OFEX mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { // standart counter mode. PULL data from subghz_block_generic_global variables - if(!subghz_block_generic_global_counter_override_get(&temp_counter_backup)) { + if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value - if((temp_counter_backup + furi_hal_subghz_get_rolling_counter_mult()) > + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFFF) { - temp_counter_backup = 0; + instance->generic.cnt = 0; } else { - temp_counter_backup += furi_hal_subghz_get_rolling_counter_mult(); + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } } } else { - // todo OFEX mode - temp_counter_backup += 1; + // TODO: OFEX mode + instance->generic.cnt += 1; + } + + if(temp_counter_backup != 0x0) { + // check OFEX mode + if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get( + &temp_counter_backup)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((temp_counter_backup + furi_hal_subghz_get_rolling_counter_mult()) > + 0xFFFFF) { + temp_counter_backup = 0; + } else { + temp_counter_backup += furi_hal_subghz_get_rolling_counter_mult(); + } + } + } else { + // todo OFEX mode + temp_counter_backup += 1; + } } } - } - data_prg[1] = instance->generic.cnt & 0xFF; + data_prg[1] = instance->generic.cnt & 0xFF; - data_prg[2] = (uint8_t)(instance->generic.seed & 0xFF); - data_prg[3] = (uint8_t)(instance->generic.seed >> 8 & 0xFF); - data_prg[4] = (uint8_t)(instance->generic.seed >> 16 & 0xFF); - data_prg[5] = (uint8_t)(instance->generic.seed >> 24); + data_prg[2] = (uint8_t)(instance->generic.seed & 0xFF); + data_prg[3] = (uint8_t)(instance->generic.seed >> 8 & 0xFF); + data_prg[4] = (uint8_t)(instance->generic.seed >> 16 & 0xFF); + data_prg[5] = (uint8_t)(instance->generic.seed >> 24); - data_prg[2] ^= data_prg[1]; - data_prg[3] ^= data_prg[1]; - data_prg[4] ^= data_prg[1]; - data_prg[5] ^= data_prg[1]; + data_prg[2] ^= data_prg[1]; + data_prg[3] ^= data_prg[1]; + data_prg[4] ^= data_prg[1]; + data_prg[5] ^= data_prg[1]; - for(uint8_t i = data_prg[1] & 0x0F; i != 0; i--) { - data_tmp = data_prg[5]; + for(uint8_t i = data_prg[1] & 0x0F; i != 0; i--) { + data_tmp = data_prg[5]; - data_prg[5] = ((data_prg[5] << 1) & 0xFF) | (data_prg[4] & 0x80) >> 7; - data_prg[4] = ((data_prg[4] << 1) & 0xFF) | (data_prg[3] & 0x80) >> 7; - data_prg[3] = ((data_prg[3] << 1) & 0xFF) | (data_prg[2] & 0x80) >> 7; - data_prg[2] = ((data_prg[2] << 1) & 0xFF) | (data_tmp & 0x80) >> 7; - } - data_prg[6] = 0x0F; - data_prg[7] = 0x52; + data_prg[5] = ((data_prg[5] << 1) & 0xFF) | (data_prg[4] & 0x80) >> 7; + data_prg[4] = ((data_prg[4] << 1) & 0xFF) | (data_prg[3] & 0x80) >> 7; + data_prg[3] = ((data_prg[3] << 1) & 0xFF) | (data_prg[2] & 0x80) >> 7; + data_prg[2] = ((data_prg[2] << 1) & 0xFF) | (data_tmp & 0x80) >> 7; + } + data_prg[6] = 0x0F; + data_prg[7] = 0x52; - uint32_t enc_prg_1 = data_prg[7] << 24 | data_prg[6] << 16 | data_prg[5] << 8 | - data_prg[4]; - uint32_t enc_prg_2 = data_prg[3] << 24 | data_prg[2] << 16 | data_prg[1] << 8 | - data_prg[0]; - instance->generic.data = (uint64_t)enc_prg_1 << 32 | enc_prg_2; - //FURI_LOG_D(TAG, "New Prog Mode Key Generated: %016llX\r", instance->generic.data); + uint32_t enc_prg_1 = data_prg[7] << 24 | data_prg[6] << 16 | data_prg[5] << 8 | + data_prg[4]; + uint32_t enc_prg_2 = data_prg[3] << 24 | data_prg[2] << 16 | data_prg[1] << 8 | + data_prg[0]; + instance->generic.data = (uint64_t)enc_prg_1 << 32 | enc_prg_2; + //FURI_LOG_D(TAG, "New Prog Mode Key Generated: %016llX\r", instance->generic.data); - return true; - } else { - if(!allow_zero_seed && (instance->generic.seed == 0x0)) { - // Do not generate new data, send data from buffer return true; + } else { + if(!allow_zero_seed && (instance->generic.seed == 0x0)) { + // Do not generate new data, send data from buffer + return true; + } + // If we are in prog mode and regular Send button is used - Do not generate new data, send data from buffer + if((faac_prog_mode == true) && (instance->generic.serial == 0x0) && + (instance->generic.btn == 0x0) && (temp_fix_backup == 0x0)) { + return true; + } } - // If we are in prog mode and regular Send button is used - Do not generate new data, send data from buffer - if((faac_prog_mode == true) && (instance->generic.serial == 0x0) && - (instance->generic.btn == 0x0) && (temp_fix_backup == 0x0)) { - return true; - } - } - // Restore main remote data when we exit programming mode - if((instance->generic.serial == 0x0) && (instance->generic.btn == 0x0) && - (temp_fix_backup != 0x0) && !faac_prog_mode) { - instance->generic.serial = temp_fix_backup >> 4; - instance->generic.btn = temp_fix_backup & 0xF; - if(temp_counter_backup != 0x0) { - instance->generic.cnt = temp_counter_backup; + // Restore main remote data when we exit programming mode + if((instance->generic.serial == 0x0) && (instance->generic.btn == 0x0) && + (temp_fix_backup != 0x0) && !faac_prog_mode) { + instance->generic.serial = temp_fix_backup >> 4; + instance->generic.btn = temp_fix_backup & 0xF; + if(temp_counter_backup != 0x0) { + instance->generic.cnt = temp_counter_backup; + } } } uint32_t fix = instance->generic.serial << 4 | instance->generic.btn; @@ -441,7 +448,7 @@ LevelDuration subghz_protocol_encoder_faac_slh_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -736,6 +743,11 @@ void subghz_protocol_decoder_faac_slh_get_string(void* context, FuriString* outp instance->generic.seed, (uint8_t)(instance->generic.cnt & 0xFF)); } else if((allow_zero_seed == false) && (instance->generic.seed == 0x0)) { + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // furi_string_cat_printf( output, "%s %dbit\r\n" @@ -756,6 +768,10 @@ void subghz_protocol_decoder_faac_slh_get_string(void* context, FuriString* outp subghz_block_generic_global.cnt_is_available = true; subghz_block_generic_global.cnt_length_bit = 20; subghz_block_generic_global.current_cnt = instance->generic.cnt; + + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; // furi_string_cat_printf( diff --git a/lib/subghz/protocols/feron.c b/lib/subghz/protocols/feron.c index 9591a4ebb..61dd5e445 100644 --- a/lib/subghz/protocols/feron.c +++ b/lib/subghz/protocols/feron.c @@ -74,7 +74,7 @@ void* subghz_protocol_encoder_feron_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_feron; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -188,7 +188,7 @@ LevelDuration subghz_protocol_encoder_feron_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } diff --git a/lib/subghz/protocols/gangqi.c b/lib/subghz/protocols/gangqi.c index 6b5542410..f3e9c0daa 100644 --- a/lib/subghz/protocols/gangqi.c +++ b/lib/subghz/protocols/gangqi.c @@ -76,7 +76,7 @@ void* subghz_protocol_encoder_gangqi_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_gangqi; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -169,6 +169,10 @@ static void subghz_protocol_encoder_gangqi_get_upload(SubGhzProtocolEncoderGangQ // Generate new key using custom or default button instance->generic.btn = subghz_protocol_gangqi_get_btn_code(); + // override button if we change it with signal settings button editor + if(subghz_block_generic_global_button_override_get(&instance->generic.btn)) + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", instance->generic.btn); + uint16_t serial = (uint16_t)((instance->generic.data >> 18) & 0xFFFF); uint8_t const_and_button = (uint8_t)(0xD0 | instance->generic.btn); uint8_t serial_high = (uint8_t)(serial >> 8); @@ -295,7 +299,7 @@ LevelDuration subghz_protocol_encoder_gangqi_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -461,6 +465,12 @@ void subghz_protocol_decoder_gangqi_get_string(void* context, FuriString* output uint8_t sum_type1 = (uint8_t)(0xC8 - serial_high - serial_low - const_and_button); uint8_t sum_type2 = (uint8_t)(0x02 + serial_high + serial_low + const_and_button); + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + furi_string_cat_printf( output, "%s %db\r\n" diff --git a/lib/subghz/protocols/gate_tx.c b/lib/subghz/protocols/gate_tx.c index 608567626..83a36be3a 100644 --- a/lib/subghz/protocols/gate_tx.c +++ b/lib/subghz/protocols/gate_tx.c @@ -75,7 +75,7 @@ void* subghz_protocol_encoder_gate_tx_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_gate_tx; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop) instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -172,7 +172,7 @@ LevelDuration subghz_protocol_encoder_gate_tx_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -311,6 +311,13 @@ void subghz_protocol_decoder_gate_tx_get_string(void* context, FuriString* outpu furi_assert(context); SubGhzProtocolDecoderGateTx* instance = context; subghz_protocol_gate_tx_check_remote_controller(&instance->generic); + + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + furi_string_cat_printf( output, "%s %dbit\r\n" diff --git a/lib/subghz/protocols/hay21.c b/lib/subghz/protocols/hay21.c index ba6119dae..3495f5253 100644 --- a/lib/subghz/protocols/hay21.c +++ b/lib/subghz/protocols/hay21.c @@ -75,7 +75,7 @@ void* subghz_protocol_encoder_hay21_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_hay21; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -144,6 +144,10 @@ static void subghz_protocol_encoder_hay21_get_upload(SubGhzProtocolEncoderHay21* // Generate new key using custom or default button instance->generic.btn = subghz_protocol_hay21_get_btn_code(); + // override button if we change it with signal settings button editor + if(subghz_block_generic_global_button_override_get(&instance->generic.btn)) + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", instance->generic.btn); + // Counter increment // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { @@ -309,7 +313,7 @@ LevelDuration subghz_protocol_encoder_hay21_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -468,6 +472,11 @@ void subghz_protocol_decoder_hay21_get_string(void* context, FuriString* output) subghz_block_generic_global.cnt_length_bit = 8; subghz_block_generic_global.current_cnt = instance->generic.cnt; + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 8; + // + furi_string_cat_printf( output, "%s - %dbit\r\n" diff --git a/lib/subghz/protocols/hollarm.c b/lib/subghz/protocols/hollarm.c index 9b2a53a05..dc388b74a 100644 --- a/lib/subghz/protocols/hollarm.c +++ b/lib/subghz/protocols/hollarm.c @@ -76,7 +76,7 @@ void* subghz_protocol_encoder_hollarm_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_hollarm; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -168,6 +168,10 @@ static void subghz_protocol_encoder_hollarm_get_upload(SubGhzProtocolEncoderHoll // Generate new key using custom or default button instance->generic.btn = subghz_protocol_hollarm_get_btn_code(); + // override button if we change it with signal settings button editor + if(subghz_block_generic_global_button_override_get(&instance->generic.btn)) + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", instance->generic.btn); + uint64_t new_key = (instance->generic.data >> 12) << 12 | (instance->generic.btn << 8); uint8_t bytesum = ((new_key >> 32) & 0xFF) + ((new_key >> 24) & 0xFF) + @@ -296,7 +300,7 @@ LevelDuration subghz_protocol_encoder_hollarm_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -468,6 +472,12 @@ void subghz_protocol_decoder_hollarm_get_string(void* context, FuriString* outpu ((instance->generic.data >> 32) & 0xFF) + ((instance->generic.data >> 24) & 0xFF) + ((instance->generic.data >> 16) & 0xFF) + ((instance->generic.data >> 8) & 0xFF); + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + furi_string_cat_printf( output, "%s %db\r\n" diff --git a/lib/subghz/protocols/holtek.c b/lib/subghz/protocols/holtek.c index 7ed5fc152..908d36a51 100644 --- a/lib/subghz/protocols/holtek.c +++ b/lib/subghz/protocols/holtek.c @@ -86,7 +86,7 @@ void* subghz_protocol_encoder_holtek_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_holtek; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -185,7 +185,7 @@ LevelDuration subghz_protocol_encoder_holtek_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -344,6 +344,12 @@ void subghz_protocol_decoder_holtek_get_string(void* context, FuriString* output SubGhzProtocolDecoderHoltek* instance = context; subghz_protocol_holtek_check_remote_controller(&instance->generic); + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + furi_string_cat_printf( output, "%s %dbit\r\n" diff --git a/lib/subghz/protocols/holtek_ht12x.c b/lib/subghz/protocols/holtek_ht12x.c index bf5e48adf..fa0ddb78b 100644 --- a/lib/subghz/protocols/holtek_ht12x.c +++ b/lib/subghz/protocols/holtek_ht12x.c @@ -94,7 +94,7 @@ void* subghz_protocol_encoder_holtek_th12x_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_holtek_th12x; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -200,7 +200,7 @@ LevelDuration subghz_protocol_encoder_holtek_th12x_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -389,6 +389,12 @@ void subghz_protocol_decoder_holtek_th12x_get_string(void* context, FuriString* SubGhzProtocolDecoderHoltek_HT12X* instance = context; subghz_protocol_holtek_th12x_check_remote_controller(&instance->generic); + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + furi_string_cat_printf( output, "%s %db\r\n" diff --git a/lib/subghz/protocols/honeywell.c b/lib/subghz/protocols/honeywell.c index 1e3f231e8..30e3f4e9c 100644 --- a/lib/subghz/protocols/honeywell.c +++ b/lib/subghz/protocols/honeywell.c @@ -244,7 +244,7 @@ LevelDuration subghz_protocol_encoder_honeywell_yield(void* context) { } LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } return ret; diff --git a/lib/subghz/protocols/honeywell_wdb.c b/lib/subghz/protocols/honeywell_wdb.c index 0b8f63a24..fb421d099 100644 --- a/lib/subghz/protocols/honeywell_wdb.c +++ b/lib/subghz/protocols/honeywell_wdb.c @@ -88,7 +88,7 @@ void* subghz_protocol_encoder_honeywell_wdb_alloc(SubGhzEnvironment* environment instance->base.protocol = &subghz_protocol_honeywell_wdb; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -186,7 +186,7 @@ LevelDuration subghz_protocol_encoder_honeywell_wdb_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } diff --git a/lib/subghz/protocols/hormann.c b/lib/subghz/protocols/hormann.c index f74a29fec..1c463ee89 100644 --- a/lib/subghz/protocols/hormann.c +++ b/lib/subghz/protocols/hormann.c @@ -80,7 +80,7 @@ void* subghz_protocol_encoder_hormann_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_hormann; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 2048; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -110,7 +110,7 @@ static bool subghz_protocol_encoder_hormann_get_upload(SubGhzProtocolEncoderHorm } else { instance->encoder.size_upload = size_upload; } - instance->encoder.repeat = 10; //original remote does 10 repeats + instance->encoder.repeat = 3; //original remote does 10 repeats for(size_t repeat = 0; repeat < 20; repeat++) { //Send start bit @@ -185,7 +185,7 @@ LevelDuration subghz_protocol_encoder_hormann_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -319,6 +319,12 @@ void subghz_protocol_decoder_hormann_get_string(void* context, FuriString* outpu SubGhzProtocolDecoderHormann* instance = context; subghz_protocol_hormann_check_remote_controller(&instance->generic); + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + furi_string_cat_printf( output, "%s\r\n" diff --git a/lib/subghz/protocols/ido.c b/lib/subghz/protocols/ido.c index 34e5c55a7..3e82b95fc 100644 --- a/lib/subghz/protocols/ido.c +++ b/lib/subghz/protocols/ido.c @@ -207,6 +207,12 @@ void subghz_protocol_decoder_ido_get_string(void* context, FuriString* output) { uint32_t code_fix = code_found_reverse & 0xFFFFFF; uint32_t code_hop = (code_found_reverse >> 24) & 0xFFFFFF; + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + furi_string_cat_printf( output, "%s %dbit\r\n" diff --git a/lib/subghz/protocols/intertechno_v3.c b/lib/subghz/protocols/intertechno_v3.c index 71513051b..fe9ad7958 100644 --- a/lib/subghz/protocols/intertechno_v3.c +++ b/lib/subghz/protocols/intertechno_v3.c @@ -86,7 +86,7 @@ void* subghz_protocol_encoder_intertechno_v3_alloc(SubGhzEnvironment* environmen instance->base.protocol = &subghz_protocol_intertechno_v3; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -207,7 +207,7 @@ LevelDuration subghz_protocol_encoder_intertechno_v3_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -444,6 +444,10 @@ void subghz_protocol_decoder_intertechno_v3_get_string(void* context, FuriString subghz_protocol_intertechno_v3_check_remote_controller(&instance->generic); + // push protocol data to global variable + subghz_block_generic_global.current_btn = instance->generic.btn; + // + furi_string_cat_printf( output, "%.11s %db\r\n" @@ -459,12 +463,16 @@ void subghz_protocol_decoder_intertechno_v3_get_string(void* context, FuriString if(instance->generic.cnt >> 5) { furi_string_cat_printf( output, "Ch: All Btn:%s\r\n", (instance->generic.btn ? "On" : "Off")); + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.btn_length_bit = 1; } else { furi_string_cat_printf( output, "Ch:" CH_PATTERN " Btn:%s\r\n", CNT_TO_CH(instance->generic.cnt), (instance->generic.btn ? "On" : "Off")); + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.btn_length_bit = 1; } } else if(instance->generic.data_count_bit == INTERTECHNO_V3_DIMMING_COUNT_BIT) { furi_string_cat_printf( @@ -472,5 +480,7 @@ void subghz_protocol_decoder_intertechno_v3_get_string(void* context, FuriString "Ch:" CH_PATTERN " Dimm:%d%%\r\n", CNT_TO_CH(instance->generic.cnt), (int)(6.67f * (float)instance->generic.btn)); + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.btn_length_bit = 4; } } diff --git a/lib/subghz/protocols/jarolift.c b/lib/subghz/protocols/jarolift.c index 9881b9892..eae35bb31 100644 --- a/lib/subghz/protocols/jarolift.c +++ b/lib/subghz/protocols/jarolift.c @@ -100,7 +100,7 @@ void* subghz_protocol_encoder_jarolift_alloc(SubGhzEnvironment* environment) { instance->generic.protocol_name = instance->base.protocol->name; instance->keystore = subghz_environment_get_keystore(environment); - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -131,7 +131,7 @@ LevelDuration subghz_protocol_encoder_jarolift_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -152,6 +152,10 @@ static bool btn = subghz_protocol_jarolift_get_btn_code(); + // override button if we change it with signal settings button editor + if(subghz_block_generic_global_button_override_get(&btn)) + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", btn); + // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { // standart counter mode. PULL data from subghz_block_generic_global variables @@ -760,6 +764,11 @@ void subghz_protocol_decoder_jarolift_get_string(void* context, FuriString* outp subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + furi_string_cat_printf( output, "%s %dbit\r\n" diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index ca0db9f7b..972229f68 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -135,6 +135,10 @@ static bool subghz_protocol_keeloq_gen_data( SubGhzProtocolEncoderKeeloq* instance, uint8_t btn, bool counter_up) { + // override button if we change it with signal settings button editor + if(subghz_block_generic_global_button_override_get(&btn)) + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", btn); + uint32_t fix = (uint32_t)btn << 28 | instance->generic.serial; uint32_t hop = 0; uint64_t man = 0; @@ -1512,9 +1516,16 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; if(strcmp(instance->manufacture_name, "BFT") == 0) { + // push protocol data to global variable subghz_block_generic_global.cnt_is_available = true; subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; + + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + ProgMode prog_mode = subghz_custom_btn_get_prog_mode(); if(prog_mode == PROG_MODE_KEELOQ_BFT) { furi_string_cat_printf( @@ -1554,6 +1565,9 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output instance->generic.seed); } } else if(strcmp(instance->manufacture_name, "Unknown") == 0) { + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; instance->generic.cnt = 0x0; furi_string_cat_printf( output, @@ -1574,6 +1588,9 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output subghz_block_generic_global.cnt_is_available = true; subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; furi_string_cat_printf( output, "%s %dbit\r\n" diff --git a/lib/subghz/protocols/kinggates_stylo_4k.c b/lib/subghz/protocols/kinggates_stylo_4k.c index 9d7313559..29922c10e 100644 --- a/lib/subghz/protocols/kinggates_stylo_4k.c +++ b/lib/subghz/protocols/kinggates_stylo_4k.c @@ -101,7 +101,7 @@ void* subghz_protocol_encoder_kinggates_stylo_4k_alloc(SubGhzEnvironment* enviro instance->generic.protocol_name = instance->base.protocol->name; instance->keystore = subghz_environment_get_keystore(environment); - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 512; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -132,7 +132,7 @@ LevelDuration subghz_protocol_encoder_kinggates_stylo_4k_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -154,6 +154,10 @@ static bool subghz_protocol_kinggates_stylo_4k_gen_data( btn = subghz_protocol_kinggates_stylo_4k_get_btn_code(); + // override button if we change it with signal settings button editor + if(subghz_block_generic_global_button_override_get(&btn)) + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", btn); + // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { // standart counter mode. PULL data from subghz_block_generic_global variables @@ -727,6 +731,11 @@ void subghz_protocol_decoder_kinggates_stylo_4k_get_string(void* context, FuriSt subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + furi_string_cat_printf( output, "%s\r\n" diff --git a/lib/subghz/protocols/legrand.c b/lib/subghz/protocols/legrand.c index 94a45694c..2a5078bde 100644 --- a/lib/subghz/protocols/legrand.c +++ b/lib/subghz/protocols/legrand.c @@ -81,7 +81,7 @@ void* subghz_protocol_encoder_legrand_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_legrand; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = subghz_protocol_legrand_const.min_count_bit_for_found * 2 + 1; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -185,7 +185,7 @@ LevelDuration subghz_protocol_encoder_legrand_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } diff --git a/lib/subghz/protocols/linear.c b/lib/subghz/protocols/linear.c index f024316e9..f97b96e24 100644 --- a/lib/subghz/protocols/linear.c +++ b/lib/subghz/protocols/linear.c @@ -81,7 +81,7 @@ void* subghz_protocol_encoder_linear_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_linear; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 28; //max 10bit*2 + 2 (start, stop) instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -190,7 +190,7 @@ LevelDuration subghz_protocol_encoder_linear_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } diff --git a/lib/subghz/protocols/linear_delta3.c b/lib/subghz/protocols/linear_delta3.c index c2f527ba8..133f2b109 100644 --- a/lib/subghz/protocols/linear_delta3.c +++ b/lib/subghz/protocols/linear_delta3.c @@ -83,7 +83,7 @@ void* subghz_protocol_encoder_linear_delta3_alloc(SubGhzEnvironment* environment instance->base.protocol = &subghz_protocol_linear_delta3; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 16; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -194,7 +194,7 @@ LevelDuration subghz_protocol_encoder_linear_delta3_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } diff --git a/lib/subghz/protocols/magellan.c b/lib/subghz/protocols/magellan.c index 55048ca61..ed1b3b95b 100644 --- a/lib/subghz/protocols/magellan.c +++ b/lib/subghz/protocols/magellan.c @@ -78,7 +78,7 @@ void* subghz_protocol_encoder_magellan_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_magellan; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -196,7 +196,7 @@ LevelDuration subghz_protocol_encoder_magellan_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -499,6 +499,13 @@ void subghz_protocol_decoder_magellan_get_string(void* context, FuriString* outp furi_assert(context); SubGhzProtocolDecoderMagellan* instance = context; subghz_protocol_magellan_check_remote_controller(&instance->generic); + + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 8; + // + furi_string_cat_printf( output, "%s %dbit\r\n" diff --git a/lib/subghz/protocols/marantec.c b/lib/subghz/protocols/marantec.c index 53e4d6895..a07a559fc 100644 --- a/lib/subghz/protocols/marantec.c +++ b/lib/subghz/protocols/marantec.c @@ -77,7 +77,7 @@ void* subghz_protocol_encoder_marantec_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_marantec; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -243,7 +243,7 @@ LevelDuration subghz_protocol_encoder_marantec_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -393,6 +393,12 @@ void subghz_protocol_decoder_marantec_get_string(void* context, FuriString* outp uint8_t crc = subghz_protocol_marantec_crc8(tdata, sizeof(tdata)); bool crc_ok = (crc == (instance->generic.data & 0xFF)); + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + furi_string_cat_printf( output, "%s %db\r\n" diff --git a/lib/subghz/protocols/marantec24.c b/lib/subghz/protocols/marantec24.c index 6f636e8ab..b03fa2095 100644 --- a/lib/subghz/protocols/marantec24.c +++ b/lib/subghz/protocols/marantec24.c @@ -73,7 +73,7 @@ void* subghz_protocol_encoder_marantec24_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_marantec24; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -183,7 +183,7 @@ LevelDuration subghz_protocol_encoder_marantec24_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -332,6 +332,12 @@ void subghz_protocol_decoder_marantec24_get_string(void* context, FuriString* ou subghz_protocol_marantec24_check_remote_controller(&instance->generic); + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + furi_string_cat_printf( output, "%s %db\r\n" diff --git a/lib/subghz/protocols/mastercode.c b/lib/subghz/protocols/mastercode.c index e4fae40b3..1dc924c7a 100644 --- a/lib/subghz/protocols/mastercode.c +++ b/lib/subghz/protocols/mastercode.c @@ -89,7 +89,7 @@ void* subghz_protocol_encoder_mastercode_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_mastercode; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 72; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -199,7 +199,7 @@ LevelDuration subghz_protocol_encoder_mastercode_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -343,10 +343,17 @@ void subghz_protocol_decoder_mastercode_get_string(void* context, FuriString* ou furi_assert(context); SubGhzProtocolDecoderMastercode* instance = context; subghz_protocol_mastercode_check_remote_controller(&instance->generic); + + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 2; + // + furi_string_cat_printf( output, "%s %dbit\r\n" - "Key:%llX Btn %X\r\n" + "Key:%llX Btn:%X\r\n" " +: " DIP_PATTERN "\r\n" " o: " DIP_PATTERN "\r\n" " -: " DIP_PATTERN "\r\n", diff --git a/lib/subghz/protocols/megacode.c b/lib/subghz/protocols/megacode.c index 2c4bf10a3..cf7737aaa 100644 --- a/lib/subghz/protocols/megacode.c +++ b/lib/subghz/protocols/megacode.c @@ -87,7 +87,7 @@ void* subghz_protocol_encoder_megacode_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_megacode; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 52; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -218,7 +218,7 @@ LevelDuration subghz_protocol_encoder_megacode_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -405,6 +405,12 @@ void subghz_protocol_decoder_megacode_get_string(void* context, FuriString* outp SubGhzProtocolDecoderMegaCode* instance = context; subghz_protocol_megacode_check_remote_controller(&instance->generic); + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 3; + // + furi_string_cat_printf( output, "%s %dbit\r\n" diff --git a/lib/subghz/protocols/nero_radio.c b/lib/subghz/protocols/nero_radio.c index da5497feb..212dc684f 100644 --- a/lib/subghz/protocols/nero_radio.c +++ b/lib/subghz/protocols/nero_radio.c @@ -77,7 +77,7 @@ void* subghz_protocol_encoder_nero_radio_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_nero_radio; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -210,7 +210,7 @@ LevelDuration subghz_protocol_encoder_nero_radio_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -430,6 +430,12 @@ void subghz_protocol_decoder_nero_radio_get_string(void* context, FuriString* ou subghz_protocol_nero_radio_parse_data(&instance->generic); + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + furi_string_cat_printf( output, "%s %dbit\r\n" diff --git a/lib/subghz/protocols/nero_sketch.c b/lib/subghz/protocols/nero_sketch.c index 64a75cfc0..a8a011aa6 100644 --- a/lib/subghz/protocols/nero_sketch.c +++ b/lib/subghz/protocols/nero_sketch.c @@ -76,7 +76,7 @@ void* subghz_protocol_encoder_nero_sketch_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_nero_sketch; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -191,7 +191,7 @@ LevelDuration subghz_protocol_encoder_nero_sketch_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } diff --git a/lib/subghz/protocols/nice_flo.c b/lib/subghz/protocols/nice_flo.c index 2e5fa96b5..f7c8fe757 100644 --- a/lib/subghz/protocols/nice_flo.c +++ b/lib/subghz/protocols/nice_flo.c @@ -75,7 +75,7 @@ void* subghz_protocol_encoder_nice_flo_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_nice_flo; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop) instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -177,7 +177,7 @@ LevelDuration subghz_protocol_encoder_nice_flo_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index 9085ee431..e1d796ae3 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -104,7 +104,7 @@ void* subghz_protocol_encoder_nice_flor_s_alloc(SubGhzEnvironment* environment) FURI_LOG_D( TAG, "Loading rainbow table from %s", instance->nice_flor_s_rainbow_table_file_name); } - instance->encoder.repeat = 10; + instance->encoder.repeat = 1; instance->encoder.size_upload = 2400; //wrong!! upload 186*16 = 2976 - actual size about 1728 instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -147,6 +147,10 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload( btn = subghz_protocol_nice_flor_s_get_btn_code(); + // override button if we change it with signal settings button editor + if(subghz_block_generic_global_button_override_get(&btn)) + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", btn); + size_t size_upload = ((instance->generic.data_count_bit * 2) + ((37 + 2 + 2) * 2) * 16); if(size_upload > instance->encoder.size_upload) { FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); @@ -349,7 +353,7 @@ LevelDuration subghz_protocol_encoder_nice_flor_s_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -937,6 +941,11 @@ void subghz_protocol_decoder_nice_flor_s_get_string(void* context, FuriString* o subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + if(instance->generic.data_count_bit == NICE_ONE_COUNT_BIT) { furi_string_cat_printf( output, diff --git a/lib/subghz/protocols/phoenix_v2.c b/lib/subghz/protocols/phoenix_v2.c index 1f2731f54..f3cd07ed1 100644 --- a/lib/subghz/protocols/phoenix_v2.c +++ b/lib/subghz/protocols/phoenix_v2.c @@ -77,7 +77,7 @@ void* subghz_protocol_encoder_phoenix_v2_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_phoenix_v2; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -251,6 +251,10 @@ static bool // This will override the btn variable if a custom button is set btn = subghz_protocol_phoenix_v2_get_btn_code(); + // override button if we change it with signal settings button editor + if(subghz_block_generic_global_button_override_get(&btn)) + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", btn); + // Reconstruction of the data // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { @@ -364,7 +368,7 @@ LevelDuration subghz_protocol_encoder_phoenix_v2_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -598,6 +602,11 @@ void subghz_protocol_decoder_phoenix_v2_get_string(void* context, FuriString* ou subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + furi_string_cat_printf( output, "V2 Phoenix %dbit\r\n" diff --git a/lib/subghz/protocols/power_smart.c b/lib/subghz/protocols/power_smart.c index 6449f720a..78915d2b6 100644 --- a/lib/subghz/protocols/power_smart.c +++ b/lib/subghz/protocols/power_smart.c @@ -85,7 +85,7 @@ void* subghz_protocol_encoder_power_smart_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_power_smart; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 1024; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -236,7 +236,7 @@ LevelDuration subghz_protocol_encoder_power_smart_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -369,6 +369,12 @@ void subghz_protocol_decoder_power_smart_get_string(void* context, FuriString* o SubGhzProtocolDecoderPowerSmart* instance = context; subghz_protocol_power_smart_remote_controller(&instance->generic); + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 2; + // + furi_string_cat_printf( output, "%s %db\r\n" diff --git a/lib/subghz/protocols/princeton.c b/lib/subghz/protocols/princeton.c index cce8a7a34..f77e0e722 100644 --- a/lib/subghz/protocols/princeton.c +++ b/lib/subghz/protocols/princeton.c @@ -93,7 +93,7 @@ void* subghz_protocol_encoder_princeton_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_princeton; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop) instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -257,6 +257,10 @@ static bool // Generate new key using custom or default button instance->generic.btn = subghz_protocol_princeton_get_btn_code(); + // override button if we change it with signal settings button editor + if(subghz_block_generic_global_button_override_get(&instance->generic.btn)) + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", instance->generic.btn); + // Reconstruction of the data // If we have 8bit button code move serial to left by 8 bits (and 4 if 4 bits) if(instance->generic.btn == 0x30 || instance->generic.btn == 0xC0) { @@ -410,7 +414,7 @@ LevelDuration subghz_protocol_encoder_princeton_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -590,8 +594,14 @@ void subghz_protocol_decoder_princeton_get_string(void* context, FuriString* out uint32_t data_rev = subghz_protocol_blocks_reverse_key( instance->generic.data, instance->generic.data_count_bit); + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + // + if(instance->generic.btn == 0x30 || instance->generic.btn == 0xC0 || instance->generic.btn == 0xF3 || instance->generic.btn == 0xFC) { + subghz_block_generic_global.btn_length_bit = 8; furi_string_cat_printf( output, "%s %dbit\r\n" @@ -610,6 +620,7 @@ void subghz_protocol_decoder_princeton_get_string(void* context, FuriString* out instance->te, instance->guard_time); } else { + subghz_block_generic_global.btn_length_bit = 4; furi_string_cat_printf( output, "%s %dbit\r\n" diff --git a/lib/subghz/protocols/revers_rb2.c b/lib/subghz/protocols/revers_rb2.c index 941ff5c56..af063051b 100644 --- a/lib/subghz/protocols/revers_rb2.c +++ b/lib/subghz/protocols/revers_rb2.c @@ -78,7 +78,7 @@ void* subghz_protocol_encoder_revers_rb2_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_revers_rb2; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -204,7 +204,7 @@ LevelDuration subghz_protocol_encoder_revers_rb2_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } diff --git a/lib/subghz/protocols/roger.c b/lib/subghz/protocols/roger.c index 9c33b11ec..8eccee566 100644 --- a/lib/subghz/protocols/roger.c +++ b/lib/subghz/protocols/roger.c @@ -76,7 +76,7 @@ void* subghz_protocol_encoder_roger_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_roger; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -178,6 +178,10 @@ static void subghz_protocol_encoder_roger_get_upload(SubGhzProtocolEncoderRoger* // This will override the btn variable if a custom button is set btn = subghz_protocol_roger_get_btn_code(); + // override button if we change it with signal settings button editor + if(subghz_block_generic_global_button_override_get(&btn)) + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", btn); + // If End is not == button - transmit as is, no custom button allowed // For "End" values 23 and 20 - transmit correct ending used for their buttons if((instance->generic.data & 0xFF) == instance->generic.btn) { @@ -303,7 +307,7 @@ LevelDuration subghz_protocol_encoder_roger_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -433,6 +437,12 @@ void subghz_protocol_decoder_roger_get_string(void* context, FuriString* output) subghz_protocol_roger_check_remote_controller(&instance->generic); + // push protocol data to global variable + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + furi_string_cat_printf( output, "%s %db\r\n" diff --git a/lib/subghz/protocols/secplus_v1.c b/lib/subghz/protocols/secplus_v1.c index 13af0d302..9b2d77913 100644 --- a/lib/subghz/protocols/secplus_v1.c +++ b/lib/subghz/protocols/secplus_v1.c @@ -98,7 +98,7 @@ void* subghz_protocol_encoder_secplus_v1_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_secplus_v1; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -344,7 +344,7 @@ LevelDuration subghz_protocol_encoder_secplus_v1_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -586,6 +586,11 @@ void subghz_protocol_decoder_secplus_v1_get_string(void* context, FuriString* ou subghz_block_generic_global.cnt_length_bit = 32; subghz_block_generic_global.current_cnt = instance->generic.cnt; + subghz_block_generic_global.btn_is_available = false; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 2; + // + furi_string_cat_printf( output, "%s %db\r\n" diff --git a/lib/subghz/protocols/secplus_v2.c b/lib/subghz/protocols/secplus_v2.c index ad343968b..cab5d575f 100644 --- a/lib/subghz/protocols/secplus_v2.c +++ b/lib/subghz/protocols/secplus_v2.c @@ -92,7 +92,7 @@ void* subghz_protocol_encoder_secplus_v2_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_secplus_v2; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -395,6 +395,10 @@ static void subghz_protocol_secplus_v2_encode(SubGhzProtocolEncoderSecPlus_v2* i instance->generic.btn = subghz_protocol_secplus_v2_get_btn_code(); + // override button if we change it with signal settings button editor + if(subghz_block_generic_global_button_override_get(&instance->generic.btn)) + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", instance->generic.btn); + uint32_t fixed_1[1] = {instance->generic.btn << 12 | instance->generic.serial >> 20}; uint32_t fixed_2[1] = {instance->generic.serial & 0xFFFFF}; uint8_t rolling_digits[18] = {0}; @@ -623,7 +627,7 @@ LevelDuration subghz_protocol_encoder_secplus_v2_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -966,6 +970,11 @@ void subghz_protocol_decoder_secplus_v2_get_string(void* context, FuriString* ou subghz_block_generic_global.cnt_length_bit = 28; subghz_block_generic_global.current_cnt = instance->generic.cnt; + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 8; + // + furi_string_cat_printf( output, "%s %db\r\n" diff --git a/lib/subghz/protocols/smc5326.c b/lib/subghz/protocols/smc5326.c index 217dbb780..7e4fd2698 100644 --- a/lib/subghz/protocols/smc5326.c +++ b/lib/subghz/protocols/smc5326.c @@ -101,7 +101,7 @@ void* subghz_protocol_encoder_smc5326_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_smc5326; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -208,7 +208,7 @@ LevelDuration subghz_protocol_encoder_smc5326_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } diff --git a/lib/subghz/protocols/somfy_keytis.c b/lib/subghz/protocols/somfy_keytis.c index c9f6f47bd..38873d064 100644 --- a/lib/subghz/protocols/somfy_keytis.c +++ b/lib/subghz/protocols/somfy_keytis.c @@ -81,7 +81,7 @@ void* subghz_protocol_encoder_somfy_keytis_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_somfy_keytis; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 512; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -130,6 +130,10 @@ static bool instance->generic.cnt = (data >> 24) & 0xFFFF; instance->generic.serial = data & 0xFFFFFF; + // override button if we change it with signal settings button editor + if(subghz_block_generic_global_button_override_get(&instance->generic.btn)) + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", instance->generic.btn); + // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { // standart counter mode. PULL data from subghz_block_generic_global variables @@ -455,7 +459,7 @@ LevelDuration subghz_protocol_encoder_somfy_keytis_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -801,13 +805,18 @@ void subghz_protocol_decoder_somfy_keytis_get_string(void* context, FuriString* subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + furi_string_cat_printf( output, "%s %db\r\n" "%lX%08lX%06lX\r\n" "Sn:0x%06lX \r\n" "Cnt:%04lX\r\n" - "Btn:%s\r\n", + "Btn:%X - %s\r\n", instance->generic.protocol_name, instance->generic.data_count_bit, @@ -816,5 +825,6 @@ void subghz_protocol_decoder_somfy_keytis_get_string(void* context, FuriString* instance->press_duration_counter, instance->generic.serial, instance->generic.cnt, + instance->generic.btn, subghz_protocol_somfy_keytis_get_name_button(instance->generic.btn)); } diff --git a/lib/subghz/protocols/somfy_telis.c b/lib/subghz/protocols/somfy_telis.c index 2be378b7d..c0b26c945 100644 --- a/lib/subghz/protocols/somfy_telis.c +++ b/lib/subghz/protocols/somfy_telis.c @@ -82,7 +82,7 @@ void* subghz_protocol_encoder_somfy_telis_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_somfy_telis; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 512; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -124,6 +124,10 @@ static bool subghz_protocol_somfy_telis_gen_data( btn = subghz_protocol_somfy_telis_get_btn_code(); + // override button if we change it with signal settings button editor + if(subghz_block_generic_global_button_override_get(&btn)) + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", btn); + // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { // standart counter mode. PULL data from subghz_block_generic_global variables @@ -384,7 +388,7 @@ LevelDuration subghz_protocol_encoder_somfy_telis_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -758,13 +762,18 @@ void subghz_protocol_decoder_somfy_telis_get_string(void* context, FuriString* o subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + furi_string_cat_printf( output, "%s %db\r\n" "Key:0x%lX%08lX\r\n" "Sn:0x%06lX \r\n" "Cnt:%04lX\r\n" - "Btn:%s\r\n", + "Btn:%X - %s\r\n", instance->generic.protocol_name, instance->generic.data_count_bit, @@ -772,5 +781,6 @@ void subghz_protocol_decoder_somfy_telis_get_string(void* context, FuriString* o (uint32_t)instance->generic.data, instance->generic.serial, instance->generic.cnt, + instance->generic.btn, subghz_protocol_somfy_telis_get_name_button(instance->generic.btn)); } diff --git a/lib/subghz/protocols/treadmill37.c b/lib/subghz/protocols/treadmill37.c index e9915c296..fdd5b3d71 100644 --- a/lib/subghz/protocols/treadmill37.c +++ b/lib/subghz/protocols/treadmill37.c @@ -73,7 +73,7 @@ void* subghz_protocol_encoder_treadmill37_alloc(SubGhzEnvironment* environment) instance->base.protocol = &subghz_protocol_treadmill37; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 10; + instance->encoder.repeat = 3; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -179,7 +179,7 @@ LevelDuration subghz_protocol_encoder_treadmill37_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -333,6 +333,13 @@ void subghz_protocol_decoder_treadmill37_get_string(void* context, FuriString* o uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key( instance->generic.data, instance->generic.data_count_bit); + // for future use + // // push protocol data to global variable + // subghz_block_generic_global.btn_is_available = false; + // subghz_block_generic_global.current_btn = instance->generic.btn; + // subghz_block_generic_global.btn_length_bit = 4; + // // + furi_string_cat_printf( output, "%s %db\r\n" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 1ad9bc413..831932efe 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,87.4,, +Version,+,87.5,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/applications.h,, Header,+,applications/services/bt/bt_service/bt.h,, @@ -3613,6 +3613,8 @@ Function,-,strxfrm_l,size_t,"char*, const char*, size_t, locale_t" Function,+,subghz_block_generic_deserialize,SubGhzProtocolStatus,"SubGhzBlockGeneric*, FlipperFormat*" Function,+,subghz_block_generic_deserialize_check_count_bit,SubGhzProtocolStatus,"SubGhzBlockGeneric*, FlipperFormat*, uint16_t" Function,+,subghz_block_generic_get_preset_name,void,"const char*, FuriString*" +Function,+,subghz_block_generic_global_button_override_get,_Bool,uint8_t* +Function,+,subghz_block_generic_global_button_override_set,void,uint8_t Function,+,subghz_block_generic_global_counter_override_get,_Bool,uint32_t* Function,+,subghz_block_generic_global_counter_override_set,void,uint32_t Function,+,subghz_block_generic_global_reset,void,void* diff --git a/targets/f7/furi_hal/furi_hal_subghz.c b/targets/f7/furi_hal/furi_hal_subghz.c index ece8dde2c..05dbfdc6f 100644 --- a/targets/f7/furi_hal/furi_hal_subghz.c +++ b/targets/f7/furi_hal/furi_hal_subghz.c @@ -677,10 +677,12 @@ static inline uint32_t furi_hal_subghz_async_tx_middleware_get_duration( } } } - +// here we fill DMA buffer by signal durations until we recieve duration=0 (that mean protocol give as full data = signal_size*repeats) +// or until we reach the end of required samples count static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { furi_check(furi_hal_subghz.state == SubGhzStateAsyncTx); - + // furi_hal_subghz_async_tx.callback - linked to protocols "_yield" function + // and return one current LevelDuration from protocol upload buffer. while(samples > 0) { volatile uint32_t duration = furi_hal_subghz_async_tx_middleware_get_duration( &furi_hal_subghz_async_tx.middleware, furi_hal_subghz_async_tx.callback); @@ -771,7 +773,7 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* // Configure DMA to update TIM2->ARR LL_DMA_InitTypeDef dma_config = {0}; // DMA settings structure - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); // DMA destination TIM2->ARR + dma_config.PeriphOrM2MSrcAddress = (uint32_t)&(TIM2->ARR); // DMA destination TIM2->ARR dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_async_tx.buffer; // DMA buffer with signals durations dma_config.Direction = @@ -838,7 +840,7 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* furi_hal_subghz_debug_gpio_buff[1] = (uint32_t)gpio->pin << GPIO_NUMBER; dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_debug_gpio_buff; - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->BSRR); + dma_config.PeriphOrM2MSrcAddress = (uint32_t)&(gpio->port->BSRR); dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; dma_config.Mode = LL_DMA_MODE_CIRCULAR; dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; From a9972e6af218dcfdfb8c915eb56029452274eea4 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 2 Feb 2026 20:47:20 +0300 Subject: [PATCH 093/160] add fix for phox --- lib/subghz/protocols/phoenix_v2.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/subghz/protocols/phoenix_v2.c b/lib/subghz/protocols/phoenix_v2.c index 56a65bc8c..2dc199795 100644 --- a/lib/subghz/protocols/phoenix_v2.c +++ b/lib/subghz/protocols/phoenix_v2.c @@ -118,9 +118,11 @@ bool subghz_protocol_phoenix_v2_create_data( local_data_rev, instance->generic.cnt); instance->generic.data = subghz_protocol_blocks_reverse_key( - (uint64_t)(((uint64_t)encrypted_counter << 40) | ((uint64_t)instance->generic.btn << 32) | - (uint64_t)instance->generic.serial), - instance->generic.data_count_bit + 4); + (uint64_t)(((uint64_t)encrypted_counter << 40) | + ((uint64_t)instance->generic.btn << 32) | + (uint64_t)instance->generic.serial), + instance->generic.data_count_bit + 4) & + 0xFFFFFFFFFFFFF; return SubGhzProtocolStatusOk == subghz_block_generic_serialize(&instance->generic, flipper_format, preset); From 6d70d0f27f43bfc99f34e4c035c643646ff36123 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 2 Feb 2026 20:48:53 +0300 Subject: [PATCH 094/160] fmt --- targets/f7/furi_hal/furi_hal_subghz.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/targets/f7/furi_hal/furi_hal_subghz.c b/targets/f7/furi_hal/furi_hal_subghz.c index 05dbfdc6f..b23b2ea75 100644 --- a/targets/f7/furi_hal/furi_hal_subghz.c +++ b/targets/f7/furi_hal/furi_hal_subghz.c @@ -678,7 +678,7 @@ static inline uint32_t furi_hal_subghz_async_tx_middleware_get_duration( } } // here we fill DMA buffer by signal durations until we recieve duration=0 (that mean protocol give as full data = signal_size*repeats) -// or until we reach the end of required samples count +// or until we reach the end of required samples count static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { furi_check(furi_hal_subghz.state == SubGhzStateAsyncTx); // furi_hal_subghz_async_tx.callback - linked to protocols "_yield" function @@ -773,7 +773,7 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* // Configure DMA to update TIM2->ARR LL_DMA_InitTypeDef dma_config = {0}; // DMA settings structure - dma_config.PeriphOrM2MSrcAddress = (uint32_t)&(TIM2->ARR); // DMA destination TIM2->ARR + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); // DMA destination TIM2->ARR dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_async_tx.buffer; // DMA buffer with signals durations dma_config.Direction = @@ -840,7 +840,7 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* furi_hal_subghz_debug_gpio_buff[1] = (uint32_t)gpio->pin << GPIO_NUMBER; dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_debug_gpio_buff; - dma_config.PeriphOrM2MSrcAddress = (uint32_t)&(gpio->port->BSRR); + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->BSRR); dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; dma_config.Mode = LL_DMA_MODE_CIRCULAR; dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; From 8676e8a7b0d799b8034a625b8d7cf204d1e17968 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Tue, 3 Feb 2026 01:33:13 +0700 Subject: [PATCH 095/160] prevent from extra ticking when key pressed with rgb_mod_installed --- .../services/notification/notification_app.c | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 68573c201..5f8f5c8db 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -33,8 +33,12 @@ static uint8_t notification_settings_get_display_brightness(NotificationApp* app static uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value); static uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app); -// --- RGB BACKLIGHT --- +// status of lcd backlight +// used to ignore backlight_on event if backlight active now +// prevent from extra ticking when key pressed with rgb_mod_installed +static bool lcd_backligth_is_on = false; +// --- RGB BACKLIGHT --- // local variable for local use uint8_t rgb_backlight_installed_variable = 0; @@ -330,6 +334,11 @@ static void notification_apply_notification_led_layer( layer->index = LayerNotification; // set layer layer->value[LayerNotification] = layer_value; + + // if layer.light = LightBacklight and backlight active now then just exit. + // prevent from extra ticking when key pressed with rgb_mod_installed + if((layer->light == LightBacklight) & lcd_backligth_is_on) return; + // apply furi_hal_light_set(layer->light, layer->value[LayerNotification]); } @@ -371,11 +380,9 @@ static void notification_reset_notification_layer( } if(reset_mask & reset_display_mask) { if(!float_is_equal(display_brightness_set, app->settings.display_brightness)) { - // --- NIGHT SHIFT --- furi_hal_light_set( LightBacklight, app->settings.display_brightness * 0xFF * app->current_night_shift * 1.0f); - // --- NIGHT SHIFT END--- } if(app->settings.display_off_delay_ms > 0) { furi_timer_start( @@ -460,26 +467,31 @@ static void notification_process_notification_message( while(notification_message != NULL) { switch(notification_message->type) { case NotificationMessageTypeLedDisplayBacklight: - // if on - switch on and start timer - // if off - switch off and stop timer - // on timer - switch off - // --- NIGHT SHIFT --- + // if on (data.led.value =0xFF) - switch on and start timer + // if off (data.led.value =0x0) - switch off and stop timer if(notification_message->data.led.value > 0x00) { + // Backlight ON notification_apply_notification_led_layer( &app->display, notification_message->data.led.value * display_brightness_setting * app->current_night_shift * 1.0f); + reset_mask |= reset_display_mask; + lcd_backligth_is_on = true; //start rgb_mod_rainbow_timer when display backlight is ON and all corresponding settings is ON too rainbow_timer_starter(app); - // --- NIGHT SHIFT END --- + } else { + // Backlight OFF reset_mask &= ~reset_display_mask; notification_reset_notification_led_layer(&app->display); + lcd_backligth_is_on = false; + if(furi_timer_is_running(app->display_timer)) { furi_timer_stop(app->display_timer); } + //stop rgb_mod_rainbow_timer when display backlight is OFF if(furi_timer_is_running(app->rainbow_timer)) { rainbow_timer_stop(app); @@ -487,13 +499,13 @@ static void notification_process_notification_message( } break; case NotificationMessageTypeLedDisplayBacklightEnforceOn: - // --- NIGHT SHIFT --- if(!app->display_led_lock) { app->display_led_lock = true; notification_apply_internal_led_layer( &app->display, notification_message->data.led.value * display_brightness_setting * app->current_night_shift * 1.0f); + lcd_backligth_is_on = true; } break; case NotificationMessageTypeLedDisplayBacklightEnforceAuto: @@ -505,7 +517,7 @@ static void notification_process_notification_message( app->current_night_shift * 1.0f); // --- NIGHT SHIFT END --- } else { - FURI_LOG_E(TAG, "Incorrect BacklightEnforce use"); + FURI_LOG_E(TAG, "Incorrect BacklightEnforceAuto usage"); } break; case NotificationMessageTypeLedRed: From da0cb9f908ef0be363146b309e1d04fae7f8bc77 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 3 Feb 2026 18:29:03 +0300 Subject: [PATCH 096/160] Update documentation link for HT12A protocol by carlogrisetti --- lib/subghz/protocols/holtek_ht12x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/subghz/protocols/holtek_ht12x.c b/lib/subghz/protocols/holtek_ht12x.c index fa0ddb78b..25dfdb5ca 100644 --- a/lib/subghz/protocols/holtek_ht12x.c +++ b/lib/subghz/protocols/holtek_ht12x.c @@ -8,7 +8,7 @@ /* * Help - * https://www.holtek.com/documents/10179/116711/HT12A_Ev130.pdf + * https://www.holtek.com/webapi/116711/HT12A_Ev130.pdf * */ From 4ab0c3cb164cefa57bb41e986a2d1084a06dcb70 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 3 Feb 2026 18:37:07 +0300 Subject: [PATCH 097/160] upd changelog --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fea108a20..4f0a4cbf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ ## Main changes -- Current API: 87.4 +- Current API: 87.5 * SubGHz: **Cardin S449 protocol full support** (64bit keeloq) (with Add manually, and all button codes) (**use FSK12K modulation to read the remote**) (closes issues #735 #908) (by @xMasterX and @zero-mega (thanks!)) * SubGHz: **Beninca ARC AES128 protocol full support** (128bit dynamic) (with Add manually, and 3 button codes) (resolves issue #596) (by @xMasterX and @zero-mega) * SubGHz: **Treadmill37 protocol support** (37bit static) (by @xMasterX) @@ -17,15 +17,18 @@ * SubGHz: KeeLoq **display decrypted hop** in `Hop` instead of showing encrypted as is (encrypted non byte reversed hop is still displayed in `Key` field) * SubGHz: **BFT KeeLoq** try decoding with **zero seed** too * SubGHz: KeeLoq **display BFT programming mode TX** (when arrow button is held) +* SubGHz: Add signals button editor and real **remote simulation** (full signal transmit with just one click) (PR #956 | by @Dmitry422) +* JS: feat: add IR capabilities to the JS engine (PR #957 | by @LuisMayo) * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * NFC: Fixes to `READ_MULTI` and `GET_BLOCK_SECURITY` commands in ISO 15693-3 emulation (by @WillyJL & @aaronjamt) * Archive: Allow folders to be pinned (by @WillyJL) -* Apps: Build tag (**27jan2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) +* Apps: Build tag (**3feb2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes * UI: Various small changes * Desktop: Disable winter holidays anims * OFW PR 4333: NFC: Fix sending 32+ byte ISO 15693-3 commands (by @WillyJL) * NFC: Fix LED not blinking at SLIX unlock (closes issue #945) +* SubGHz: Fix documentation link for HT12A protocol (by @carlogrisetti) * SubGHz: Improve docs on low level code (PR #949 | by @Dmitry422) * SubGHz: Fix Alutech AT4N false positives * SubGHz: Cleanup of extra local variables From 1088e342e230f1b0428482a56ea73bead4b96185 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 3 Feb 2026 22:35:27 +0300 Subject: [PATCH 098/160] fix typo [ci skip] --- applications/services/notification/notification_app.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 5f8f5c8db..97a7401a8 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -36,7 +36,7 @@ static uint32_t notification_settings_display_off_delay_ticks(NotificationApp* a // status of lcd backlight // used to ignore backlight_on event if backlight active now // prevent from extra ticking when key pressed with rgb_mod_installed -static bool lcd_backligth_is_on = false; +static bool lcd_backlight_is_on = false; // --- RGB BACKLIGHT --- // local variable for local use @@ -337,7 +337,7 @@ static void notification_apply_notification_led_layer( // if layer.light = LightBacklight and backlight active now then just exit. // prevent from extra ticking when key pressed with rgb_mod_installed - if((layer->light == LightBacklight) & lcd_backligth_is_on) return; + if((layer->light == LightBacklight) & lcd_backlight_is_on) return; // apply furi_hal_light_set(layer->light, layer->value[LayerNotification]); @@ -477,7 +477,7 @@ static void notification_process_notification_message( app->current_night_shift * 1.0f); reset_mask |= reset_display_mask; - lcd_backligth_is_on = true; + lcd_backlight_is_on = true; //start rgb_mod_rainbow_timer when display backlight is ON and all corresponding settings is ON too rainbow_timer_starter(app); @@ -486,7 +486,7 @@ static void notification_process_notification_message( // Backlight OFF reset_mask &= ~reset_display_mask; notification_reset_notification_led_layer(&app->display); - lcd_backligth_is_on = false; + lcd_backlight_is_on = false; if(furi_timer_is_running(app->display_timer)) { furi_timer_stop(app->display_timer); @@ -505,7 +505,7 @@ static void notification_process_notification_message( &app->display, notification_message->data.led.value * display_brightness_setting * app->current_night_shift * 1.0f); - lcd_backligth_is_on = true; + lcd_backlight_is_on = true; } break; case NotificationMessageTypeLedDisplayBacklightEnforceAuto: From 67e191b135960726b1ecb194272bc5e0a816263b Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 5 Feb 2026 01:06:02 +0300 Subject: [PATCH 099/160] Keeloq ultimate, and some fixes and improvements [ci skip] - fix repeat values - fix endless tx missing - add mode 7 aka counter bypass - take some ram - free some ram - fix comments --- .../scenes/subghz_scene_signal_settings.c | 6 +- lib/subghz/protocols/came_twee.c | 2 +- lib/subghz/protocols/elplast.c | 2 +- lib/subghz/protocols/hay21.c | 2 +- lib/subghz/protocols/hollarm.c | 2 +- lib/subghz/protocols/hormann.c | 6 +- lib/subghz/protocols/keeloq.c | 214 +++++++++++------- lib/subghz/protocols/nice_flor_s.c | 2 +- lib/subghz/protocols/roger.c | 2 +- lib/subghz/protocols/treadmill37.c | 2 +- 10 files changed, 144 insertions(+), 96 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_signal_settings.c b/applications/main/subghz/scenes/subghz_scene_signal_settings.c index ae52e7314..90f99e50c 100644 --- a/applications/main/subghz/scenes/subghz_scene_signal_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_signal_settings.c @@ -22,7 +22,7 @@ static uint8_t* btn_byte_ptr = NULL; static uint8_t submenu_called = 0; -#define COUNTER_MODE_COUNT 7 +#define COUNTER_MODE_COUNT 8 static const char* const counter_mode_text[COUNTER_MODE_COUNT] = { "System", "Mode 1", @@ -31,6 +31,7 @@ static const char* const counter_mode_text[COUNTER_MODE_COUNT] = { "Mode 4", "Mode 5", "Mode 6", + "Mode 7", }; static const int32_t counter_mode_value[COUNTER_MODE_COUNT] = { @@ -41,6 +42,7 @@ static const int32_t counter_mode_value[COUNTER_MODE_COUNT] = { 4, 5, 6, + 7, }; typedef struct { @@ -53,7 +55,7 @@ static Protocols protocols[] = { {"Nice FloR-S", 3}, {"CAME Atomo", 4}, {"Alutech AT-4N", 3}, - {"KeeLoq", 7}, + {"KeeLoq", 8}, {"Phoenix_V2", 3}, }; diff --git a/lib/subghz/protocols/came_twee.c b/lib/subghz/protocols/came_twee.c index 20a4c5cc3..d6b656a57 100644 --- a/lib/subghz/protocols/came_twee.c +++ b/lib/subghz/protocols/came_twee.c @@ -110,7 +110,7 @@ void* subghz_protocol_encoder_came_twee_alloc(SubGhzEnvironment* environment) { instance->generic.protocol_name = instance->base.protocol->name; instance->encoder.repeat = 3; - instance->encoder.size_upload = 1536; //max upload 92*14 = 1288 !!!! + instance->encoder.size_upload = 1536; // 1308 instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; return instance; diff --git a/lib/subghz/protocols/elplast.c b/lib/subghz/protocols/elplast.c index 909689830..ee029bfc7 100644 --- a/lib/subghz/protocols/elplast.c +++ b/lib/subghz/protocols/elplast.c @@ -74,7 +74,7 @@ void* subghz_protocol_encoder_elplast_alloc(SubGhzEnvironment* environment) { instance->generic.protocol_name = instance->base.protocol->name; instance->encoder.repeat = 3; - instance->encoder.size_upload = 256; + instance->encoder.size_upload = 64; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; return instance; diff --git a/lib/subghz/protocols/hay21.c b/lib/subghz/protocols/hay21.c index 3495f5253..19995932c 100644 --- a/lib/subghz/protocols/hay21.c +++ b/lib/subghz/protocols/hay21.c @@ -76,7 +76,7 @@ void* subghz_protocol_encoder_hay21_alloc(SubGhzEnvironment* environment) { instance->generic.protocol_name = instance->base.protocol->name; instance->encoder.repeat = 3; - instance->encoder.size_upload = 256; + instance->encoder.size_upload = 64; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; return instance; diff --git a/lib/subghz/protocols/hollarm.c b/lib/subghz/protocols/hollarm.c index dc388b74a..fade91278 100644 --- a/lib/subghz/protocols/hollarm.c +++ b/lib/subghz/protocols/hollarm.c @@ -77,7 +77,7 @@ void* subghz_protocol_encoder_hollarm_alloc(SubGhzEnvironment* environment) { instance->generic.protocol_name = instance->base.protocol->name; instance->encoder.repeat = 3; - instance->encoder.size_upload = 256; + instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; return instance; diff --git a/lib/subghz/protocols/hormann.c b/lib/subghz/protocols/hormann.c index 1c463ee89..f8a2a9ed5 100644 --- a/lib/subghz/protocols/hormann.c +++ b/lib/subghz/protocols/hormann.c @@ -80,8 +80,8 @@ void* subghz_protocol_encoder_hormann_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_hormann; instance->generic.protocol_name = instance->base.protocol->name; - instance->encoder.repeat = 3; - instance->encoder.size_upload = 2048; + instance->encoder.repeat = 1; + instance->encoder.size_upload = 1850; // 1801 instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; return instance; @@ -110,7 +110,6 @@ static bool subghz_protocol_encoder_hormann_get_upload(SubGhzProtocolEncoderHorm } else { instance->encoder.size_upload = size_upload; } - instance->encoder.repeat = 3; //original remote does 10 repeats for(size_t repeat = 0; repeat < 20; repeat++) { //Send start bit @@ -137,6 +136,7 @@ static bool subghz_protocol_encoder_hormann_get_upload(SubGhzProtocolEncoderHorm } instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)subghz_protocol_hormann_const.te_short * 24); + return true; } diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 972229f68..d2182a396 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -100,6 +100,14 @@ static uint32_t subghz_protocol_keeloq_check_remote_controller( SubGhzKeystore* keystore, const char** manufacture_name); +/** + * Defines the button value for the current btn_id + * Basic set | 0x1 | 0x2 | 0x4 | 0x8 | 0xA or Special Learning Code | + * @param last_btn_code Candidate for the last button + * @return Button code + */ +static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code); + void* subghz_protocol_encoder_keeloq_alloc(SubGhzEnvironment* environment) { SubGhzProtocolEncoderKeeloq* instance = malloc(sizeof(SubGhzProtocolEncoderKeeloq)); @@ -107,8 +115,8 @@ void* subghz_protocol_encoder_keeloq_alloc(SubGhzEnvironment* environment) { instance->generic.protocol_name = instance->base.protocol->name; instance->keystore = subghz_environment_get_keystore(environment); - instance->encoder.repeat = 100; - instance->encoder.size_upload = 256; + instance->encoder.repeat = 3; + instance->encoder.size_upload = 1100; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; @@ -134,7 +142,57 @@ void subghz_protocol_encoder_keeloq_free(void* context) { static bool subghz_protocol_keeloq_gen_data( SubGhzProtocolEncoderKeeloq* instance, uint8_t btn, - bool counter_up) { + bool counter_up, + bool skip_btn_check) { + // No mf name set? -> set to "" + if(instance->manufacture_name == 0x0) { + instance->manufacture_name = ""; + } + // add gendata part + ProgMode prog_mode = subghz_custom_btn_get_prog_mode(); + if(!skip_btn_check && (keeloq_counter_mode != 7)) { + // Save original button + if(subghz_custom_btn_get_original() == 0) { + subghz_custom_btn_set_original(btn); + } + + // Prog mode checks and extra fixage of MF Names + if(prog_mode == PROG_MODE_KEELOQ_BFT) { + instance->manufacture_name = "BFT"; + } else if(prog_mode == PROG_MODE_KEELOQ_APRIMATIC) { + instance->manufacture_name = "Aprimatic"; + } else if(prog_mode == PROG_MODE_KEELOQ_DEA_MIO) { + instance->manufacture_name = "Dea_Mio"; + } + // Custom button (programming mode button) for BFT, Aprimatic, Dea_Mio + uint8_t klq_last_custom_btn = 0xA; + if((strcmp(instance->manufacture_name, "BFT") == 0) || + (strcmp(instance->manufacture_name, "Aprimatic") == 0) || + (strcmp(instance->manufacture_name, "Dea_Mio") == 0) || + (strcmp(instance->manufacture_name, "NICE_MHOUSE") == 0)) { + klq_last_custom_btn = 0xF; + } else if( + (strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) || + (strcmp(instance->manufacture_name, "Monarch") == 0) || + (strcmp(instance->manufacture_name, "NICE_Smilo") == 0)) { + klq_last_custom_btn = 0xB; + } else if( + (strcmp(instance->manufacture_name, "Novoferm") == 0) || + (strcmp(instance->manufacture_name, "Stilmatic") == 0)) { + klq_last_custom_btn = 0x9; + } else if( + (strcmp(instance->manufacture_name, "EcoStar") == 0) || + (strcmp(instance->manufacture_name, "Sommer") == 0)) { + klq_last_custom_btn = 0x6; + } else if((strcmp(instance->manufacture_name, "AN-Motors") == 0)) { + klq_last_custom_btn = 0xC; + } else if((strcmp(instance->manufacture_name, "Cardin_S449") == 0)) { + klq_last_custom_btn = 0xD; + } + + btn = subghz_protocol_keeloq_get_btn_code(klq_last_custom_btn); + } + // end gendata part // override button if we change it with signal settings button editor if(subghz_block_generic_global_button_override_get(&btn)) FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", btn); @@ -150,7 +208,6 @@ static bool subghz_protocol_keeloq_gen_data( } // programming mode on / off conditions - ProgMode prog_mode = subghz_custom_btn_get_prog_mode(); if(strcmp(instance->manufacture_name, "BFT") == 0) { // BFT programming mode on / off conditions if(btn == 0xF) { @@ -259,8 +316,16 @@ static bool subghz_protocol_keeloq_gen_data( } else { instance->generic.cnt = 0xFFFF; } - } else { + } else if(keeloq_counter_mode == 6) { // Mode 6 - Freeze counter + } else { + // Mode 7 - Make 12 signals in row with mode 2 + // + 0x3333 each time + if((instance->generic.cnt + 0x3333) > 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += 0x3333; + } } } if(prog_mode == PROG_MODE_OFF) { @@ -437,7 +502,7 @@ bool subghz_protocol_keeloq_create_data( instance->generic.cnt = cnt; instance->manufacture_name = manufacture_name; instance->generic.data_count_bit = 64; - if(subghz_protocol_keeloq_gen_data(instance, btn, false)) { + if(subghz_protocol_keeloq_gen_data(instance, btn, false, true)) { return ( subghz_block_generic_serialize(&instance->generic, flipper_format, preset) == SubGhzProtocolStatusOk); @@ -463,7 +528,7 @@ bool subghz_protocol_keeloq_bft_create_data( instance->manufacture_name = manufacture_name; instance->generic.data_count_bit = 64; // hehehehe - if(subghz_protocol_keeloq_gen_data(instance, btn, false)) { + if(subghz_protocol_keeloq_gen_data(instance, btn, false, true)) { return ( subghz_block_generic_serialize(&instance->generic, flipper_format, preset) == SubGhzProtocolStatusOk); @@ -471,88 +536,22 @@ bool subghz_protocol_keeloq_bft_create_data( return false; } -/** - * Defines the button value for the current btn_id - * Basic set | 0x1 | 0x2 | 0x4 | 0x8 | 0xA or Special Learning Code | - * @param last_btn_code Candidate for the last button - * @return Button code - */ -static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code); - -/** - * Generating an upload from data. - * @param instance Pointer to a SubGhzProtocolEncoderKeeloq instance - * @return true On success - */ -static bool - subghz_protocol_encoder_keeloq_get_upload(SubGhzProtocolEncoderKeeloq* instance, uint8_t btn) { +static size_t subghz_protocol_encoder_keeloq_encode_to_timings( + SubGhzProtocolEncoderKeeloq* instance, + uint8_t btn, + bool counter_up, + size_t index) { furi_assert(instance); - - // Save original button - if(subghz_custom_btn_get_original() == 0) { - subghz_custom_btn_set_original(btn); - } - - // No mf name set? -> set to "" - if(instance->manufacture_name == 0x0) { - instance->manufacture_name = ""; - } - // Prog mode checks and extra fixage of MF Names - ProgMode prog_mode = subghz_custom_btn_get_prog_mode(); - if(prog_mode == PROG_MODE_KEELOQ_BFT) { - instance->manufacture_name = "BFT"; - } else if(prog_mode == PROG_MODE_KEELOQ_APRIMATIC) { - instance->manufacture_name = "Aprimatic"; - } else if(prog_mode == PROG_MODE_KEELOQ_DEA_MIO) { - instance->manufacture_name = "Dea_Mio"; - } - // Custom button (programming mode button) for BFT, Aprimatic, Dea_Mio - uint8_t klq_last_custom_btn = 0xA; - if((strcmp(instance->manufacture_name, "BFT") == 0) || - (strcmp(instance->manufacture_name, "Aprimatic") == 0) || - (strcmp(instance->manufacture_name, "Dea_Mio") == 0) || - (strcmp(instance->manufacture_name, "NICE_MHOUSE") == 0)) { - klq_last_custom_btn = 0xF; - } else if( - (strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) || - (strcmp(instance->manufacture_name, "Monarch") == 0) || - (strcmp(instance->manufacture_name, "NICE_Smilo") == 0)) { - klq_last_custom_btn = 0xB; - } else if( - (strcmp(instance->manufacture_name, "Novoferm") == 0) || - (strcmp(instance->manufacture_name, "Stilmatic") == 0)) { - klq_last_custom_btn = 0x9; - } else if( - (strcmp(instance->manufacture_name, "EcoStar") == 0) || - (strcmp(instance->manufacture_name, "Sommer") == 0)) { - klq_last_custom_btn = 0x6; - } else if((strcmp(instance->manufacture_name, "AN-Motors") == 0)) { - klq_last_custom_btn = 0xC; - } else if((strcmp(instance->manufacture_name, "Cardin_S449") == 0)) { - klq_last_custom_btn = 0xD; - } - - uint32_t gap_duration = subghz_protocol_keeloq_const.te_short * 40; - if((strcmp(instance->manufacture_name, "Sommer") == 0)) { - gap_duration = subghz_protocol_keeloq_const.te_short * 29; - } - - btn = subghz_protocol_keeloq_get_btn_code(klq_last_custom_btn); - // Generate new key - if(subghz_protocol_keeloq_gen_data(instance, btn, true)) { + if(subghz_protocol_keeloq_gen_data(instance, btn, counter_up, false)) { // OK } else { return false; } - size_t index = 0; - size_t size_upload = 11 * 2 + 2 + (instance->generic.data_count_bit * 2) + 4; - if(size_upload > instance->encoder.size_upload) { - FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); - return false; - } else { - instance->encoder.size_upload = size_upload; + uint32_t gap_duration = subghz_protocol_keeloq_const.te_short * 40; + if((strcmp(instance->manufacture_name, "Sommer") == 0)) { + gap_duration = subghz_protocol_keeloq_const.te_short * 29; } //Send header @@ -593,6 +592,52 @@ static bool level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short); instance->encoder.upload[index++] = level_duration_make(false, gap_duration); + return index; +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderKeeloq instance + * @return true On success + */ +static bool + subghz_protocol_encoder_keeloq_get_upload(SubGhzProtocolEncoderKeeloq* instance, uint8_t btn) { + furi_assert(instance); + + instance->encoder.size_upload = 0; + size_t upindex = 0; + + if(keeloq_counter_mode == 7) { + uint16_t temp_cnt = instance->generic.cnt; + instance->encoder.repeat = 1; + for(uint8_t i = 7; i > 0; i--) { + if(i == 3) { + instance->generic.cnt = 0x0000; + upindex = subghz_protocol_encoder_keeloq_encode_to_timings( + instance, (uint8_t)0x00, false, upindex); + continue; + } else if(i == 2) { + instance->generic.cnt = temp_cnt; + upindex = subghz_protocol_encoder_keeloq_encode_to_timings( + instance, btn, false, upindex); + continue; + } else if(i == 1) { + instance->generic.cnt = temp_cnt + 1; + upindex = subghz_protocol_encoder_keeloq_encode_to_timings( + instance, btn, false, upindex); + continue; + } + upindex = subghz_protocol_encoder_keeloq_encode_to_timings( + instance, (uint8_t)0x00, true, upindex); + } + instance->encoder.size_upload = upindex; + return true; + } else { + instance->encoder.repeat = 3; + instance->encoder.size_upload = + subghz_protocol_encoder_keeloq_encode_to_timings(instance, btn, true, upindex); + } + return true; } @@ -719,7 +764,7 @@ LevelDuration subghz_protocol_encoder_keeloq_yield(void* context) { LevelDuration ret = instance->encoder.upload[instance->encoder.front]; if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; instance->encoder.front = 0; } @@ -1366,7 +1411,8 @@ static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code) { // Set custom button // Basic set | 0x1 | 0x2 | 0x4 | 0x8 | 0xA or Special Learning Code | - if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) { + if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0) && + (keeloq_counter_mode != 7)) { // Restore original button code btn = original_btn_code; } else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) { diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index e1d796ae3..b554deccf 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -105,7 +105,7 @@ void* subghz_protocol_encoder_nice_flor_s_alloc(SubGhzEnvironment* environment) TAG, "Loading rainbow table from %s", instance->nice_flor_s_rainbow_table_file_name); } instance->encoder.repeat = 1; - instance->encoder.size_upload = 2400; //wrong!! upload 186*16 = 2976 - actual size about 1728 + instance->encoder.size_upload = 2400; // 2368 for Nice ONE instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; return instance; diff --git a/lib/subghz/protocols/roger.c b/lib/subghz/protocols/roger.c index 8eccee566..35d80788d 100644 --- a/lib/subghz/protocols/roger.c +++ b/lib/subghz/protocols/roger.c @@ -77,7 +77,7 @@ void* subghz_protocol_encoder_roger_alloc(SubGhzEnvironment* environment) { instance->generic.protocol_name = instance->base.protocol->name; instance->encoder.repeat = 3; - instance->encoder.size_upload = 256; + instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; return instance; diff --git a/lib/subghz/protocols/treadmill37.c b/lib/subghz/protocols/treadmill37.c index fdd5b3d71..ddb8ba021 100644 --- a/lib/subghz/protocols/treadmill37.c +++ b/lib/subghz/protocols/treadmill37.c @@ -74,7 +74,7 @@ void* subghz_protocol_encoder_treadmill37_alloc(SubGhzEnvironment* environment) instance->generic.protocol_name = instance->base.protocol->name; instance->encoder.repeat = 3; - instance->encoder.size_upload = 256; + instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; return instance; From 97eaee54c8f12c0103487c7c5c8df6ba0b538e12 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 5 Feb 2026 01:48:58 +0300 Subject: [PATCH 100/160] upd changelog and docs --- CHANGELOG.md | 2 ++ documentation/SubGHzCounterMode.md | 6 ++++++ lib/subghz/protocols/keeloq.c | 13 +++---------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f0a4cbf0..aed0abbae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ * SubGHz: KeeLoq **display decrypted hop** in `Hop` instead of showing encrypted as is (encrypted non byte reversed hop is still displayed in `Key` field) * SubGHz: **BFT KeeLoq** try decoding with **zero seed** too * SubGHz: KeeLoq **display BFT programming mode TX** (when arrow button is held) +* SubGHz: KeeLoq **add counter mode 7 (sends 7 signals increasing counter with 0x3333 steps)** - may bypass counter on some receivers! * SubGHz: Add signals button editor and real **remote simulation** (full signal transmit with just one click) (PR #956 | by @Dmitry422) * JS: feat: add IR capabilities to the JS engine (PR #957 | by @LuisMayo) * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) @@ -28,6 +29,7 @@ * Desktop: Disable winter holidays anims * OFW PR 4333: NFC: Fix sending 32+ byte ISO 15693-3 commands (by @WillyJL) * NFC: Fix LED not blinking at SLIX unlock (closes issue #945) +* SubGHz: Added some RAM * SubGHz: Fix documentation link for HT12A protocol (by @carlogrisetti) * SubGHz: Improve docs on low level code (PR #949 | by @Dmitry422) * SubGHz: Fix Alutech AT4N false positives diff --git a/documentation/SubGHzCounterMode.md b/documentation/SubGHzCounterMode.md index 76eac58e4..47fc8cf1f 100644 --- a/documentation/SubGHzCounterMode.md +++ b/documentation/SubGHzCounterMode.md @@ -127,6 +127,12 @@ CounterMode: 1 **Mode 6:** - Counter freeze - do not increment +**Mode 7:** +- Incremental mode: `+0x3333` 5 times to current counter and return original value back adding +1 - 2 times - 7 signals in pack total +- Might work with Doorhan, seen in some "universal remotes" +- One click of Send button on flipper may bypass receiver counter, wait for full transmission + + --- ### 5. V2 Phoenix (Phox) diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index d2182a396..f47f53492 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -202,10 +202,6 @@ static bool subghz_protocol_keeloq_gen_data( uint64_t man = 0; uint64_t code_found_reverse; int res = 0; - // No mf name set? -> set to "" - if(instance->manufacture_name == 0x0) { - instance->manufacture_name = ""; - } // programming mode on / off conditions if(strcmp(instance->manufacture_name, "BFT") == 0) { @@ -543,10 +539,8 @@ static size_t subghz_protocol_encoder_keeloq_encode_to_timings( size_t index) { furi_assert(instance); // Generate new key - if(subghz_protocol_keeloq_gen_data(instance, btn, counter_up, false)) { - // OK - } else { - return false; + if(!subghz_protocol_keeloq_gen_data(instance, btn, counter_up, false)) { + return 0; } uint32_t gap_duration = subghz_protocol_keeloq_const.te_short * 40; @@ -1411,8 +1405,7 @@ static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code) { // Set custom button // Basic set | 0x1 | 0x2 | 0x4 | 0x8 | 0xA or Special Learning Code | - if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0) && - (keeloq_counter_mode != 7)) { + if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) { // Restore original button code btn = original_btn_code; } else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) { From 80158e84a21aabb42f4e3926718636333b7871cd Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Thu, 5 Feb 2026 18:04:42 +0700 Subject: [PATCH 101/160] subgh rpc refactor to "one click send signal" --- .../main/subghz/scenes/subghz_scene_rpc.c | 102 +++++++++++------- 1 file changed, 63 insertions(+), 39 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index b262679a4..bb6b29fc7 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -1,6 +1,9 @@ #include "../subghz_i.h" #include +#include +//#include +#include "applications/main/subghz/helpers/subghz_txrx_i.h" typedef enum { SubGhzRpcStateIdle, @@ -52,9 +55,13 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubGhzCustomEventSceneRpcButtonPress) { bool result = false; if(state == SubGhzRpcStateLoaded) { + // START endless TX until user release button + // variable used in protocol yield for endless TX + subghz_block_generic_global.endless_tx = true; switch( subghz_txrx_tx_start(subghz->txrx, subghz_txrx_get_fff_data(subghz->txrx))) { case SubGhzTxRxStartTxStateErrorOnlyRx: + subghz_block_generic_global.endless_tx = false; rpc_system_app_set_error_code( subghz->rpc_ctx, RpcAppSystemErrorCodeRegionLock); rpc_system_app_set_error_text( @@ -62,6 +69,7 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { "Transmission on this frequency is restricted in your settings"); break; case SubGhzTxRxStartTxStateErrorParserOthers: + subghz_block_generic_global.endless_tx = false; rpc_system_app_set_error_code( subghz->rpc_ctx, RpcAppSystemErrorCodeInternalParse); rpc_system_app_set_error_text( @@ -80,50 +88,53 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) { bool result = false; if(state == SubGhzRpcStateTx) { - subghz_txrx_stop(subghz->txrx); - subghz_blink_stop(subghz); + // user release button + // set endless TX to OFF and switch off TX in section event.type == SceneManagerEventTypeTick + subghz_block_generic_global.endless_tx = false; result = true; } - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle); + // scene_manager_set_scene_state( + // subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle); rpc_system_app_confirm(subghz->rpc_ctx, result); - } else if(event.event == SubGhzCustomEventSceneRpcButtonPressRelease) { - bool result = false; - if(state == SubGhzRpcStateLoaded) { - switch( - subghz_txrx_tx_start(subghz->txrx, subghz_txrx_get_fff_data(subghz->txrx))) { - case SubGhzTxRxStartTxStateErrorOnlyRx: - rpc_system_app_set_error_code( - subghz->rpc_ctx, RpcAppSystemErrorCodeRegionLock); - rpc_system_app_set_error_text( - subghz->rpc_ctx, - "Transmission on this frequency is restricted in your region"); - break; - case SubGhzTxRxStartTxStateErrorParserOthers: - rpc_system_app_set_error_code( - subghz->rpc_ctx, RpcAppSystemErrorCodeInternalParse); - rpc_system_app_set_error_text( - subghz->rpc_ctx, "Error in protocol parameters description"); - break; - default: //if(SubGhzTxRxStartTxStateOk) - result = true; - subghz_blink_start(subghz); - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateTx); - break; - } - } + // USELESS PART + // } else if(event.event == SubGhzCustomEventSceneRpcButtonPressRelease) { + // bool result = false; + // if(state == SubGhzRpcStateLoaded) { + // switch( + // subghz_txrx_tx_start(subghz->txrx, subghz_txrx_get_fff_data(subghz->txrx))) { + // case SubGhzTxRxStartTxStateErrorOnlyRx: + // rpc_system_app_set_error_code( + // subghz->rpc_ctx, RpcAppSystemErrorCodeRegionLock); + // rpc_system_app_set_error_text( + // subghz->rpc_ctx, + // "Transmission on this frequency is restricted in your region"); + // break; + // case SubGhzTxRxStartTxStateErrorParserOthers: + // rpc_system_app_set_error_code( + // subghz->rpc_ctx, RpcAppSystemErrorCodeInternalParse); + // rpc_system_app_set_error_text( + // subghz->rpc_ctx, "Error in protocol parameters description"); + // break; - // Stop transmission - if(state == SubGhzRpcStateTx) { - subghz_txrx_stop(subghz->txrx); - subghz_blink_stop(subghz); - result = true; - } - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle); - rpc_system_app_confirm(subghz->rpc_ctx, result); + // default: //if(SubGhzTxRxStartTxStateOk) + // result = true; + // subghz_blink_start(subghz); + // scene_manager_set_scene_state( + // subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateTx); + // break; + // } + // } + + // // Stop transmission + // if(state == SubGhzRpcStateTx) { + // subghz_txrx_stop(subghz->txrx); + // subghz_blink_stop(subghz); + // result = true; + // } + // scene_manager_set_scene_state( + // subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle); + // rpc_system_app_confirm(subghz->rpc_ctx, result); } else if(event.event == SubGhzCustomEventSceneRpcLoad) { bool result = false; if(state == SubGhzRpcStateIdle) { @@ -139,6 +150,19 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { } rpc_system_app_confirm(subghz->rpc_ctx, result); } + } else if(event.type == SceneManagerEventTypeTick) { + // if hardware TX finished then stop TX correctly + if(subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { + bool result = false; + if(state == SubGhzRpcStateTx) { + subghz_txrx_stop(subghz->txrx); + subghz_blink_stop(subghz); + result = true; + } + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle); + rpc_system_app_confirm(subghz->rpc_ctx, result); + } } return consumed; } From 162f9d3da33bd4be35b8e38b2edf3082997d6d3f Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Thu, 5 Feb 2026 18:16:31 +0700 Subject: [PATCH 102/160] clean --- applications/main/subghz/scenes/subghz_scene_rpc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index bb6b29fc7..f3753a3bc 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -2,7 +2,6 @@ #include #include -//#include #include "applications/main/subghz/helpers/subghz_txrx_i.h" typedef enum { From 30d48c112b86bf16e9f79419426d8ee91d427733 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 5 Feb 2026 14:18:11 +0300 Subject: [PATCH 103/160] upd changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aed0abbae..c1272d88d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ * SubGHz: **BFT KeeLoq** try decoding with **zero seed** too * SubGHz: KeeLoq **display BFT programming mode TX** (when arrow button is held) * SubGHz: KeeLoq **add counter mode 7 (sends 7 signals increasing counter with 0x3333 steps)** - may bypass counter on some receivers! -* SubGHz: Add signals button editor and real **remote simulation** (full signal transmit with just one click) (PR #956 | by @Dmitry422) +* SubGHz: Add signals button editor and real **remote simulation** (full signal transmit with just one click) (PR #956 #958 | by @Dmitry422) * JS: feat: add IR capabilities to the JS engine (PR #957 | by @LuisMayo) * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * NFC: Fixes to `READ_MULTI` and `GET_BLOCK_SECURITY` commands in ISO 15693-3 emulation (by @WillyJL & @aaronjamt) From a515f435fc31d121848526d040ea955e9824f05f Mon Sep 17 00:00:00 2001 From: Leeroy <135471162+LeeroysHub@users.noreply.github.com> Date: Wed, 4 Feb 2026 17:11:03 +1100 Subject: [PATCH 104/160] UNLEASHED:: TX Power setting to SubGhz App * Works in Read, and Read RAW. * You can now adjust the TX power for testing devices without desyncing them from inside * Lets you do RTL testing etc on very low power. CODE REFACTORED, subghz_txrx_set_tx_power added. --- .../main/subghz/helpers/subghz_txrx.c | 50 ++++++++++-- .../main/subghz/helpers/subghz_txrx.h | 18 ++++- .../subghz/scenes/subghz_scene_read_raw.c | 3 +- .../subghz/scenes/subghz_scene_receiver.c | 6 +- .../scenes/subghz_scene_receiver_config.c | 78 +++++++++++++++++-- .../scenes/subghz_scene_receiver_info.c | 4 + applications/main/subghz/subghz.c | 8 +- applications/main/subghz/subghz_i.c | 11 ++- applications/main/subghz/subghz_i.h | 2 +- .../main/subghz/subghz_last_settings.c | 9 +++ .../main/subghz/subghz_last_settings.h | 1 + 11 files changed, 167 insertions(+), 23 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index ca3f0b300..46d0a7eef 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -101,12 +101,39 @@ void subghz_txrx_set_preset( size_t preset_data_size) { furi_assert(instance); furi_string_set(instance->preset->name, preset_name); + SubGhzRadioPreset* preset = instance->preset; preset->frequency = frequency; preset->data = preset_data; preset->data_size = preset_data_size; } +uint8_t* + subghz_txrx_set_tx_power(uint8_t* preset_data, size_t preset_data_size, uint32_t tx_power) { +#define TX_POWER_OFFSET 7 +#define TX_PRESET_POWER_COUNT 11 + const uint32_t tx_power_value[TX_PRESET_POWER_COUNT] = { + 0, + 0xC0, + 0xC5, + 0xCD, + 0x86, + 0x50, + 0x37, + 0x26, + 0x1D, + 0x17, + 0x03, + }; + + //Set the TX Power Here in the CC1101 register... + if(tx_power) + preset_data[preset_data_size - TX_POWER_OFFSET] = (uint8_t)tx_power_value[tx_power]; + + //Pass back the preset_so we can call one liners. + return preset_data; +} + const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset) { UNUSED(instance); const char* preset_name = ""; @@ -677,20 +704,27 @@ void subghz_txrx_set_default_preset(SubGhzTxRx* instance, uint32_t frequency) { subghz_txrx_set_preset(instance, default_modulation, frequency, NULL, 0); } -const char* - subghz_txrx_set_preset_internal(SubGhzTxRx* instance, uint32_t frequency, uint8_t index) { +const char* subghz_txrx_set_preset_internal( + SubGhzTxRx* instance, + uint32_t frequency, + uint8_t index, + uint32_t tx_power) { furi_assert(instance); + //Grab the prset name. SubGhzSetting* setting = subghz_txrx_get_setting(instance); const char* preset_name = subghz_setting_get_preset_name(setting, index); subghz_setting_set_default_frequency(setting, frequency); - subghz_txrx_set_preset( - instance, - preset_name, - frequency, - subghz_setting_get_preset_data(setting, index), - subghz_setting_get_preset_data_size(setting, index)); + //Get the preset data now so we can set TX power. + uint8_t* preset_data = subghz_setting_get_preset_data(setting, index); + size_t preset_data_size = subghz_setting_get_preset_data_size(setting, index); + + //Edit TX power, if necessary. + subghz_txrx_set_tx_power(preset_data, preset_data_size, tx_power); + + //Set the Updated Preset. + subghz_txrx_set_preset(instance, preset_name, frequency, preset_data, preset_data_size); return preset_name; } diff --git a/applications/main/subghz/helpers/subghz_txrx.h b/applications/main/subghz/helpers/subghz_txrx.h index 0f3b64304..259fddfc2 100644 --- a/applications/main/subghz/helpers/subghz_txrx.h +++ b/applications/main/subghz/helpers/subghz_txrx.h @@ -57,6 +57,16 @@ void subghz_txrx_set_preset( uint8_t* preset_data, size_t preset_data_size); +/** + * Set TX Power + * + * @param preset_data Data of preset + * @param preset_data_size Size of preset data + * @param tx_power Menu Index of TX Power Setting. (Saves iterating in Config enter) + */ +uint8_t* + subghz_txrx_set_tx_power(uint8_t* preset_data, size_t preset_data_size, uint32_t tx_power); + /** * Get name of preset * @@ -360,7 +370,11 @@ void subghz_txrx_set_default_preset(SubGhzTxRx* instance, uint32_t frequency); * @param instance - instance Pointer to a SubGhzTxRx * @param frequency - frequency of new preset * @param index - index of preset taken from SubGhzSetting + * @param tx_power - index of TX Power menu index option to use. * @return const char* - name of preset */ -const char* - subghz_txrx_set_preset_internal(SubGhzTxRx* instance, uint32_t frequency, uint8_t index); +const char* subghz_txrx_set_preset_internal( + SubGhzTxRx* instance, + uint32_t frequency, + uint8_t index, + uint32_t tx_power); diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 355c339ff..6fe093dfc 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -110,7 +110,8 @@ void subghz_scene_read_raw_on_enter(void* context) { subghz_txrx_set_preset_internal( subghz->txrx, subghz->last_settings->frequency, - subghz->last_settings->preset_index); + subghz->last_settings->preset_index, + subghz->last_settings->tx_power); } } subghz_scene_read_raw_update_statusbar(subghz); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 1a0063418..b525a2847 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -165,11 +165,15 @@ void subghz_scene_receiver_on_enter(void* context) { if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateIDLE) { subghz_txrx_set_preset_internal( - subghz->txrx, subghz->last_settings->frequency, subghz->last_settings->preset_index); + subghz->txrx, + subghz->last_settings->frequency, + subghz->last_settings->preset_index, + subghz->last_settings->tx_power); subghz->filter = subghz->last_settings->filter; subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); subghz->ignore_filter = subghz->last_settings->ignore_filter; + subghz->tx_power = subghz->last_settings->tx_power; subghz_history_reset(history); subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index a6e3324be..6842ca727 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -7,6 +7,7 @@ enum SubGhzSettingIndex { SubGhzSettingIndexFrequency, SubGhzSettingIndexHopping, SubGhzSettingIndexModulation, + SubGhzSettingIndexTXPower, SubGhzSettingIndexBinRAW, SubGhzSettingIndexIgnoreReversRB2, SubGhzSettingIndexIgnoreAlarms, @@ -102,6 +103,22 @@ const char* const combobox_text[COMBO_BOX_COUNT] = { "ON", }; +//TX Power +#define TX_POWER_COUNT 11 +const char* const tx_power_text[TX_POWER_COUNT] = { + "Preset", + "12dBm", + "10dBm", + "7dBm", + "5dBm", + "0dBm", + "-6dBm", + "-10dBm", + "-15dBm", + "-20dBm", + "-30dBm", +}; + static void subghz_scene_receiver_config_set_ignore_filter(VariableItem* item, SubGhzProtocolFlag filter) { SubGhz* subghz = variable_item_get_context(item); @@ -185,6 +202,11 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { frequency / 1000000, (frequency % 1000000) / 10000); variable_item_set_current_value_text(item, text_buf); + + //Set TX Power + subghz_txrx_set_tx_power(preset.data, preset.data_size, subghz->tx_power); + + //Set the preset now. subghz_txrx_set_preset( subghz->txrx, furi_string_get_cstr(preset.name), @@ -211,12 +233,14 @@ static void subghz_scene_receiver_config_set_preset(VariableItem* item) { variable_item_set_current_value_text(item, preset_name); //subghz->last_settings->preset = index; SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + uint8_t* preset_data = subghz_setting_get_preset_data(setting, index); + size_t preset_data_size = subghz_setting_get_preset_data_size(setting, index); + + //Edit TX power, if necessary. + subghz_txrx_set_tx_power(preset_data, preset_data_size, subghz->tx_power); + subghz_txrx_set_preset( - subghz->txrx, - preset_name, - preset.frequency, - subghz_setting_get_preset_data(setting, index), - subghz_setting_get_preset_data_size(setting, index)); + subghz->txrx, preset_name, preset.frequency, preset_data, preset_data_size); subghz->last_settings->preset_index = index; } @@ -242,6 +266,9 @@ static void subghz_scene_receiver_config_set_hopping(VariableItem* item) { (frequency % 1000000) / 10000); variable_item_set_current_value_text(frequency_item, text_buf); + //Edit TX power, if necessary. + subghz_txrx_set_tx_power(preset.data, preset.data_size, subghz->tx_power); + // Maybe better add one more function with only with the frequency argument? subghz_txrx_set_preset( subghz->txrx, @@ -273,6 +300,30 @@ static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { subghz_txrx_speaker_set_state(subghz->txrx, speaker_value[index]); } +static void subghz_scene_receiver_config_set_tx_power(VariableItem* item) { + SubGhz* subghz = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + //Update the Menu Item on screen + variable_item_set_current_value_text(item, tx_power_text[index]); + + //Set TX power and remember setting + subghz->tx_power = index; + subghz->last_settings->tx_power = subghz->tx_power; + + //Get current preset and frequency so I can update preset wit TX power. + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + uint32_t frequency = subghz_setting_get_default_frequency(setting); + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + + //Edit TX power, if necessary. + subghz_txrx_set_tx_power(preset.data, preset.data_size, subghz->tx_power); + + // Maybe better add one more function with only with the frequency argument? + subghz_txrx_set_preset( + subghz->txrx, furi_string_get_cstr(preset.name), frequency, preset.data, preset.data_size); +} + static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -341,7 +392,8 @@ static void subghz_scene_receiver_config_var_list_enter_callback(void* context, subghz_txrx_set_preset_internal( subghz->txrx, SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY, - SUBGHZ_LAST_SETTING_DEFAULT_PRESET); + SUBGHZ_LAST_SETTING_DEFAULT_PRESET, + 0); SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); @@ -359,7 +411,7 @@ static void subghz_scene_receiver_config_var_list_enter_callback(void* context, subghz->last_settings->ignore_filter = subghz->ignore_filter; subghz->last_settings->filter = subghz->filter; subghz->last_settings->delete_old_signals = false; - + subghz->last_settings->tx_power = subghz->tx_power = 0; subghz_txrx_speaker_set_state(subghz->txrx, speaker_value[default_index]); subghz_txrx_hopper_set_state(subghz->txrx, hopping_value[default_index]); @@ -429,6 +481,18 @@ void subghz_scene_receiver_config_on_enter(void* context) { variable_item_set_current_value_text(item, hopping_mode_text[value_index]); } + //Add TX Power + item = variable_item_list_add( + subghz->variable_item_list, + "TX Power", + TX_POWER_COUNT, + subghz_scene_receiver_config_set_tx_power, + subghz); + + value_index = subghz->tx_power; + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, tx_power_text[value_index]); + if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != SubGhzCustomEventManagerSet) { item = variable_item_list_add( diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index f2970d343..61502c16a 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -36,6 +36,10 @@ static bool subghz_scene_receiver_info_update_parser(void* context) { SubGhzRadioPreset* preset = subghz_history_get_radio_preset(subghz->history, subghz->idx_menu_chosen); + + //Edit TX power, if necessary. + subghz_txrx_set_tx_power(preset->data, preset->data_size, subghz->tx_power); + subghz_txrx_set_preset( subghz->txrx, furi_string_get_cstr(preset->name), diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index f8877551d..51b7316e4 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -207,7 +207,10 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { if(!alloc_for_tx_only) { subghz_txrx_set_preset_internal( - subghz->txrx, subghz->last_settings->frequency, subghz->last_settings->preset_index); + subghz->txrx, + subghz->last_settings->frequency, + subghz->last_settings->preset_index, + subghz->tx_power); subghz->history = subghz_history_alloc(); } @@ -218,10 +221,13 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { if(!alloc_for_tx_only) { subghz->ignore_filter = subghz->last_settings->ignore_filter; subghz->filter = subghz->last_settings->filter; + subghz->tx_power = subghz->last_settings->tx_power; } else { subghz->filter = SubGhzProtocolFlag_Decodable; subghz->ignore_filter = 0x0; + subghz->tx_power = 0; } + subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); subghz_txrx_set_need_save_callback(subghz->txrx, subghz_save_to_file, subghz); diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 1bdaf07d9..078fa1f2c 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -137,12 +137,19 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { } size_t preset_index = subghz_setting_get_inx_preset_by_name(setting, furi_string_get_cstr(temp_str)); + + //Edit TX power, if necessary. + uint8_t* preset_data = subghz_setting_get_preset_data(setting, preset_index); + size_t preset_data_size = subghz_setting_get_preset_data_size(setting, preset_index); + subghz_txrx_set_tx_power(preset_data, preset_data_size, subghz->tx_power); + + //Set the Updated Preset. subghz_txrx_set_preset( subghz->txrx, furi_string_get_cstr(temp_str), temp_data32, - subghz_setting_get_preset_data(setting, preset_index), - subghz_setting_get_preset_data_size(setting, preset_index)); + preset_data, + preset_data_size); //Load protocol if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 10a2ce9f8..01f3ccf2f 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -93,7 +93,7 @@ struct SubGhz { uint16_t idx_menu_chosen; SubGhzLoadTypeFile load_type_file; - + uint32_t tx_power; void* rpc_ctx; }; diff --git a/applications/main/subghz/subghz_last_settings.c b/applications/main/subghz/subghz_last_settings.c index 0a4783a23..a38f39026 100644 --- a/applications/main/subghz/subghz_last_settings.c +++ b/applications/main/subghz/subghz_last_settings.c @@ -19,6 +19,7 @@ #define SUBGHZ_LAST_SETTING_FIELD_DELETE_OLD "DelOldSignals" #define SUBGHZ_LAST_SETTING_FIELD_HOPPING_THRESHOLD "HoppingThreshold" #define SUBGHZ_LAST_SETTING_FIELD_LED_AND_POWER_AMP "LedAndPowerAmp" +#define SUBGHZ_LAST_SETTING_FIELD_TX_POWER "TXPower" SubGhzLastSettings* subghz_last_settings_alloc(void) { SubGhzLastSettings* instance = malloc(sizeof(SubGhzLastSettings)); @@ -119,6 +120,10 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count 1)) { flipper_format_rewind(fff_data_file); } + if(!flipper_format_read_uint32( + fff_data_file, SUBGHZ_LAST_SETTING_FIELD_TX_POWER, &instance->tx_power, 1)) { + flipper_format_rewind(fff_data_file); + } if(!flipper_format_read_float( fff_data_file, SUBGHZ_LAST_SETTING_FIELD_HOPPING_THRESHOLD, @@ -222,6 +227,10 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) { file, SUBGHZ_LAST_SETTING_FIELD_DELETE_OLD, &instance->delete_old_signals, 1)) { break; } + if(!flipper_format_write_uint32( + file, SUBGHZ_LAST_SETTING_FIELD_TX_POWER, &instance->tx_power, 1)) { + break; + } if(!flipper_format_write_float( file, SUBGHZ_LAST_SETTING_FIELD_HOPPING_THRESHOLD, diff --git a/applications/main/subghz/subghz_last_settings.h b/applications/main/subghz/subghz_last_settings.h index 78de5e51c..e42ee868d 100644 --- a/applications/main/subghz/subghz_last_settings.h +++ b/applications/main/subghz/subghz_last_settings.h @@ -26,6 +26,7 @@ typedef struct { bool delete_old_signals; float hopping_threshold; bool leds_and_amp; + uint32_t tx_power; } SubGhzLastSettings; SubGhzLastSettings* subghz_last_settings_alloc(void); From e0c1a89c5dc766cef270bdc2ca0a62396331f8e7 Mon Sep 17 00:00:00 2001 From: Leeroy <135471162+LeeroysHub@users.noreply.github.com> Date: Sat, 7 Feb 2026 22:00:19 +1100 Subject: [PATCH 105/160] Refactor: Replace 2 assignments with one-liner --- applications/main/subghz/scenes/subghz_scene_receiver_config.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index 6842ca727..c743e660c 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -308,8 +308,7 @@ static void subghz_scene_receiver_config_set_tx_power(VariableItem* item) { variable_item_set_current_value_text(item, tx_power_text[index]); //Set TX power and remember setting - subghz->tx_power = index; - subghz->last_settings->tx_power = subghz->tx_power; + subghz->last_settings->tx_power = subghz->tx_power = index; //Get current preset and frequency so I can update preset wit TX power. SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); From 8f248a49da5e26e9c413a387a19f33df1596d99b Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Sun, 8 Feb 2026 10:16:15 +0700 Subject: [PATCH 106/160] Backlight settings bug --- applications/services/notification/notification.h | 1 + .../services/notification/notification_app.c | 13 +++++++++++++ .../services/notification/notification_messages.c | 12 ++++++++++++ .../services/notification/notification_messages.h | 3 ++- .../notification_settings_app.c | 7 +++---- targets/f7/api_symbols.csv | 3 ++- 6 files changed, 33 insertions(+), 6 deletions(-) diff --git a/applications/services/notification/notification.h b/applications/services/notification/notification.h index 0e1c07e5d..54e1eb895 100644 --- a/applications/services/notification/notification.h +++ b/applications/services/notification/notification.h @@ -65,6 +65,7 @@ typedef enum { NotificationMessageTypeDelay, NotificationMessageTypeLedDisplayBacklight, + NotificationMessageTypeLedDisplayBacklightForceOn, NotificationMessageTypeLedDisplayBacklightEnforceOn, NotificationMessageTypeLedDisplayBacklightEnforceAuto, diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 97a7401a8..b4b0effa3 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -498,6 +498,19 @@ static void notification_process_notification_message( } } break; + case NotificationMessageTypeLedDisplayBacklightForceOn: + // Force Backlight ON even if its ON now + lcd_backlight_is_on = false; + notification_apply_notification_led_layer( + &app->display, + notification_message->data.led.value * display_brightness_setting * + app->current_night_shift * 1.0f); + reset_mask |= reset_display_mask; + lcd_backlight_is_on = true; + + //start rgb_mod_rainbow_timer when display backlight is ON and all corresponding settings is ON too + rainbow_timer_starter(app); + break; case NotificationMessageTypeLedDisplayBacklightEnforceOn: if(!app->display_led_lock) { app->display_led_lock = true; diff --git a/applications/services/notification/notification_messages.c b/applications/services/notification/notification_messages.c index 3dc154654..e3f4fbc2c 100644 --- a/applications/services/notification/notification_messages.c +++ b/applications/services/notification/notification_messages.c @@ -17,6 +17,12 @@ const NotificationMessage message_display_backlight_off = { .data.led.value = 0x00, }; +/** Display: backlight wakeup even if its ON now */ +const NotificationMessage message_display_backlight_force_on = { + .type = NotificationMessageTypeLedDisplayBacklightForceOn, + .data.led.value = 0xFF, +}; + /** Display: backlight always on */ const NotificationMessage message_display_backlight_enforce_on = { .type = NotificationMessageTypeLedDisplayBacklightEnforceOn, @@ -259,6 +265,12 @@ const NotificationSequence sequence_display_backlight_off = { NULL, }; +/** Display: backlight wakeup even if its ON now */ +const NotificationSequence sequence_display_backlight_force_on = { + &message_display_backlight_force_on, + NULL, +}; + /** Display: backlight always on lock */ const NotificationSequence sequence_display_backlight_enforce_on = { &message_display_backlight_enforce_on, diff --git a/applications/services/notification/notification_messages.h b/applications/services/notification/notification_messages.h index 3960d93b7..8af499841 100644 --- a/applications/services/notification/notification_messages.h +++ b/applications/services/notification/notification_messages.h @@ -87,7 +87,8 @@ extern const NotificationSequence sequence_display_backlight_on; extern const NotificationSequence sequence_display_backlight_off; /** Display: backlight force off after a delay of 1000ms */ extern const NotificationSequence sequence_display_backlight_off_delay_1000; - +/** Display: backlight wakeup even if its ON now */ +extern const NotificationSequence sequence_display_backlight_force_on; /** Display: backlight always on lock */ extern const NotificationSequence sequence_display_backlight_enforce_on; /** Display: backlight always on unlock */ diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 533db3cd0..4d95a8ac6 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -295,7 +295,7 @@ static void backlight_changed(VariableItem* item) { variable_item_set_current_value_text(item, backlight_text[index]); app->notification->settings.display_brightness = backlight_value[index]; - notification_message(app->notification, &sequence_display_backlight_on); + notification_message(app->notification, &sequence_display_backlight_force_on); } static void screen_changed(VariableItem* item) { @@ -557,11 +557,10 @@ static void night_shift_changed(VariableItem* item) { variable_item_set_current_value_text(item, night_shift_text[index]); app->notification->settings.night_shift = night_shift_value[index]; - app->notification->current_night_shift = night_shift_value[index]; - app->notification->current_night_shift = night_shift_value[index]; // force demo night_shift brightness to rgb backlight and stock backlight - notification_message(app->notification, &sequence_display_backlight_on); + // app->notification->current_night_shift = night_shift_value[index]; + // notification_message(app->notification, &sequence_display_backlight_force_on); for(int i = 4; i < 6; i++) { VariableItem* t_item = variable_item_list_get(app->variable_item_list, i); diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 831932efe..e3159a17e 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,87.5,, +Version,+,87.6,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/applications.h,, Header,+,applications/services/bt/bt_service/bt.h,, @@ -5383,6 +5383,7 @@ Variable,+,sequence_charged,const NotificationSequence, Variable,+,sequence_charging,const NotificationSequence, Variable,+,sequence_display_backlight_enforce_auto,const NotificationSequence, Variable,+,sequence_display_backlight_enforce_on,const NotificationSequence, +Variable,+,sequence_display_backlight_force_on,const NotificationSequence, Variable,+,sequence_display_backlight_off,const NotificationSequence, Variable,+,sequence_display_backlight_off_delay_1000,const NotificationSequence, Variable,+,sequence_display_backlight_on,const NotificationSequence, From 168240c2378c76e7b29b3a0c5513d985e69ad545 Mon Sep 17 00:00:00 2001 From: Leeroy <135471162+LeeroysHub@users.noreply.github.com> Date: Sun, 8 Feb 2026 14:17:04 +1100 Subject: [PATCH 107/160] TX POWER: Move from Receiver Config to Radio Settings --- .../scenes/subghz_scene_radio_settings.c | 42 +++++++++++++++ .../scenes/subghz_scene_receiver_config.c | 54 +------------------ 2 files changed, 43 insertions(+), 53 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_radio_settings.c b/applications/main/subghz/scenes/subghz_scene_radio_settings.c index 8e48d0c91..87e2d8269 100644 --- a/applications/main/subghz/scenes/subghz_scene_radio_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_radio_settings.c @@ -66,6 +66,22 @@ const int32_t debug_counter_val[DEBUG_COUNTER_COUNT] = { -50, }; +//TX Power +#define TX_POWER_COUNT 11 +const char* const tx_power_text[TX_POWER_COUNT] = { + "Preset", + "12dBm", + "10dBm", + "7dBm", + "5dBm", + "0dBm", + "-6dBm", + "-10dBm", + "-15dBm", + "-20dBm", + "-30dBm", +}; + static void subghz_scene_radio_settings_set_device(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -80,6 +96,20 @@ static void subghz_scene_radio_settings_set_device(VariableItem* item) { subghz_txrx_radio_device_set(subghz->txrx, radio_device_value[index]); } +static void subghz_scene_radio_settings_set_tx_power(VariableItem* item) { + SubGhz* subghz = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + //Update the Menu Item on screen + variable_item_set_current_value_text(item, tx_power_text[index]); + + //Set TX power and remember setting + subghz->last_settings->tx_power = subghz->tx_power = index; + + //Save the settings now, this is the convention here! + subghz_last_settings_save(subghz->last_settings); +} + static void subghz_scene_receiver_config_set_debug_pin(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -144,6 +174,18 @@ void subghz_scene_radio_settings_on_enter(void* context) { variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, radio_device_text[value_index]); + //Add TX Power + item = variable_item_list_add( + subghz->variable_item_list, + "TX Power", + TX_POWER_COUNT, + subghz_scene_radio_settings_set_tx_power, + subghz); + + value_index = subghz->tx_power; + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, tx_power_text[value_index]); + item = variable_item_list_add( variable_item_list, "Protocol Names", diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index c743e660c..4781b326e 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -7,7 +7,6 @@ enum SubGhzSettingIndex { SubGhzSettingIndexFrequency, SubGhzSettingIndexHopping, SubGhzSettingIndexModulation, - SubGhzSettingIndexTXPower, SubGhzSettingIndexBinRAW, SubGhzSettingIndexIgnoreReversRB2, SubGhzSettingIndexIgnoreAlarms, @@ -103,22 +102,6 @@ const char* const combobox_text[COMBO_BOX_COUNT] = { "ON", }; -//TX Power -#define TX_POWER_COUNT 11 -const char* const tx_power_text[TX_POWER_COUNT] = { - "Preset", - "12dBm", - "10dBm", - "7dBm", - "5dBm", - "0dBm", - "-6dBm", - "-10dBm", - "-15dBm", - "-20dBm", - "-30dBm", -}; - static void subghz_scene_receiver_config_set_ignore_filter(VariableItem* item, SubGhzProtocolFlag filter) { SubGhz* subghz = variable_item_get_context(item); @@ -300,29 +283,6 @@ static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { subghz_txrx_speaker_set_state(subghz->txrx, speaker_value[index]); } -static void subghz_scene_receiver_config_set_tx_power(VariableItem* item) { - SubGhz* subghz = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - - //Update the Menu Item on screen - variable_item_set_current_value_text(item, tx_power_text[index]); - - //Set TX power and remember setting - subghz->last_settings->tx_power = subghz->tx_power = index; - - //Get current preset and frequency so I can update preset wit TX power. - SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); - uint32_t frequency = subghz_setting_get_default_frequency(setting); - SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); - - //Edit TX power, if necessary. - subghz_txrx_set_tx_power(preset.data, preset.data_size, subghz->tx_power); - - // Maybe better add one more function with only with the frequency argument? - subghz_txrx_set_preset( - subghz->txrx, furi_string_get_cstr(preset.name), frequency, preset.data, preset.data_size); -} - static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -392,7 +352,7 @@ static void subghz_scene_receiver_config_var_list_enter_callback(void* context, subghz->txrx, SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY, SUBGHZ_LAST_SETTING_DEFAULT_PRESET, - 0); + subghz->tx_power); SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); @@ -480,18 +440,6 @@ void subghz_scene_receiver_config_on_enter(void* context) { variable_item_set_current_value_text(item, hopping_mode_text[value_index]); } - //Add TX Power - item = variable_item_list_add( - subghz->variable_item_list, - "TX Power", - TX_POWER_COUNT, - subghz_scene_receiver_config_set_tx_power, - subghz); - - value_index = subghz->tx_power; - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, tx_power_text[value_index]); - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != SubGhzCustomEventManagerSet) { item = variable_item_list_add( From 8af7467b02c2aa120c693552f2b54b098b18e6b2 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Sun, 8 Feb 2026 17:57:56 +0700 Subject: [PATCH 108/160] Rework night shift setting demo --- .../services/notification/notification_app.c | 1275 +++++++++-------- .../services/notification/notification_app.h | 1 + .../notification_settings_app.c | 16 +- 3 files changed, 657 insertions(+), 635 deletions(-) diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index b4b0effa3..d3a0e65bc 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -248,7 +248,7 @@ void night_shift_timer_start(NotificationApp* app) { if(furi_timer_is_running(app->night_shift_timer)) { furi_timer_stop(app->night_shift_timer); } - furi_timer_start(app->night_shift_timer, furi_ms_to_ticks(2000)); + furi_timer_start(app->night_shift_timer, furi_ms_to_ticks(1000)); } } @@ -277,710 +277,723 @@ void night_shift_timer_callback(void* context) { } } -// --- NIGHT SHIFT END --- - -void notification_message_save_settings(NotificationApp* app) { - NotificationAppMessage m = { - .type = SaveSettingsMessage, .back_event = furi_event_flag_alloc()}; - furi_check(furi_message_queue_put(app->queue, &m, FuriWaitForever) == FuriStatusOk); - furi_event_flag_wait( - m.back_event, NOTIFICATION_EVENT_COMPLETE, FuriFlagWaitAny, FuriWaitForever); - furi_event_flag_free(m.back_event); +// force backlight ON when night_shift_demo_timer will be ended +void night_shift_demo_timer_callback(void* context) { + furi_assert(context); + NotificationApp* app = context; + notification_message(app, &sequence_display_backlight_force_on); } + // --- NIGHT SHIFT END --- -// internal layer -static void - notification_apply_internal_led_layer(NotificationLedLayer* layer, uint8_t layer_value) { - furi_assert(layer); - furi_assert(layer->index < LayerMAX); + void notification_message_save_settings(NotificationApp * app) { + NotificationAppMessage m = { + .type = SaveSettingsMessage, .back_event = furi_event_flag_alloc()}; + furi_check(furi_message_queue_put(app->queue, &m, FuriWaitForever) == FuriStatusOk); + furi_event_flag_wait( + m.back_event, NOTIFICATION_EVENT_COMPLETE, FuriFlagWaitAny, FuriWaitForever); + furi_event_flag_free(m.back_event); + } - // set value - layer->value[LayerInternal] = layer_value; + // internal layer + static void notification_apply_internal_led_layer( + NotificationLedLayer * layer, uint8_t layer_value) { + furi_assert(layer); + furi_assert(layer->index < LayerMAX); - // apply if current layer is internal - if(layer->index == LayerInternal) { + // set value + layer->value[LayerInternal] = layer_value; + + // apply if current layer is internal + if(layer->index == LayerInternal) { + furi_hal_light_set(layer->light, layer->value[LayerInternal]); + } + } + + static void notification_apply_lcd_contrast(NotificationApp * app) { + Gui* gui = furi_record_open(RECORD_GUI); + u8x8_d_st756x_set_contrast(&gui->canvas->fb.u8x8, app->settings.contrast); + furi_record_close(RECORD_GUI); + } + + static bool notification_is_any_led_layer_internal_and_not_empty(NotificationApp * app) { + bool result = false; + if((app->led[0].index == LayerInternal) || (app->led[1].index == LayerInternal) || + (app->led[2].index == LayerInternal)) { + if((app->led[0].value[LayerInternal] != 0x00) || + (app->led[1].value[LayerInternal] != 0x00) || + (app->led[2].value[LayerInternal] != 0x00)) { + result = true; + } + } + + return result; + } + + // notification layer + static void notification_apply_notification_led_layer( + NotificationLedLayer * layer, const uint8_t layer_value) { + furi_assert(layer); + furi_assert(layer->index < LayerMAX); + + // set value + layer->index = LayerNotification; + // set layer + layer->value[LayerNotification] = layer_value; + + // if layer.light = LightBacklight and backlight active now then just exit. + // prevent from extra ticking when key pressed with rgb_mod_installed + if((layer->light == LightBacklight) & lcd_backlight_is_on) return; + + // apply + furi_hal_light_set(layer->light, layer->value[LayerNotification]); + } + + static void notification_reset_notification_led_layer(NotificationLedLayer * layer) { + furi_assert(layer); + furi_assert(layer->index < LayerMAX); + + // set value + layer->value[LayerNotification] = 0; + // set layer + layer->index = LayerInternal; + + // apply furi_hal_light_set(layer->light, layer->value[LayerInternal]); } -} -static void notification_apply_lcd_contrast(NotificationApp* app) { - Gui* gui = furi_record_open(RECORD_GUI); - u8x8_d_st756x_set_contrast(&gui->canvas->fb.u8x8, app->settings.contrast); - furi_record_close(RECORD_GUI); -} - -static bool notification_is_any_led_layer_internal_and_not_empty(NotificationApp* app) { - bool result = false; - if((app->led[0].index == LayerInternal) || (app->led[1].index == LayerInternal) || - (app->led[2].index == LayerInternal)) { - if((app->led[0].value[LayerInternal] != 0x00) || - (app->led[1].value[LayerInternal] != 0x00) || - (app->led[2].value[LayerInternal] != 0x00)) { - result = true; + static void notification_reset_notification_layer( + NotificationApp * app, uint8_t reset_mask, float display_brightness_set) { + if(reset_mask & reset_blink_mask) { + furi_hal_light_blink_stop(); + } + if(reset_mask & reset_red_mask) { + notification_reset_notification_led_layer(&app->led[0]); + } + if(reset_mask & reset_green_mask) { + notification_reset_notification_led_layer(&app->led[1]); + } + if(reset_mask & reset_blue_mask) { + notification_reset_notification_led_layer(&app->led[2]); + } + if(reset_mask & reset_vibro_mask) { + notification_vibro_off(); + } + if(reset_mask & reset_sound_mask) { + notification_sound_off(); + } + if(reset_mask & reset_display_mask) { + if(!float_is_equal(display_brightness_set, app->settings.display_brightness)) { + furi_hal_light_set( + LightBacklight, + app->settings.display_brightness * 0xFF * app->current_night_shift * 1.0f); + } + if(app->settings.display_off_delay_ms > 0) { + furi_timer_start( + app->display_timer, notification_settings_display_off_delay_ticks(app)); + } } } - return result; -} - -// notification layer -static void notification_apply_notification_led_layer( - NotificationLedLayer* layer, - const uint8_t layer_value) { - furi_assert(layer); - furi_assert(layer->index < LayerMAX); - - // set value - layer->index = LayerNotification; - // set layer - layer->value[LayerNotification] = layer_value; - - // if layer.light = LightBacklight and backlight active now then just exit. - // prevent from extra ticking when key pressed with rgb_mod_installed - if((layer->light == LightBacklight) & lcd_backlight_is_on) return; - - // apply - furi_hal_light_set(layer->light, layer->value[LayerNotification]); -} - -static void notification_reset_notification_led_layer(NotificationLedLayer* layer) { - furi_assert(layer); - furi_assert(layer->index < LayerMAX); - - // set value - layer->value[LayerNotification] = 0; - // set layer - layer->index = LayerInternal; - - // apply - furi_hal_light_set(layer->light, layer->value[LayerInternal]); -} - -static void notification_reset_notification_layer( - NotificationApp* app, - uint8_t reset_mask, - float display_brightness_set) { - if(reset_mask & reset_blink_mask) { - furi_hal_light_blink_stop(); - } - if(reset_mask & reset_red_mask) { - notification_reset_notification_led_layer(&app->led[0]); - } - if(reset_mask & reset_green_mask) { - notification_reset_notification_led_layer(&app->led[1]); - } - if(reset_mask & reset_blue_mask) { - notification_reset_notification_led_layer(&app->led[2]); - } - if(reset_mask & reset_vibro_mask) { - notification_vibro_off(); - } - if(reset_mask & reset_sound_mask) { - notification_sound_off(); - } - if(reset_mask & reset_display_mask) { - if(!float_is_equal(display_brightness_set, app->settings.display_brightness)) { - furi_hal_light_set( - LightBacklight, - app->settings.display_brightness * 0xFF * app->current_night_shift * 1.0f); - } - if(app->settings.display_off_delay_ms > 0) { - furi_timer_start( - app->display_timer, notification_settings_display_off_delay_ticks(app)); + static void notification_apply_notification_leds( + NotificationApp * app, const uint8_t* values) { + for(uint8_t i = 0; i < NOTIFICATION_LED_COUNT; i++) { + notification_apply_notification_led_layer( + &app->led[i], notification_settings_get_rgb_led_brightness(app, values[i])); } } -} -static void notification_apply_notification_leds(NotificationApp* app, const uint8_t* values) { - for(uint8_t i = 0; i < NOTIFICATION_LED_COUNT; i++) { - notification_apply_notification_led_layer( - &app->led[i], notification_settings_get_rgb_led_brightness(app, values[i])); + // settings + uint8_t notification_settings_get_display_brightness(NotificationApp * app, uint8_t value) { + return value * app->settings.display_brightness; } -} -// settings -uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8_t value) { - return value * app->settings.display_brightness; -} - -static uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value) { - return value * app->settings.led_brightness; -} - -static uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app) { - return (float)(app->settings.display_off_delay_ms) / - (1000.0f / furi_kernel_get_tick_frequency()); -} - -// generics -static void notification_vibro_on(bool force) { - if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) { - furi_hal_vibro_on(true); + static uint8_t notification_settings_get_rgb_led_brightness( + NotificationApp * app, uint8_t value) { + return value * app->settings.led_brightness; } -} -static void notification_vibro_off(void) { - furi_hal_vibro_on(false); -} + static uint32_t notification_settings_display_off_delay_ticks(NotificationApp * app) { + return (float)(app->settings.display_off_delay_ms) / + (1000.0f / furi_kernel_get_tick_frequency()); + } -static void notification_sound_on(float freq, float volume, bool force) { - if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) { - if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) { - furi_hal_speaker_start(freq, volume); + // generics + static void notification_vibro_on(bool force) { + if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) { + furi_hal_vibro_on(true); } } -} -static void notification_sound_off(void) { - if(furi_hal_speaker_is_mine()) { - furi_hal_speaker_stop(); - furi_hal_speaker_release(); + static void notification_vibro_off(void) { + furi_hal_vibro_on(false); } -} -// display timer -static void notification_display_timer(void* ctx) { - furi_assert(ctx); - NotificationApp* app = ctx; - notification_message(app, &sequence_display_backlight_off); -} + static void notification_sound_on(float freq, float volume, bool force) { + if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) { + if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) { + furi_hal_speaker_start(freq, volume); + } + } + } -// message processing -static void notification_process_notification_message( - NotificationApp* app, - NotificationAppMessage* message) { - uint32_t notification_message_index = 0; - bool force_volume = false; - bool force_vibro = false; - const NotificationMessage* notification_message; - notification_message = (*message->sequence)[notification_message_index]; + static void notification_sound_off(void) { + if(furi_hal_speaker_is_mine()) { + furi_hal_speaker_stop(); + furi_hal_speaker_release(); + } + } - bool led_active = false; - uint8_t led_values[NOTIFICATION_LED_COUNT] = {0x00, 0x00, 0x00}; - bool reset_notifications = true; - float speaker_volume_setting = app->settings.speaker_volume; - bool vibro_setting = app->settings.vibro_on; - float display_brightness_setting = app->settings.display_brightness; + // display timer + static void notification_display_timer(void* ctx) { + furi_assert(ctx); + NotificationApp* app = ctx; + notification_message(app, &sequence_display_backlight_off); + } - uint8_t reset_mask = 0; + // message processing + static void notification_process_notification_message( + NotificationApp * app, NotificationAppMessage * message) { + uint32_t notification_message_index = 0; + bool force_volume = false; + bool force_vibro = false; + const NotificationMessage* notification_message; + notification_message = (*message->sequence)[notification_message_index]; - while(notification_message != NULL) { - switch(notification_message->type) { - case NotificationMessageTypeLedDisplayBacklight: - // if on (data.led.value =0xFF) - switch on and start timer - // if off (data.led.value =0x0) - switch off and stop timer - if(notification_message->data.led.value > 0x00) { - // Backlight ON + bool led_active = false; + uint8_t led_values[NOTIFICATION_LED_COUNT] = {0x00, 0x00, 0x00}; + bool reset_notifications = true; + float speaker_volume_setting = app->settings.speaker_volume; + bool vibro_setting = app->settings.vibro_on; + float display_brightness_setting = app->settings.display_brightness; + + uint8_t reset_mask = 0; + + while(notification_message != NULL) { + switch(notification_message->type) { + case NotificationMessageTypeLedDisplayBacklight: + // if on (data.led.value =0xFF) - switch on and start timer + // if off (data.led.value =0x0) - switch off and stop timer + if(notification_message->data.led.value > 0x00) { + // Backlight ON + notification_apply_notification_led_layer( + &app->display, + notification_message->data.led.value * display_brightness_setting * + app->current_night_shift * 1.0f); + + reset_mask |= reset_display_mask; + lcd_backlight_is_on = true; + + //start rgb_mod_rainbow_timer when display backlight is ON and all corresponding settings is ON too + rainbow_timer_starter(app); + + } else { + // Backlight OFF + reset_mask &= ~reset_display_mask; + notification_reset_notification_led_layer(&app->display); + lcd_backlight_is_on = false; + + if(furi_timer_is_running(app->display_timer)) { + furi_timer_stop(app->display_timer); + } + + //stop rgb_mod_rainbow_timer when display backlight is OFF + if(furi_timer_is_running(app->rainbow_timer)) { + rainbow_timer_stop(app); + } + } + break; + case NotificationMessageTypeLedDisplayBacklightForceOn: + // Force Backlight ON even if its ON now + lcd_backlight_is_on = false; notification_apply_notification_led_layer( &app->display, notification_message->data.led.value * display_brightness_setting * app->current_night_shift * 1.0f); - reset_mask |= reset_display_mask; lcd_backlight_is_on = true; //start rgb_mod_rainbow_timer when display backlight is ON and all corresponding settings is ON too rainbow_timer_starter(app); - - } else { - // Backlight OFF - reset_mask &= ~reset_display_mask; - notification_reset_notification_led_layer(&app->display); - lcd_backlight_is_on = false; - - if(furi_timer_is_running(app->display_timer)) { - furi_timer_stop(app->display_timer); + break; + case NotificationMessageTypeLedDisplayBacklightEnforceOn: + if(!app->display_led_lock) { + app->display_led_lock = true; + notification_apply_internal_led_layer( + &app->display, + notification_message->data.led.value * display_brightness_setting * + app->current_night_shift * 1.0f); + lcd_backlight_is_on = true; } - - //stop rgb_mod_rainbow_timer when display backlight is OFF - if(furi_timer_is_running(app->rainbow_timer)) { - rainbow_timer_stop(app); + break; + case NotificationMessageTypeLedDisplayBacklightEnforceAuto: + if(app->display_led_lock) { + app->display_led_lock = false; + notification_apply_internal_led_layer( + &app->display, + notification_message->data.led.value * display_brightness_setting * + app->current_night_shift * 1.0f); + // --- NIGHT SHIFT END --- + } else { + FURI_LOG_E(TAG, "Incorrect BacklightEnforceAuto usage"); } - } - break; - case NotificationMessageTypeLedDisplayBacklightForceOn: - // Force Backlight ON even if its ON now - lcd_backlight_is_on = false; - notification_apply_notification_led_layer( - &app->display, - notification_message->data.led.value * display_brightness_setting * - app->current_night_shift * 1.0f); - reset_mask |= reset_display_mask; - lcd_backlight_is_on = true; - - //start rgb_mod_rainbow_timer when display backlight is ON and all corresponding settings is ON too - rainbow_timer_starter(app); - break; - case NotificationMessageTypeLedDisplayBacklightEnforceOn: - if(!app->display_led_lock) { - app->display_led_lock = true; - notification_apply_internal_led_layer( - &app->display, - notification_message->data.led.value * display_brightness_setting * - app->current_night_shift * 1.0f); - lcd_backlight_is_on = true; - } - break; - case NotificationMessageTypeLedDisplayBacklightEnforceAuto: - if(app->display_led_lock) { - app->display_led_lock = false; - notification_apply_internal_led_layer( - &app->display, - notification_message->data.led.value * display_brightness_setting * - app->current_night_shift * 1.0f); - // --- NIGHT SHIFT END --- - } else { - FURI_LOG_E(TAG, "Incorrect BacklightEnforceAuto usage"); - } - break; - case NotificationMessageTypeLedRed: - // store and send on delay or after seq - led_active = true; - led_values[0] = notification_message->data.led.value; - app->led[0].value_last[LayerNotification] = led_values[0]; - reset_mask |= reset_red_mask; - break; - case NotificationMessageTypeLedGreen: - // store and send on delay or after seq - led_active = true; - led_values[1] = notification_message->data.led.value; - app->led[1].value_last[LayerNotification] = led_values[1]; - reset_mask |= reset_green_mask; - break; - case NotificationMessageTypeLedBlue: - // store and send on delay or after seq - led_active = true; - led_values[2] = notification_message->data.led.value; - app->led[2].value_last[LayerNotification] = led_values[2]; - reset_mask |= reset_blue_mask; - break; - case NotificationMessageTypeLedBlinkStart: - // store and send on delay or after seq - led_active = true; - furi_hal_light_blink_start( - notification_message->data.led_blink.color, - app->settings.led_brightness * 255, - notification_message->data.led_blink.on_time, - notification_message->data.led_blink.period); - reset_mask |= reset_blink_mask; - reset_mask |= reset_red_mask; - reset_mask |= reset_green_mask; - reset_mask |= reset_blue_mask; - break; - case NotificationMessageTypeLedBlinkColor: - led_active = true; - furi_hal_light_blink_set_color(notification_message->data.led_blink.color); - break; - case NotificationMessageTypeLedBlinkStop: - furi_hal_light_blink_stop(); - reset_mask &= ~reset_blink_mask; - reset_mask |= reset_red_mask; - reset_mask |= reset_green_mask; - reset_mask |= reset_blue_mask; - break; - case NotificationMessageTypeVibro: - if(notification_message->data.vibro.on) { - if(vibro_setting) notification_vibro_on(force_vibro); - } else { - notification_vibro_off(); - } - reset_mask |= reset_vibro_mask; - break; - case NotificationMessageTypeSoundOn: - notification_sound_on( - notification_message->data.sound.frequency, - notification_message->data.sound.volume * speaker_volume_setting, - force_volume); - reset_mask |= reset_sound_mask; - break; - case NotificationMessageTypeSoundOff: - notification_sound_off(); - reset_mask |= reset_sound_mask; - break; - case NotificationMessageTypeDelay: - if(led_active) { - if(notification_is_any_led_layer_internal_and_not_empty(app)) { - notification_apply_notification_leds(app, led_off_values); - furi_delay_ms(minimal_delay); - } - - led_active = false; - - notification_apply_notification_leds(app, led_values); + break; + case NotificationMessageTypeLedRed: + // store and send on delay or after seq + led_active = true; + led_values[0] = notification_message->data.led.value; + app->led[0].value_last[LayerNotification] = led_values[0]; + reset_mask |= reset_red_mask; + break; + case NotificationMessageTypeLedGreen: + // store and send on delay or after seq + led_active = true; + led_values[1] = notification_message->data.led.value; + app->led[1].value_last[LayerNotification] = led_values[1]; + reset_mask |= reset_green_mask; + break; + case NotificationMessageTypeLedBlue: + // store and send on delay or after seq + led_active = true; + led_values[2] = notification_message->data.led.value; + app->led[2].value_last[LayerNotification] = led_values[2]; + reset_mask |= reset_blue_mask; + break; + case NotificationMessageTypeLedBlinkStart: + // store and send on delay or after seq + led_active = true; + furi_hal_light_blink_start( + notification_message->data.led_blink.color, + app->settings.led_brightness * 255, + notification_message->data.led_blink.on_time, + notification_message->data.led_blink.period); + reset_mask |= reset_blink_mask; reset_mask |= reset_red_mask; reset_mask |= reset_green_mask; reset_mask |= reset_blue_mask; + break; + case NotificationMessageTypeLedBlinkColor: + led_active = true; + furi_hal_light_blink_set_color(notification_message->data.led_blink.color); + break; + case NotificationMessageTypeLedBlinkStop: + furi_hal_light_blink_stop(); + reset_mask &= ~reset_blink_mask; + reset_mask |= reset_red_mask; + reset_mask |= reset_green_mask; + reset_mask |= reset_blue_mask; + break; + case NotificationMessageTypeVibro: + if(notification_message->data.vibro.on) { + if(vibro_setting) notification_vibro_on(force_vibro); + } else { + notification_vibro_off(); + } + reset_mask |= reset_vibro_mask; + break; + case NotificationMessageTypeSoundOn: + notification_sound_on( + notification_message->data.sound.frequency, + notification_message->data.sound.volume * speaker_volume_setting, + force_volume); + reset_mask |= reset_sound_mask; + break; + case NotificationMessageTypeSoundOff: + notification_sound_off(); + reset_mask |= reset_sound_mask; + break; + case NotificationMessageTypeDelay: + if(led_active) { + if(notification_is_any_led_layer_internal_and_not_empty(app)) { + notification_apply_notification_leds(app, led_off_values); + furi_delay_ms(minimal_delay); + } + + led_active = false; + + notification_apply_notification_leds(app, led_values); + reset_mask |= reset_red_mask; + reset_mask |= reset_green_mask; + reset_mask |= reset_blue_mask; + } + + furi_delay_ms(notification_message->data.delay.length); + break; + case NotificationMessageTypeDoNotReset: + reset_notifications = false; + break; + case NotificationMessageTypeForceSpeakerVolumeSetting: + speaker_volume_setting = notification_message->data.forced_settings.speaker_volume; + force_volume = true; + break; + case NotificationMessageTypeForceVibroSetting: + vibro_setting = notification_message->data.forced_settings.vibro; + force_vibro = true; + break; + case NotificationMessageTypeForceDisplayBrightnessSetting: + display_brightness_setting = + notification_message->data.forced_settings.display_brightness; + break; + case NotificationMessageTypeLedBrightnessSettingApply: + led_active = true; + for(uint8_t i = 0; i < NOTIFICATION_LED_COUNT; i++) { + led_values[i] = app->led[i].value_last[LayerNotification]; + } + reset_mask |= reset_red_mask; + reset_mask |= reset_green_mask; + reset_mask |= reset_blue_mask; + break; + case NotificationMessageTypeLcdContrastUpdate: + notification_apply_lcd_contrast(app); + break; + } + notification_message_index++; + notification_message = (*message->sequence)[notification_message_index]; + }; + + // send and do minimal delay + if(led_active) { + bool need_minimal_delay = false; + if(notification_is_any_led_layer_internal_and_not_empty(app)) { + need_minimal_delay = true; } - furi_delay_ms(notification_message->data.delay.length); - break; - case NotificationMessageTypeDoNotReset: - reset_notifications = false; - break; - case NotificationMessageTypeForceSpeakerVolumeSetting: - speaker_volume_setting = notification_message->data.forced_settings.speaker_volume; - force_volume = true; - break; - case NotificationMessageTypeForceVibroSetting: - vibro_setting = notification_message->data.forced_settings.vibro; - force_vibro = true; - break; - case NotificationMessageTypeForceDisplayBrightnessSetting: - display_brightness_setting = - notification_message->data.forced_settings.display_brightness; - break; - case NotificationMessageTypeLedBrightnessSettingApply: - led_active = true; - for(uint8_t i = 0; i < NOTIFICATION_LED_COUNT; i++) { - led_values[i] = app->led[i].value_last[LayerNotification]; - } + notification_apply_notification_leds(app, led_values); reset_mask |= reset_red_mask; reset_mask |= reset_green_mask; reset_mask |= reset_blue_mask; - break; - case NotificationMessageTypeLcdContrastUpdate: - notification_apply_lcd_contrast(app); - break; - } - notification_message_index++; - notification_message = (*message->sequence)[notification_message_index]; - }; - // send and do minimal delay - if(led_active) { - bool need_minimal_delay = false; - if(notification_is_any_led_layer_internal_and_not_empty(app)) { - need_minimal_delay = true; - } - - notification_apply_notification_leds(app, led_values); - reset_mask |= reset_red_mask; - reset_mask |= reset_green_mask; - reset_mask |= reset_blue_mask; - - if((need_minimal_delay) && (reset_notifications)) { - notification_apply_notification_leds(app, led_off_values); - furi_delay_ms(minimal_delay); - } - } - - if(reset_notifications) { - notification_reset_notification_layer(app, reset_mask, display_brightness_setting); - } -} - -static void - notification_process_internal_message(NotificationApp* app, NotificationAppMessage* message) { - uint32_t notification_message_index = 0; - const NotificationMessage* notification_message; - notification_message = (*message->sequence)[notification_message_index]; - - while(notification_message != NULL) { - switch(notification_message->type) { - case NotificationMessageTypeLedDisplayBacklight: - notification_apply_internal_led_layer( - &app->display, - notification_settings_get_display_brightness( - app, notification_message->data.led.value)); - break; - case NotificationMessageTypeLedRed: - app->led[0].value_last[LayerInternal] = notification_message->data.led.value; - notification_apply_internal_led_layer( - &app->led[0], - notification_settings_get_rgb_led_brightness( - app, notification_message->data.led.value)); - break; - case NotificationMessageTypeLedGreen: - app->led[1].value_last[LayerInternal] = notification_message->data.led.value; - notification_apply_internal_led_layer( - &app->led[1], - notification_settings_get_rgb_led_brightness( - app, notification_message->data.led.value)); - break; - case NotificationMessageTypeLedBlue: - app->led[2].value_last[LayerInternal] = notification_message->data.led.value; - notification_apply_internal_led_layer( - &app->led[2], - notification_settings_get_rgb_led_brightness( - app, notification_message->data.led.value)); - break; - case NotificationMessageTypeLedBrightnessSettingApply: - for(uint8_t i = 0; i < NOTIFICATION_LED_COUNT; i++) { - uint8_t new_val = notification_settings_get_rgb_led_brightness( - app, app->led[i].value_last[LayerInternal]); - notification_apply_internal_led_layer(&app->led[i], new_val); + if((need_minimal_delay) && (reset_notifications)) { + notification_apply_notification_leds(app, led_off_values); + furi_delay_ms(minimal_delay); } - break; - default: - break; } - notification_message_index++; + + if(reset_notifications) { + notification_reset_notification_layer(app, reset_mask, display_brightness_setting); + } + } + + static void notification_process_internal_message( + NotificationApp * app, NotificationAppMessage * message) { + uint32_t notification_message_index = 0; + const NotificationMessage* notification_message; notification_message = (*message->sequence)[notification_message_index]; - } -} -static bool notification_load_settings(NotificationApp* app) { - NotificationSettings settings; - File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); - const size_t settings_size = sizeof(NotificationSettings); - - FURI_LOG_I(TAG, "Loading \"%s\"", NOTIFICATION_SETTINGS_PATH); - bool fs_result = - storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING); - - if(fs_result) { - size_t bytes_count = storage_file_read(file, &settings, settings_size); - - if(bytes_count != settings_size) { - fs_result = false; + while(notification_message != NULL) { + switch(notification_message->type) { + case NotificationMessageTypeLedDisplayBacklight: + notification_apply_internal_led_layer( + &app->display, + notification_settings_get_display_brightness( + app, notification_message->data.led.value)); + break; + case NotificationMessageTypeLedRed: + app->led[0].value_last[LayerInternal] = notification_message->data.led.value; + notification_apply_internal_led_layer( + &app->led[0], + notification_settings_get_rgb_led_brightness( + app, notification_message->data.led.value)); + break; + case NotificationMessageTypeLedGreen: + app->led[1].value_last[LayerInternal] = notification_message->data.led.value; + notification_apply_internal_led_layer( + &app->led[1], + notification_settings_get_rgb_led_brightness( + app, notification_message->data.led.value)); + break; + case NotificationMessageTypeLedBlue: + app->led[2].value_last[LayerInternal] = notification_message->data.led.value; + notification_apply_internal_led_layer( + &app->led[2], + notification_settings_get_rgb_led_brightness( + app, notification_message->data.led.value)); + break; + case NotificationMessageTypeLedBrightnessSettingApply: + for(uint8_t i = 0; i < NOTIFICATION_LED_COUNT; i++) { + uint8_t new_val = notification_settings_get_rgb_led_brightness( + app, app->led[i].value_last[LayerInternal]); + notification_apply_internal_led_layer(&app->led[i], new_val); + } + break; + default: + break; + } + notification_message_index++; + notification_message = (*message->sequence)[notification_message_index]; } } - if(fs_result) { - if(settings.version != NOTIFICATION_SETTINGS_VERSION) { - FURI_LOG_E( - TAG, "version(%d != %d) mismatch", settings.version, NOTIFICATION_SETTINGS_VERSION); + static bool notification_load_settings(NotificationApp * app) { + NotificationSettings settings; + File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); + const size_t settings_size = sizeof(NotificationSettings); + + FURI_LOG_I(TAG, "Loading \"%s\"", NOTIFICATION_SETTINGS_PATH); + bool fs_result = + storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING); + + if(fs_result) { + size_t bytes_count = storage_file_read(file, &settings, settings_size); + + if(bytes_count != settings_size) { + fs_result = false; + } + } + + if(fs_result) { + if(settings.version != NOTIFICATION_SETTINGS_VERSION) { + FURI_LOG_E( + TAG, + "version(%d != %d) mismatch", + settings.version, + NOTIFICATION_SETTINGS_VERSION); + } else { + furi_kernel_lock(); + memcpy(&app->settings, &settings, settings_size); + furi_kernel_unlock(); + } } else { - furi_kernel_lock(); - memcpy(&app->settings, &settings, settings_size); - furi_kernel_unlock(); + FURI_LOG_E(TAG, "Load failed, %s", storage_file_get_error_desc(file)); } - } else { - FURI_LOG_E(TAG, "Load failed, %s", storage_file_get_error_desc(file)); + + storage_file_close(file); + storage_file_free(file); + furi_record_close(RECORD_STORAGE); + + return fs_result; } - storage_file_close(file); - storage_file_free(file); - furi_record_close(RECORD_STORAGE); + static bool notification_save_settings(NotificationApp * app) { + NotificationSettings settings; + File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); + const size_t settings_size = sizeof(NotificationSettings); - return fs_result; -} + FURI_LOG_I(TAG, "Saving \"%s\"", NOTIFICATION_SETTINGS_PATH); -static bool notification_save_settings(NotificationApp* app) { - NotificationSettings settings; - File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); - const size_t settings_size = sizeof(NotificationSettings); + furi_kernel_lock(); + memcpy(&settings, &app->settings, settings_size); + furi_kernel_unlock(); - FURI_LOG_I(TAG, "Saving \"%s\"", NOTIFICATION_SETTINGS_PATH); + bool fs_result = + storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS); - furi_kernel_lock(); - memcpy(&settings, &app->settings, settings_size); - furi_kernel_unlock(); + if(fs_result) { + size_t bytes_count = storage_file_write(file, &settings, settings_size); - bool fs_result = - storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS); - - if(fs_result) { - size_t bytes_count = storage_file_write(file, &settings, settings_size); - - if(bytes_count != settings_size) { - fs_result = false; + if(bytes_count != settings_size) { + fs_result = false; + } } - } - if(fs_result) { - } else { - FURI_LOG_E(TAG, "Save failed, %s", storage_file_get_error_desc(file)); - } - - storage_file_close(file); - storage_file_free(file); - furi_record_close(RECORD_STORAGE); - - return fs_result; -} - -static void input_event_callback(const void* value, void* context) { - furi_assert(value); - furi_assert(context); - NotificationApp* app = context; - notification_message(app, &sequence_display_backlight_on); -} - -// App alloc -static NotificationApp* notification_app_alloc(void) { - NotificationApp* app = malloc(sizeof(NotificationApp)); - app->queue = furi_message_queue_alloc(8, sizeof(NotificationAppMessage)); - app->display_timer = furi_timer_alloc(notification_display_timer, FuriTimerTypeOnce, app); - - app->settings.speaker_volume = 1.0f; - app->settings.display_brightness = 1.0f; - app->settings.led_brightness = 1.0f; - app->settings.display_off_delay_ms = 30000; - app->settings.vibro_on = true; - - app->display.value[LayerInternal] = 0x00; - app->display.value[LayerNotification] = 0x00; - app->display.index = LayerInternal; - app->display.light = LightBacklight; - - app->led[0].value[LayerInternal] = 0x00; - app->led[0].value[LayerNotification] = 0x00; - app->led[0].index = LayerInternal; - app->led[0].light = LightRed; - - app->led[1].value[LayerInternal] = 0x00; - app->led[1].value[LayerNotification] = 0x00; - app->led[1].index = LayerInternal; - app->led[1].light = LightGreen; - - app->led[2].value[LayerInternal] = 0x00; - app->led[2].value[LayerNotification] = 0x00; - app->led[2].index = LayerInternal; - app->led[2].light = LightBlue; - - app->settings.version = NOTIFICATION_SETTINGS_VERSION; - - // display backlight control - app->event_record = furi_record_open(RECORD_INPUT_EVENTS); - furi_pubsub_subscribe(app->event_record, input_event_callback, app); - notification_message(app, &sequence_display_backlight_on); - - // --- NIGHT SHIFT --- - app->current_night_shift = 1.0f; - app->current_night_shift = 1.0f; - app->settings.night_shift = 1.0f; - app->settings.night_shift_start = 1020; - app->settings.night_shift_end = 300; - app->night_shift_timer = - furi_timer_alloc(night_shift_timer_callback, FuriTimerTypePeriodic, app); - // --- NIGHT SHIFT END --- - - // init working variables - app->rainbow_hue = 1; - app->current_night_shift = 1.0f; - - // init rgb.segings values - app->settings.rgb.rgb_backlight_installed = 0; - app->settings.rgb.led_2_color_index = 0; - app->settings.rgb.led_1_color_index = 0; - app->settings.rgb.led_0_color_index = 0; - app->settings.rgb.rainbow_speed_ms = 100; - app->settings.rgb.rainbow_step = 1; - app->settings.rgb.rainbow_saturation = 255; - app->settings.rgb.rainbow_wide = 50; - - // set inital value, later it will be rewriten by loading settings from file - app->settings.lcd_inversion = false; - - return app; -} - -static void notification_storage_callback(const void* message, void* context) { - furi_assert(context); - NotificationApp* app = context; - const StorageEvent* event = message; - - if(event->type == StorageEventTypeCardMount) { - NotificationAppMessage m = { - .type = LoadSettingsMessage, - }; - - furi_check(furi_message_queue_put(app->queue, &m, FuriWaitForever) == FuriStatusOk); - } -} - -static void notification_apply_settings(NotificationApp* app) { - if(!notification_load_settings(app)) { - notification_save_settings(app); - } - - notification_apply_lcd_contrast(app); - - // --- NIGHT SHIFT --- - // if night_shift enabled then start timer for controlling current_night_shift multiplicator value depent from current time - if(app->settings.night_shift != 1) { - night_shift_timer_start(app); - } - // --- NIGHT SHIFT END --- - - // check RECORD_GUI is exist (insurance on boot time) then use it to setup lcd inversion mode from loaded settings; - if(furi_record_exists(RECORD_GUI)) { - Gui* gui = furi_record_open(RECORD_GUI); - u8x8_d_st756x_set_inversion(&gui->canvas->fb.u8x8, app->settings.lcd_inversion); - furi_record_close(RECORD_GUI); - } -} - -static void notification_init_settings(NotificationApp* app) { - Storage* storage = furi_record_open(RECORD_STORAGE); - furi_pubsub_subscribe(storage_get_pubsub(storage), notification_storage_callback, app); - - if(storage_sd_status(storage) != FSE_OK) { - FURI_LOG_D(TAG, "SD Card not ready, skipping settings"); - return; - } - - notification_apply_settings(app); -} - -// App -int32_t notification_srv(void* p) { - UNUSED(p); - NotificationApp* app = notification_app_alloc(); - - notification_init_settings(app); - - notification_vibro_off(); - notification_sound_off(); - notification_apply_internal_led_layer(&app->display, 0x00); - notification_apply_internal_led_layer(&app->led[0], 0x00); - notification_apply_internal_led_layer(&app->led[1], 0x00); - notification_apply_internal_led_layer(&app->led[2], 0x00); - - furi_record_create(RECORD_NOTIFICATION, app); - - // --- RGB BACKLIGHT SECTION --- - - //setup local variable - set_rgb_backlight_installed_variable(app->settings.rgb.rgb_backlight_installed); - - // define rainbow_timer and they callback - app->rainbow_timer = furi_timer_alloc(rainbow_timer_callback, FuriTimerTypePeriodic, app); - - // if rgb_backlight_installed then start rainbow or set leds colors from saved settings (default index = 0) - if(app->settings.rgb.rgb_backlight_installed) { - if(app->settings.rgb.rainbow_mode > 0) { - rainbow_timer_start(app); + if(fs_result) { } else { - rgb_backlight_set_led_static_color(2, app->settings.rgb.led_2_color_index); - rgb_backlight_set_led_static_color(1, app->settings.rgb.led_1_color_index); - rgb_backlight_set_led_static_color(0, app->settings.rgb.led_0_color_index); - rgb_backlight_update(app->settings.display_brightness * app->current_night_shift); + FURI_LOG_E(TAG, "Save failed, %s", storage_file_get_error_desc(file)); } - // if rgb_backlight not installed then set default static orange color(index=0) to all leds (0-2) and force light on - } else { - rgb_backlight_set_led_static_color(2, 0); - rgb_backlight_set_led_static_color(1, 0); - rgb_backlight_set_led_static_color(0, 0); - SK6805_update(); + + storage_file_close(file); + storage_file_free(file); + furi_record_close(RECORD_STORAGE); + + return fs_result; } - // --- RGB BACKLIGHT SECTION END --- + static void input_event_callback(const void* value, void* context) { + furi_assert(value); + furi_assert(context); + NotificationApp* app = context; + notification_message(app, &sequence_display_backlight_on); + } - NotificationAppMessage message; - while(1) { - furi_check(furi_message_queue_get(app->queue, &message, FuriWaitForever) == FuriStatusOk); + // App alloc + static NotificationApp* notification_app_alloc(void) { + NotificationApp* app = malloc(sizeof(NotificationApp)); + app->queue = furi_message_queue_alloc(8, sizeof(NotificationAppMessage)); + app->display_timer = furi_timer_alloc(notification_display_timer, FuriTimerTypeOnce, app); - switch(message.type) { - case NotificationLayerMessage: - notification_process_notification_message(app, &message); - break; - case InternalLayerMessage: - notification_process_internal_message(app, &message); - break; - case SaveSettingsMessage: + app->settings.speaker_volume = 1.0f; + app->settings.display_brightness = 1.0f; + app->settings.led_brightness = 1.0f; + app->settings.display_off_delay_ms = 30000; + app->settings.vibro_on = true; + + app->display.value[LayerInternal] = 0x00; + app->display.value[LayerNotification] = 0x00; + app->display.index = LayerInternal; + app->display.light = LightBacklight; + + app->led[0].value[LayerInternal] = 0x00; + app->led[0].value[LayerNotification] = 0x00; + app->led[0].index = LayerInternal; + app->led[0].light = LightRed; + + app->led[1].value[LayerInternal] = 0x00; + app->led[1].value[LayerNotification] = 0x00; + app->led[1].index = LayerInternal; + app->led[1].light = LightGreen; + + app->led[2].value[LayerInternal] = 0x00; + app->led[2].value[LayerNotification] = 0x00; + app->led[2].index = LayerInternal; + app->led[2].light = LightBlue; + + app->settings.version = NOTIFICATION_SETTINGS_VERSION; + + // display backlight control + app->event_record = furi_record_open(RECORD_INPUT_EVENTS); + furi_pubsub_subscribe(app->event_record, input_event_callback, app); + notification_message(app, &sequence_display_backlight_on); + + // --- NIGHT SHIFT --- + app->current_night_shift = 1.0f; + app->current_night_shift = 1.0f; + app->settings.night_shift = 1.0f; + app->settings.night_shift_start = 1020; + app->settings.night_shift_end = 300; + app->night_shift_timer = + furi_timer_alloc(night_shift_timer_callback, FuriTimerTypePeriodic, app); + // --- NIGHT SHIFT END --- + + // init working variables + app->rainbow_hue = 1; + app->current_night_shift = 1.0f; + + // init rgb.segings values + app->settings.rgb.rgb_backlight_installed = 0; + app->settings.rgb.led_2_color_index = 0; + app->settings.rgb.led_1_color_index = 0; + app->settings.rgb.led_0_color_index = 0; + app->settings.rgb.rainbow_speed_ms = 100; + app->settings.rgb.rainbow_step = 1; + app->settings.rgb.rainbow_saturation = 255; + app->settings.rgb.rainbow_wide = 50; + + // set inital value, later it will be rewriten by loading settings from file + app->settings.lcd_inversion = false; + + return app; + } + + static void notification_storage_callback(const void* message, void* context) { + furi_assert(context); + NotificationApp* app = context; + const StorageEvent* event = message; + + if(event->type == StorageEventTypeCardMount) { + NotificationAppMessage m = { + .type = LoadSettingsMessage, + }; + + furi_check(furi_message_queue_put(app->queue, &m, FuriWaitForever) == FuriStatusOk); + } + } + + static void notification_apply_settings(NotificationApp * app) { + if(!notification_load_settings(app)) { notification_save_settings(app); - break; - case LoadSettingsMessage: - notification_load_settings(app); - break; } - if(message.back_event != NULL) { - furi_event_flag_set(message.back_event, NOTIFICATION_EVENT_COMPLETE); + notification_apply_lcd_contrast(app); + + // --- NIGHT SHIFT --- + // if night_shift enabled then start timer for controlling current_night_shift multiplicator value depent from current time + if(app->settings.night_shift != 1) { + night_shift_timer_start(app); + } + // --- NIGHT SHIFT END --- + + // check RECORD_GUI is exist (insurance on boot time) then use it to setup lcd inversion mode from loaded settings; + if(furi_record_exists(RECORD_GUI)) { + Gui* gui = furi_record_open(RECORD_GUI); + u8x8_d_st756x_set_inversion(&gui->canvas->fb.u8x8, app->settings.lcd_inversion); + furi_record_close(RECORD_GUI); } } - return 0; -} + static void notification_init_settings(NotificationApp * app) { + Storage* storage = furi_record_open(RECORD_STORAGE); + furi_pubsub_subscribe(storage_get_pubsub(storage), notification_storage_callback, app); + + if(storage_sd_status(storage) != FSE_OK) { + FURI_LOG_D(TAG, "SD Card not ready, skipping settings"); + return; + } + + notification_apply_settings(app); + } + + // App + int32_t notification_srv(void* p) { + UNUSED(p); + NotificationApp* app = notification_app_alloc(); + + notification_init_settings(app); + + notification_vibro_off(); + notification_sound_off(); + notification_apply_internal_led_layer(&app->display, 0x00); + notification_apply_internal_led_layer(&app->led[0], 0x00); + notification_apply_internal_led_layer(&app->led[1], 0x00); + notification_apply_internal_led_layer(&app->led[2], 0x00); + + furi_record_create(RECORD_NOTIFICATION, app); + + // --- RGB BACKLIGHT SECTION --- + + //setup local variable + set_rgb_backlight_installed_variable(app->settings.rgb.rgb_backlight_installed); + + // define rainbow_timer and they callback + app->rainbow_timer = furi_timer_alloc(rainbow_timer_callback, FuriTimerTypePeriodic, app); + + // define night_shift_demo_timer and they callback. + // used for Setting menu to demonstrate night_shift_backlight when user change value + app->night_shift_demo_timer = + furi_timer_alloc(night_shift_demo_timer_callback, FuriTimerTypeOnce, app); + + // if rgb_backlight_installed then start rainbow or set leds colors from saved settings (default index = 0) + if(app->settings.rgb.rgb_backlight_installed) { + if(app->settings.rgb.rainbow_mode > 0) { + rainbow_timer_start(app); + } else { + rgb_backlight_set_led_static_color(2, app->settings.rgb.led_2_color_index); + rgb_backlight_set_led_static_color(1, app->settings.rgb.led_1_color_index); + rgb_backlight_set_led_static_color(0, app->settings.rgb.led_0_color_index); + rgb_backlight_update(app->settings.display_brightness * app->current_night_shift); + } + // if rgb_backlight not installed then set default static orange color(index=0) to all leds (0-2) and force light on + } else { + rgb_backlight_set_led_static_color(2, 0); + rgb_backlight_set_led_static_color(1, 0); + rgb_backlight_set_led_static_color(0, 0); + SK6805_update(); + } + + // --- RGB BACKLIGHT SECTION END --- + + NotificationAppMessage message; + while(1) { + furi_check( + furi_message_queue_get(app->queue, &message, FuriWaitForever) == FuriStatusOk); + + switch(message.type) { + case NotificationLayerMessage: + notification_process_notification_message(app, &message); + break; + case InternalLayerMessage: + notification_process_internal_message(app, &message); + break; + case SaveSettingsMessage: + notification_save_settings(app); + break; + case LoadSettingsMessage: + notification_load_settings(app); + break; + } + + if(message.back_event != NULL) { + furi_event_flag_set(message.back_event, NOTIFICATION_EVENT_COMPLETE); + } + } + + return 0; + } diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index abf3cc15e..111fbd481 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -86,6 +86,7 @@ struct NotificationApp { NotificationSettings settings; FuriTimer* night_shift_timer; + FuriTimer* night_shift_demo_timer; float current_night_shift; FuriTimer* rainbow_timer; diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 4d95a8ac6..84a2747f7 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -558,10 +558,6 @@ static void night_shift_changed(VariableItem* item) { variable_item_set_current_value_text(item, night_shift_text[index]); app->notification->settings.night_shift = night_shift_value[index]; - // force demo night_shift brightness to rgb backlight and stock backlight - // app->notification->current_night_shift = night_shift_value[index]; - // notification_message(app->notification, &sequence_display_backlight_force_on); - for(int i = 4; i < 6; i++) { VariableItem* t_item = variable_item_list_get(app->variable_item_list, i); if(index == 0) { @@ -571,10 +567,22 @@ static void night_shift_changed(VariableItem* item) { } } + // force demo night_shift brightness to rgb backlight and stock backlight for 1,2 sec + // while 1,2 seconds are running, there is another timer "night_shift_timer" can change current_night_shift to day or night value + // so when night_shift_demo_timer ended backlight force ON to day or night brightness + app->notification->current_night_shift = night_shift_value[index]; + notification_message(app->notification, &sequence_display_backlight_force_on); + if(night_shift_value[index] != 1) { night_shift_timer_start(app->notification); + if(furi_timer_is_running(app->notification->night_shift_demo_timer)) { + furi_timer_stop(app->notification->night_shift_demo_timer); + } + furi_timer_start(app->notification->night_shift_demo_timer, furi_ms_to_ticks(1200)); } else { night_shift_timer_stop(app->notification); + if(furi_timer_is_running(app->notification->night_shift_demo_timer)) + furi_timer_stop(app->notification->night_shift_demo_timer); } notification_message_save_settings(app->notification); From ed5c87fb144c355204c5edfb6300b5e757a7613e Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Sun, 8 Feb 2026 18:39:28 +0700 Subject: [PATCH 109/160] backlight time correction --- applications/services/notification/notification_app.h | 2 +- .../notification_settings/notification_settings_app.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 111fbd481..094027d89 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -39,7 +39,7 @@ typedef struct { Light light; } NotificationLedLayer; -#define NOTIFICATION_SETTINGS_VERSION 0x05 +#define NOTIFICATION_SETTINGS_VERSION 0x06 #define NOTIFICATION_SETTINGS_PATH INT_PATH(NOTIFICATION_SETTINGS_FILE_NAME) typedef struct { diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 84a2747f7..e82b02c87 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -87,7 +87,7 @@ const float volume_value[VOLUME_COUNT] = { #define DELAY_COUNT 12 const char* const delay_text[DELAY_COUNT] = { "Always ON", - "1s", + "2s", "5s", "10s", "15s", @@ -100,7 +100,7 @@ const char* const delay_text[DELAY_COUNT] = { "30min", }; const uint32_t delay_value[DELAY_COUNT] = - {0, 1000, 5000, 10000, 15000, 30000, 60000, 90000, 120000, 300000, 600000, 1800000}; + {0, 2000, 5000, 10000, 15000, 30000, 60000, 90000, 120000, 300000, 600000, 1800000}; #define VIBRO_COUNT 2 const char* const vibro_text[VIBRO_COUNT] = { From 7bb166e2acdc20327da205bd8117b5708b83b96c Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Sun, 8 Feb 2026 19:00:52 +0700 Subject: [PATCH 110/160] "kostylling" ))) --- .../services/notification/notification_app.c | 1267 +++++++++-------- .../services/notification/notification_app.h | 2 +- 2 files changed, 635 insertions(+), 634 deletions(-) diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index d3a0e65bc..8a62f7ac9 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -283,717 +283,718 @@ void night_shift_demo_timer_callback(void* context) { NotificationApp* app = context; notification_message(app, &sequence_display_backlight_force_on); } - // --- NIGHT SHIFT END --- +// --- NIGHT SHIFT END --- - void notification_message_save_settings(NotificationApp * app) { - NotificationAppMessage m = { - .type = SaveSettingsMessage, .back_event = furi_event_flag_alloc()}; - furi_check(furi_message_queue_put(app->queue, &m, FuriWaitForever) == FuriStatusOk); - furi_event_flag_wait( - m.back_event, NOTIFICATION_EVENT_COMPLETE, FuriFlagWaitAny, FuriWaitForever); - furi_event_flag_free(m.back_event); - } +void notification_message_save_settings(NotificationApp* app) { + NotificationAppMessage m = { + .type = SaveSettingsMessage, .back_event = furi_event_flag_alloc()}; + furi_check(furi_message_queue_put(app->queue, &m, FuriWaitForever) == FuriStatusOk); + furi_event_flag_wait( + m.back_event, NOTIFICATION_EVENT_COMPLETE, FuriFlagWaitAny, FuriWaitForever); + furi_event_flag_free(m.back_event); +} - // internal layer - static void notification_apply_internal_led_layer( - NotificationLedLayer * layer, uint8_t layer_value) { - furi_assert(layer); - furi_assert(layer->index < LayerMAX); +// internal layer +static void + notification_apply_internal_led_layer(NotificationLedLayer* layer, uint8_t layer_value) { + furi_assert(layer); + furi_assert(layer->index < LayerMAX); - // set value - layer->value[LayerInternal] = layer_value; + // set value + layer->value[LayerInternal] = layer_value; - // apply if current layer is internal - if(layer->index == LayerInternal) { - furi_hal_light_set(layer->light, layer->value[LayerInternal]); - } - } - - static void notification_apply_lcd_contrast(NotificationApp * app) { - Gui* gui = furi_record_open(RECORD_GUI); - u8x8_d_st756x_set_contrast(&gui->canvas->fb.u8x8, app->settings.contrast); - furi_record_close(RECORD_GUI); - } - - static bool notification_is_any_led_layer_internal_and_not_empty(NotificationApp * app) { - bool result = false; - if((app->led[0].index == LayerInternal) || (app->led[1].index == LayerInternal) || - (app->led[2].index == LayerInternal)) { - if((app->led[0].value[LayerInternal] != 0x00) || - (app->led[1].value[LayerInternal] != 0x00) || - (app->led[2].value[LayerInternal] != 0x00)) { - result = true; - } - } - - return result; - } - - // notification layer - static void notification_apply_notification_led_layer( - NotificationLedLayer * layer, const uint8_t layer_value) { - furi_assert(layer); - furi_assert(layer->index < LayerMAX); - - // set value - layer->index = LayerNotification; - // set layer - layer->value[LayerNotification] = layer_value; - - // if layer.light = LightBacklight and backlight active now then just exit. - // prevent from extra ticking when key pressed with rgb_mod_installed - if((layer->light == LightBacklight) & lcd_backlight_is_on) return; - - // apply - furi_hal_light_set(layer->light, layer->value[LayerNotification]); - } - - static void notification_reset_notification_led_layer(NotificationLedLayer * layer) { - furi_assert(layer); - furi_assert(layer->index < LayerMAX); - - // set value - layer->value[LayerNotification] = 0; - // set layer - layer->index = LayerInternal; - - // apply + // apply if current layer is internal + if(layer->index == LayerInternal) { furi_hal_light_set(layer->light, layer->value[LayerInternal]); } +} - static void notification_reset_notification_layer( - NotificationApp * app, uint8_t reset_mask, float display_brightness_set) { - if(reset_mask & reset_blink_mask) { - furi_hal_light_blink_stop(); - } - if(reset_mask & reset_red_mask) { - notification_reset_notification_led_layer(&app->led[0]); - } - if(reset_mask & reset_green_mask) { - notification_reset_notification_led_layer(&app->led[1]); - } - if(reset_mask & reset_blue_mask) { - notification_reset_notification_led_layer(&app->led[2]); - } - if(reset_mask & reset_vibro_mask) { - notification_vibro_off(); - } - if(reset_mask & reset_sound_mask) { - notification_sound_off(); - } - if(reset_mask & reset_display_mask) { - if(!float_is_equal(display_brightness_set, app->settings.display_brightness)) { - furi_hal_light_set( - LightBacklight, - app->settings.display_brightness * 0xFF * app->current_night_shift * 1.0f); - } - if(app->settings.display_off_delay_ms > 0) { - furi_timer_start( - app->display_timer, notification_settings_display_off_delay_ticks(app)); - } +static void notification_apply_lcd_contrast(NotificationApp* app) { + Gui* gui = furi_record_open(RECORD_GUI); + u8x8_d_st756x_set_contrast(&gui->canvas->fb.u8x8, app->settings.contrast); + furi_record_close(RECORD_GUI); +} + +static bool notification_is_any_led_layer_internal_and_not_empty(NotificationApp* app) { + bool result = false; + if((app->led[0].index == LayerInternal) || (app->led[1].index == LayerInternal) || + (app->led[2].index == LayerInternal)) { + if((app->led[0].value[LayerInternal] != 0x00) || + (app->led[1].value[LayerInternal] != 0x00) || + (app->led[2].value[LayerInternal] != 0x00)) { + result = true; } } - static void notification_apply_notification_leds( - NotificationApp * app, const uint8_t* values) { - for(uint8_t i = 0; i < NOTIFICATION_LED_COUNT; i++) { - notification_apply_notification_led_layer( - &app->led[i], notification_settings_get_rgb_led_brightness(app, values[i])); + return result; +} + +// notification layer +static void notification_apply_notification_led_layer( + NotificationLedLayer* layer, + const uint8_t layer_value) { + furi_assert(layer); + furi_assert(layer->index < LayerMAX); + + // set value + layer->index = LayerNotification; + // set layer + layer->value[LayerNotification] = layer_value; + + // if layer.light = LightBacklight and backlight active now then just exit. + // prevent from extra ticking when key pressed with rgb_mod_installed + if((layer->light == LightBacklight) & lcd_backlight_is_on) return; + + // apply + furi_hal_light_set(layer->light, layer->value[LayerNotification]); +} + +static void notification_reset_notification_led_layer(NotificationLedLayer* layer) { + furi_assert(layer); + furi_assert(layer->index < LayerMAX); + + // set value + layer->value[LayerNotification] = 0; + // set layer + layer->index = LayerInternal; + + // apply + furi_hal_light_set(layer->light, layer->value[LayerInternal]); +} + +static void notification_reset_notification_layer( + NotificationApp* app, + uint8_t reset_mask, + float display_brightness_set) { + if(reset_mask & reset_blink_mask) { + furi_hal_light_blink_stop(); + } + if(reset_mask & reset_red_mask) { + notification_reset_notification_led_layer(&app->led[0]); + } + if(reset_mask & reset_green_mask) { + notification_reset_notification_led_layer(&app->led[1]); + } + if(reset_mask & reset_blue_mask) { + notification_reset_notification_led_layer(&app->led[2]); + } + if(reset_mask & reset_vibro_mask) { + notification_vibro_off(); + } + if(reset_mask & reset_sound_mask) { + notification_sound_off(); + } + if(reset_mask & reset_display_mask) { + if(!float_is_equal(display_brightness_set, app->settings.display_brightness)) { + furi_hal_light_set( + LightBacklight, + app->settings.display_brightness * 0xFF * app->current_night_shift * 1.0f); + } + if(app->settings.display_off_delay_ms > 0) { + furi_timer_start( + app->display_timer, notification_settings_display_off_delay_ticks(app)); } } +} - // settings - uint8_t notification_settings_get_display_brightness(NotificationApp * app, uint8_t value) { - return value * app->settings.display_brightness; +static void notification_apply_notification_leds(NotificationApp* app, const uint8_t* values) { + for(uint8_t i = 0; i < NOTIFICATION_LED_COUNT; i++) { + notification_apply_notification_led_layer( + &app->led[i], notification_settings_get_rgb_led_brightness(app, values[i])); } +} - static uint8_t notification_settings_get_rgb_led_brightness( - NotificationApp * app, uint8_t value) { - return value * app->settings.led_brightness; +// settings +uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8_t value) { + return value * app->settings.display_brightness; +} + +static uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value) { + return value * app->settings.led_brightness; +} + +static uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app) { + return (float)(app->settings.display_off_delay_ms) / + (1000.0f / furi_kernel_get_tick_frequency()); +} + +// generics +static void notification_vibro_on(bool force) { + if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) { + furi_hal_vibro_on(true); } +} - static uint32_t notification_settings_display_off_delay_ticks(NotificationApp * app) { - return (float)(app->settings.display_off_delay_ms) / - (1000.0f / furi_kernel_get_tick_frequency()); - } +static void notification_vibro_off(void) { + furi_hal_vibro_on(false); +} - // generics - static void notification_vibro_on(bool force) { - if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) { - furi_hal_vibro_on(true); +static void notification_sound_on(float freq, float volume, bool force) { + if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) { + if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) { + furi_hal_speaker_start(freq, volume); } } +} - static void notification_vibro_off(void) { - furi_hal_vibro_on(false); +static void notification_sound_off(void) { + if(furi_hal_speaker_is_mine()) { + furi_hal_speaker_stop(); + furi_hal_speaker_release(); } +} - static void notification_sound_on(float freq, float volume, bool force) { - if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) { - if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) { - furi_hal_speaker_start(freq, volume); - } - } - } +// display timer +static void notification_display_timer(void* ctx) { + furi_assert(ctx); + NotificationApp* app = ctx; + notification_message(app, &sequence_display_backlight_off); +} - static void notification_sound_off(void) { - if(furi_hal_speaker_is_mine()) { - furi_hal_speaker_stop(); - furi_hal_speaker_release(); - } - } +// message processing +static void notification_process_notification_message( + NotificationApp* app, + NotificationAppMessage* message) { + uint32_t notification_message_index = 0; + bool force_volume = false; + bool force_vibro = false; + const NotificationMessage* notification_message; + notification_message = (*message->sequence)[notification_message_index]; - // display timer - static void notification_display_timer(void* ctx) { - furi_assert(ctx); - NotificationApp* app = ctx; - notification_message(app, &sequence_display_backlight_off); - } + bool led_active = false; + uint8_t led_values[NOTIFICATION_LED_COUNT] = {0x00, 0x00, 0x00}; + bool reset_notifications = true; + float speaker_volume_setting = app->settings.speaker_volume; + bool vibro_setting = app->settings.vibro_on; + float display_brightness_setting = app->settings.display_brightness; - // message processing - static void notification_process_notification_message( - NotificationApp * app, NotificationAppMessage * message) { - uint32_t notification_message_index = 0; - bool force_volume = false; - bool force_vibro = false; - const NotificationMessage* notification_message; - notification_message = (*message->sequence)[notification_message_index]; + uint8_t reset_mask = 0; - bool led_active = false; - uint8_t led_values[NOTIFICATION_LED_COUNT] = {0x00, 0x00, 0x00}; - bool reset_notifications = true; - float speaker_volume_setting = app->settings.speaker_volume; - bool vibro_setting = app->settings.vibro_on; - float display_brightness_setting = app->settings.display_brightness; - - uint8_t reset_mask = 0; - - while(notification_message != NULL) { - switch(notification_message->type) { - case NotificationMessageTypeLedDisplayBacklight: - // if on (data.led.value =0xFF) - switch on and start timer - // if off (data.led.value =0x0) - switch off and stop timer - if(notification_message->data.led.value > 0x00) { - // Backlight ON - notification_apply_notification_led_layer( - &app->display, - notification_message->data.led.value * display_brightness_setting * - app->current_night_shift * 1.0f); - - reset_mask |= reset_display_mask; - lcd_backlight_is_on = true; - - //start rgb_mod_rainbow_timer when display backlight is ON and all corresponding settings is ON too - rainbow_timer_starter(app); - - } else { - // Backlight OFF - reset_mask &= ~reset_display_mask; - notification_reset_notification_led_layer(&app->display); - lcd_backlight_is_on = false; - - if(furi_timer_is_running(app->display_timer)) { - furi_timer_stop(app->display_timer); - } - - //stop rgb_mod_rainbow_timer when display backlight is OFF - if(furi_timer_is_running(app->rainbow_timer)) { - rainbow_timer_stop(app); - } - } - break; - case NotificationMessageTypeLedDisplayBacklightForceOn: - // Force Backlight ON even if its ON now - lcd_backlight_is_on = false; + while(notification_message != NULL) { + switch(notification_message->type) { + case NotificationMessageTypeLedDisplayBacklight: + // if on (data.led.value =0xFF) - switch on and start timer + // if off (data.led.value =0x0) - switch off and stop timer + if(notification_message->data.led.value > 0x00) { + // Backlight ON notification_apply_notification_led_layer( &app->display, notification_message->data.led.value * display_brightness_setting * app->current_night_shift * 1.0f); + reset_mask |= reset_display_mask; lcd_backlight_is_on = true; //start rgb_mod_rainbow_timer when display backlight is ON and all corresponding settings is ON too rainbow_timer_starter(app); - break; - case NotificationMessageTypeLedDisplayBacklightEnforceOn: - if(!app->display_led_lock) { - app->display_led_lock = true; - notification_apply_internal_led_layer( - &app->display, - notification_message->data.led.value * display_brightness_setting * - app->current_night_shift * 1.0f); - lcd_backlight_is_on = true; - } - break; - case NotificationMessageTypeLedDisplayBacklightEnforceAuto: - if(app->display_led_lock) { - app->display_led_lock = false; - notification_apply_internal_led_layer( - &app->display, - notification_message->data.led.value * display_brightness_setting * - app->current_night_shift * 1.0f); - // --- NIGHT SHIFT END --- - } else { - FURI_LOG_E(TAG, "Incorrect BacklightEnforceAuto usage"); - } - break; - case NotificationMessageTypeLedRed: - // store and send on delay or after seq - led_active = true; - led_values[0] = notification_message->data.led.value; - app->led[0].value_last[LayerNotification] = led_values[0]; - reset_mask |= reset_red_mask; - break; - case NotificationMessageTypeLedGreen: - // store and send on delay or after seq - led_active = true; - led_values[1] = notification_message->data.led.value; - app->led[1].value_last[LayerNotification] = led_values[1]; - reset_mask |= reset_green_mask; - break; - case NotificationMessageTypeLedBlue: - // store and send on delay or after seq - led_active = true; - led_values[2] = notification_message->data.led.value; - app->led[2].value_last[LayerNotification] = led_values[2]; - reset_mask |= reset_blue_mask; - break; - case NotificationMessageTypeLedBlinkStart: - // store and send on delay or after seq - led_active = true; - furi_hal_light_blink_start( - notification_message->data.led_blink.color, - app->settings.led_brightness * 255, - notification_message->data.led_blink.on_time, - notification_message->data.led_blink.period); - reset_mask |= reset_blink_mask; - reset_mask |= reset_red_mask; - reset_mask |= reset_green_mask; - reset_mask |= reset_blue_mask; - break; - case NotificationMessageTypeLedBlinkColor: - led_active = true; - furi_hal_light_blink_set_color(notification_message->data.led_blink.color); - break; - case NotificationMessageTypeLedBlinkStop: - furi_hal_light_blink_stop(); - reset_mask &= ~reset_blink_mask; - reset_mask |= reset_red_mask; - reset_mask |= reset_green_mask; - reset_mask |= reset_blue_mask; - break; - case NotificationMessageTypeVibro: - if(notification_message->data.vibro.on) { - if(vibro_setting) notification_vibro_on(force_vibro); - } else { - notification_vibro_off(); - } - reset_mask |= reset_vibro_mask; - break; - case NotificationMessageTypeSoundOn: - notification_sound_on( - notification_message->data.sound.frequency, - notification_message->data.sound.volume * speaker_volume_setting, - force_volume); - reset_mask |= reset_sound_mask; - break; - case NotificationMessageTypeSoundOff: - notification_sound_off(); - reset_mask |= reset_sound_mask; - break; - case NotificationMessageTypeDelay: - if(led_active) { - if(notification_is_any_led_layer_internal_and_not_empty(app)) { - notification_apply_notification_leds(app, led_off_values); - furi_delay_ms(minimal_delay); - } - led_active = false; + } else { + // Backlight OFF + reset_mask &= ~reset_display_mask; + notification_reset_notification_led_layer(&app->display); + lcd_backlight_is_on = false; - notification_apply_notification_leds(app, led_values); - reset_mask |= reset_red_mask; - reset_mask |= reset_green_mask; - reset_mask |= reset_blue_mask; + if(furi_timer_is_running(app->display_timer)) { + furi_timer_stop(app->display_timer); } - furi_delay_ms(notification_message->data.delay.length); - break; - case NotificationMessageTypeDoNotReset: - reset_notifications = false; - break; - case NotificationMessageTypeForceSpeakerVolumeSetting: - speaker_volume_setting = notification_message->data.forced_settings.speaker_volume; - force_volume = true; - break; - case NotificationMessageTypeForceVibroSetting: - vibro_setting = notification_message->data.forced_settings.vibro; - force_vibro = true; - break; - case NotificationMessageTypeForceDisplayBrightnessSetting: - display_brightness_setting = - notification_message->data.forced_settings.display_brightness; - break; - case NotificationMessageTypeLedBrightnessSettingApply: - led_active = true; - for(uint8_t i = 0; i < NOTIFICATION_LED_COUNT; i++) { - led_values[i] = app->led[i].value_last[LayerNotification]; + //stop rgb_mod_rainbow_timer when display backlight is OFF + if(furi_timer_is_running(app->rainbow_timer)) { + rainbow_timer_stop(app); } - reset_mask |= reset_red_mask; - reset_mask |= reset_green_mask; - reset_mask |= reset_blue_mask; - break; - case NotificationMessageTypeLcdContrastUpdate: - notification_apply_lcd_contrast(app); - break; } - notification_message_index++; - notification_message = (*message->sequence)[notification_message_index]; - }; + break; + case NotificationMessageTypeLedDisplayBacklightForceOn: + // Force Backlight ON even if its ON now + lcd_backlight_is_on = false; + notification_apply_notification_led_layer( + &app->display, + notification_message->data.led.value * display_brightness_setting * + app->current_night_shift * 1.0f); + reset_mask |= reset_display_mask; + lcd_backlight_is_on = true; - // send and do minimal delay - if(led_active) { - bool need_minimal_delay = false; - if(notification_is_any_led_layer_internal_and_not_empty(app)) { - need_minimal_delay = true; + //start rgb_mod_rainbow_timer when display backlight is ON and all corresponding settings is ON too + rainbow_timer_starter(app); + break; + case NotificationMessageTypeLedDisplayBacklightEnforceOn: + if(!app->display_led_lock) { + app->display_led_lock = true; + notification_apply_internal_led_layer( + &app->display, + notification_message->data.led.value * display_brightness_setting * + app->current_night_shift * 1.0f); + lcd_backlight_is_on = true; } - - notification_apply_notification_leds(app, led_values); + break; + case NotificationMessageTypeLedDisplayBacklightEnforceAuto: + if(app->display_led_lock) { + app->display_led_lock = false; + notification_apply_internal_led_layer( + &app->display, + notification_message->data.led.value * display_brightness_setting * + app->current_night_shift * 1.0f); + // --- NIGHT SHIFT END --- + } else { + FURI_LOG_E(TAG, "Incorrect BacklightEnforceAuto usage"); + } + break; + case NotificationMessageTypeLedRed: + // store and send on delay or after seq + led_active = true; + led_values[0] = notification_message->data.led.value; + app->led[0].value_last[LayerNotification] = led_values[0]; + reset_mask |= reset_red_mask; + break; + case NotificationMessageTypeLedGreen: + // store and send on delay or after seq + led_active = true; + led_values[1] = notification_message->data.led.value; + app->led[1].value_last[LayerNotification] = led_values[1]; + reset_mask |= reset_green_mask; + break; + case NotificationMessageTypeLedBlue: + // store and send on delay or after seq + led_active = true; + led_values[2] = notification_message->data.led.value; + app->led[2].value_last[LayerNotification] = led_values[2]; + reset_mask |= reset_blue_mask; + break; + case NotificationMessageTypeLedBlinkStart: + // store and send on delay or after seq + led_active = true; + furi_hal_light_blink_start( + notification_message->data.led_blink.color, + app->settings.led_brightness * 255, + notification_message->data.led_blink.on_time, + notification_message->data.led_blink.period); + reset_mask |= reset_blink_mask; reset_mask |= reset_red_mask; reset_mask |= reset_green_mask; reset_mask |= reset_blue_mask; - - if((need_minimal_delay) && (reset_notifications)) { - notification_apply_notification_leds(app, led_off_values); - furi_delay_ms(minimal_delay); + break; + case NotificationMessageTypeLedBlinkColor: + led_active = true; + furi_hal_light_blink_set_color(notification_message->data.led_blink.color); + break; + case NotificationMessageTypeLedBlinkStop: + furi_hal_light_blink_stop(); + reset_mask &= ~reset_blink_mask; + reset_mask |= reset_red_mask; + reset_mask |= reset_green_mask; + reset_mask |= reset_blue_mask; + break; + case NotificationMessageTypeVibro: + if(notification_message->data.vibro.on) { + if(vibro_setting) notification_vibro_on(force_vibro); + } else { + notification_vibro_off(); } - } - - if(reset_notifications) { - notification_reset_notification_layer(app, reset_mask, display_brightness_setting); - } - } - - static void notification_process_internal_message( - NotificationApp * app, NotificationAppMessage * message) { - uint32_t notification_message_index = 0; - const NotificationMessage* notification_message; - notification_message = (*message->sequence)[notification_message_index]; - - while(notification_message != NULL) { - switch(notification_message->type) { - case NotificationMessageTypeLedDisplayBacklight: - notification_apply_internal_led_layer( - &app->display, - notification_settings_get_display_brightness( - app, notification_message->data.led.value)); - break; - case NotificationMessageTypeLedRed: - app->led[0].value_last[LayerInternal] = notification_message->data.led.value; - notification_apply_internal_led_layer( - &app->led[0], - notification_settings_get_rgb_led_brightness( - app, notification_message->data.led.value)); - break; - case NotificationMessageTypeLedGreen: - app->led[1].value_last[LayerInternal] = notification_message->data.led.value; - notification_apply_internal_led_layer( - &app->led[1], - notification_settings_get_rgb_led_brightness( - app, notification_message->data.led.value)); - break; - case NotificationMessageTypeLedBlue: - app->led[2].value_last[LayerInternal] = notification_message->data.led.value; - notification_apply_internal_led_layer( - &app->led[2], - notification_settings_get_rgb_led_brightness( - app, notification_message->data.led.value)); - break; - case NotificationMessageTypeLedBrightnessSettingApply: - for(uint8_t i = 0; i < NOTIFICATION_LED_COUNT; i++) { - uint8_t new_val = notification_settings_get_rgb_led_brightness( - app, app->led[i].value_last[LayerInternal]); - notification_apply_internal_led_layer(&app->led[i], new_val); + reset_mask |= reset_vibro_mask; + break; + case NotificationMessageTypeSoundOn: + notification_sound_on( + notification_message->data.sound.frequency, + notification_message->data.sound.volume * speaker_volume_setting, + force_volume); + reset_mask |= reset_sound_mask; + break; + case NotificationMessageTypeSoundOff: + notification_sound_off(); + reset_mask |= reset_sound_mask; + break; + case NotificationMessageTypeDelay: + if(led_active) { + if(notification_is_any_led_layer_internal_and_not_empty(app)) { + notification_apply_notification_leds(app, led_off_values); + furi_delay_ms(minimal_delay); } - break; - default: - break; + + led_active = false; + + notification_apply_notification_leds(app, led_values); + reset_mask |= reset_red_mask; + reset_mask |= reset_green_mask; + reset_mask |= reset_blue_mask; } - notification_message_index++; - notification_message = (*message->sequence)[notification_message_index]; + + furi_delay_ms(notification_message->data.delay.length); + break; + case NotificationMessageTypeDoNotReset: + reset_notifications = false; + break; + case NotificationMessageTypeForceSpeakerVolumeSetting: + speaker_volume_setting = notification_message->data.forced_settings.speaker_volume; + force_volume = true; + break; + case NotificationMessageTypeForceVibroSetting: + vibro_setting = notification_message->data.forced_settings.vibro; + force_vibro = true; + break; + case NotificationMessageTypeForceDisplayBrightnessSetting: + display_brightness_setting = + notification_message->data.forced_settings.display_brightness; + break; + case NotificationMessageTypeLedBrightnessSettingApply: + led_active = true; + for(uint8_t i = 0; i < NOTIFICATION_LED_COUNT; i++) { + led_values[i] = app->led[i].value_last[LayerNotification]; + } + reset_mask |= reset_red_mask; + reset_mask |= reset_green_mask; + reset_mask |= reset_blue_mask; + break; + case NotificationMessageTypeLcdContrastUpdate: + notification_apply_lcd_contrast(app); + break; + } + notification_message_index++; + notification_message = (*message->sequence)[notification_message_index]; + }; + + // send and do minimal delay + if(led_active) { + bool need_minimal_delay = false; + if(notification_is_any_led_layer_internal_and_not_empty(app)) { + need_minimal_delay = true; + } + + notification_apply_notification_leds(app, led_values); + reset_mask |= reset_red_mask; + reset_mask |= reset_green_mask; + reset_mask |= reset_blue_mask; + + if((need_minimal_delay) && (reset_notifications)) { + notification_apply_notification_leds(app, led_off_values); + furi_delay_ms(minimal_delay); } } - static bool notification_load_settings(NotificationApp * app) { - NotificationSettings settings; - File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); - const size_t settings_size = sizeof(NotificationSettings); + if(reset_notifications) { + notification_reset_notification_layer(app, reset_mask, display_brightness_setting); + } +} - FURI_LOG_I(TAG, "Loading \"%s\"", NOTIFICATION_SETTINGS_PATH); - bool fs_result = - storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING); +static void + notification_process_internal_message(NotificationApp* app, NotificationAppMessage* message) { + uint32_t notification_message_index = 0; + const NotificationMessage* notification_message; + notification_message = (*message->sequence)[notification_message_index]; - if(fs_result) { - size_t bytes_count = storage_file_read(file, &settings, settings_size); - - if(bytes_count != settings_size) { - fs_result = false; + while(notification_message != NULL) { + switch(notification_message->type) { + case NotificationMessageTypeLedDisplayBacklight: + notification_apply_internal_led_layer( + &app->display, + notification_settings_get_display_brightness( + app, notification_message->data.led.value)); + break; + case NotificationMessageTypeLedRed: + app->led[0].value_last[LayerInternal] = notification_message->data.led.value; + notification_apply_internal_led_layer( + &app->led[0], + notification_settings_get_rgb_led_brightness( + app, notification_message->data.led.value)); + break; + case NotificationMessageTypeLedGreen: + app->led[1].value_last[LayerInternal] = notification_message->data.led.value; + notification_apply_internal_led_layer( + &app->led[1], + notification_settings_get_rgb_led_brightness( + app, notification_message->data.led.value)); + break; + case NotificationMessageTypeLedBlue: + app->led[2].value_last[LayerInternal] = notification_message->data.led.value; + notification_apply_internal_led_layer( + &app->led[2], + notification_settings_get_rgb_led_brightness( + app, notification_message->data.led.value)); + break; + case NotificationMessageTypeLedBrightnessSettingApply: + for(uint8_t i = 0; i < NOTIFICATION_LED_COUNT; i++) { + uint8_t new_val = notification_settings_get_rgb_led_brightness( + app, app->led[i].value_last[LayerInternal]); + notification_apply_internal_led_layer(&app->led[i], new_val); } + break; + default: + break; } + notification_message_index++; + notification_message = (*message->sequence)[notification_message_index]; + } +} - if(fs_result) { - if(settings.version != NOTIFICATION_SETTINGS_VERSION) { - FURI_LOG_E( - TAG, - "version(%d != %d) mismatch", - settings.version, - NOTIFICATION_SETTINGS_VERSION); - } else { - furi_kernel_lock(); - memcpy(&app->settings, &settings, settings_size); - furi_kernel_unlock(); - } +static bool notification_load_settings(NotificationApp* app) { + NotificationSettings settings; + File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); + const size_t settings_size = sizeof(NotificationSettings); + + FURI_LOG_I(TAG, "Loading \"%s\"", NOTIFICATION_SETTINGS_PATH); + bool fs_result = + storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING); + + if(fs_result) { + size_t bytes_count = storage_file_read(file, &settings, settings_size); + + if(bytes_count != settings_size) { + fs_result = false; + } + } + + if(fs_result) { + if(settings.version != NOTIFICATION_SETTINGS_VERSION) { + FURI_LOG_E( + TAG, "version(%d != %d) mismatch", settings.version, NOTIFICATION_SETTINGS_VERSION); } else { - FURI_LOG_E(TAG, "Load failed, %s", storage_file_get_error_desc(file)); + furi_kernel_lock(); + memcpy(&app->settings, &settings, settings_size); + furi_kernel_unlock(); } - - storage_file_close(file); - storage_file_free(file); - furi_record_close(RECORD_STORAGE); - - return fs_result; + } else { + FURI_LOG_E(TAG, "Load failed, %s", storage_file_get_error_desc(file)); } - static bool notification_save_settings(NotificationApp * app) { - NotificationSettings settings; - File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); - const size_t settings_size = sizeof(NotificationSettings); + storage_file_close(file); + storage_file_free(file); + furi_record_close(RECORD_STORAGE); - FURI_LOG_I(TAG, "Saving \"%s\"", NOTIFICATION_SETTINGS_PATH); + // "kostyl" for update old setting to new without change settings version + if(app->settings.display_off_delay_ms < 2000) app->settings.display_off_delay_ms = 2000; + + return fs_result; +} - furi_kernel_lock(); - memcpy(&settings, &app->settings, settings_size); - furi_kernel_unlock(); +static bool notification_save_settings(NotificationApp* app) { + NotificationSettings settings; + File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); + const size_t settings_size = sizeof(NotificationSettings); - bool fs_result = - storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS); + FURI_LOG_I(TAG, "Saving \"%s\"", NOTIFICATION_SETTINGS_PATH); - if(fs_result) { - size_t bytes_count = storage_file_write(file, &settings, settings_size); + furi_kernel_lock(); + memcpy(&settings, &app->settings, settings_size); + furi_kernel_unlock(); - if(bytes_count != settings_size) { - fs_result = false; - } + bool fs_result = + storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS); + + if(fs_result) { + size_t bytes_count = storage_file_write(file, &settings, settings_size); + + if(bytes_count != settings_size) { + fs_result = false; } + } - if(fs_result) { + if(fs_result) { + } else { + FURI_LOG_E(TAG, "Save failed, %s", storage_file_get_error_desc(file)); + } + + storage_file_close(file); + storage_file_free(file); + furi_record_close(RECORD_STORAGE); + + return fs_result; +} + +static void input_event_callback(const void* value, void* context) { + furi_assert(value); + furi_assert(context); + NotificationApp* app = context; + notification_message(app, &sequence_display_backlight_on); +} + +// App alloc +static NotificationApp* notification_app_alloc(void) { + NotificationApp* app = malloc(sizeof(NotificationApp)); + app->queue = furi_message_queue_alloc(8, sizeof(NotificationAppMessage)); + app->display_timer = furi_timer_alloc(notification_display_timer, FuriTimerTypeOnce, app); + + app->settings.speaker_volume = 1.0f; + app->settings.display_brightness = 1.0f; + app->settings.led_brightness = 1.0f; + app->settings.display_off_delay_ms = 30000; + app->settings.vibro_on = true; + + app->display.value[LayerInternal] = 0x00; + app->display.value[LayerNotification] = 0x00; + app->display.index = LayerInternal; + app->display.light = LightBacklight; + + app->led[0].value[LayerInternal] = 0x00; + app->led[0].value[LayerNotification] = 0x00; + app->led[0].index = LayerInternal; + app->led[0].light = LightRed; + + app->led[1].value[LayerInternal] = 0x00; + app->led[1].value[LayerNotification] = 0x00; + app->led[1].index = LayerInternal; + app->led[1].light = LightGreen; + + app->led[2].value[LayerInternal] = 0x00; + app->led[2].value[LayerNotification] = 0x00; + app->led[2].index = LayerInternal; + app->led[2].light = LightBlue; + + app->settings.version = NOTIFICATION_SETTINGS_VERSION; + + // display backlight control + app->event_record = furi_record_open(RECORD_INPUT_EVENTS); + furi_pubsub_subscribe(app->event_record, input_event_callback, app); + notification_message(app, &sequence_display_backlight_on); + + // --- NIGHT SHIFT --- + app->current_night_shift = 1.0f; + app->current_night_shift = 1.0f; + app->settings.night_shift = 1.0f; + app->settings.night_shift_start = 1020; + app->settings.night_shift_end = 300; + app->night_shift_timer = + furi_timer_alloc(night_shift_timer_callback, FuriTimerTypePeriodic, app); + // --- NIGHT SHIFT END --- + + // init working variables + app->rainbow_hue = 1; + app->current_night_shift = 1.0f; + + // init rgb.segings values + app->settings.rgb.rgb_backlight_installed = 0; + app->settings.rgb.led_2_color_index = 0; + app->settings.rgb.led_1_color_index = 0; + app->settings.rgb.led_0_color_index = 0; + app->settings.rgb.rainbow_speed_ms = 100; + app->settings.rgb.rainbow_step = 1; + app->settings.rgb.rainbow_saturation = 255; + app->settings.rgb.rainbow_wide = 50; + + // set inital value, later it will be rewriten by loading settings from file + app->settings.lcd_inversion = false; + + return app; +} + +static void notification_storage_callback(const void* message, void* context) { + furi_assert(context); + NotificationApp* app = context; + const StorageEvent* event = message; + + if(event->type == StorageEventTypeCardMount) { + NotificationAppMessage m = { + .type = LoadSettingsMessage, + }; + + furi_check(furi_message_queue_put(app->queue, &m, FuriWaitForever) == FuriStatusOk); + } +} + +static void notification_apply_settings(NotificationApp* app) { + if(!notification_load_settings(app)) { + notification_save_settings(app); + } + + notification_apply_lcd_contrast(app); + + // --- NIGHT SHIFT --- + // if night_shift enabled then start timer for controlling current_night_shift multiplicator value depent from current time + if(app->settings.night_shift != 1) { + night_shift_timer_start(app); + } + // --- NIGHT SHIFT END --- + + // check RECORD_GUI is exist (insurance on boot time) then use it to setup lcd inversion mode from loaded settings; + if(furi_record_exists(RECORD_GUI)) { + Gui* gui = furi_record_open(RECORD_GUI); + u8x8_d_st756x_set_inversion(&gui->canvas->fb.u8x8, app->settings.lcd_inversion); + furi_record_close(RECORD_GUI); + } +} + +static void notification_init_settings(NotificationApp* app) { + Storage* storage = furi_record_open(RECORD_STORAGE); + furi_pubsub_subscribe(storage_get_pubsub(storage), notification_storage_callback, app); + + if(storage_sd_status(storage) != FSE_OK) { + FURI_LOG_D(TAG, "SD Card not ready, skipping settings"); + return; + } + + notification_apply_settings(app); +} + +// App +int32_t notification_srv(void* p) { + UNUSED(p); + NotificationApp* app = notification_app_alloc(); + + notification_init_settings(app); + + notification_vibro_off(); + notification_sound_off(); + notification_apply_internal_led_layer(&app->display, 0x00); + notification_apply_internal_led_layer(&app->led[0], 0x00); + notification_apply_internal_led_layer(&app->led[1], 0x00); + notification_apply_internal_led_layer(&app->led[2], 0x00); + + furi_record_create(RECORD_NOTIFICATION, app); + + // --- RGB BACKLIGHT SECTION --- + + //setup local variable + set_rgb_backlight_installed_variable(app->settings.rgb.rgb_backlight_installed); + + // define rainbow_timer and they callback + app->rainbow_timer = furi_timer_alloc(rainbow_timer_callback, FuriTimerTypePeriodic, app); + + // define night_shift_demo_timer and they callback. + // used for Setting menu to demonstrate night_shift_backlight when user change value + app->night_shift_demo_timer = + furi_timer_alloc(night_shift_demo_timer_callback, FuriTimerTypeOnce, app); + + // if rgb_backlight_installed then start rainbow or set leds colors from saved settings (default index = 0) + if(app->settings.rgb.rgb_backlight_installed) { + if(app->settings.rgb.rainbow_mode > 0) { + rainbow_timer_start(app); } else { - FURI_LOG_E(TAG, "Save failed, %s", storage_file_get_error_desc(file)); + rgb_backlight_set_led_static_color(2, app->settings.rgb.led_2_color_index); + rgb_backlight_set_led_static_color(1, app->settings.rgb.led_1_color_index); + rgb_backlight_set_led_static_color(0, app->settings.rgb.led_0_color_index); + rgb_backlight_update(app->settings.display_brightness * app->current_night_shift); } - - storage_file_close(file); - storage_file_free(file); - furi_record_close(RECORD_STORAGE); - - return fs_result; + // if rgb_backlight not installed then set default static orange color(index=0) to all leds (0-2) and force light on + } else { + rgb_backlight_set_led_static_color(2, 0); + rgb_backlight_set_led_static_color(1, 0); + rgb_backlight_set_led_static_color(0, 0); + SK6805_update(); } - static void input_event_callback(const void* value, void* context) { - furi_assert(value); - furi_assert(context); - NotificationApp* app = context; - notification_message(app, &sequence_display_backlight_on); - } + // --- RGB BACKLIGHT SECTION END --- - // App alloc - static NotificationApp* notification_app_alloc(void) { - NotificationApp* app = malloc(sizeof(NotificationApp)); - app->queue = furi_message_queue_alloc(8, sizeof(NotificationAppMessage)); - app->display_timer = furi_timer_alloc(notification_display_timer, FuriTimerTypeOnce, app); + NotificationAppMessage message; + while(1) { + furi_check(furi_message_queue_get(app->queue, &message, FuriWaitForever) == FuriStatusOk); - app->settings.speaker_volume = 1.0f; - app->settings.display_brightness = 1.0f; - app->settings.led_brightness = 1.0f; - app->settings.display_off_delay_ms = 30000; - app->settings.vibro_on = true; - - app->display.value[LayerInternal] = 0x00; - app->display.value[LayerNotification] = 0x00; - app->display.index = LayerInternal; - app->display.light = LightBacklight; - - app->led[0].value[LayerInternal] = 0x00; - app->led[0].value[LayerNotification] = 0x00; - app->led[0].index = LayerInternal; - app->led[0].light = LightRed; - - app->led[1].value[LayerInternal] = 0x00; - app->led[1].value[LayerNotification] = 0x00; - app->led[1].index = LayerInternal; - app->led[1].light = LightGreen; - - app->led[2].value[LayerInternal] = 0x00; - app->led[2].value[LayerNotification] = 0x00; - app->led[2].index = LayerInternal; - app->led[2].light = LightBlue; - - app->settings.version = NOTIFICATION_SETTINGS_VERSION; - - // display backlight control - app->event_record = furi_record_open(RECORD_INPUT_EVENTS); - furi_pubsub_subscribe(app->event_record, input_event_callback, app); - notification_message(app, &sequence_display_backlight_on); - - // --- NIGHT SHIFT --- - app->current_night_shift = 1.0f; - app->current_night_shift = 1.0f; - app->settings.night_shift = 1.0f; - app->settings.night_shift_start = 1020; - app->settings.night_shift_end = 300; - app->night_shift_timer = - furi_timer_alloc(night_shift_timer_callback, FuriTimerTypePeriodic, app); - // --- NIGHT SHIFT END --- - - // init working variables - app->rainbow_hue = 1; - app->current_night_shift = 1.0f; - - // init rgb.segings values - app->settings.rgb.rgb_backlight_installed = 0; - app->settings.rgb.led_2_color_index = 0; - app->settings.rgb.led_1_color_index = 0; - app->settings.rgb.led_0_color_index = 0; - app->settings.rgb.rainbow_speed_ms = 100; - app->settings.rgb.rainbow_step = 1; - app->settings.rgb.rainbow_saturation = 255; - app->settings.rgb.rainbow_wide = 50; - - // set inital value, later it will be rewriten by loading settings from file - app->settings.lcd_inversion = false; - - return app; - } - - static void notification_storage_callback(const void* message, void* context) { - furi_assert(context); - NotificationApp* app = context; - const StorageEvent* event = message; - - if(event->type == StorageEventTypeCardMount) { - NotificationAppMessage m = { - .type = LoadSettingsMessage, - }; - - furi_check(furi_message_queue_put(app->queue, &m, FuriWaitForever) == FuriStatusOk); - } - } - - static void notification_apply_settings(NotificationApp * app) { - if(!notification_load_settings(app)) { + switch(message.type) { + case NotificationLayerMessage: + notification_process_notification_message(app, &message); + break; + case InternalLayerMessage: + notification_process_internal_message(app, &message); + break; + case SaveSettingsMessage: notification_save_settings(app); + break; + case LoadSettingsMessage: + notification_load_settings(app); + break; } - notification_apply_lcd_contrast(app); - - // --- NIGHT SHIFT --- - // if night_shift enabled then start timer for controlling current_night_shift multiplicator value depent from current time - if(app->settings.night_shift != 1) { - night_shift_timer_start(app); - } - // --- NIGHT SHIFT END --- - - // check RECORD_GUI is exist (insurance on boot time) then use it to setup lcd inversion mode from loaded settings; - if(furi_record_exists(RECORD_GUI)) { - Gui* gui = furi_record_open(RECORD_GUI); - u8x8_d_st756x_set_inversion(&gui->canvas->fb.u8x8, app->settings.lcd_inversion); - furi_record_close(RECORD_GUI); + if(message.back_event != NULL) { + furi_event_flag_set(message.back_event, NOTIFICATION_EVENT_COMPLETE); } } - static void notification_init_settings(NotificationApp * app) { - Storage* storage = furi_record_open(RECORD_STORAGE); - furi_pubsub_subscribe(storage_get_pubsub(storage), notification_storage_callback, app); - - if(storage_sd_status(storage) != FSE_OK) { - FURI_LOG_D(TAG, "SD Card not ready, skipping settings"); - return; - } - - notification_apply_settings(app); - } - - // App - int32_t notification_srv(void* p) { - UNUSED(p); - NotificationApp* app = notification_app_alloc(); - - notification_init_settings(app); - - notification_vibro_off(); - notification_sound_off(); - notification_apply_internal_led_layer(&app->display, 0x00); - notification_apply_internal_led_layer(&app->led[0], 0x00); - notification_apply_internal_led_layer(&app->led[1], 0x00); - notification_apply_internal_led_layer(&app->led[2], 0x00); - - furi_record_create(RECORD_NOTIFICATION, app); - - // --- RGB BACKLIGHT SECTION --- - - //setup local variable - set_rgb_backlight_installed_variable(app->settings.rgb.rgb_backlight_installed); - - // define rainbow_timer and they callback - app->rainbow_timer = furi_timer_alloc(rainbow_timer_callback, FuriTimerTypePeriodic, app); - - // define night_shift_demo_timer and they callback. - // used for Setting menu to demonstrate night_shift_backlight when user change value - app->night_shift_demo_timer = - furi_timer_alloc(night_shift_demo_timer_callback, FuriTimerTypeOnce, app); - - // if rgb_backlight_installed then start rainbow or set leds colors from saved settings (default index = 0) - if(app->settings.rgb.rgb_backlight_installed) { - if(app->settings.rgb.rainbow_mode > 0) { - rainbow_timer_start(app); - } else { - rgb_backlight_set_led_static_color(2, app->settings.rgb.led_2_color_index); - rgb_backlight_set_led_static_color(1, app->settings.rgb.led_1_color_index); - rgb_backlight_set_led_static_color(0, app->settings.rgb.led_0_color_index); - rgb_backlight_update(app->settings.display_brightness * app->current_night_shift); - } - // if rgb_backlight not installed then set default static orange color(index=0) to all leds (0-2) and force light on - } else { - rgb_backlight_set_led_static_color(2, 0); - rgb_backlight_set_led_static_color(1, 0); - rgb_backlight_set_led_static_color(0, 0); - SK6805_update(); - } - - // --- RGB BACKLIGHT SECTION END --- - - NotificationAppMessage message; - while(1) { - furi_check( - furi_message_queue_get(app->queue, &message, FuriWaitForever) == FuriStatusOk); - - switch(message.type) { - case NotificationLayerMessage: - notification_process_notification_message(app, &message); - break; - case InternalLayerMessage: - notification_process_internal_message(app, &message); - break; - case SaveSettingsMessage: - notification_save_settings(app); - break; - case LoadSettingsMessage: - notification_load_settings(app); - break; - } - - if(message.back_event != NULL) { - furi_event_flag_set(message.back_event, NOTIFICATION_EVENT_COMPLETE); - } - } - - return 0; - } + return 0; +} diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 094027d89..111fbd481 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -39,7 +39,7 @@ typedef struct { Light light; } NotificationLedLayer; -#define NOTIFICATION_SETTINGS_VERSION 0x06 +#define NOTIFICATION_SETTINGS_VERSION 0x05 #define NOTIFICATION_SETTINGS_PATH INT_PATH(NOTIFICATION_SETTINGS_FILE_NAME) typedef struct { From f91e33daa6013a85fe21dd6127c0576f4910cb00 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 9 Feb 2026 17:27:30 +0300 Subject: [PATCH 111/160] fix typo [ci skip] --- lib/subghz/protocols/power_smart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/subghz/protocols/power_smart.c b/lib/subghz/protocols/power_smart.c index 78915d2b6..8acf714de 100644 --- a/lib/subghz/protocols/power_smart.c +++ b/lib/subghz/protocols/power_smart.c @@ -267,7 +267,7 @@ void subghz_protocol_decoder_power_smart_reset(void* context) { NULL); } -bool subghz_protocol_power_smart_chek_valid(uint64_t packet) { +bool subghz_protocol_power_smart_check_valid(uint64_t packet) { uint32_t data_1 = (uint32_t)((packet >> 40) & 0xFFFF); uint32_t data_2 = (uint32_t)((~packet >> 8) & 0xFFFF); uint8_t data_3 = (uint8_t)(packet >> 32) & 0xFF; @@ -311,7 +311,7 @@ void subghz_protocol_decoder_power_smart_feed( } if((instance->decoder.decode_data & POWER_SMART_PACKET_HEADER_MASK) == POWER_SMART_PACKET_HEADER) { - if(subghz_protocol_power_smart_chek_valid(instance->decoder.decode_data)) { + if(subghz_protocol_power_smart_check_valid(instance->decoder.decode_data)) { instance->generic.data = instance->decoder.decode_data; instance->generic.data_count_bit = subghz_protocol_power_smart_const.min_count_bit_for_found; From e242f489b0ce11b9649a4791498b6465de1a7415 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 10 Feb 2026 00:05:21 +0300 Subject: [PATCH 112/160] fmt --- applications/services/notification/notification_app.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 8a62f7ac9..408c9473b 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -761,7 +761,7 @@ static bool notification_load_settings(NotificationApp* app) { // "kostyl" for update old setting to new without change settings version if(app->settings.display_off_delay_ms < 2000) app->settings.display_off_delay_ms = 2000; - + return fs_result; } From 273aa1b807508657ddd20dcd778e79e49630fd47 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 10 Feb 2026 00:11:44 +0300 Subject: [PATCH 113/160] don't use much bits for 8bit values [ci skip] --- applications/main/subghz/helpers/subghz_txrx.c | 6 +++--- applications/main/subghz/helpers/subghz_txrx.h | 5 ++--- applications/main/subghz/subghz_i.h | 2 +- applications/main/subghz/subghz_last_settings.h | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index 46d0a7eef..1af603f40 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -109,10 +109,10 @@ void subghz_txrx_set_preset( } uint8_t* - subghz_txrx_set_tx_power(uint8_t* preset_data, size_t preset_data_size, uint32_t tx_power) { + subghz_txrx_set_tx_power(uint8_t* preset_data, size_t preset_data_size, uint8_t tx_power) { #define TX_POWER_OFFSET 7 #define TX_PRESET_POWER_COUNT 11 - const uint32_t tx_power_value[TX_PRESET_POWER_COUNT] = { + const uint8_t tx_power_value[TX_PRESET_POWER_COUNT] = { 0, 0xC0, 0xC5, @@ -708,7 +708,7 @@ const char* subghz_txrx_set_preset_internal( SubGhzTxRx* instance, uint32_t frequency, uint8_t index, - uint32_t tx_power) { + uint8_t tx_power) { furi_assert(instance); //Grab the prset name. diff --git a/applications/main/subghz/helpers/subghz_txrx.h b/applications/main/subghz/helpers/subghz_txrx.h index 259fddfc2..5d1cd8ee4 100644 --- a/applications/main/subghz/helpers/subghz_txrx.h +++ b/applications/main/subghz/helpers/subghz_txrx.h @@ -64,8 +64,7 @@ void subghz_txrx_set_preset( * @param preset_data_size Size of preset data * @param tx_power Menu Index of TX Power Setting. (Saves iterating in Config enter) */ -uint8_t* - subghz_txrx_set_tx_power(uint8_t* preset_data, size_t preset_data_size, uint32_t tx_power); +uint8_t* subghz_txrx_set_tx_power(uint8_t* preset_data, size_t preset_data_size, uint8_t tx_power); /** * Get name of preset @@ -377,4 +376,4 @@ const char* subghz_txrx_set_preset_internal( SubGhzTxRx* instance, uint32_t frequency, uint8_t index, - uint32_t tx_power); + uint8_t tx_power); diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 01f3ccf2f..578995157 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -93,7 +93,7 @@ struct SubGhz { uint16_t idx_menu_chosen; SubGhzLoadTypeFile load_type_file; - uint32_t tx_power; + uint8_t tx_power; void* rpc_ctx; }; diff --git a/applications/main/subghz/subghz_last_settings.h b/applications/main/subghz/subghz_last_settings.h index e42ee868d..fcd6e1c1b 100644 --- a/applications/main/subghz/subghz_last_settings.h +++ b/applications/main/subghz/subghz_last_settings.h @@ -26,7 +26,7 @@ typedef struct { bool delete_old_signals; float hopping_threshold; bool leds_and_amp; - uint32_t tx_power; + uint8_t tx_power; } SubGhzLastSettings; SubGhzLastSettings* subghz_last_settings_alloc(void); From e96b38da3665580580b7a30c97ea749a31704697 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 10 Feb 2026 00:21:44 +0300 Subject: [PATCH 114/160] fmt --- applications/main/subghz/scenes/subghz_scene_transmitter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index ed2f04389..273e72a03 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -38,6 +38,7 @@ bool subghz_scene_transmitter_update_data_show(void* context) { furi_string_get_cstr(frequency_str), furi_string_get_cstr(modulation_str), subghz_txrx_protocol_is_transmittable(subghz->txrx, false)); + ret = true; } furi_string_free(frequency_str); From 48db77f307c2b998a34e99317e7a8add0c9e7d18 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 10 Feb 2026 00:32:20 +0300 Subject: [PATCH 115/160] fix settings [ci skip] --- applications/main/subghz/subghz_last_settings.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/applications/main/subghz/subghz_last_settings.c b/applications/main/subghz/subghz_last_settings.c index a38f39026..d7b2b357e 100644 --- a/applications/main/subghz/subghz_last_settings.c +++ b/applications/main/subghz/subghz_last_settings.c @@ -120,10 +120,12 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count 1)) { flipper_format_rewind(fff_data_file); } + uint32_t tx_power = 0; if(!flipper_format_read_uint32( - fff_data_file, SUBGHZ_LAST_SETTING_FIELD_TX_POWER, &instance->tx_power, 1)) { + fff_data_file, SUBGHZ_LAST_SETTING_FIELD_TX_POWER, &tx_power, 1)) { flipper_format_rewind(fff_data_file); } + instance->tx_power = (uint8_t)(tx_power & 0xFF); if(!flipper_format_read_float( fff_data_file, SUBGHZ_LAST_SETTING_FIELD_HOPPING_THRESHOLD, @@ -227,8 +229,8 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) { file, SUBGHZ_LAST_SETTING_FIELD_DELETE_OLD, &instance->delete_old_signals, 1)) { break; } - if(!flipper_format_write_uint32( - file, SUBGHZ_LAST_SETTING_FIELD_TX_POWER, &instance->tx_power, 1)) { + uint32_t tx_power = instance->tx_power; + if(!flipper_format_write_uint32(file, SUBGHZ_LAST_SETTING_FIELD_TX_POWER, &tx_power, 1)) { break; } if(!flipper_format_write_float( From 9f9ceee1493f4c857735baf2034d590a4de60146 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 10 Feb 2026 01:37:42 +0300 Subject: [PATCH 116/160] fix storage settings scene exit via favs --- .../scenes/storage_settings_scene_benchmark.c | 20 +++++++++++++++---- ...storage_settings_scene_benchmark_confirm.c | 8 +++++++- .../storage_settings_scene_factory_reset.c | 8 +++++++- .../storage_settings_scene_format_confirm.c | 8 +++++++- .../storage_settings_scene_formatting.c | 10 ++++++++-- .../storage_settings_scene_internal_info.c | 8 +++++++- .../scenes/storage_settings_scene_sd_info.c | 8 +++++++- .../storage_settings_scene_unmount_confirm.c | 8 +++++++- .../scenes/storage_settings_scene_unmounted.c | 10 ++++++++-- .../storage_settings/storage_settings.c | 3 +++ .../storage_settings/storage_settings.h | 2 ++ 11 files changed, 79 insertions(+), 14 deletions(-) diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c index c07ab1ae6..b4f52b879 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c @@ -156,14 +156,26 @@ bool storage_settings_scene_benchmark_on_event(void* context, SceneManagerEvent if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { case DialogExResultCenter: - consumed = scene_manager_search_and_switch_to_previous_scene( - app->scene_manager, StorageSettingsStart); + if(app->from_favorites) { + storage_settings_scene_benchmark_on_exit(app); + view_dispatcher_stop(app->view_dispatcher); + return true; + } else { + consumed = scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, StorageSettingsStart); + } break; } } else if(event.type == SceneManagerEventTypeBack) { if(sd_status == FSE_OK) { - consumed = scene_manager_search_and_switch_to_previous_scene( - app->scene_manager, StorageSettingsStart); + if(app->from_favorites) { + storage_settings_scene_benchmark_on_exit(app); + view_dispatcher_stop(app->view_dispatcher); + return true; + } else { + consumed = scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, StorageSettingsStart); + } } else { consumed = true; } diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark_confirm.c b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark_confirm.c index 2f8644761..462aa4cee 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark_confirm.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark_confirm.c @@ -48,7 +48,13 @@ bool storage_settings_scene_benchmark_confirm_on_event(void* context, SceneManag switch(event.event) { case DialogExResultLeft: case DialogExResultCenter: - consumed = scene_manager_previous_scene(app->scene_manager); + if(app->from_favorites) { + storage_settings_scene_benchmark_confirm_on_exit(app); + view_dispatcher_stop(app->view_dispatcher); + return true; + } else { + consumed = scene_manager_previous_scene(app->scene_manager); + } break; case DialogExResultRight: scene_manager_next_scene(app->scene_manager, StorageSettingsBenchmark); diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_factory_reset.c b/applications/settings/storage_settings/scenes/storage_settings_scene_factory_reset.c index 0f8e1aa96..7fa925487 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_factory_reset.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_factory_reset.c @@ -44,7 +44,13 @@ bool storage_settings_scene_factory_reset_on_event(void* context, SceneManagerEv switch(event.event) { case DialogExResultLeft: scene_manager_set_scene_state(app->scene_manager, StorageSettingsFactoryReset, 0); - consumed = scene_manager_previous_scene(app->scene_manager); + if(app->from_favorites) { + storage_settings_scene_factory_reset_on_exit(app); + view_dispatcher_stop(app->view_dispatcher); + return true; + } else { + consumed = scene_manager_previous_scene(app->scene_manager); + } break; case DialogExResultRight: counter++; diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_format_confirm.c b/applications/settings/storage_settings/scenes/storage_settings_scene_format_confirm.c index 13b368d3f..2670f1495 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_format_confirm.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_format_confirm.c @@ -41,7 +41,13 @@ bool storage_settings_scene_format_confirm_on_event(void* context, SceneManagerE switch(event.event) { case DialogExResultLeft: case DialogExResultCenter: - consumed = scene_manager_previous_scene(app->scene_manager); + if(app->from_favorites) { + storage_settings_scene_format_confirm_on_exit(app); + view_dispatcher_stop(app->view_dispatcher); + return true; + } else { + consumed = scene_manager_previous_scene(app->scene_manager); + } break; case DialogExResultRight: scene_manager_next_scene(app->scene_manager, StorageSettingsFormatting); diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_formatting.c b/applications/settings/storage_settings/scenes/storage_settings_scene_formatting.c index 6a958610e..0ae18741e 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_formatting.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_formatting.c @@ -69,8 +69,14 @@ bool storage_settings_scene_formatting_on_event(void* context, SceneManagerEvent if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { case DialogExResultLeft: - consumed = scene_manager_search_and_switch_to_previous_scene( - app->scene_manager, StorageSettingsStart); + if(app->from_favorites) { + storage_settings_scene_formatting_on_exit(app); + view_dispatcher_stop(app->view_dispatcher); + return true; + } else { + consumed = scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, StorageSettingsStart); + } break; } } else if(event.type == SceneManagerEventTypeBack) { diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_internal_info.c b/applications/settings/storage_settings/scenes/storage_settings_scene_internal_info.c index 87a7ac655..e3e5ffe96 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_internal_info.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_internal_info.c @@ -56,7 +56,13 @@ bool storage_settings_scene_internal_info_on_event(void* context, SceneManagerEv if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { case DialogExResultLeft: - consumed = scene_manager_previous_scene(app->scene_manager); + if(app->from_favorites) { + storage_settings_scene_internal_info_on_exit(app); + view_dispatcher_stop(app->view_dispatcher); + return true; + } else { + consumed = scene_manager_previous_scene(app->scene_manager); + } break; } } diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c b/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c index cad3fbfaf..d168894b4 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c @@ -78,7 +78,13 @@ bool storage_settings_scene_sd_info_on_event(void* context, SceneManagerEvent ev switch(event.event) { case DialogExResultLeft: case DialogExResultCenter: - consumed = scene_manager_previous_scene(app->scene_manager); + if(app->from_favorites) { + storage_settings_scene_sd_info_on_exit(app); + view_dispatcher_stop(app->view_dispatcher); + return true; + } else { + consumed = scene_manager_previous_scene(app->scene_manager); + } break; case DialogExResultRight: scene_manager_next_scene(app->scene_manager, StorageSettingsUnmounted); diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_unmount_confirm.c b/applications/settings/storage_settings/scenes/storage_settings_scene_unmount_confirm.c index 1b9970f9f..65049c33f 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_unmount_confirm.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_unmount_confirm.c @@ -46,7 +46,13 @@ bool storage_settings_scene_unmount_confirm_on_event(void* context, SceneManager switch(event.event) { case DialogExResultCenter: case DialogExResultLeft: - consumed = scene_manager_previous_scene(app->scene_manager); + if(app->from_favorites) { + storage_settings_scene_unmount_confirm_on_exit(app); + view_dispatcher_stop(app->view_dispatcher); + return true; + } else { + consumed = scene_manager_previous_scene(app->scene_manager); + } break; case DialogExResultRight: scene_manager_next_scene(app->scene_manager, StorageSettingsUnmounted); diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_unmounted.c b/applications/settings/storage_settings/scenes/storage_settings_scene_unmounted.c index 86398b1c9..5b64adb63 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_unmounted.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_unmounted.c @@ -57,8 +57,14 @@ bool storage_settings_scene_unmounted_on_event(void* context, SceneManagerEvent if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { case DialogExResultCenter: - consumed = scene_manager_search_and_switch_to_previous_scene( - app->scene_manager, StorageSettingsStart); + if(app->from_favorites) { + storage_settings_scene_unmounted_on_exit(app); + view_dispatcher_stop(app->view_dispatcher); + return true; + } else { + consumed = scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, StorageSettingsStart); + } break; } } else if(event.type == SceneManagerEventTypeBack) { diff --git a/applications/settings/storage_settings/storage_settings.c b/applications/settings/storage_settings/storage_settings.c index 07656431c..570ca3411 100644 --- a/applications/settings/storage_settings/storage_settings.c +++ b/applications/settings/storage_settings/storage_settings.c @@ -98,7 +98,10 @@ int32_t storage_settings_app(void* p) { StorageSettings* app = storage_settings_alloc(); if(!submenu_settings_helpers_app_start(app->settings_helper, p)) { + app->from_favorites = false; scene_manager_next_scene(app->scene_manager, StorageSettingsStart); + } else { + app->from_favorites = true; } view_dispatcher_run(app->view_dispatcher); diff --git a/applications/settings/storage_settings/storage_settings.h b/applications/settings/storage_settings/storage_settings.h index 5f4c6404e..a0f7a81b4 100644 --- a/applications/settings/storage_settings/storage_settings.h +++ b/applications/settings/storage_settings/storage_settings.h @@ -44,6 +44,8 @@ typedef struct { // helpers SubmenuSettingsHelperDescriptor* helper_descriptor; SubmenuSettingsHelper* settings_helper; + + bool from_favorites; } StorageSettings; typedef enum { From 422f3a576d924bc8e06bcd114123739a4ef10aed Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 10 Feb 2026 01:37:50 +0300 Subject: [PATCH 117/160] upd changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1272d88d..9fb479013 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,12 +19,15 @@ * SubGHz: KeeLoq **display BFT programming mode TX** (when arrow button is held) * SubGHz: KeeLoq **add counter mode 7 (sends 7 signals increasing counter with 0x3333 steps)** - may bypass counter on some receivers! * SubGHz: Add signals button editor and real **remote simulation** (full signal transmit with just one click) (PR #956 #958 | by @Dmitry422) +* SubGHz: TX Power setting (PR #960 | by @LeeroysHub) * JS: feat: add IR capabilities to the JS engine (PR #957 | by @LuisMayo) * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * NFC: Fixes to `READ_MULTI` and `GET_BLOCK_SECURITY` commands in ISO 15693-3 emulation (by @WillyJL & @aaronjamt) * Archive: Allow folders to be pinned (by @WillyJL) * Apps: Build tag (**3feb2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes +* Settings: Storage settings exit scenes properly if used via favourites (fixes issue #951) +* LCD: Backlight settings bug fix (PR #962 | by @Dmitry422) * UI: Various small changes * Desktop: Disable winter holidays anims * OFW PR 4333: NFC: Fix sending 32+ byte ISO 15693-3 commands (by @WillyJL) From aec6045392fc1c55fc70754777d7dfc855406b6a Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 10 Feb 2026 01:38:11 +0300 Subject: [PATCH 118/160] upd changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fb479013..6184d09f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ ## Main changes -- Current API: 87.5 +- Current API: 87.6 * SubGHz: **Cardin S449 protocol full support** (64bit keeloq) (with Add manually, and all button codes) (**use FSK12K modulation to read the remote**) (closes issues #735 #908) (by @xMasterX and @zero-mega (thanks!)) * SubGHz: **Beninca ARC AES128 protocol full support** (128bit dynamic) (with Add manually, and 3 button codes) (resolves issue #596) (by @xMasterX and @zero-mega) * SubGHz: **Treadmill37 protocol support** (37bit static) (by @xMasterX) From a6ca43e8775351781695a9edb004d580192af200 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 10 Feb 2026 03:11:50 +0300 Subject: [PATCH 119/160] upd changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6184d09f1..0bf9ac068 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,7 @@ * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * NFC: Fixes to `READ_MULTI` and `GET_BLOCK_SECURITY` commands in ISO 15693-3 emulation (by @WillyJL & @aaronjamt) * Archive: Allow folders to be pinned (by @WillyJL) -* Apps: Build tag (**3feb2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) +* Apps: Build tag (**10feb2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes * Settings: Storage settings exit scenes properly if used via favourites (fixes issue #951) * LCD: Backlight settings bug fix (PR #962 | by @Dmitry422) From bc6b0d199ecf402d25f83ebc02e62403571aa368 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 12 Feb 2026 04:25:06 +0300 Subject: [PATCH 120/160] storage settings use scene manager for exit --- .../scenes/storage_settings_scene_benchmark.c | 4 ++-- .../scenes/storage_settings_scene_benchmark_confirm.c | 2 +- .../scenes/storage_settings_scene_factory_reset.c | 2 +- .../scenes/storage_settings_scene_format_confirm.c | 2 +- .../scenes/storage_settings_scene_formatting.c | 2 +- .../scenes/storage_settings_scene_internal_info.c | 2 +- .../storage_settings/scenes/storage_settings_scene_sd_info.c | 2 +- .../scenes/storage_settings_scene_unmount_confirm.c | 2 +- .../scenes/storage_settings_scene_unmounted.c | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c index b4f52b879..a4a12caa1 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c @@ -157,7 +157,7 @@ bool storage_settings_scene_benchmark_on_event(void* context, SceneManagerEvent switch(event.event) { case DialogExResultCenter: if(app->from_favorites) { - storage_settings_scene_benchmark_on_exit(app); + scene_manager_stop(app->scene_manager); view_dispatcher_stop(app->view_dispatcher); return true; } else { @@ -169,7 +169,7 @@ bool storage_settings_scene_benchmark_on_event(void* context, SceneManagerEvent } else if(event.type == SceneManagerEventTypeBack) { if(sd_status == FSE_OK) { if(app->from_favorites) { - storage_settings_scene_benchmark_on_exit(app); + scene_manager_stop(app->scene_manager); view_dispatcher_stop(app->view_dispatcher); return true; } else { diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark_confirm.c b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark_confirm.c index 462aa4cee..db63ba631 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark_confirm.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark_confirm.c @@ -49,7 +49,7 @@ bool storage_settings_scene_benchmark_confirm_on_event(void* context, SceneManag case DialogExResultLeft: case DialogExResultCenter: if(app->from_favorites) { - storage_settings_scene_benchmark_confirm_on_exit(app); + scene_manager_stop(app->scene_manager); view_dispatcher_stop(app->view_dispatcher); return true; } else { diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_factory_reset.c b/applications/settings/storage_settings/scenes/storage_settings_scene_factory_reset.c index 7fa925487..53afaf634 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_factory_reset.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_factory_reset.c @@ -45,7 +45,7 @@ bool storage_settings_scene_factory_reset_on_event(void* context, SceneManagerEv case DialogExResultLeft: scene_manager_set_scene_state(app->scene_manager, StorageSettingsFactoryReset, 0); if(app->from_favorites) { - storage_settings_scene_factory_reset_on_exit(app); + scene_manager_stop(app->scene_manager); view_dispatcher_stop(app->view_dispatcher); return true; } else { diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_format_confirm.c b/applications/settings/storage_settings/scenes/storage_settings_scene_format_confirm.c index 2670f1495..550f9be10 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_format_confirm.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_format_confirm.c @@ -42,7 +42,7 @@ bool storage_settings_scene_format_confirm_on_event(void* context, SceneManagerE case DialogExResultLeft: case DialogExResultCenter: if(app->from_favorites) { - storage_settings_scene_format_confirm_on_exit(app); + scene_manager_stop(app->scene_manager); view_dispatcher_stop(app->view_dispatcher); return true; } else { diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_formatting.c b/applications/settings/storage_settings/scenes/storage_settings_scene_formatting.c index 0ae18741e..85b1450c7 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_formatting.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_formatting.c @@ -70,7 +70,7 @@ bool storage_settings_scene_formatting_on_event(void* context, SceneManagerEvent switch(event.event) { case DialogExResultLeft: if(app->from_favorites) { - storage_settings_scene_formatting_on_exit(app); + scene_manager_stop(app->scene_manager); view_dispatcher_stop(app->view_dispatcher); return true; } else { diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_internal_info.c b/applications/settings/storage_settings/scenes/storage_settings_scene_internal_info.c index e3e5ffe96..b7e332e47 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_internal_info.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_internal_info.c @@ -57,7 +57,7 @@ bool storage_settings_scene_internal_info_on_event(void* context, SceneManagerEv switch(event.event) { case DialogExResultLeft: if(app->from_favorites) { - storage_settings_scene_internal_info_on_exit(app); + scene_manager_stop(app->scene_manager); view_dispatcher_stop(app->view_dispatcher); return true; } else { diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c b/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c index d168894b4..d47d43447 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c @@ -79,7 +79,7 @@ bool storage_settings_scene_sd_info_on_event(void* context, SceneManagerEvent ev case DialogExResultLeft: case DialogExResultCenter: if(app->from_favorites) { - storage_settings_scene_sd_info_on_exit(app); + scene_manager_stop(app->scene_manager); view_dispatcher_stop(app->view_dispatcher); return true; } else { diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_unmount_confirm.c b/applications/settings/storage_settings/scenes/storage_settings_scene_unmount_confirm.c index 65049c33f..e9acb7b4b 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_unmount_confirm.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_unmount_confirm.c @@ -47,7 +47,7 @@ bool storage_settings_scene_unmount_confirm_on_event(void* context, SceneManager case DialogExResultCenter: case DialogExResultLeft: if(app->from_favorites) { - storage_settings_scene_unmount_confirm_on_exit(app); + scene_manager_stop(app->scene_manager); view_dispatcher_stop(app->view_dispatcher); return true; } else { diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_unmounted.c b/applications/settings/storage_settings/scenes/storage_settings_scene_unmounted.c index 5b64adb63..6a3d98604 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_unmounted.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_unmounted.c @@ -58,7 +58,7 @@ bool storage_settings_scene_unmounted_on_event(void* context, SceneManagerEvent switch(event.event) { case DialogExResultCenter: if(app->from_favorites) { - storage_settings_scene_unmounted_on_exit(app); + scene_manager_stop(app->scene_manager); view_dispatcher_stop(app->view_dispatcher); return true; } else { From 14269286eb6eaa66b53d41ebfe02265bc6fb7c71 Mon Sep 17 00:00:00 2001 From: Leeroy <135471162+LeeroysHub@users.noreply.github.com> Date: Thu, 12 Feb 2026 18:04:53 +1100 Subject: [PATCH 121/160] TX Power: Use correct Offset and Values for FM PA table. --- .../main/subghz/helpers/subghz_txrx.c | 50 +++++++++++++------ .../scenes/subghz_scene_radio_settings.c | 6 +-- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index 46d0a7eef..93f197399 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -110,25 +110,45 @@ void subghz_txrx_set_preset( uint8_t* subghz_txrx_set_tx_power(uint8_t* preset_data, size_t preset_data_size, uint32_t tx_power) { -#define TX_POWER_OFFSET 7 -#define TX_PRESET_POWER_COUNT 11 - const uint32_t tx_power_value[TX_PRESET_POWER_COUNT] = { +#define TX_POWER_OFFSET_FM 8 +#define TX_POWER_OFFSET_AM 7 +#define TX_PRESET_POWER_COUNT 9 + //I had to skip the +10dBM and -6dBm Values, use only ones AM/FM have in common. + //Highest Value is 12dBm for AM, 10 for FM. So Menu needs to reflect that. + const uint8_t tx_power_value_AM[TX_PRESET_POWER_COUNT] = { 0, - 0xC0, - 0xC5, - 0xCD, - 0x86, - 0x50, - 0x37, - 0x26, - 0x1D, - 0x17, - 0x03, + 0xC0, //12dBm + 0xCD, //7dBm + 0x86, //5dBm + 0x50, //0dBm + 0x26, // -10dBm + 0x1D, // -15dBm + 0x17, //-20dBm + 0x03 //-30dBm + }; + + //FM PATable Values. We have 8, not 10 (missing 12dBM and -6dBm that are in AM) + const uint8_t tx_power_value_FM[TX_PRESET_POWER_COUNT] = { + 0, + 0xC0, // 10dBm + 0xC8, //7dBm + 0x84, //5dBm + 0x60, //0dBm + 0x34, //-10dBm + 0x1D, //-15dBm + 0x0E, // -20dBm + 0x12, //-30dBm }; //Set the TX Power Here in the CC1101 register... - if(tx_power) - preset_data[preset_data_size - TX_POWER_OFFSET] = (uint8_t)tx_power_value[tx_power]; + if(tx_power) { + //Are we on an AM or FM preset? The PA table is different! + if(preset_data[preset_data_size - TX_POWER_OFFSET_FM]) { + preset_data[preset_data_size - TX_POWER_OFFSET_FM] = tx_power_value_FM[tx_power]; + } else if(preset_data[preset_data_size - TX_POWER_OFFSET_AM]) { + preset_data[preset_data_size - TX_POWER_OFFSET_AM] = tx_power_value_AM[tx_power]; + } //else //Must be a custom Preset with weird PA table not in FW code, dont touch it. + } //Pass back the preset_so we can call one liners. return preset_data; diff --git a/applications/main/subghz/scenes/subghz_scene_radio_settings.c b/applications/main/subghz/scenes/subghz_scene_radio_settings.c index 87e2d8269..be75723be 100644 --- a/applications/main/subghz/scenes/subghz_scene_radio_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_radio_settings.c @@ -67,15 +67,13 @@ const int32_t debug_counter_val[DEBUG_COUNTER_COUNT] = { }; //TX Power -#define TX_POWER_COUNT 11 +#define TX_POWER_COUNT 9 const char* const tx_power_text[TX_POWER_COUNT] = { "Preset", - "12dBm", - "10dBm", + "10dBm +", "7dBm", "5dBm", "0dBm", - "-6dBm", "-10dBm", "-15dBm", "-20dBm", From 808774c05f83c14ccfc1469fcc17f5ba966f0c7f Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Thu, 12 Feb 2026 16:55:19 +0700 Subject: [PATCH 122/160] BT on/off to desktop_lock_menu --- applications/services/bt/bt_service/bt_api.c | 3 +-- applications/services/bt/bt_service/bt_api.h | 5 +++++ .../desktop/scenes/desktop_scene_lock_menu.c | 21 +++++++++++++++---- .../services/desktop/views/desktop_events.h | 3 ++- .../desktop/views/desktop_view_lock_menu.c | 17 ++++++++++----- 5 files changed, 37 insertions(+), 12 deletions(-) create mode 100644 applications/services/bt/bt_service/bt_api.h diff --git a/applications/services/bt/bt_service/bt_api.c b/applications/services/bt/bt_service/bt_api.c index 39b9a099d..8b42d7920 100644 --- a/applications/services/bt/bt_service/bt_api.c +++ b/applications/services/bt/bt_service/bt_api.c @@ -1,5 +1,4 @@ -#include "bt_i.h" -#include +#include "bt_api.h" FuriHalBleProfileBase* bt_profile_start( Bt* bt, diff --git a/applications/services/bt/bt_service/bt_api.h b/applications/services/bt/bt_service/bt_api.h new file mode 100644 index 000000000..5120ccc7f --- /dev/null +++ b/applications/services/bt/bt_service/bt_api.h @@ -0,0 +1,5 @@ +#pragma once +#include "bt_i.h" +#include + +extern void bt_set_settings(Bt* bt, const BtSettings* settings); \ No newline at end of file diff --git a/applications/services/desktop/scenes/desktop_scene_lock_menu.c b/applications/services/desktop/scenes/desktop_scene_lock_menu.c index 5ca95c4c5..b74ca7f48 100644 --- a/applications/services/desktop/scenes/desktop_scene_lock_menu.c +++ b/applications/services/desktop/scenes/desktop_scene_lock_menu.c @@ -10,6 +10,8 @@ #include "../views/desktop_view_lock_menu.h" #include "desktop_scene.h" +#include "applications/services/bt/bt_service/bt_api.h" + #define TAG "DesktopSceneLock" void desktop_scene_lock_menu_callback(DesktopEvent event, void* context) { @@ -34,6 +36,9 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { Desktop* desktop = (Desktop*)context; bool consumed = false; + Bt* bt = furi_record_open(RECORD_BT); + BtSettings bts = bt->bt_settings; + if(event.type == SceneManagerEventTypeTick) { bool check_pin_changed = scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLockMenu); @@ -42,10 +47,17 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { } } else if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { - case DesktopLockMenuEventLock: - scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); - desktop_lock(desktop); - consumed = true; + // old use case + // case DesktopLockMenuEventLock: + // scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); + // desktop_lock(desktop); + // consumed = true; + // break; + case DesktopLockMenuEventBt: + bts.enabled = !bts.enabled; + bt_set_settings(bt, &bts); + scene_manager_search_and_switch_to_previous_scene( + desktop->scene_manager, DesktopSceneMain); break; case DesktopLockMenuEventDummyModeOn: desktop_set_dummy_mode_state(desktop, true); @@ -78,4 +90,5 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { void desktop_scene_lock_menu_on_exit(void* context) { UNUSED(context); + furi_record_close(RECORD_BT); } diff --git a/applications/services/desktop/views/desktop_events.h b/applications/services/desktop/views/desktop_events.h index b89ef5158..724761d48 100644 --- a/applications/services/desktop/views/desktop_events.h +++ b/applications/services/desktop/views/desktop_events.h @@ -37,7 +37,8 @@ typedef enum { DesktopDebugEventToggleDebugMode, DesktopDebugEventExit, - DesktopLockMenuEventLock, + //DesktopLockMenuEventLock, + DesktopLockMenuEventBt, DesktopLockMenuEventDummyModeOn, DesktopLockMenuEventDummyModeOff, DesktopLockMenuEventStealthModeOn, diff --git a/applications/services/desktop/views/desktop_view_lock_menu.c b/applications/services/desktop/views/desktop_view_lock_menu.c index 1b6bdab9c..fefb7b1bd 100644 --- a/applications/services/desktop/views/desktop_view_lock_menu.c +++ b/applications/services/desktop/views/desktop_view_lock_menu.c @@ -6,7 +6,8 @@ #include "desktop_view_lock_menu.h" typedef enum { - DesktopLockMenuIndexLock, + //DesktopLockMenuIndexLock, + DesktopLockMenuIndexBt, DesktopLockMenuIndexStealth, DesktopLockMenuIndexDummy, @@ -56,8 +57,9 @@ void desktop_lock_menu_draw_callback(Canvas* canvas, void* model) { for(size_t i = 0; i < DesktopLockMenuIndexTotalCount; ++i) { const char* str = NULL; - if(i == DesktopLockMenuIndexLock) { - str = "Lock"; + //if(i == DesktopLockMenuIndexLock) { + if(i == DesktopLockMenuIndexBt) { + str = "Bluetooth On/Off"; } else if(i == DesktopLockMenuIndexStealth) { if(m->stealth_mode) { str = "Unmute"; @@ -126,10 +128,15 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) { update); if(event->key == InputKeyOk) { - if(idx == DesktopLockMenuIndexLock) { + if(idx == DesktopLockMenuIndexBt) { if(event->type == InputTypeShort) { - lock_menu->callback(DesktopLockMenuEventLock, lock_menu->context); + lock_menu->callback(DesktopLockMenuEventBt, lock_menu->context); } + // old use case + // } else if(idx == DesktopLockMenuIndexLock) { + // if(event->type == InputTypeShort) { + // lock_menu->callback(DesktopLockMenuEventLock, lock_menu->context); + // } } else if(idx == DesktopLockMenuIndexStealth) { if((stealth_mode == false) && (event->type == InputTypeShort)) { lock_menu->callback(DesktopLockMenuEventStealthModeOn, lock_menu->context); From a98c610f6dcee25eed7c53800672485d8e9f788b Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Thu, 12 Feb 2026 17:27:28 +0700 Subject: [PATCH 123/160] BT string in desktop_lock_menu naming depent from BT ON|OFF --- .../desktop/scenes/desktop_scene_lock_menu.c | 1 + .../desktop/views/desktop_view_lock_menu.c | 14 +++++++++++++- .../desktop/views/desktop_view_lock_menu.h | 2 ++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/applications/services/desktop/scenes/desktop_scene_lock_menu.c b/applications/services/desktop/scenes/desktop_scene_lock_menu.c index b74ca7f48..369dcc0ef 100644 --- a/applications/services/desktop/scenes/desktop_scene_lock_menu.c +++ b/applications/services/desktop/scenes/desktop_scene_lock_menu.c @@ -27,6 +27,7 @@ void desktop_scene_lock_menu_on_enter(void* context) { desktop_lock_menu_set_dummy_mode_state(desktop->lock_menu, desktop->settings.dummy_mode); desktop_lock_menu_set_stealth_mode_state( desktop->lock_menu, furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)); + desktop_lock_menu_set_bt_mode_state(desktop->lock_menu, furi_hal_bt_is_active()); desktop_lock_menu_set_idx(desktop->lock_menu, 0); view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdLockMenu); diff --git a/applications/services/desktop/views/desktop_view_lock_menu.c b/applications/services/desktop/views/desktop_view_lock_menu.c index fefb7b1bd..975db7749 100644 --- a/applications/services/desktop/views/desktop_view_lock_menu.c +++ b/applications/services/desktop/views/desktop_view_lock_menu.c @@ -40,6 +40,14 @@ void desktop_lock_menu_set_stealth_mode_state(DesktopLockMenuView* lock_menu, bo true); } +void desktop_lock_menu_set_bt_mode_state(DesktopLockMenuView* lock_menu, bool bt_mode) { + with_view_model( + lock_menu->view, + DesktopLockMenuViewModel * model, + { model->bt_mode = bt_mode; }, + true); +} + void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx) { furi_assert(idx < DesktopLockMenuIndexTotalCount); with_view_model( @@ -59,7 +67,11 @@ void desktop_lock_menu_draw_callback(Canvas* canvas, void* model) { //if(i == DesktopLockMenuIndexLock) { if(i == DesktopLockMenuIndexBt) { - str = "Bluetooth On/Off"; + if(m->bt_mode) { + str = "Bluetooth OFF"; + } else { + str = "Bluetooth ON"; + } } else if(i == DesktopLockMenuIndexStealth) { if(m->stealth_mode) { str = "Unmute"; diff --git a/applications/services/desktop/views/desktop_view_lock_menu.h b/applications/services/desktop/views/desktop_view_lock_menu.h index a44e6b132..b2db7efb2 100644 --- a/applications/services/desktop/views/desktop_view_lock_menu.h +++ b/applications/services/desktop/views/desktop_view_lock_menu.h @@ -19,6 +19,7 @@ typedef struct { uint8_t idx; bool dummy_mode; bool stealth_mode; + bool bt_mode; } DesktopLockMenuViewModel; void desktop_lock_menu_set_callback( @@ -29,6 +30,7 @@ void desktop_lock_menu_set_callback( View* desktop_lock_menu_get_view(DesktopLockMenuView* lock_menu); void desktop_lock_menu_set_dummy_mode_state(DesktopLockMenuView* lock_menu, bool dummy_mode); void desktop_lock_menu_set_stealth_mode_state(DesktopLockMenuView* lock_menu, bool stealth_mode); +void desktop_lock_menu_set_bt_mode_state(DesktopLockMenuView* lock_menu, bool bt_mode); void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx); DesktopLockMenuView* desktop_lock_menu_alloc(void); void desktop_lock_menu_free(DesktopLockMenuView* lock_menu); From c6421c9fff228f8ea5ca714cc9d48449f092e5fa Mon Sep 17 00:00:00 2001 From: Leeroy <135471162+LeeroysHub@users.noreply.github.com> Date: Thu, 12 Feb 2026 21:42:03 +1100 Subject: [PATCH 124/160] REFACTOR: Tx power fixes (Use 1 array, dont play with Weird Custom Presets) --- .../main/subghz/helpers/subghz_txrx.c | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index 93f197399..4c2765196 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -110,12 +110,14 @@ void subghz_txrx_set_preset( uint8_t* subghz_txrx_set_tx_power(uint8_t* preset_data, size_t preset_data_size, uint32_t tx_power) { -#define TX_POWER_OFFSET_FM 8 -#define TX_POWER_OFFSET_AM 7 -#define TX_PRESET_POWER_COUNT 9 +#define PRESET_POWER_OFFSET_FM 8 +#define PRESET_POWER_OFFSET_AM 7 +#define TX_PATABLE_OFFSET_AM 8 +#define TX_PATABLE_COUNT 17 + //I had to skip the +10dBM and -6dBm Values, use only ones AM/FM have in common. //Highest Value is 12dBm for AM, 10 for FM. So Menu needs to reflect that. - const uint8_t tx_power_value_AM[TX_PRESET_POWER_COUNT] = { + const uint8_t tx_pa_table[TX_PATABLE_COUNT] = { 0, 0xC0, //12dBm 0xCD, //7dBm @@ -124,12 +126,7 @@ uint8_t* 0x26, // -10dBm 0x1D, // -15dBm 0x17, //-20dBm - 0x03 //-30dBm - }; - - //FM PATable Values. We have 8, not 10 (missing 12dBM and -6dBm that are in AM) - const uint8_t tx_power_value_FM[TX_PRESET_POWER_COUNT] = { - 0, + 0x03, //-30dBm 0xC0, // 10dBm 0xC8, //7dBm 0x84, //5dBm @@ -142,12 +139,19 @@ uint8_t* //Set the TX Power Here in the CC1101 register... if(tx_power) { - //Are we on an AM or FM preset? The PA table is different! - if(preset_data[preset_data_size - TX_POWER_OFFSET_FM]) { - preset_data[preset_data_size - TX_POWER_OFFSET_FM] = tx_power_value_FM[tx_power]; - } else if(preset_data[preset_data_size - TX_POWER_OFFSET_AM]) { - preset_data[preset_data_size - TX_POWER_OFFSET_AM] = tx_power_value_AM[tx_power]; - } //else //Must be a custom Preset with weird PA table not in FW code, dont touch it. + //Grab the AM and FM byte now, so we can do proper checks. + uint8_t fm_byte = preset_data[preset_data_size - PRESET_POWER_OFFSET_FM]; + uint8_t am_byte = preset_data[preset_data_size - PRESET_POWER_OFFSET_AM]; + + //If we have both bytes 1st bytes set or none, this isnt a preset we can deal with here. + if(fm_byte & !am_byte) { + //Use FM Table + preset_data[preset_data_size - PRESET_POWER_OFFSET_FM] = tx_pa_table[tx_power]; + } else if(am_byte & !fm_byte) { + //Use AM Table + preset_data[preset_data_size - PRESET_POWER_OFFSET_AM] = + tx_pa_table[TX_PATABLE_OFFSET_AM + tx_power]; + } } //Pass back the preset_so we can call one liners. From ab8261e1404bf8dee92cdb6c7c42dff33a90e1bf Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 12 Feb 2026 18:34:37 +0300 Subject: [PATCH 125/160] power exit into settings [ci skip] --- .../scenes/power_settings_scene_power_off.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/applications/settings/power_settings_app/scenes/power_settings_scene_power_off.c b/applications/settings/power_settings_app/scenes/power_settings_scene_power_off.c index 6328a2381..073116ae5 100644 --- a/applications/settings/power_settings_app/scenes/power_settings_scene_power_off.c +++ b/applications/settings/power_settings_app/scenes/power_settings_scene_power_off.c @@ -27,7 +27,7 @@ void power_settings_scene_power_off_on_enter(void* context) { dialog, " I will be\nwaiting for\n you here...", 78, 14, AlignLeft, AlignTop); dialog_ex_set_icon(dialog, 14, 10, &I_dolph_cry_49x54); } - dialog_ex_set_left_button_text(dialog, "Cancel"); + dialog_ex_set_left_button_text(dialog, "Settings"); dialog_ex_set_right_button_text(dialog, "Power Off"); dialog_ex_set_result_callback(dialog, power_settings_scene_power_off_dialog_callback); dialog_ex_set_context(dialog, app); @@ -42,8 +42,7 @@ bool power_settings_scene_power_off_on_event(void* context, SceneManagerEvent ev if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultLeft) { if(!scene_manager_previous_scene(app->scene_manager)) { - scene_manager_stop(app->scene_manager); - view_dispatcher_stop(app->view_dispatcher); + scene_manager_next_scene(app->scene_manager, PowerSettingsAppSceneStart); } } else if(event.event == DialogExResultRight) { power_off(app->power); From 3f0f90e0a376db8123a827a9c6f07134b59380c9 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 12 Feb 2026 18:50:03 +0300 Subject: [PATCH 126/160] formatting, text fixes --- applications/services/bt/bt_service/bt_api.c | 2 +- applications/services/bt/bt_service/bt_api.h | 2 +- .../desktop/views/desktop_view_lock_menu.c | 19 ++++++++----------- .../scenes/power_settings_scene_power_off.c | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/applications/services/bt/bt_service/bt_api.c b/applications/services/bt/bt_service/bt_api.c index 8b42d7920..861569d71 100644 --- a/applications/services/bt/bt_service/bt_api.c +++ b/applications/services/bt/bt_service/bt_api.c @@ -1,4 +1,4 @@ -#include "bt_api.h" +#include "bt_api.h" FuriHalBleProfileBase* bt_profile_start( Bt* bt, diff --git a/applications/services/bt/bt_service/bt_api.h b/applications/services/bt/bt_service/bt_api.h index 5120ccc7f..24801d13b 100644 --- a/applications/services/bt/bt_service/bt_api.h +++ b/applications/services/bt/bt_service/bt_api.h @@ -2,4 +2,4 @@ #include "bt_i.h" #include -extern void bt_set_settings(Bt* bt, const BtSettings* settings); \ No newline at end of file +extern void bt_set_settings(Bt* bt, const BtSettings* settings); diff --git a/applications/services/desktop/views/desktop_view_lock_menu.c b/applications/services/desktop/views/desktop_view_lock_menu.c index 975db7749..995a47f95 100644 --- a/applications/services/desktop/views/desktop_view_lock_menu.c +++ b/applications/services/desktop/views/desktop_view_lock_menu.c @@ -42,10 +42,7 @@ void desktop_lock_menu_set_stealth_mode_state(DesktopLockMenuView* lock_menu, bo void desktop_lock_menu_set_bt_mode_state(DesktopLockMenuView* lock_menu, bool bt_mode) { with_view_model( - lock_menu->view, - DesktopLockMenuViewModel * model, - { model->bt_mode = bt_mode; }, - true); + lock_menu->view, DesktopLockMenuViewModel * model, { model->bt_mode = bt_mode; }, true); } void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx) { @@ -68,9 +65,9 @@ void desktop_lock_menu_draw_callback(Canvas* canvas, void* model) { //if(i == DesktopLockMenuIndexLock) { if(i == DesktopLockMenuIndexBt) { if(m->bt_mode) { - str = "Bluetooth OFF"; + str = "Bluetooth Off"; } else { - str = "Bluetooth ON"; + str = "Bluetooth On"; } } else if(i == DesktopLockMenuIndexStealth) { if(m->stealth_mode) { @@ -144,11 +141,11 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) { if(event->type == InputTypeShort) { lock_menu->callback(DesktopLockMenuEventBt, lock_menu->context); } - // old use case - // } else if(idx == DesktopLockMenuIndexLock) { - // if(event->type == InputTypeShort) { - // lock_menu->callback(DesktopLockMenuEventLock, lock_menu->context); - // } + // old use case + // } else if(idx == DesktopLockMenuIndexLock) { + // if(event->type == InputTypeShort) { + // lock_menu->callback(DesktopLockMenuEventLock, lock_menu->context); + // } } else if(idx == DesktopLockMenuIndexStealth) { if((stealth_mode == false) && (event->type == InputTypeShort)) { lock_menu->callback(DesktopLockMenuEventStealthModeOn, lock_menu->context); diff --git a/applications/settings/power_settings_app/scenes/power_settings_scene_power_off.c b/applications/settings/power_settings_app/scenes/power_settings_scene_power_off.c index 073116ae5..b89c2d0b8 100644 --- a/applications/settings/power_settings_app/scenes/power_settings_scene_power_off.c +++ b/applications/settings/power_settings_app/scenes/power_settings_scene_power_off.c @@ -25,7 +25,7 @@ void power_settings_scene_power_off_on_enter(void* context) { if(!settings.happy_mode) { dialog_ex_set_text( dialog, " I will be\nwaiting for\n you here...", 78, 14, AlignLeft, AlignTop); - dialog_ex_set_icon(dialog, 14, 10, &I_dolph_cry_49x54); + dialog_ex_set_icon(dialog, 24, 10, &I_dolph_cry_49x54); } dialog_ex_set_left_button_text(dialog, "Settings"); dialog_ex_set_right_button_text(dialog, "Power Off"); From 9eb8e475ccb46aa28e193d25a325401bf5b0d68c Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 12 Feb 2026 20:24:32 +0300 Subject: [PATCH 127/160] fix switching, etc. --- .../main/subghz/helpers/subghz_txrx.c | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index cf066acbf..9e972ad40 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -109,7 +109,7 @@ void subghz_txrx_set_preset( } uint8_t* - subghz_txrx_set_tx_power(uint8_t* preset_data, size_t preset_data_size, uint32_t tx_power) { + subghz_txrx_set_tx_power(uint8_t* preset_data, size_t preset_data_size, uint8_t tx_power) { #define PRESET_POWER_OFFSET_FM 8 #define PRESET_POWER_OFFSET_AM 7 #define TX_PATABLE_OFFSET_AM 8 @@ -137,20 +137,29 @@ uint8_t* 0x12, //-30dBm }; - //Set the TX Power Here in the CC1101 register... - if(tx_power) { - //Grab the AM and FM byte now, so we can do proper checks. - uint8_t fm_byte = preset_data[preset_data_size - PRESET_POWER_OFFSET_FM]; - uint8_t am_byte = preset_data[preset_data_size - PRESET_POWER_OFFSET_AM]; + //Grab the AM and FM byte now, so we can do proper checks. + uint8_t fm_byte = preset_data[preset_data_size - PRESET_POWER_OFFSET_FM]; + uint8_t am_byte = preset_data[preset_data_size - PRESET_POWER_OFFSET_AM]; - //If we have both bytes 1st bytes set or none, this isnt a preset we can deal with here. - if(fm_byte & !am_byte) { - //Use FM Table - preset_data[preset_data_size - PRESET_POWER_OFFSET_FM] = tx_pa_table[tx_power]; - } else if(am_byte & !fm_byte) { - //Use AM Table - preset_data[preset_data_size - PRESET_POWER_OFFSET_AM] = + //Set the TX Power Here in the CC1101 register... + + //If we have both bytes 1st bytes set or none, this isnt a preset we can deal with here. + if(fm_byte && !am_byte) { + //Use FM Table + if(tx_power) { + preset_data[preset_data_size - PRESET_POWER_OFFSET_FM] = tx_pa_table[TX_PATABLE_OFFSET_AM + tx_power]; + } else { + preset_data[preset_data_size - PRESET_POWER_OFFSET_FM] = + tx_pa_table[1]; //Max Power 0xC0 10dBm + } + } else if(am_byte && !fm_byte) { + //Use AM Table + if(tx_power) { + preset_data[preset_data_size - PRESET_POWER_OFFSET_AM] = tx_pa_table[tx_power]; + } else { + preset_data[preset_data_size - PRESET_POWER_OFFSET_AM] = + tx_pa_table[1]; //Max Power 0xC0 12dBm } } From 0032c55a39ca402f7b1ecbac4b52275298d2b8ef Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 12 Feb 2026 21:55:47 +0300 Subject: [PATCH 128/160] upd changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bf9ac068..0e2adab8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,11 +20,13 @@ * SubGHz: KeeLoq **add counter mode 7 (sends 7 signals increasing counter with 0x3333 steps)** - may bypass counter on some receivers! * SubGHz: Add signals button editor and real **remote simulation** (full signal transmit with just one click) (PR #956 #958 | by @Dmitry422) * SubGHz: TX Power setting (PR #960 | by @LeeroysHub) +* Desktop: BT ON/OFF instead of Lock/Unlock action in desktop lock menu (To lock - hold Up button) (PR #965 | by @Dmitry422) (idea by Dezederix) +* Desktop: Holding back button to power off menu now allows to open power settings on left button (idea by Dezederix) * JS: feat: add IR capabilities to the JS engine (PR #957 | by @LuisMayo) * NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) * NFC: Fixes to `READ_MULTI` and `GET_BLOCK_SECURITY` commands in ISO 15693-3 emulation (by @WillyJL & @aaronjamt) * Archive: Allow folders to be pinned (by @WillyJL) -* Apps: Build tag (**10feb2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) +* Apps: Build tag (**12feb2026p3**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes * Settings: Storage settings exit scenes properly if used via favourites (fixes issue #951) * LCD: Backlight settings bug fix (PR #962 | by @Dmitry422) From 75d426382258512e30440a723b88f583662bbdb2 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 15 Feb 2026 16:39:58 +0300 Subject: [PATCH 129/160] fix endless tx state at receiver info --- applications/main/subghz/helpers/subghz_types.h | 1 + .../main/subghz/scenes/subghz_scene_receiver_info.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_types.h b/applications/main/subghz/helpers/subghz_types.h index 6fbdc9e33..790d00557 100644 --- a/applications/main/subghz/helpers/subghz_types.h +++ b/applications/main/subghz/helpers/subghz_types.h @@ -10,6 +10,7 @@ typedef enum { SubGhzNotificationStateTx, SubGhzNotificationStateRx, SubGhzNotificationStateRxDone, + SubGhzNotificationStateTxWait, } SubGhzNotificationState; /** SubGhzTxRx state */ diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 61502c16a..1d1f827f6 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -153,7 +153,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) // user release OK // we switch off endless_tx - that mean protocols yield finish endless transmission, // send upload "repeat=xx" times, and after will be stoped by the tick event down in this code - subghz->state_notifications = SubGhzNotificationStateIDLE; + subghz->state_notifications = SubGhzNotificationStateTxWait; subghz_block_generic_global.endless_tx = false; return true; @@ -192,7 +192,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) notification_message(subghz->notifications, &sequence_blink_green_100); subghz->state_notifications = SubGhzNotificationStateRx; break; - case SubGhzNotificationStateIDLE: + case SubGhzNotificationStateTxWait: // we wait until hardware TX finished and after stop TX and start RX, else just blink led if(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { notification_message(subghz->notifications, &sequence_blink_magenta_10); @@ -202,6 +202,8 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) widget_reset(subghz->widget); subghz_scene_receiver_info_draw_widget(subghz); + subghz->state_notifications = SubGhzNotificationStateIDLE; + if(!scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneDecodeRAW)) { subghz_txrx_rx_start(subghz->txrx); subghz_txrx_hopper_unpause(subghz->txrx); From 9700c98c38cf7fe103dc195f67a971f23c5c29e6 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Sun, 15 Feb 2026 22:35:47 +0700 Subject: [PATCH 130/160] Small refactor Signal Settings for best user expirience. Save and apply counter mode immidiatly after changing, without exit from signal_settings menu. --- .../scenes/subghz_scene_signal_settings.c | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_signal_settings.c b/applications/main/subghz/scenes/subghz_scene_signal_settings.c index 90f99e50c..9b582d2ee 100644 --- a/applications/main/subghz/scenes/subghz_scene_signal_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_signal_settings.c @@ -65,6 +65,38 @@ void subghz_scene_signal_settings_counter_mode_changed(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, counter_mode_text[index]); counter_mode = counter_mode_value[index]; + + SubGhz* subghz = variable_item_get_context(item); + const char* file_path = furi_string_get_cstr(subghz->file_path); + + furi_assert(subghz); + furi_assert(file_path); + + // update file every time when we change mode + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); + + // check is the file available for update/insert CounterMode value + if(flipper_format_file_open_existing(fff_data_file, file_path)) { + if(flipper_format_insert_or_update_uint32(fff_data_file, "CounterMode", &counter_mode, 1)) { + FURI_LOG_D(TAG, "Successfully updated/inserted CounterMode value %li", counter_mode); + } else { + FURI_LOG_E(TAG, "Error update/insert CounterMode value"); + } + } else { + FURI_LOG_E(TAG, "Error open file %s for writing", file_path); + } + + flipper_format_file_close(fff_data_file); + flipper_format_free(fff_data_file); + furi_record_close(RECORD_STORAGE); + + // we need to reload file after editing it + if(subghz_key_load(subghz, file_path, false)) { + FURI_LOG_D(TAG, "Subghz file was successfully reloaded"); + } else { + FURI_LOG_E(TAG, "Error reloading subghz file"); + } } void subghz_scene_signal_settings_byte_input_callback(void* context) { @@ -311,40 +343,8 @@ bool subghz_scene_signal_settings_on_event(void* context, SceneManagerEvent even void subghz_scene_signal_settings_on_exit(void* context) { SubGhz* subghz = context; - const char* file_path = furi_string_get_cstr(subghz->file_path); furi_assert(subghz); - furi_assert(file_path); - - // if ConterMode was changed from 0xff then we must update or write new value to file - if(counter_mode != 0xff) { - Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); - - // check is the file available for update/insert CounterMode value - if(flipper_format_file_open_existing(fff_data_file, file_path)) { - if(flipper_format_insert_or_update_uint32( - fff_data_file, "CounterMode", &counter_mode, 1)) { - FURI_LOG_D( - TAG, "Successfully updated/inserted CounterMode value %li", counter_mode); - } else { - FURI_LOG_E(TAG, "Error update/insert CounterMode value"); - } - } else { - FURI_LOG_E(TAG, "Error open file %s for writing", file_path); - } - - flipper_format_file_close(fff_data_file); - flipper_format_free(fff_data_file); - furi_record_close(RECORD_STORAGE); - - // we need to reload file after editing when we exit from Signal Settings menu. - if(subghz_key_load(subghz, file_path, false)) { - FURI_LOG_D(TAG, "Subghz file was successfully reloaded"); - } else { - FURI_LOG_E(TAG, "Error reloading subghz file"); - } - } // Clear views variable_item_list_set_selected_item(subghz->variable_item_list, 0); From fbf03ecf3814b00422e2066f18825d4e383b74f5 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Sun, 15 Feb 2026 23:04:15 +0700 Subject: [PATCH 131/160] Start. Special case. Bypass counter_modes if we just change signal counter. --- lib/subghz/protocols/alutech_at_4n.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 186d5fd25..3723c7ff9 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -293,9 +293,11 @@ static bool subghz_protocol_alutech_at_4n_gen_data( instance->generic.serial = (uint32_t)(data >> 24) & 0xFFFFFFFF; } - if(alutech_at4n_counter_mode == 0) { + // if we change counter in SignalSettings menu then we must passthru counter_modes, just gen and save signal file. + if((alutech_at4n_counter_mode == 0) || subghz_block_generic_global.cnt_need_override) { // Check for OFEX (overflow experimental) mode - if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { + if((furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) || + subghz_block_generic_global.cnt_need_override) { // standart counter mode. PULL data from subghz_block_generic_global variables if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value From 927c563efa9a36a3f15eea311a86d6b26c12cc7c Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Mon, 16 Feb 2026 22:19:11 +0700 Subject: [PATCH 132/160] finish --- lib/subghz/protocols/alutech_at_4n.c | 17 ++++++++++++----- lib/subghz/protocols/came_atomo.c | 13 +++++++++++-- lib/subghz/protocols/keeloq.c | 16 +++++++++++++--- lib/subghz/protocols/nice_flor_s.c | 16 +++++++++++++--- lib/subghz/protocols/phoenix_v2.c | 15 ++++++++++++--- 5 files changed, 61 insertions(+), 16 deletions(-) diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 3723c7ff9..959e3dbdb 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -12,6 +12,9 @@ #define SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE 0xFFFFFFFFFFFFFFFF #define SUBGHZ_ALUTECH_AT_4N_RAINBOW_TABLE_SIZE_BYTES 32 +//variable used to bypass CounterMode settings if user just change Counter or Button +static bool bypass = false; + static const SubGhzBlockConst subghz_protocol_alutech_at_4n_const = { .te_short = 400, .te_long = 800, @@ -293,11 +296,13 @@ static bool subghz_protocol_alutech_at_4n_gen_data( instance->generic.serial = (uint32_t)(data >> 24) & 0xFFFFFFFF; } - // if we change counter in SignalSettings menu then we must passthru counter_modes, just gen and save signal file. - if((alutech_at4n_counter_mode == 0) || subghz_block_generic_global.cnt_need_override) { + // if we change counter/button in SignalSettings menu then we must bypass counter_modes, just gen and save signal file. + if(subghz_block_generic_global.cnt_need_override) bypass = true; + + if((alutech_at4n_counter_mode == 0) || bypass) { // Check for OFEX (overflow experimental) mode - if((furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) || - subghz_block_generic_global.cnt_need_override) { + if((furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) || bypass) { + bypass = false; // standart counter mode. PULL data from subghz_block_generic_global variables if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value @@ -403,8 +408,10 @@ static bool subghz_protocol_encoder_alutech_at_4n_get_upload( btn = subghz_protocol_alutech_at_4n_get_btn_code(); // override button if we change it with signal settings button editor - if(subghz_block_generic_global_button_override_get(&btn)) + if(subghz_block_generic_global_button_override_get(&btn)) { + bypass = true; FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", btn); + } // Gen new key if(!subghz_protocol_alutech_at_4n_gen_data(instance, btn)) { diff --git a/lib/subghz/protocols/came_atomo.c b/lib/subghz/protocols/came_atomo.c index f46b90b2d..bd21dafd1 100644 --- a/lib/subghz/protocols/came_atomo.c +++ b/lib/subghz/protocols/came_atomo.c @@ -11,6 +11,9 @@ #define TAG "SubGhzProtocoCameAtomo" +//variable used to bypass CounterMode settings if user just change Counter or Button +static bool bypass = false; + static const SubGhzBlockConst subghz_protocol_came_atomo_const = { .te_short = 600, .te_long = 1200, @@ -187,9 +190,15 @@ static void subghz_protocol_encoder_came_atomo_get_upload( uint8_t pack[8] = {}; - if(came_atomo_counter_mode == 0) { + // if we change counter/button in SignalSettings menu then we must bypass counter_modes, just gen and save signal file. + if(subghz_block_generic_global.cnt_need_override || + subghz_block_generic_global.btn_need_override) + bypass = true; + + if(came_atomo_counter_mode == 0 || bypass) { // Check for OFEX (overflow experimental) mode - if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { + if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF || bypass) { + bypass = false; // standart counter mode. PULL data from subghz_block_generic_global variables if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index f47f53492..0ed600ece 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -15,6 +15,9 @@ #define TAG "SubGhzProtocolKeeloq" +//variable used to bypass CounterMode settings if user just change Counter or Button +static bool bypass = false; + static const SubGhzBlockConst subghz_protocol_keeloq_const = { .te_short = 400, .te_long = 800, @@ -241,9 +244,10 @@ static bool subghz_protocol_keeloq_gen_data( if(counter_up && prog_mode == PROG_MODE_OFF) { // Counter increment conditions - if(keeloq_counter_mode == 0) { + if(keeloq_counter_mode == 0 || bypass) { // Check for OFEX (overflow experimental) mode - if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { + if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF || bypass) { + bypass = false; // standart counter mode. PULL data from subghz_block_generic_global variables if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value @@ -601,7 +605,13 @@ static bool instance->encoder.size_upload = 0; size_t upindex = 0; - if(keeloq_counter_mode == 7) { + // if we change counter/button in SignalSettings menu then we must bypass counter_modes, just gen and save signal file. + if(subghz_block_generic_global.cnt_need_override || + subghz_block_generic_global.btn_need_override) + bypass = true; + + // Create mode7 upload only if counter and button was not changed by SignalSettings menu + if(keeloq_counter_mode == 7 && !bypass) { uint16_t temp_cnt = instance->generic.cnt; instance->encoder.repeat = 1; for(uint8_t i = 7; i > 0; i--) { diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index b554deccf..5b301573e 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -21,6 +21,9 @@ #define SUBGHZ_NICE_FLOR_S_RAINBOW_TABLE_SIZE_BYTES 32 #define SUBGHZ_NO_NICE_FLOR_S_RAINBOW_TABLE 0 +//variable used to bypass CounterMode settings if user just change Counter or Button +static bool bypass = false; + static const SubGhzBlockConst subghz_protocol_nice_flor_s_const = { .te_short = 500, .te_long = 1000, @@ -148,8 +151,10 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload( btn = subghz_protocol_nice_flor_s_get_btn_code(); // override button if we change it with signal settings button editor - if(subghz_block_generic_global_button_override_get(&btn)) + if(subghz_block_generic_global_button_override_get(&btn)) { + bypass = true; FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", btn); + } size_t size_upload = ((instance->generic.data_count_bit * 2) + ((37 + 2 + 2) * 2) * 16); if(size_upload > instance->encoder.size_upload) { @@ -157,9 +162,14 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload( } else { instance->encoder.size_upload = size_upload; } - if(nice_flors_counter_mode == 0) { + + // if we change counter/button in SignalSettings menu then we must bypass counter_modes, just gen and save signal file. + if(subghz_block_generic_global.cnt_need_override) bypass = true; + + if(nice_flors_counter_mode == 0 || bypass) { // Check for OFEX (overflow experimental) mode - if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { + if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF || bypass) { + bypass = false; // standart counter mode. PULL data from subghz_block_generic_global variables if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value diff --git a/lib/subghz/protocols/phoenix_v2.c b/lib/subghz/protocols/phoenix_v2.c index 2dc199795..41f4e1c7d 100644 --- a/lib/subghz/protocols/phoenix_v2.c +++ b/lib/subghz/protocols/phoenix_v2.c @@ -10,6 +10,9 @@ #define TAG "SubGhzProtocolPhoenixV2" +//variable used to bypass CounterMode settings if user just change Counter or Button +static bool bypass = false; + static const SubGhzBlockConst subghz_protocol_phoenix_v2_const = { .te_short = 427, .te_long = 853, @@ -256,13 +259,19 @@ static bool btn = subghz_protocol_phoenix_v2_get_btn_code(); // override button if we change it with signal settings button editor - if(subghz_block_generic_global_button_override_get(&btn)) + if(subghz_block_generic_global_button_override_get(&btn)) { + bypass = true; FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", btn); + } // Reconstruction of the data - if(v2_phoenix_counter_mode == 0) { + // if we change counter/button in SignalSettings menu then we must bypass counter_modes, just gen and save signal file. + if(subghz_block_generic_global.cnt_need_override) bypass = true; + + if(v2_phoenix_counter_mode == 0 || bypass) { // Check for OFEX (overflow experimental) mode - if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { + if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF || bypass) { + bypass = false; // standart counter mode. PULL data from subghz_block_generic_global variables if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value From 937e937d3229906cc339e0641870aac36c28c916 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 16 Feb 2026 23:15:07 +0300 Subject: [PATCH 133/160] update mfkey to 4.1 [ci skip] --- applications/system/mfkey/application.fam | 5 +- applications/system/mfkey/crypto1.c | 1 - applications/system/mfkey/crypto1.h | 136 +++- applications/system/mfkey/mfkey.c | 513 +------------ applications/system/mfkey/mfkey.h | 7 +- applications/system/mfkey/mfkey_attack.c | 287 +++++++ applications/system/mfkey/mfkey_attack.h | 21 + .../system/mfkey/mfkey_batch_prelude.c | 707 ++++++++++++++++++ .../system/mfkey/mfkey_batch_prelude.h | 12 + applications/system/mfkey/mfkey_bs_verify.c | 530 +++++++++++++ applications/system/mfkey/mfkey_bs_verify.h | 71 ++ applications/system/mfkey/mfkey_dedup.h | 141 ++++ applications/system/mfkey/mfkey_recovery.c | 288 +++++++ applications/system/mfkey/mfkey_recovery.h | 31 + .../system/mfkey/mfkey_state_expansion.c | 152 ++++ .../system/mfkey/mfkey_state_expansion.h | 17 + 16 files changed, 2390 insertions(+), 529 deletions(-) create mode 100644 applications/system/mfkey/mfkey_attack.c create mode 100644 applications/system/mfkey/mfkey_attack.h create mode 100644 applications/system/mfkey/mfkey_batch_prelude.c create mode 100644 applications/system/mfkey/mfkey_batch_prelude.h create mode 100644 applications/system/mfkey/mfkey_bs_verify.c create mode 100644 applications/system/mfkey/mfkey_bs_verify.h create mode 100644 applications/system/mfkey/mfkey_dedup.h create mode 100644 applications/system/mfkey/mfkey_recovery.c create mode 100644 applications/system/mfkey/mfkey_recovery.h create mode 100644 applications/system/mfkey/mfkey_state_expansion.c create mode 100644 applications/system/mfkey/mfkey_state_expansion.h diff --git a/applications/system/mfkey/application.fam b/applications/system/mfkey/application.fam index 5ece9e777..ec5b730b2 100644 --- a/applications/system/mfkey/application.fam +++ b/applications/system/mfkey/application.fam @@ -8,14 +8,13 @@ App( "gui", "storage", ], - stack_size=1 * 1024, + stack_size=8 * 1024, fap_icon="mfkey.png", fap_category="NFC", fap_author="@noproto", fap_icon_assets="images", - fap_weburl="https://github.com/noproto/FlipperMfkey", fap_description="MIFARE Classic key recovery tool", - fap_version="4.0", + fap_version="4.1", ) App( diff --git a/applications/system/mfkey/crypto1.c b/applications/system/mfkey/crypto1.c index e862b14d1..78a400a96 100644 --- a/applications/system/mfkey/crypto1.c +++ b/applications/system/mfkey/crypto1.c @@ -1,5 +1,4 @@ #pragma GCC optimize("O3") -#pragma GCC optimize("-funroll-all-loops") #include #include "crypto1.h" diff --git a/applications/system/mfkey/crypto1.h b/applications/system/mfkey/crypto1.h index 25205ed70..405a37f9b 100644 --- a/applications/system/mfkey/crypto1.h +++ b/applications/system/mfkey/crypto1.h @@ -2,14 +2,22 @@ #define CRYPTO1_H #include + #include "mfkey.h" #include #include #define LF_POLY_ODD (0x29CE5C) #define LF_POLY_EVEN (0x870804) -#define BIT(x, n) ((x) >> (n) & 1) -#define BEBIT(x, n) BIT(x, (n) ^ 24) + +// Precomputed mask constants for extend_table +#define CONST_M1_1 (LF_POLY_EVEN << 1 | 1) +#define CONST_M2_1 (LF_POLY_ODD << 1) +#define CONST_M1_2 (LF_POLY_ODD) +#define CONST_M2_2 (LF_POLY_EVEN << 1 | 1) + +#define BIT(x, n) ((x) >> (n) & 1) +#define BEBIT(x, n) BIT(x, (n) ^ 24) #define SWAPENDIAN(x) \ ((x) = ((x) >> 8 & 0xff00ff) | ((x) & 0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16) @@ -31,7 +39,7 @@ static inline void rollback_word_noret(struct Crypto1State* s, uint32_t in, int static inline uint8_t napi_lfsr_rollback_bit(struct Crypto1State* s, uint32_t in, int fb); static inline uint32_t napi_lfsr_rollback_word(struct Crypto1State* s, uint32_t in, int fb); -static const uint8_t lookup1[256] = { +static const uint8_t __attribute__((aligned(4))) lookup1[256] = { 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, 8, 8, 24, 24, 8, 24, 8, 8, @@ -43,7 +51,7 @@ static const uint8_t lookup1[256] = { 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24}; -static const uint8_t lookup2[256] = { +static const uint8_t __attribute__((aligned(4))) lookup2[256] = { 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 2, 2, 6, 6, 2, 6, 2, @@ -54,29 +62,104 @@ static const uint8_t lookup2[256] = { 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6}; -static inline int filter(uint32_t const x) { +static inline __attribute__((always_inline)) int filter(uint32_t const x) { uint32_t f; f = lookup1[x & 0xff] | lookup2[(x >> 8) & 0xff]; f |= 0x0d938 >> (x >> 16 & 0xf) & 1; return BIT(0xEC57E80A, f); } -#ifdef __ARM_ARCH_7EM__ -static inline uint8_t evenparity32(uint32_t x) { - // fold 32 bits -> 16 -> 8 -> 4 +// Optimized: compute filter(v) and filter(v|1) with shared work +// Returns packed (f1 << 1 | f0) to avoid pointer overhead +static inline __attribute__((always_inline)) uint32_t filter_pair(uint32_t v) { + // Shared indices (v|1 only changes bit 0) + uint32_t idx_hi = (v >> 8) & 0xff; + uint32_t idx_nib = (v >> 16) & 0xf; + + // Shared lookups and computation + uint8_t l2 = lookup2[idx_hi]; + uint32_t nib_bit = (0x0d938 >> idx_nib) & 1; + uint32_t shared = l2 | nib_bit; + + // lookup1 differs only in bit 0 + uint32_t idx0_lo = v & 0xff; + uint8_t l1_0 = lookup1[idx0_lo]; + uint8_t l1_1 = lookup1[idx0_lo | 1]; + + // Compute both filters + int f0 = BIT(0xEC57E80A, l1_0 | shared); + int f1 = BIT(0xEC57E80A, l1_1 | shared); + + // Pack: bit 0 = f0, bit 1 = f1 + return (uint32_t)f0 | ((uint32_t)f1 << 1); +} + +// Compute filter pair using pre-XOR'd filter constant +// adj_filter = 0xEC57E80A ^ (-(uint32_t)BIT(xks, round)) +// Returns f0/f1 already XOR'd with xks_bit, eliminating xks_bit as a variable +static inline __attribute__((always_inline)) uint32_t + filter_pair_xor(uint32_t v, uint32_t adj_filter) { + uint32_t idx_hi = (v >> 8) & 0xff; + uint32_t idx_nib = (v >> 16) & 0xf; + uint8_t l2 = lookup2[idx_hi]; + uint32_t nib_bit = (0x0d938 >> idx_nib) & 1; + uint32_t shared = l2 | nib_bit; + uint32_t idx0_lo = v & 0xff; + uint8_t l1_0 = lookup1[idx0_lo]; + uint8_t l1_1 = lookup1[idx0_lo | 1]; + int f0 = BIT(adj_filter, l1_0 | shared); + int f1 = BIT(adj_filter, l1_1 | shared); + return (uint32_t)f0 | ((uint32_t)f1 << 1); +} + +// Unpack macros for filter_pair result +#define FILTER_F0(fp) ((fp) & 1) +#define FILTER_F1(fp) (((fp) >> 1) & 1) + +// Optimized filter_pair with precomputed nibble bit +// nib_bit must be 0 or 1 (the result of (0x0d938 >> nibble) & 1) +static inline __attribute__((always_inline)) uint32_t + filter_pair_with_nib(uint32_t v, uint32_t nib_bit) { + uint32_t idx_hi = (v >> 8) & 0xff; + + uint8_t l2 = lookup2[idx_hi]; + uint32_t shared = l2 | nib_bit; // nib_bit precomputed, no shift/mask needed + + uint32_t idx0_lo = v & 0xff; + uint8_t l1_0 = lookup1[idx0_lo]; + uint8_t l1_1 = lookup1[idx0_lo | 1]; + + int f0 = BIT(0xEC57E80A, l1_0 | shared); + int f1 = BIT(0xEC57E80A, l1_1 | shared); + + return (uint32_t)f0 | ((uint32_t)f1 << 1); +} + +// Register-based parity update (avoids array access overhead) +// Calculates new state with parity bits without array/pointer access +static inline __attribute__((always_inline)) uint32_t + update_contribution_reg(uint32_t v, int mask1, int mask2) { + uint32_t p = v >> 25; + p = (p << 1) | evenparity32(v & mask1); + p = (p << 1) | evenparity32(v & mask2); + return (p << 24) | (v & 0xffffff); +} + +static inline __attribute__((always_inline)) uint8_t evenparity32(uint32_t x) { x ^= x >> 16; x ^= x >> 8; x ^= x >> 4; - // magic 0x6996: bit i tells you parity of i (0 ≤ i < 16) - return (uint8_t)((0x6996u >> (x & 0xF)) & 1); + x ^= x >> 2; + x ^= x >> 1; + return (uint8_t)(x & 1); } -#endif -static inline void update_contribution(unsigned int data[], int item, int mask1, int mask2) { - int p = data[item] >> 25; +static inline __attribute__((always_inline)) void + update_contribution(unsigned int data[], int item, int mask1, int mask2) { + unsigned int p = data[item] >> 25; // Use unsigned to avoid UB on left shift p = p << 1 | evenparity32(data[item] & mask1); p = p << 1 | evenparity32(data[item] & mask2); - data[item] = p << 24 | (data[item] & 0xffffff); + data[item] = (p << 24) | (data[item] & 0xffffff); } static inline uint32_t crypt_word(struct Crypto1State* s) { @@ -187,29 +270,6 @@ static inline void rollback_word_noret(struct Crypto1State* s, uint32_t in, int return; } -// TODO: -/* -uint32_t rollback_word(struct Crypto1State *s, uint32_t in, int x) { - uint32_t res_ret = 0; - uint8_t ret; - uint32_t feedin, t, next_in; - for (int i = 31; i >= 0; i--) { - next_in = BEBIT(in, i); - s->odd &= 0xffffff; - t = s->odd, s->odd = s->even, s->even = t; - ret = filter(s->odd); - feedin = ret & (!!x); - feedin ^= s->even & 1; - feedin ^= LF_POLY_EVEN & (s->even >>= 1); - feedin ^= LF_POLY_ODD & s->odd; - feedin ^= !!next_in; - s->even |= (evenparity32(feedin)) << 23; - res_ret |= (ret << (24 ^ i)); - } - return res_ret; -} -*/ - uint8_t napi_lfsr_rollback_bit(struct Crypto1State* s, uint32_t in, int fb) { int out; uint8_t ret; @@ -231,7 +291,7 @@ uint32_t napi_lfsr_rollback_word(struct Crypto1State* s, uint32_t in, int fb) { int i; uint32_t ret = 0; for(i = 31; i >= 0; --i) - ret |= napi_lfsr_rollback_bit(s, BEBIT(in, i), fb) << (i ^ 24); + ret |= (uint32_t)napi_lfsr_rollback_bit(s, BEBIT(in, i), fb) << (i ^ 24); return ret; } diff --git a/applications/system/mfkey/mfkey.c b/applications/system/mfkey/mfkey.c index db700be32..97ccbb8c8 100644 --- a/applications/system/mfkey/mfkey.c +++ b/applications/system/mfkey/mfkey.c @@ -1,5 +1,4 @@ #pragma GCC optimize("O3") -#pragma GCC optimize("-funroll-all-loops") // TODO: More efficient dictionary bruteforce by scanning through hardcoded very common keys and previously found dictionary keys first? // (a cache for key_already_found_for_nonce_in_dict) @@ -18,14 +17,17 @@ #include #include "mfkey_icons.h" #include +#include #include #include #include #include #include +#include #include #include "mfkey.h" #include "crypto1.h" +#include "mfkey_attack.h" #include "plugin_interface.h" #include #include @@ -42,12 +44,13 @@ #define LF_POLY_ODD (0x29CE5C) #define LF_POLY_EVEN (0x870804) -#define CONST_M1_1 (LF_POLY_EVEN << 1 | 1) -#define CONST_M2_1 (LF_POLY_ODD << 1) -#define CONST_M1_2 (LF_POLY_ODD) -#define CONST_M2_2 (LF_POLY_EVEN << 1 | 1) -#define BIT(x, n) ((x) >> (n) & 1) -#define BEBIT(x, n) BIT(x, (n) ^ 24) + +#define CONST_M1_1 (LF_POLY_EVEN << 1 | 1) +#define CONST_M2_1 (LF_POLY_ODD << 1) +#define CONST_M1_2 (LF_POLY_ODD) +#define CONST_M2_2 (LF_POLY_EVEN << 1 | 1) +#define BIT(x, n) ((x) >> (n) & 1) +#define BEBIT(x, n) BIT(x, (n) ^ 24) #define SWAP(a, b) \ do { \ unsigned int t = a; \ @@ -59,18 +62,18 @@ // #define SIZEOF(arr) sizeof(arr) / sizeof(*arr) // Reduced to 16-bit as these values are small and don't need 32-bit -static int16_t eta_round_time = 44; -static int16_t eta_total_time = 705; +static int16_t eta_round_time = 30; +static int16_t eta_total_time = 481; // MSB_LIMIT: Chunk size (out of 256) - can be 8-bit as it's a small value -static uint8_t MSB_LIMIT = 16; +// Not static - referenced by mfkey_attack.c +uint8_t MSB_LIMIT = 16; -static inline void flush_key_buffer(ProgramState* program_state) { +// Not static - referenced by mfkey_attack.c for static_encrypted attacks +void flush_key_buffer(ProgramState* program_state) { if(program_state->key_buffer && program_state->key_buffer_count > 0 && program_state->cuid_dict) { // Pre-allocate exact size needed: 2 hex chars (key_idx) + 12 hex chars (key) + 1 newline per key size_t total_size = program_state->key_buffer_count * 15; - //FURI_LOG_I(TAG, "Flushing key buffer: %d keys", program_state->key_buffer_count); - //FURI_LOG_I(TAG, "Total size: %d bytes", total_size); char* batch_buffer = malloc(total_size + 1); // +1 for null terminator char* ptr = batch_buffer; @@ -109,323 +112,8 @@ static inline void flush_key_buffer(ProgramState* program_state) { } } -static inline int - check_state(struct Crypto1State* t, MfClassicNonce* n, ProgramState* program_state) { - if(!(t->odd | t->even)) return 0; - if(n->attack == mfkey32) { - uint32_t rb = (napi_lfsr_rollback_word(t, 0, 0) ^ n->p64); - if(rb != n->ar0_enc) { - return 0; - } - rollback_word_noret(t, n->nr0_enc, 1); - rollback_word_noret(t, n->uid_xor_nt0, 0); - struct Crypto1State temp = {t->odd, t->even}; - crypt_word_noret(t, n->uid_xor_nt1, 0); - crypt_word_noret(t, n->nr1_enc, 1); - if(n->ar1_enc == (crypt_word(t) ^ n->p64b)) { - crypto1_get_lfsr(&temp, &(n->key)); - return 1; - } - } else if(n->attack == static_nested) { - struct Crypto1State temp = {t->odd, t->even}; - rollback_word_noret(t, n->uid_xor_nt1, 0); - if(n->ks1_1_enc == crypt_word_ret(t, n->uid_xor_nt0, 0)) { - rollback_word_noret(&temp, n->uid_xor_nt1, 0); - crypto1_get_lfsr(&temp, &(n->key)); - return 1; - } - } else if(n->attack == static_encrypted) { - // TODO: Parity bits from rollback_word? - if(n->ks1_1_enc == napi_lfsr_rollback_word(t, n->uid_xor_nt0, 0)) { - // Reduce with parity - uint8_t local_parity_keystream_bits; - struct Crypto1State temp = {t->odd, t->even}; - if((crypt_word_par(&temp, n->uid_xor_nt0, 0, n->nt0, &local_parity_keystream_bits) == - n->ks1_1_enc) && - (local_parity_keystream_bits == n->par_1)) { - // Found key candidate - crypto1_get_lfsr(t, &(n->key)); - program_state->num_candidates++; - - // Use key buffer - buffer is guaranteed to be available for static_encrypted - program_state->key_buffer[program_state->key_buffer_count] = n->key; - program_state->key_idx_buffer[program_state->key_buffer_count] = n->key_idx; - program_state->key_buffer_count++; - - // Flush buffer when full - if(program_state->key_buffer_count >= program_state->key_buffer_size) { - flush_key_buffer(program_state); - } - } - } - } - return 0; -} - -static inline __attribute__((hot)) int - state_loop(unsigned int* states_buffer, int xks, int m1, int m2, unsigned int in, int and_val) { - int states_tail = 0; - int xks_bit = 0, round_in = 0; - - // Unroll first 4 rounds (no round_in calculations needed) - // Hoist the filter() calls to just one iteration and reuse the results - // This avoids redundant calculations and improves performance and gives us 2000b of extra ram (11496b free on run) - // V.28/04. Aprox 3s speedup per round. Total 3 keys 7mins 17s!! - for(int round = 1; round <= 4; ++round) { - xks_bit = BIT(xks, round); - for(int s = 0; s <= states_tail; ++s) { - unsigned int v = states_buffer[s] << 1; - states_buffer[s] = v; - int f0 = filter(v); - int f1 = filter(v | 1); - - if(__builtin_expect((f0 ^ f1) != 0, 0)) { - states_buffer[s] |= f0 ^ xks_bit; - } else if(__builtin_expect(f0 == xks_bit, 1)) { - states_buffer[++states_tail] = states_buffer[++s]; - states_buffer[s] = states_buffer[s - 1] | 1; - } else { - states_buffer[s--] = states_buffer[states_tail--]; - } - } - } - - // Round 5 (unrolled) - { - xks_bit = BIT(xks, 5); - int r5_in = ((in >> 2) & and_val) << 24; // 2*(5-4)=2 - for(int s = 0; s <= states_tail; ++s) { - unsigned int v = states_buffer[s] << 1; - states_buffer[s] = v; - int f0 = filter(v), f1 = filter(v | 1); - if(__builtin_expect((f0 ^ f1) != 0, 0)) { - states_buffer[s] |= f0 ^ xks_bit; - update_contribution(states_buffer, s, m1, m2); - states_buffer[s] ^= r5_in; - } else if(__builtin_expect(f0 == xks_bit, 1)) { - states_buffer[++states_tail] = states_buffer[s + 1]; - states_buffer[s + 1] = v | 1; - update_contribution(states_buffer, s, m1, m2); - states_buffer[s++] ^= r5_in; - update_contribution(states_buffer, s, m1, m2); - states_buffer[s] ^= r5_in; - } else { - states_buffer[s--] = states_buffer[states_tail--]; - } - } - } - - // Round 6 (unrolled) - { - xks_bit = BIT(xks, 6); - int r6_in = ((in >> 4) & and_val) << 24; // 2*(6-4)=4 - for(int s = 0; s <= states_tail; ++s) { - unsigned int v = states_buffer[s] << 1; - states_buffer[s] = v; - int f0 = filter(v), f1 = filter(v | 1); - if(__builtin_expect((f0 ^ f1) != 0, 0)) { - states_buffer[s] |= f0 ^ xks_bit; - update_contribution(states_buffer, s, m1, m2); - states_buffer[s] ^= r6_in; - } else if(__builtin_expect(f0 == xks_bit, 1)) { - states_buffer[++states_tail] = states_buffer[s + 1]; - states_buffer[s + 1] = v | 1; - update_contribution(states_buffer, s, m1, m2); - states_buffer[s++] ^= r6_in; - update_contribution(states_buffer, s, m1, m2); - states_buffer[s] ^= r6_in; - } else { - states_buffer[s--] = states_buffer[states_tail--]; - } - } - } - - // Loop rounds 7–12 - for(int round = 7; round <= 12; ++round) { - xks_bit = BIT(xks, round); - round_in = ((in >> (2 * (round - 4))) & and_val) << 24; - for(int s = 0; s <= states_tail; ++s) { - unsigned int v = states_buffer[s] << 1; - states_buffer[s] = v; - int f0 = filter(v), f1 = filter(v | 1); - if(__builtin_expect((f0 ^ f1) != 0, 0)) { - states_buffer[s] |= f0 ^ xks_bit; - update_contribution(states_buffer, s, m1, m2); - states_buffer[s] ^= round_in; - } else if(__builtin_expect(f0 == xks_bit, 1)) { - states_buffer[++states_tail] = states_buffer[s + 1]; - states_buffer[s + 1] = v | 1; - update_contribution(states_buffer, s, m1, m2); - states_buffer[s++] ^= round_in; - update_contribution(states_buffer, s, m1, m2); - states_buffer[s] ^= round_in; - } else { - states_buffer[s--] = states_buffer[states_tail--]; - } - } - } - - return states_tail; -} - -int binsearch(unsigned int data[], int start, int stop) { - int mid, val = data[stop] & 0xff000000; - while(start != stop) { - mid = (stop - start) >> 1; - if((data[start + mid] ^ 0x80000000) > (val ^ 0x80000000)) - stop = start + mid; - else - start += mid + 1; - } - return start; -} - -void quicksort(unsigned int array[], int low, int high) { - // Use insertion sort for small arrays (threshold determined by testing) - if(high - low < 16) { - // Insertion sort - for(int i = low + 1; i <= high; i++) { - unsigned int key = array[i]; - int j = i - 1; - while(j >= low && array[j] > key) { - array[j + 1] = array[j]; - j--; - } - array[j + 1] = key; - } - return; - } - - if(low >= high) return; - - // Median-of-three pivot selection - int middle = low + (high - low) / 2; - if(array[middle] < array[low]) SWAP(array[middle], array[low]); - if(array[high] < array[low]) SWAP(array[high], array[low]); - if(array[high] < array[middle]) SWAP(array[high], array[middle]); - - unsigned int pivot = array[middle]; - - // Rest of quicksort with improved partitioning - int i = low, j = high; - while(i <= j) { - while(array[i] < pivot) - i++; - while(array[j] > pivot) - j--; - if(i <= j) { - // swap - unsigned int temp = array[i]; - array[i] = array[j]; - array[j] = temp; - i++; - j--; - } - } - - if(low < j) quicksort(array, low, j); - if(high > i) quicksort(array, i, high); -} - -int extend_table(unsigned int data[], int tbl, int end, int bit, int m1, int m2, unsigned int in) { - in <<= 24; - for(data[tbl] <<= 1; tbl <= end; data[++tbl] <<= 1) { - if((filter(data[tbl]) ^ filter(data[tbl] | 1)) != 0) { - data[tbl] |= filter(data[tbl]) ^ bit; - update_contribution(data, tbl, m1, m2); - data[tbl] ^= in; - } else if(filter(data[tbl]) == bit) { - data[++end] = data[tbl + 1]; - data[tbl + 1] = data[tbl] | 1; - update_contribution(data, tbl, m1, m2); - data[tbl++] ^= in; - update_contribution(data, tbl, m1, m2); - data[tbl] ^= in; - } else { - data[tbl--] = data[end--]; - } - } - return end; -} - -int old_recover( - unsigned int odd[], - int o_head, - int o_tail, - int oks, - unsigned int even[], - int e_head, - int e_tail, - int eks, - int rem, - int s, - MfClassicNonce* n, - unsigned int in, - int first_run, - ProgramState* program_state) { - int o, e, i; - if(rem == -1) { - for(e = e_head; e <= e_tail; ++e) { - even[e] = (even[e] << 1) ^ evenparity32(even[e] & LF_POLY_EVEN) ^ (!!(in & 4)); - for(o = o_head; o <= o_tail; ++o, ++s) { - struct Crypto1State temp = {0, 0}; - temp.even = odd[o]; - temp.odd = even[e] ^ evenparity32(odd[o] & LF_POLY_ODD); - if(check_state(&temp, n, program_state)) { - return -1; - } - } - } - return s; - } - if(first_run == 0) { - for(i = 0; (i < 4) && (rem-- != 0); i++) { - oks >>= 1; - eks >>= 1; - in >>= 2; - o_tail = extend_table( - odd, o_head, o_tail, oks & 1, LF_POLY_EVEN << 1 | 1, LF_POLY_ODD << 1, 0); - if(o_head > o_tail) return s; - e_tail = extend_table( - even, e_head, e_tail, eks & 1, LF_POLY_ODD, LF_POLY_EVEN << 1 | 1, in & 3); - if(e_head > e_tail) return s; - } - } - first_run = 0; - quicksort(odd, o_head, o_tail); - quicksort(even, e_head, e_tail); - while(o_tail >= o_head && e_tail >= e_head) { - if(((odd[o_tail] ^ even[e_tail]) >> 24) == 0) { - o_tail = binsearch(odd, o_head, o = o_tail); - e_tail = binsearch(even, e_head, e = e_tail); - s = old_recover( - odd, - o_tail--, - o, - oks, - even, - e_tail--, - e, - eks, - rem, - s, - n, - in, - first_run, - program_state); - if(s == -1) { - break; - } - } else if((odd[o_tail] ^ 0x80000000) > (even[e_tail] ^ 0x80000000)) { - o_tail = binsearch(odd, o_head, o_tail) - 1; - } else { - e_tail = binsearch(even, e_head, e_tail) - 1; - } - } - return s; -} - -static inline int sync_state(ProgramState* program_state) { +// Not static - referenced by mfkey_attack.c +int sync_state(ProgramState* program_state) { int ts = furi_hal_rtc_get_timestamp(); int elapsed_time = ts - program_state->eta_timestamp; if(elapsed_time < program_state->eta_round) { @@ -445,148 +133,6 @@ static inline int sync_state(ProgramState* program_state) { return 0; } -int calculate_msb_tables( - int oks, - int eks, - int msb_round, - MfClassicNonce* n, - unsigned int* states_buffer, - struct Msb* odd_msbs, - struct Msb* even_msbs, - unsigned int* temp_states_odd, - unsigned int* temp_states_even, - unsigned int in, - ProgramState* program_state) { - unsigned int msb_head = (MSB_LIMIT * msb_round); - unsigned int msb_tail = (MSB_LIMIT * (msb_round + 1)); - int states_tail = 0; - int semi_state = 0; - unsigned int msb = 0; - - // Preprocessed in value - in = ((in >> 16 & 0xff) | (in << 16) | (in & 0xff00)) << 1; - - // Clear MSB arrays once before loop instead of inside loop - memset(odd_msbs, 0, MSB_LIMIT * sizeof(struct Msb)); - memset(even_msbs, 0, MSB_LIMIT * sizeof(struct Msb)); - - // Bit values to check - calculate once outside the loop - int oks_bit = oks & 1; - int eks_bit = eks & 1; - - // Check for stop request less frequently - int sync_check_interval = 32768 * 2; // Doubled the interval - - for(semi_state = 1 << 20; semi_state >= 0; semi_state--) { - if(semi_state % sync_check_interval == 0) { - if(sync_state(program_state) == 1) { - return 0; - } - } - - // Process both filter conditions in one pass when possible - int filter_semi_state = filter(semi_state); - - // Check oks condition - if(filter_semi_state == oks_bit) { - states_buffer[0] = semi_state; - states_tail = state_loop(states_buffer, oks, CONST_M1_1, CONST_M2_1, 0, 0); - - for(int i = states_tail; i >= 0; i--) { - msb = states_buffer[i] >> 24; - if((msb >= msb_head) && (msb < msb_tail)) { - // Calculate index once - int msb_idx = msb - msb_head; - - // Avoid sequential scan by using a direct flag - int found = 0; - for(int j = 0; j < odd_msbs[msb_idx].tail; j++) { - if(odd_msbs[msb_idx].states[j] == states_buffer[i]) { - found = 1; - break; - } - } - - if(!found) { - int tail = odd_msbs[msb_idx].tail++; - odd_msbs[msb_idx].states[tail] = states_buffer[i]; - } - } - } - } - - // Check eks condition - if(filter_semi_state == eks_bit) { - states_buffer[0] = semi_state; - states_tail = state_loop(states_buffer, eks, CONST_M1_2, CONST_M2_2, in, 3); - - for(int i = 0; i <= states_tail; i++) { - msb = states_buffer[i] >> 24; - if((msb >= msb_head) && (msb < msb_tail)) { - // Calculate index once - int msb_idx = msb - msb_head; - - // Avoid sequential scan - int found = 0; - for(int j = 0; j < even_msbs[msb_idx].tail; j++) { - if(even_msbs[msb_idx].states[j] == states_buffer[i]) { - found = 1; - break; - } - } - - if(!found) { - int tail = even_msbs[msb_idx].tail++; - even_msbs[msb_idx].states[tail] = states_buffer[i]; - } - } - } - } - } - - // Shift once outside the loop - oks >>= 12; - eks >>= 12; - - // Process results - for(int i = 0; i < MSB_LIMIT; i++) { - if((i % 4) == 0 && sync_state(program_state) == 1) { - return 0; - } - - // Only clear buffers if they're going to be used - if(odd_msbs[i].tail > 0 || even_msbs[i].tail > 0) { - memset(temp_states_even, 0, sizeof(unsigned int) * (1280)); - memset(temp_states_odd, 0, sizeof(unsigned int) * (1280)); - memcpy(temp_states_odd, odd_msbs[i].states, odd_msbs[i].tail * sizeof(unsigned int)); - memcpy( - temp_states_even, even_msbs[i].states, even_msbs[i].tail * sizeof(unsigned int)); - - int res = old_recover( - temp_states_odd, - 0, - odd_msbs[i].tail, - oks, - temp_states_even, - 0, - even_msbs[i].tail, - eks, - 3, - 0, - n, - in >> 16, - 1, - program_state); - - if(res == -1) { - return 1; - } - } - } - - return 0; -} - void** allocate_blocks(const size_t* block_sizes, int num_blocks) { void** block_pointers = malloc(num_blocks * sizeof(void*)); if(!block_pointers) { @@ -619,12 +165,15 @@ void** allocate_blocks(const size_t* block_sizes, int num_blocks) { bool recover(MfClassicNonce* n, int ks2, unsigned int in, ProgramState* program_state) { bool found = false; - const size_t block_sizes[] = {49216, 49216, 5120, 5120, 4096}; - const size_t reduced_block_sizes[] = {24608, 24608, 5120, 5120, 4096}; + // Packed 24-bit Msb format: 16 buckets × 2312 bytes each = 36992 + // states_buffer needs 1024 elements × 4 bytes = 4096 + const size_t block_sizes[] = {36992, 36992, 5120, 5120, 4096}; + // Reduced: 8 buckets × 2312 bytes each = 18496 + const size_t reduced_block_sizes[] = {18496, 18496, 5120, 5120, 4096}; const int num_blocks = sizeof(block_sizes) / sizeof(block_sizes[0]); // Reset globals each nonce - eta_round_time = 44; - eta_total_time = 705; + eta_round_time = 30; + eta_total_time = 481; MSB_LIMIT = 16; // Use half speed (reduced block sizes) for static encrypted nonces so we can buffer keys @@ -720,7 +269,7 @@ bool recover(MfClassicNonce* n, int ks2, unsigned int in, ProgramState* program_ program_state->search = msb; program_state->eta_round = eta_round_time; program_state->eta_total = eta_total_time - (eta_round_time * msb); - if(calculate_msb_tables( + if(calculate_msb_tables_optimized( oks, eks, msb, @@ -732,8 +281,6 @@ bool recover(MfClassicNonce* n, int ks2, unsigned int in, ProgramState* program_ temp_states_even, in, program_state)) { - // int bench_stop = furi_hal_rtc_get_timestamp(); - // FURI_LOG_I(TAG, "Cracked in %i seconds", bench_stop - bench_start); found = true; break; } @@ -810,7 +357,6 @@ void mfkey(ProgramState* program_state) { } uint32_t i = 0, j = 0; - // FURI_LOG_I(TAG, "Free heap before alloc(): %zub", memmgr_get_free_heap()); Storage* storage = furi_record_open(RECORD_STORAGE); FlipperApplication* app = flipper_application_alloc(storage, firmware_api_interface); flipper_application_preload(app, APP_ASSETS_PATH("plugins/mfkey_init_plugin.fal")); @@ -873,7 +419,6 @@ void mfkey(ProgramState* program_state) { // TODO: Already closed? buffered_file_stream_close(nonce_arr->stream); stream_free(nonce_arr->stream); - // FURI_LOG_I(TAG, "Free heap after free(): %zub", memmgr_get_free_heap()); program_state->mfkey_state = MFKeyAttack; // TODO: Work backwards on this array and free memory for(i = 0; i < nonce_arr->total_nonces; i++) { @@ -884,7 +429,6 @@ void mfkey(ProgramState* program_state) { (program_state->num_completed)++; continue; } - // FURI_LOG_I(TAG, "Beginning recovery for %8lx", next_nonce.uid); FuriString* cuid_dict_path; switch(next_nonce.attack) { case mfkey32: @@ -961,9 +505,7 @@ void mfkey(ProgramState* program_state) { } // TODO: Update display to show all keys were found // TODO: Prepend found key(s) to user dictionary file - // FURI_LOG_I(TAG, "Unique keys found:"); for(i = 0; i < keyarray_size; i++) { - // FURI_LOG_I(TAG, "%012" PRIx64, keyarray[i]); keys_dict_add_key(user_dict, keyarray[i].data, sizeof(MfClassicKey)); } if(keyarray_size > 0) { @@ -975,7 +517,6 @@ void mfkey(ProgramState* program_state) { if(program_state->mfkey_state == Error) { return; } - // FURI_LOG_I(TAG, "mfkey function completed normally"); // DEBUG program_state->mfkey_state = Complete; // No need to alert the user if they asked it to stop if(!(program_state->close_thread_please)) { @@ -1124,7 +665,7 @@ int32_t mfkey_main() { gui_add_view_port(gui, view_port, GuiLayerFullscreen); program_state->mfkeythread = - furi_thread_alloc_ex("MFKeyWorker", 2048, mfkey_worker_thread, program_state); + furi_thread_alloc_ex("MFKeyWorker", 4096, mfkey_worker_thread, program_state); InputEvent input_event; for(bool main_loop = true; main_loop;) { diff --git a/applications/system/mfkey/mfkey.h b/applications/system/mfkey/mfkey.h index 0e5ff01dd..c01d3a989 100644 --- a/applications/system/mfkey/mfkey.h +++ b/applications/system/mfkey/mfkey.h @@ -12,9 +12,14 @@ struct Crypto1State { uint32_t odd, even; }; + +#define MSB_BUCKET_CAPACITY 768 + struct Msb { int tail; - uint32_t states[768]; + // Store 24-bit states packed into bytes (MSB is implicit from bucket index). + // CAPACITY * 3 bytes for data + 4 bytes padding for safe unaligned 32-bit write. + uint8_t states[MSB_BUCKET_CAPACITY * 3 + 4]; }; typedef enum { diff --git a/applications/system/mfkey/mfkey_attack.c b/applications/system/mfkey/mfkey_attack.c new file mode 100644 index 000000000..2fd1257f3 --- /dev/null +++ b/applications/system/mfkey/mfkey_attack.c @@ -0,0 +1,287 @@ +#pragma GCC optimize("O3") + +#include +#include + +#include +#include "mfkey_attack.h" + +#include "crypto1.h" +#include "mfkey_bs_verify.h" +#include "mfkey_dedup.h" +#include "mfkey_state_expansion.h" +#include "mfkey_recovery.h" +#include "mfkey_batch_prelude.h" + +volatile bool g_abort_attack = false; +ProgramState* g_program_state = NULL; // For static_encrypted key buffering + +extern int sync_state(ProgramState* program_state); +extern void flush_key_buffer(ProgramState* program_state); +extern uint8_t MSB_LIMIT; + +#define SWAP(a, b) \ + do { \ + unsigned int t = a; \ + a = b; \ + b = t; \ + } while(0) + +// Forces x into a register, preventing the compiler from hoisting BIT(x, n) +// extractions out of loops and spilling all 16 keystream bits to stack. +#define OPT_BARRIER(x) __asm__ volatile("" : "+r"(x)) + +// Precomputed Round 4 lane survival masks, indexed by [shared_value][target_bit]. +// Each 16-bit half covers one half-batch (lo/hi). + +static const uint16_t R4_LANE_MASK[8][2] = { + /* shared=0 */ {0xFFFF, 0x26C7}, + /* shared=1 */ {0xD938, 0x26C7}, + /* shared=2 */ {0xFFFF, 0xFFFF}, + /* shared=3 */ {0x26C7, 0xFFFF}, + /* shared=4 */ {0xFFFF, 0x26C7}, + /* shared=5 */ {0x26C7, 0xD938}, + /* shared=6 */ {0x26C7, 0xFFFF}, + /* shared=7 */ {0x26C7, 0xD938}, +}; + +int calculate_msb_tables_optimized( + int oks, + int eks, + int msb_round, + MfClassicNonce* n, + unsigned int* states_buffer, + struct Msb* odd_msbs, + struct Msb* even_msbs, + unsigned int* temp_states_odd, + unsigned int* temp_states_even, + unsigned int in, + ProgramState* program_state) { + // Set global state for hot-path functions (avoids passing through recursion) + g_program_state = program_state; + g_abort_attack = false; + + unsigned int msb_head = (MSB_LIMIT * msb_round); + unsigned int msb_tail = (MSB_LIMIT * (msb_round + 1)); + + int states_tail = 0; + unsigned int msb = 0; + + // Preprocessed in value + in = ((in >> 16 & 0xff) | (in << 16) | (in & 0xff00)) << 1; + + // Clear MSB arrays + memset(odd_msbs, 0, MSB_LIMIT * sizeof(struct Msb)); + memset(even_msbs, 0, MSB_LIMIT * sizeof(struct Msb)); + +// Identity mask deduplication +#define DISABLE_IDENTITY_FILTER 0 +#if !DISABLE_IDENTITY_FILTER + // Use the idle temp_states buffers as scratch space for bitmask filters. + // Each filter needs (MSB_LIMIT * 64) = 1024 uint32_t entries = 4096 bytes + // temp_states_odd/even are each 1280 elements, so we split them: + uint32_t* odd_msb_filters = (uint32_t*)temp_states_odd; + uint32_t* even_msb_filters = (uint32_t*)temp_states_even; + memset(temp_states_odd, 0, 1024 * sizeof(unsigned int)); + memset(temp_states_even, 0, 1024 * sizeof(unsigned int)); +#endif + + // Iterate in batches of 32 (batch_base has bits 0-4 = 0) + for(int batch_base = (1 << 20) & ~31; batch_base >= 0; batch_base -= 32) { + // Prevent compiler from hoisting BIT(oks/eks, N) extractions out of loop + OPT_BARRIER(oks); + OPT_BARRIER(eks); + + // Periodic sync check (every 2048 batches = 65536 semi-states) + if((batch_base & 0xFFE0) == 0) { + if(sync_state(program_state) == 1) { + return 0; + } + } + + // R4 Lane Mask: precompute full 32-bit masks for both streams + // shared_lo/hi, BIT(oks,4), BIT(eks,4) are all constant per batch, + // so the entire R4 mask is batch-invariant. Precompute once here to + // avoid 2 Flash table reads + address arithmetic per inner-loop hit. + uint32_t nib_bit_r4 = (0x0d938 >> ((batch_base >> 12) & 0xF)) & 1; + uint32_t l2_base_r4 = (batch_base >> 4) & 0xFE; + uint32_t shared_lo_r4 = lookup2[l2_base_r4] | nib_bit_r4; + uint32_t shared_hi_r4 = lookup2[l2_base_r4 | 1] | nib_bit_r4; + uint32_t r4_mask_oks = (uint32_t)R4_LANE_MASK[shared_lo_r4][BIT(oks, 4)] | + ((uint32_t)R4_LANE_MASK[shared_hi_r4][BIT(oks, 4)] << 16); + uint32_t r4_mask_eks = (uint32_t)R4_LANE_MASK[shared_lo_r4][BIT(eks, 4)] | + ((uint32_t)R4_LANE_MASK[shared_hi_r4][BIT(eks, 4)] << 16); + + // OKS processing + uint32_t oks_leaf_masks[8]; + uint32_t valid_oks = batch_prelude_unified(batch_base, oks, r4_mask_oks, oks_leaf_masks); + + if(valid_oks) { + uint32_t node_base = (batch_base << 3); + uint32_t active = valid_oks; + while(active) { + int lane = __builtin_ctz(active); + active &= active - 1; + + uint32_t lane_bit = 1u << lane; + uint32_t base_state = node_base | (lane << 3); + int count = 0; + for(int c = 0; c < 8; c++) + if(oks_leaf_masks[c] & lane_bit) states_buffer[count++] = base_state | c; + + if(count > 0) { + states_tail = + state_loop_r4(states_buffer, count, oks, CONST_M1_1, CONST_M2_1, 0, 0); + + // Bucket Insertion + for(int i = states_tail; i >= 0; i--) { + msb = states_buffer[i] >> 24; + if((msb >= msb_head) && (msb < msb_tail)) { + int msb_idx = msb - msb_head; + uint32_t state = states_buffer[i]; + +#if DISABLE_IDENTITY_FILTER + if(odd_msbs[msb_idx].tail < MSB_BUCKET_CAPACITY) { + int tail = odd_msbs[msb_idx].tail++; + memcpy(&odd_msbs[msb_idx].states[tail * 3], &state, 3); + } +#else + uint32_t fingerprint = FIB_HASH_20BIT(state); + uint32_t filter_idx = (msb_idx << 6) | (fingerprint >> 5); + uint32_t mask = 1U << (fingerprint & 31); + + bool already_exists = false; + if(odd_msb_filters[filter_idx] & mask) { + already_exists = scan_for_duplicate_8x( + odd_msbs[msb_idx].states, + odd_msbs[msb_idx].tail, + state & 0x00FFFFFF); + } + + if(!already_exists && odd_msbs[msb_idx].tail < MSB_BUCKET_CAPACITY) { + odd_msb_filters[filter_idx] |= mask; + int tail = odd_msbs[msb_idx].tail++; + memcpy(&odd_msbs[msb_idx].states[tail * 3], &state, 3); + } +#endif + } + } + } + } + } + + // EKS processing + uint32_t eks_leaf_masks[8]; + uint32_t valid_eks = batch_prelude_unified(batch_base, eks, r4_mask_eks, eks_leaf_masks); + + if(valid_eks) { + uint32_t node_base = (batch_base << 3); + uint32_t active = valid_eks; + while(active) { + int lane = __builtin_ctz(active); + active &= active - 1; + + uint32_t lane_bit = 1u << lane; + uint32_t base_state = node_base | (lane << 3); + int count = 0; + for(int c = 0; c < 8; c++) + if(eks_leaf_masks[c] & lane_bit) states_buffer[count++] = base_state | c; + + if(count > 0) { + states_tail = + state_loop_r4(states_buffer, count, eks, CONST_M1_2, CONST_M2_2, in, 3); + + // Bucket Insertion + for(int i = 0; i <= states_tail; i++) { + msb = states_buffer[i] >> 24; + if((msb >= msb_head) && (msb < msb_tail)) { + int msb_idx = msb - msb_head; + uint32_t state = states_buffer[i]; + +#if DISABLE_IDENTITY_FILTER + if(even_msbs[msb_idx].tail < MSB_BUCKET_CAPACITY) { + int tail = even_msbs[msb_idx].tail++; + memcpy(&even_msbs[msb_idx].states[tail * 3], &state, 3); + } +#else + uint32_t fingerprint = FIB_HASH_20BIT(state); + uint32_t filter_idx = (msb_idx << 6) | (fingerprint >> 5); + uint32_t mask = 1U << (fingerprint & 31); + + bool already_exists = false; + if(even_msb_filters[filter_idx] & mask) { + already_exists = scan_for_duplicate_8x( + even_msbs[msb_idx].states, + even_msbs[msb_idx].tail, + state & 0x00FFFFFF); + } + + if(!already_exists && even_msbs[msb_idx].tail < MSB_BUCKET_CAPACITY) { + even_msb_filters[filter_idx] |= mask; + int tail = even_msbs[msb_idx].tail++; + memcpy(&even_msbs[msb_idx].states[tail * 3], &state, 3); + } +#endif + } + } + } + } + } + } + + // Shift keystream for old_recover + oks >>= 12; + eks >>= 12; + + // Verification phase + for(int i = 0; i < MSB_LIMIT; i++) { + if((i % 4) == 0) { + if(sync_state(program_state) == 1) { + g_abort_attack = true; + return 0; + } + } + + // Only process MSB buckets with candidates on both sides + if(odd_msbs[i].tail > 0 && even_msbs[i].tail > 0) { + uint32_t current_msb_val = (uint32_t)(msb_head + i) << 24; + + for(int k = 0; k < odd_msbs[i].tail; k++) { + uint32_t raw = 0; + memcpy(&raw, &odd_msbs[i].states[k * 3], 3); + temp_states_odd[k] = raw | current_msb_val; + } + + for(int k = 0; k < even_msbs[i].tail; k++) { + uint32_t raw = 0; + memcpy(&raw, &even_msbs[i].states[k * 3], 3); + temp_states_even[k] = raw | current_msb_val; + } + + // Bitsliced verification for all attack types (mfkey32, static_nested, + // static_encrypted). Each type uses its own 32-way SWAR kernel. + int res = old_recover_bs( + temp_states_odd, + 0, + odd_msbs[i].tail - 1, + oks, + temp_states_even, + 0, + even_msbs[i].tail - 1, + eks, + 3, + 0, + n, + in >> 16, + 1); + + if(res == -1) { + return 1; // Key found + } else if(res == -2) { + return 0; // User aborted + } + } + } + + return 0; +} diff --git a/applications/system/mfkey/mfkey_attack.h b/applications/system/mfkey/mfkey_attack.h new file mode 100644 index 000000000..a6fbf5783 --- /dev/null +++ b/applications/system/mfkey/mfkey_attack.h @@ -0,0 +1,21 @@ +#ifndef MFKEY_ATTACK_H +#define MFKEY_ATTACK_H + +#include "mfkey.h" + +// Main MSB table calculation - runs attack for one MSB round +// Returns 1 if key found, 0 otherwise +int calculate_msb_tables_optimized( + int oks, + int eks, + int msb_round, + MfClassicNonce* n, + unsigned int* states_buffer, + struct Msb* odd_msbs, + struct Msb* even_msbs, + unsigned int* temp_states_odd, + unsigned int* temp_states_even, + unsigned int in, + ProgramState* program_state); + +#endif // MFKEY_ATTACK_H diff --git a/applications/system/mfkey/mfkey_batch_prelude.c b/applications/system/mfkey/mfkey_batch_prelude.c new file mode 100644 index 000000000..63b1290e4 --- /dev/null +++ b/applications/system/mfkey/mfkey_batch_prelude.c @@ -0,0 +1,707 @@ +// MFKey Batch Prelude - 32-lane parallel tree expansion through rounds 0-3 +// Extracted from mfkey_attack.c for better code organization + +#pragma GCC optimize("O3") + +#include "mfkey_batch_prelude.h" +#include "crypto1.h" +#include "mfkey_dedup.h" +#include + +// Precomputed filter LUTs for shared input values 0..7 +// Derived from 0xEC57E80A stride 8 (lookup2 outputs even values, nibble adds 0 or 1) +static const uint8_t FILTER_LUT_TABLE[8] = {0x4, 0x5, 0xC, 0xB, 0x4, 0xA, 0xE, 0xA}; + +// Super-LUT: Combined bitmasks indexed by full LUT value (0-15) +// Eliminates conditional branches - single indexed load per round +// Total: 2KB (8×16 + 4×2×16 + 2×4×16 + 8×16 = 512 uint32_t) + +// Round 0: 8 offsets × 16 LUT values (regenerated from filter() brute-force) +static const uint32_t R0_COMBINED[8][16] = { + { + 0x00000000, + 0x0DD30DD3, + 0x00000000, + 0x0DD30DD3, + 0xF22CF22C, + 0xFFFFFFFF, + 0xF22CF22C, + 0xFFFFFFFF, + 0x00000000, + 0x0DD30DD3, + 0x00000000, + 0x0DD30DD3, + 0xF22CF22C, + 0xFFFFFFFF, + 0xF22CF22C, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x00000DD3, + 0x0DD30000, + 0x0DD30DD3, + 0x0000F22C, + 0x0000FFFF, + 0x0DD3F22C, + 0x0DD3FFFF, + 0xF22C0000, + 0xF22C0DD3, + 0xFFFF0000, + 0xFFFF0DD3, + 0xF22CF22C, + 0xF22CFFFF, + 0xFFFFF22C, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x00000000, + 0x0DD30DD3, + 0x0DD30DD3, + 0x00000000, + 0x00000000, + 0x0DD30DD3, + 0x0DD30DD3, + 0xF22CF22C, + 0xF22CF22C, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xF22CF22C, + 0xF22CF22C, + 0xFFFFFFFF, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x0DD30DD3, + 0x00000000, + 0x0DD30DD3, + 0xF22CF22C, + 0xFFFFFFFF, + 0xF22CF22C, + 0xFFFFFFFF, + 0x00000000, + 0x0DD30DD3, + 0x00000000, + 0x0DD30DD3, + 0xF22CF22C, + 0xFFFFFFFF, + 0xF22CF22C, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x0DD30000, + 0x00000DD3, + 0x0DD30DD3, + 0xF22C0000, + 0xFFFF0000, + 0xF22C0DD3, + 0xFFFF0DD3, + 0x0000F22C, + 0x0DD3F22C, + 0x0000FFFF, + 0x0DD3FFFF, + 0xF22CF22C, + 0xFFFFF22C, + 0xF22CFFFF, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x00000DD3, + 0x0DD30000, + 0x0DD30DD3, + 0x0000F22C, + 0x0000FFFF, + 0x0DD3F22C, + 0x0DD3FFFF, + 0xF22C0000, + 0xF22C0DD3, + 0xFFFF0000, + 0xFFFF0DD3, + 0xF22CF22C, + 0xF22CFFFF, + 0xFFFFF22C, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x0DD30000, + 0x00000DD3, + 0x0DD30DD3, + 0xF22C0000, + 0xFFFF0000, + 0xF22C0DD3, + 0xFFFF0DD3, + 0x0000F22C, + 0x0DD3F22C, + 0x0000FFFF, + 0x0DD3FFFF, + 0xF22CF22C, + 0xFFFFF22C, + 0xF22CFFFF, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x00000000, + 0x0DD30DD3, + 0x0DD30DD3, + 0x00000000, + 0x00000000, + 0x0DD30DD3, + 0x0DD30DD3, + 0xF22CF22C, + 0xF22CF22C, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xF22CF22C, + 0xF22CF22C, + 0xFFFFFFFF, + 0xFFFFFFFF, + }, +}; + +// Round 1: 4 offsets × 2 children × 16 LUT values (regenerated from filter() brute-force) +static const uint32_t R1_COMBINED[4][2][16] = { + { + { + 0x00000000, + 0x003D3D3D, + 0x3D000000, + 0x3D3D3D3D, + 0x00C2C2C2, + 0x00FFFFFF, + 0x3DC2C2C2, + 0x3DFFFFFF, + 0xC2000000, + 0xC23D3D3D, + 0xFF000000, + 0xFF3D3D3D, + 0xC2C2C2C2, + 0xC2FFFFFF, + 0xFFC2C2C2, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x00292929, + 0x29000000, + 0x29292929, + 0x00D6D6D6, + 0x00FFFFFF, + 0x29D6D6D6, + 0x29FFFFFF, + 0xD6000000, + 0xD6292929, + 0xFF000000, + 0xFF292929, + 0xD6D6D6D6, + 0xD6FFFFFF, + 0xFFD6D6D6, + 0xFFFFFFFF, + }, + }, + { + { + 0x00000000, + 0x3D3D0000, + 0x00003D3D, + 0x3D3D3D3D, + 0xC2C20000, + 0xFFFF0000, + 0xC2C23D3D, + 0xFFFF3D3D, + 0x0000C2C2, + 0x3D3DC2C2, + 0x0000FFFF, + 0x3D3DFFFF, + 0xC2C2C2C2, + 0xFFFFC2C2, + 0xC2C2FFFF, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x29290000, + 0x00002929, + 0x29292929, + 0xD6D60000, + 0xFFFF0000, + 0xD6D62929, + 0xFFFF2929, + 0x0000D6D6, + 0x2929D6D6, + 0x0000FFFF, + 0x2929FFFF, + 0xD6D6D6D6, + 0xFFFFD6D6, + 0xD6D6FFFF, + 0xFFFFFFFF, + }, + }, + { + { + 0x00000000, + 0x003D3D00, + 0x3D00003D, + 0x3D3D3D3D, + 0x00C2C200, + 0x00FFFF00, + 0x3DC2C23D, + 0x3DFFFF3D, + 0xC20000C2, + 0xC23D3DC2, + 0xFF0000FF, + 0xFF3D3DFF, + 0xC2C2C2C2, + 0xC2FFFFC2, + 0xFFC2C2FF, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x00292900, + 0x29000029, + 0x29292929, + 0x00D6D600, + 0x00FFFF00, + 0x29D6D629, + 0x29FFFF29, + 0xD60000D6, + 0xD62929D6, + 0xFF0000FF, + 0xFF2929FF, + 0xD6D6D6D6, + 0xD6FFFFD6, + 0xFFD6D6FF, + 0xFFFFFFFF, + }, + }, + { + { + 0x00000000, + 0x00003D00, + 0x3D3D003D, + 0x3D3D3D3D, + 0x0000C200, + 0x0000FF00, + 0x3D3DC23D, + 0x3D3DFF3D, + 0xC2C200C2, + 0xC2C23DC2, + 0xFFFF00FF, + 0xFFFF3DFF, + 0xC2C2C2C2, + 0xC2C2FFC2, + 0xFFFFC2FF, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x00002900, + 0x29290029, + 0x29292929, + 0x0000D600, + 0x0000FF00, + 0x2929D629, + 0x2929FF29, + 0xD6D600D6, + 0xD6D629D6, + 0xFFFF00FF, + 0xFFFF29FF, + 0xD6D6D6D6, + 0xD6D6FFD6, + 0xFFFFD6FF, + 0xFFFFFFFF, + }, + }, +}; + +// Round 2: 2 offsets × 4 children × 16 LUT values (regenerated from filter() brute-force) +static const uint32_t R2_COMBINED[2][4][16] = { + { + { + 0x00000000, + 0x77000777, + 0x00777000, + 0x77777777, + 0x88000888, + 0xFF000FFF, + 0x88777888, + 0xFF777FFF, + 0x00888000, + 0x77888777, + 0x00FFF000, + 0x77FFF777, + 0x88888888, + 0xFF888FFF, + 0x88FFF888, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x11000111, + 0x00111000, + 0x11111111, + 0xEE000EEE, + 0xFF000FFF, + 0xEE111EEE, + 0xFF111FFF, + 0x00EEE000, + 0x11EEE111, + 0x00FFF000, + 0x11FFF111, + 0xEEEEEEEE, + 0xFFEEEFFF, + 0xEEFFFEEE, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x66000666, + 0x00666000, + 0x66666666, + 0x99000999, + 0xFF000FFF, + 0x99666999, + 0xFF666FFF, + 0x00999000, + 0x66999666, + 0x00FFF000, + 0x66FFF666, + 0x99999999, + 0xFF999FFF, + 0x99FFF999, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x66000666, + 0x00666000, + 0x66666666, + 0x99000999, + 0xFF000FFF, + 0x99666999, + 0xFF666FFF, + 0x00999000, + 0x66999666, + 0x00FFF000, + 0x66FFF666, + 0x99999999, + 0xFF999FFF, + 0x99FFF999, + 0xFFFFFFFF, + }, + }, + { + { + 0x00000000, + 0x00700770, + 0x77077007, + 0x77777777, + 0x00800880, + 0x00F00FF0, + 0x77877887, + 0x77F77FF7, + 0x88088008, + 0x88788778, + 0xFF0FF00F, + 0xFF7FF77F, + 0x88888888, + 0x88F88FF8, + 0xFF8FF88F, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x00100110, + 0x11011001, + 0x11111111, + 0x00E00EE0, + 0x00F00FF0, + 0x11E11EE1, + 0x11F11FF1, + 0xEE0EE00E, + 0xEE1EE11E, + 0xFF0FF00F, + 0xFF1FF11F, + 0xEEEEEEEE, + 0xEEFEEFFE, + 0xFFEFFEEF, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x00600660, + 0x66066006, + 0x66666666, + 0x00900990, + 0x00F00FF0, + 0x66966996, + 0x66F66FF6, + 0x99099009, + 0x99699669, + 0xFF0FF00F, + 0xFF6FF66F, + 0x99999999, + 0x99F99FF9, + 0xFF9FF99F, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x00600660, + 0x66066006, + 0x66666666, + 0x00900990, + 0x00F00FF0, + 0x66966996, + 0x66F66FF6, + 0x99099009, + 0x99699669, + 0xFF0FF00F, + 0xFF6FF66F, + 0x99999999, + 0x99F99FF9, + 0xFF9FF99F, + 0xFFFFFFFF, + }, + }, +}; + +// Round 3: Individual child masks for target=1 — [child_idx][lut] +// child_idx c encodes R1-R2-R3 binary choices (b0*4 + b1*2 + b2) +// For target=0: use ~mask at runtime (complement) +// Replaces R3_PAIRED: same total size (512 bytes) +// Verification: R3_PAIRED[1][i][lut] == R3_INDIVIDUAL[2*i][lut] | R3_INDIVIDUAL[2*i+1][lut] +static const uint32_t R3_INDIVIDUAL[8][16] = { + { + 0x00000000, + 0x0C3CF03F, + 0xF3C30FC0, + 0xFFFFFFFF, + 0x00000000, + 0x0C3CF03F, + 0xF3C30FC0, + 0xFFFFFFFF, + 0x00000000, + 0x0C3CF03F, + 0xF3C30FC0, + 0xFFFFFFFF, + 0x00000000, + 0x0C3CF03F, + 0xF3C30FC0, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x04145015, + 0x51410540, + 0x55555555, + 0x0828A02A, + 0x0C3CF03F, + 0x5969A56A, + 0x5D7DF57F, + 0xA2820A80, + 0xA6965A95, + 0xF3C30FC0, + 0xF7D75FD5, + 0xAAAAAAAA, + 0xAEBEFABF, + 0xFBEBAFEA, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x0828A02A, + 0xA2820A80, + 0xAAAAAAAA, + 0x04145015, + 0x0C3CF03F, + 0xA6965A95, + 0xAEBEFABF, + 0x51410540, + 0x5969A56A, + 0xF3C30FC0, + 0xFBEBAFEA, + 0x55555555, + 0x5D7DF57F, + 0xF7D75FD5, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x0828A02A, + 0xA2820A80, + 0xAAAAAAAA, + 0x04145015, + 0x0C3CF03F, + 0xA6965A95, + 0xAEBEFABF, + 0x51410540, + 0x5969A56A, + 0xF3C30FC0, + 0xFBEBAFEA, + 0x55555555, + 0x5D7DF57F, + 0xF7D75FD5, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x04145015, + 0x51410540, + 0x55555555, + 0x0828A02A, + 0x0C3CF03F, + 0x5969A56A, + 0x5D7DF57F, + 0xA2820A80, + 0xA6965A95, + 0xF3C30FC0, + 0xF7D75FD5, + 0xAAAAAAAA, + 0xAEBEFABF, + 0xFBEBAFEA, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0C3CF03F, + 0x0C3CF03F, + 0x0C3CF03F, + 0x0C3CF03F, + 0xF3C30FC0, + 0xF3C30FC0, + 0xF3C30FC0, + 0xF3C30FC0, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x04145015, + 0x51410540, + 0x55555555, + 0x0828A02A, + 0x0C3CF03F, + 0x5969A56A, + 0x5D7DF57F, + 0xA2820A80, + 0xA6965A95, + 0xF3C30FC0, + 0xF7D75FD5, + 0xAAAAAAAA, + 0xAEBEFABF, + 0xFBEBAFEA, + 0xFFFFFFFF, + }, + { + 0x00000000, + 0x04145015, + 0x51410540, + 0x55555555, + 0x0828A02A, + 0x0C3CF03F, + 0x5969A56A, + 0x5D7DF57F, + 0xA2820A80, + 0xA6965A95, + 0xF3C30FC0, + 0xF7D75FD5, + 0xAAAAAAAA, + 0xAEBEFABF, + 0xFBEBAFEA, + 0xFFFFFFFF, + }, +}; + +// Combined prefilter + reconstruction in one pass. +// leaf_masks[c] (c=0..7) gives lanes where child c survives R0-R3+R4. +// Return value is OR of all 8 leaf_masks (= lane survival mask). +uint32_t + batch_prelude_unified(uint32_t batch_base, int oks, uint32_t r4_mask, uint32_t leaf_masks[8]) { + OPT_BARRIER(oks); + + // --- ROUND 0 --- + uint32_t idx_hi = (batch_base >> 8) & 0xFF; + uint32_t idx_nib = (batch_base >> 16) & 0xF; + uint32_t shared = lookup2[idx_hi] | ((0x0d938 >> idx_nib) & 1); + int lut = FILTER_LUT_TABLE[shared]; + uint32_t off0 = (batch_base >> 5) & 7; + + uint32_t valid = R0_COMBINED[off0][lut]; + if((oks & 1) == 0) valid = ~valid; + if(!valid) return 0; + + // --- ROUND 1 --- + int target = BIT(oks, 1); + uint32_t node_base = (batch_base << 1); + shared = lookup2[(node_base >> 8) & 0xFF] | ((0x0d938 >> ((node_base >> 16) & 0xF)) & 1); + lut = FILTER_LUT_TABLE[shared]; + uint32_t off1 = (batch_base >> 5) & 3; + + uint32_t p0 = R1_COMBINED[off1][0][lut]; + uint32_t p1 = R1_COMBINED[off1][1][lut]; + if(target == 0) { + p0 = ~p0; + p1 = ~p1; + } + p0 &= valid; + p1 &= valid; + if(!(p0 | p1)) return 0; + + // --- ROUND 2 --- + target = BIT(oks, 2); + node_base = (batch_base << 2); + shared = lookup2[(node_base >> 8) & 0xFF] | ((0x0d938 >> ((node_base >> 16) & 0xF)) & 1); + lut = FILTER_LUT_TABLE[shared]; + uint32_t off2 = (batch_base >> 5) & 1; + + uint32_t p00 = R2_COMBINED[off2][0][lut]; + uint32_t p01 = R2_COMBINED[off2][1][lut]; + uint32_t p10 = R2_COMBINED[off2][2][lut]; + uint32_t p11 = R2_COMBINED[off2][3][lut]; + if(target == 0) { + p00 = ~p00; + p01 = ~p01; + p10 = ~p10; + p11 = ~p11; + } + p00 &= p0; + p01 &= p0; + p10 &= p1; + p11 &= p1; + if(!(p00 | p01 | p10 | p11)) return 0; + + // --- ROUND 3 (individual child masks) --- + node_base = (batch_base << 3); + shared = lookup2[(node_base >> 8) & 0xFF] | ((0x0d938 >> ((node_base >> 16) & 0xF)) & 1); + lut = FILTER_LUT_TABLE[shared]; + + int target3 = BIT(oks, 3); + + // Load 8 individual child masks, apply target complement, AND with parent + r4_mask + // Child c: parent is p[c>>2][c&2 ? 1 : 0] → parent index from R1 bit (c>>2) and R2 bit ((c>>1)&1) + // Parent mapping: c=0,1→p00 c=2,3→p01 c=4,5→p10 c=6,7→p11 + const uint32_t parents[4] = {p00, p01, p10, p11}; + uint32_t all = 0; + for(int c = 0; c < 8; c++) { + uint32_t m = R3_INDIVIDUAL[c][lut]; + if(target3 == 0) m = ~m; + m &= parents[c >> 1]; + m &= r4_mask; + leaf_masks[c] = m; + all |= m; + } + + return all; +} diff --git a/applications/system/mfkey/mfkey_batch_prelude.h b/applications/system/mfkey/mfkey_batch_prelude.h new file mode 100644 index 000000000..7e113bc04 --- /dev/null +++ b/applications/system/mfkey/mfkey_batch_prelude.h @@ -0,0 +1,12 @@ +#ifndef MFKEY_BATCH_PRELUDE_H +#define MFKEY_BATCH_PRELUDE_H + +#include +#include "mfkey.h" + +// Returns lane survival mask AND per-child leaf masks. +// leaf_masks[c] (c=0..7) gives lanes where child c survives R0-R3+R4. +uint32_t + batch_prelude_unified(uint32_t batch_base, int oks, uint32_t r4_mask, uint32_t leaf_masks[8]); + +#endif // MFKEY_BATCH_PRELUDE_H diff --git a/applications/system/mfkey/mfkey_bs_verify.c b/applications/system/mfkey/mfkey_bs_verify.c new file mode 100644 index 000000000..6f312ba0f --- /dev/null +++ b/applications/system/mfkey/mfkey_bs_verify.c @@ -0,0 +1,530 @@ +// 32-way SWAR (SIMD Within A Register) verification of candidate LFSR states. +// Each bit position in a uint32_t represents one of 32 parallel lanes. + +#pragma GCC optimize("O3") + +#include "mfkey_bs_verify.h" +#include "crypto1.h" +#include + +// VFP register parking: use the M4F's 32 FPU registers (s0-s31) to stash +// slow-changing values during filter execution, freeing GP registers. + +#if defined(__arm__) && defined(__ARM_FP) +#define VFP_PARK(var, slot) \ + float slot; \ + __asm__ volatile("vmov %0, %1" : "=t"(slot) : "r"(var)) +#define VFP_UNPARK(var, slot) __asm__ volatile("vmov %0, %1" : "=r"(var) : "t"(slot)) +#else +#define VFP_PARK(var, slot) uint32_t slot = (var) +#define VFP_UNPARK(var, slot) (var) = (slot) +#endif + +// Bit-sliced filter function (minimized sum-of-products form) + +static inline __attribute__((always_inline)) uint32_t + crypto1_lut_a(uint32_t d, uint32_t c, uint32_t b, uint32_t a) { + return (c & d) | (a & c & ~b) | (a & d & ~b) | (b & ~c & ~d); +} + +static inline __attribute__((always_inline)) uint32_t + crypto1_lut_b(uint32_t d, uint32_t c, uint32_t b, uint32_t a) { + return (b & c & d) | (a & b & ~c) | (c & ~b & ~d) | (d & ~a & ~b); +} + +static inline __attribute__((always_inline)) uint32_t + crypto1_bs_filter(const uint32_t* odd, uint32_t head) { + const uint32_t* p = odd + head; + uint32_t f4 = crypto1_lut_a(p[3], p[2], p[1], p[0]); + uint32_t f3 = crypto1_lut_b(p[7], p[6], p[5], p[4]); + uint32_t f2 = crypto1_lut_a(p[11], p[10], p[9], p[8]); + uint32_t f1 = crypto1_lut_a(p[15], p[14], p[13], p[12]); + uint32_t f0 = crypto1_lut_b(p[19], p[18], p[17], p[16]); + + uint32_t f32 = f3 & f2; + uint32_t res = (f32 & (f0 | f1)); + res |= (f4 & ((f1 & f3) | ~(f0 | f3))); + res |= (f0 & ~f2 & ((f1 & ~f4) | ~(f1 | f3))); + return res; +} + +// LFSR polynomial tap XOR functions + +static inline __attribute__((always_inline)) uint32_t + crypto1_bs_xor_taps_odd(const uint32_t* reg, uint32_t head) { + const uint32_t* p = reg + head; + uint32_t acc0 = p[2] ^ p[3] ^ p[4]; + uint32_t acc1 = p[6] ^ p[9] ^ p[10]; + uint32_t acc2 = p[11] ^ p[14] ^ p[15]; + uint32_t acc3 = p[16] ^ p[19] ^ p[21]; + return acc0 ^ acc1 ^ acc2 ^ acc3; +} + +static inline __attribute__((always_inline)) uint32_t + crypto1_bs_xor_taps_even(const uint32_t* reg, uint32_t head) { + const uint32_t* p = reg + head; + uint32_t acc0 = p[2] ^ p[11] ^ p[16]; + uint32_t acc1 = p[17] ^ p[18] ^ p[23]; + return acc0 ^ acc1; +} + +static inline __attribute__((always_inline)) uint32_t + poly_even_rollback_xor(const uint32_t* even, uint32_t head) { + const uint32_t* p = even + head; + return p[2] ^ p[11] ^ p[16] ^ p[17] ^ p[18]; +} + +// 32x32 SWAR butterfly transpose + +static void transpose_32x32(uint32_t* d) { + uint32_t t, r0, r1, r2, r3, r4, r5, r6, r7; + + // Step 1: 16x16 blocks + for(int i = 0; i < 16; i++) { + t = (d[i] >> 16 ^ d[i + 16]) & 0x0000FFFF; + d[i] ^= t << 16; + d[i + 16] ^= t; + } + + // Step 2: 8x8 blocks + for(int i = 0; i < 32; i += 16) { + for(int j = 0; j < 8; j++) { + t = (d[i + j] >> 8 ^ d[i + j + 8]) & 0x00FF00FF; + d[i + j] ^= t << 8; + d[i + j + 8] ^= t; + } + } + + // Steps 3-5: Process in 8-row blocks entirely in registers + for(int b = 0; b < 32; b += 8) { + r0 = d[b + 0]; + r1 = d[b + 1]; + r2 = d[b + 2]; + r3 = d[b + 3]; + r4 = d[b + 4]; + r5 = d[b + 5]; + r6 = d[b + 6]; + r7 = d[b + 7]; + + // Step 3: 4x4 blocks + t = (r0 >> 4 ^ r4) & 0x0F0F0F0F; + r0 ^= t << 4; + r4 ^= t; + t = (r1 >> 4 ^ r5) & 0x0F0F0F0F; + r1 ^= t << 4; + r5 ^= t; + t = (r2 >> 4 ^ r6) & 0x0F0F0F0F; + r2 ^= t << 4; + r6 ^= t; + t = (r3 >> 4 ^ r7) & 0x0F0F0F0F; + r3 ^= t << 4; + r7 ^= t; + + // Step 4: 2x2 blocks + t = (r0 >> 2 ^ r2) & 0x33333333; + r0 ^= t << 2; + r2 ^= t; + t = (r1 >> 2 ^ r3) & 0x33333333; + r1 ^= t << 2; + r3 ^= t; + t = (r4 >> 2 ^ r6) & 0x33333333; + r4 ^= t << 2; + r6 ^= t; + t = (r5 >> 2 ^ r7) & 0x33333333; + r5 ^= t << 2; + r7 ^= t; + + // Step 5: 1x1 blocks + t = (r0 >> 1 ^ r1) & 0x55555555; + r0 ^= t << 1; + r1 ^= t; + t = (r2 >> 1 ^ r3) & 0x55555555; + r2 ^= t << 1; + r3 ^= t; + t = (r4 >> 1 ^ r5) & 0x55555555; + r4 ^= t << 1; + r5 ^= t; + t = (r6 >> 1 ^ r7) & 0x55555555; + r6 ^= t << 1; + r7 ^= t; + + d[b + 0] = r0; + d[b + 1] = r1; + d[b + 2] = r2; + d[b + 3] = r3; + d[b + 4] = r4; + d[b + 5] = r5; + d[b + 6] = r6; + d[b + 7] = r7; + } +} + +void bs_init_from_candidates(Crypto1BitSlice* bs, const BsCandidateBatch* batch) { + bs->odd_head = 0; + bs->even_head = 0; + + uint32_t temp_odd[32]; + uint32_t temp_even[32]; + + int count = batch->count; + if(count >= 32) { + memcpy(temp_odd, batch->odd, 32 * sizeof(uint32_t)); + memcpy(temp_even, batch->even, 32 * sizeof(uint32_t)); + } else { + memcpy(temp_odd, batch->odd, count * sizeof(uint32_t)); + memcpy(temp_even, batch->even, count * sizeof(uint32_t)); + memset(temp_odd + count, 0, (32 - count) * sizeof(uint32_t)); + memset(temp_even + count, 0, (32 - count) * sizeof(uint32_t)); + } + + transpose_32x32(temp_odd); + transpose_32x32(temp_even); + + for(int i = 0; i < 24; i++) { + bs->odd[i] = temp_odd[i]; + bs->odd[i + 24] = temp_odd[i]; + bs->even[i] = temp_even[i]; + bs->even[i + 24] = temp_even[i]; + } +} + +// Rollback without keystream collection +static inline __attribute__((always_inline)) void + bs_rollback_word_noret(Crypto1BitSlice* bs, uint32_t in, uint32_t fb_mask) { + uint32_t* odd_ptr = bs->odd; + uint32_t* even_ptr = bs->even; + uint32_t oh = bs->odd_head; + uint32_t eh = bs->even_head; + + // Process first 16 bits (i = 31..16) + for(int i = 31; i >= 16; i--) { + uint32_t* tmp_ptr = odd_ptr; + odd_ptr = even_ptr; + even_ptr = tmp_ptr; + + uint32_t tmp_head = oh; + oh = eh; + eh = tmp_head; + + int bit_pos = 24 ^ i; // Crypto1 big-endian bit ordering + uint32_t in_bits = ((in >> bit_pos) & 1) ? 0xFFFFFFFF : 0; // Broadcast bit to all 32 lanes + + uint32_t extracted = even_ptr[eh]; + VFP_PARK(extracted, _vfp_extracted); + + uint32_t ks = crypto1_bs_filter(odd_ptr, oh); + VFP_UNPARK(extracted, _vfp_extracted); + uint32_t new_eh = eh + 1; + + uint32_t recovered_msb = extracted; + recovered_msb ^= poly_even_rollback_xor(even_ptr, new_eh); + recovered_msb ^= crypto1_bs_xor_taps_odd(odd_ptr, oh); + recovered_msb ^= in_bits; + recovered_msb ^= (ks & fb_mask); + + even_ptr[new_eh + 23] = recovered_msb; + if(new_eh + 23 >= 24) even_ptr[new_eh + 23 - 24] = recovered_msb; + + eh = new_eh; + } + + // Intermediate normalization + if(oh >= 24) oh -= 24; + if(eh >= 24) eh -= 24; + + // Process remaining 16 bits (i = 15..0) + for(int i = 15; i >= 0; i--) { + uint32_t* tmp_ptr = odd_ptr; + odd_ptr = even_ptr; + even_ptr = tmp_ptr; + + uint32_t tmp_head = oh; + oh = eh; + eh = tmp_head; + + int bit_pos = 24 ^ i; + uint32_t in_bits = ((in >> bit_pos) & 1) ? 0xFFFFFFFF : 0; // Sign-extend bit without UB + + uint32_t extracted = even_ptr[eh]; + VFP_PARK(extracted, _vfp_extracted); + + uint32_t ks = crypto1_bs_filter(odd_ptr, oh); + VFP_UNPARK(extracted, _vfp_extracted); + uint32_t new_eh = eh + 1; + + uint32_t recovered_msb = extracted; + recovered_msb ^= poly_even_rollback_xor(even_ptr, new_eh); + recovered_msb ^= crypto1_bs_xor_taps_odd(odd_ptr, oh); + recovered_msb ^= in_bits; + recovered_msb ^= (ks & fb_mask); + + even_ptr[new_eh + 23] = recovered_msb; + if(new_eh + 23 >= 24) even_ptr[new_eh + 23 - 24] = recovered_msb; + + eh = new_eh; + } + + if(oh >= 24) oh -= 24; + if(eh >= 24) eh -= 24; + + bs->odd_head = oh; + bs->even_head = eh; +} + +static inline __attribute__((always_inline)) void + bs_crypt_word_noret(Crypto1BitSlice* bs, uint32_t in, uint32_t enc_mask) { + uint32_t* odd_ptr = bs->odd; + uint32_t* even_ptr = bs->even; + uint32_t oh = bs->odd_head; + uint32_t eh = bs->even_head; + + for(int i = 0; i < 32; i++) { + int bit_pos = 24 ^ i; + uint32_t in_bits = ((in >> bit_pos) & 1) ? 0xFFFFFFFF : 0; // Sign-extend bit without UB + + VFP_PARK(in_bits, _vfp_in_bits); + uint32_t ks = crypto1_bs_filter(odd_ptr, oh); + VFP_UNPARK(in_bits, _vfp_in_bits); + uint32_t feed = (ks & enc_mask) ^ in_bits; + feed ^= crypto1_bs_xor_taps_odd(odd_ptr, oh); + feed ^= crypto1_bs_xor_taps_even(even_ptr, eh); + + uint32_t new_eh = (eh == 0) ? 23 : (eh - 1); + + even_ptr[new_eh] = feed; + even_ptr[new_eh + 24] = feed; + eh = new_eh; + + uint32_t* tmp_ptr = odd_ptr; + odd_ptr = even_ptr; + even_ptr = tmp_ptr; + + uint32_t tmp_head = oh; + oh = eh; + eh = tmp_head; + } + + bs->odd_head = oh; + bs->even_head = eh; +} + +// Fused rollback + keystream comparison with byte-boundary early exit. +// fb_mask: 0 when keystream does not feed back into LFSR. + +static inline __attribute__((always_inline)) uint32_t bs_rollback_word_check_ks( + Crypto1BitSlice* bs, + uint32_t in, + uint32_t fb_mask, + uint32_t expected, + uint32_t alive) { + uint32_t* odd_ptr = bs->odd; + uint32_t* even_ptr = bs->even; + uint32_t oh = bs->odd_head; + uint32_t eh = bs->even_head; + + for(int i = 31; i >= 0; i--) { + uint32_t* tmp_ptr = odd_ptr; + odd_ptr = even_ptr; + even_ptr = tmp_ptr; + + uint32_t tmp_head = oh; + oh = eh; + eh = tmp_head; + + int bit_pos = 24 ^ i; + uint32_t in_bits = ((in >> bit_pos) & 1) ? 0xFFFFFFFF : 0; + + uint32_t extracted = even_ptr[eh]; + uint32_t new_eh = eh + 1; + + // Park values not needed during filter in VFP registers + VFP_PARK(alive, _vfp_alive); + VFP_PARK(extracted, _vfp_extracted); + VFP_PARK(new_eh, _vfp_new_eh); + + uint32_t ks = crypto1_bs_filter(odd_ptr, oh); + + // Restore from VFP + VFP_UNPARK(alive, _vfp_alive); + VFP_UNPARK(extracted, _vfp_extracted); + VFP_UNPARK(new_eh, _vfp_new_eh); + + // Compare keystream bit against expected + uint32_t exp_broadcast = ((expected >> bit_pos) & 1) ? 0xFFFFFFFF : 0; + alive &= ~(ks ^ exp_broadcast); + + // Rollback LFSR step + uint32_t recovered_msb = extracted; + recovered_msb ^= poly_even_rollback_xor(even_ptr, new_eh); + recovered_msb ^= crypto1_bs_xor_taps_odd(odd_ptr, oh); + recovered_msb ^= in_bits; + recovered_msb ^= (ks & fb_mask); + + even_ptr[new_eh + 23] = recovered_msb; + if(new_eh + 23 >= 24) even_ptr[new_eh + 23 - 24] = recovered_msb; + + eh = new_eh; + + // Early exit at byte boundaries + if((i & 7) == 0 && !alive) { + if(oh >= 24) oh -= 24; + if(eh >= 24) eh -= 24; + bs->odd_head = oh; + bs->even_head = eh; + return 0; + } + } + + if(oh >= 24) oh -= 24; + if(eh >= 24) eh -= 24; + bs->odd_head = oh; + bs->even_head = eh; + return alive; +} + +// Fused forward crypt + keystream comparison with byte-boundary early exit. +// enc_mask: 0 when keystream does not feed back into LFSR. + +static inline __attribute__((always_inline)) uint32_t bs_crypt_word_check_ks( + Crypto1BitSlice* bs, + uint32_t in, + uint32_t enc_mask, + uint32_t expected, + uint32_t alive) { + uint32_t* odd_ptr = bs->odd; + uint32_t* even_ptr = bs->even; + uint32_t oh = bs->odd_head; + uint32_t eh = bs->even_head; + + for(int i = 0; i < 32; i++) { + int bit_pos = 24 ^ i; + uint32_t in_bits = ((in >> bit_pos) & 1) ? 0xFFFFFFFF : 0; + + // Park alive in VFP during heavy filter computation + VFP_PARK(alive, _vfp_alive); + + uint32_t ks = crypto1_bs_filter(odd_ptr, oh); + + // Restore alive from VFP + VFP_UNPARK(alive, _vfp_alive); + + // Compare keystream bit against expected + uint32_t exp_broadcast = ((expected >> bit_pos) & 1) ? 0xFFFFFFFF : 0; + alive &= ~(ks ^ exp_broadcast); + + // LFSR advance + uint32_t feed = (ks & enc_mask) ^ in_bits; + feed ^= crypto1_bs_xor_taps_odd(odd_ptr, oh); + feed ^= crypto1_bs_xor_taps_even(even_ptr, eh); + + uint32_t new_eh = (eh == 0) ? 23 : (eh - 1); + even_ptr[new_eh] = feed; + even_ptr[new_eh + 24] = feed; + eh = new_eh; + + uint32_t* tmp_ptr = odd_ptr; + odd_ptr = even_ptr; + even_ptr = tmp_ptr; + uint32_t tmp_head = oh; + oh = eh; + eh = tmp_head; + + // Early exit at byte boundaries + if((i & 7) == 7 && !alive) { + bs->odd_head = oh; + bs->even_head = eh; + return 0; + } + } + + bs->odd_head = oh; + bs->even_head = eh; + return alive; +} + +// mfkey32 verification kernel +uint32_t bs_verify_batch_32(Crypto1BitSlice* bs, MfClassicNonce* nonce, uint32_t alive) { + // Checkpoint 1: rollback with keystream check + uint32_t expected1 = nonce->ar0_enc ^ nonce->p64; + alive = bs_rollback_word_check_ks(bs, 0, 0, expected1, alive); + if(!alive) return 0; + + // Intermediate rollback/crypt (no keystream check) + bs_rollback_word_noret(bs, nonce->nr0_enc, 0xFFFFFFFF); + bs_rollback_word_noret(bs, nonce->uid_xor_nt0, 0); + bs_crypt_word_noret(bs, nonce->uid_xor_nt1, 0); + bs_crypt_word_noret(bs, nonce->nr1_enc, 0xFFFFFFFF); + + // Checkpoint 2: forward crypt with keystream check + uint32_t expected2 = nonce->ar1_enc ^ nonce->p64b; + alive = bs_crypt_word_check_ks(bs, 0, 0, expected2, alive); + + return alive; +} + +void bs_extract_key(const BsCandidateBatch* batch, int lane, MfClassicNonce* nonce) { + struct Crypto1State t; + t.odd = batch->odd[lane]; + t.even = batch->even[lane]; + + if(nonce->attack == mfkey32) { + napi_lfsr_rollback_word(&t, 0, 0); + rollback_word_noret(&t, nonce->nr0_enc, 1); + rollback_word_noret(&t, nonce->uid_xor_nt0, 0); + } else if(nonce->attack == static_nested) { + rollback_word_noret(&t, nonce->uid_xor_nt1, 0); + } else { + napi_lfsr_rollback_word(&t, nonce->uid_xor_nt0, 0); + } + + crypto1_get_lfsr(&t, &nonce->key); +} + +// static_nested verification kernel +uint32_t bs_verify_batch_32_nested(Crypto1BitSlice* bs, MfClassicNonce* nonce, uint32_t alive) { + // Step 1: Rollback uid_xor_nt1 (fb=0) — no keystream check + bs_rollback_word_noret(bs, nonce->uid_xor_nt1, 0); + + // Step 2: Forward crypt uid_xor_nt0 (enc_mask=0) with keystream check + alive = bs_crypt_word_check_ks(bs, nonce->uid_xor_nt0, 0, nonce->ks1_1_enc, alive); + + return alive; +} + +// Scalar parity validation (cold path, typically 0-2 survivors) +static uint32_t validate_survivors_parity( + const BsCandidateBatch* batch, + MfClassicNonce* nonce, + uint32_t alive) { + uint32_t parity_valid = 0; + uint32_t remaining = alive; + while(remaining) { + int lane = __builtin_ctz(remaining); + remaining &= remaining - 1; + + struct Crypto1State t; + t.odd = batch->odd[lane]; + t.even = batch->even[lane]; + napi_lfsr_rollback_word(&t, nonce->uid_xor_nt0, 0); + + uint8_t pk; + struct Crypto1State temp = {t.odd, t.even}; + if((crypt_word_par(&temp, nonce->uid_xor_nt0, 0, nonce->nt0, &pk) == nonce->ks1_1_enc) && + (pk == nonce->par_1)) { + parity_valid |= (1U << lane); + } + } + return parity_valid; +} + +// static_encrypted verification kernel +// Hybrid: bitsliced keystream pruning + scalar parity on survivors. +uint32_t bs_verify_batch_32_encrypted( + Crypto1BitSlice* bs, + const BsCandidateBatch* batch, + MfClassicNonce* nonce, + uint32_t alive) { + alive = bs_rollback_word_check_ks(bs, nonce->uid_xor_nt0, 0, nonce->ks1_1_enc, alive); + if(!alive) return 0; + return validate_survivors_parity(batch, nonce, alive); +} diff --git a/applications/system/mfkey/mfkey_bs_verify.h b/applications/system/mfkey/mfkey_bs_verify.h new file mode 100644 index 000000000..2555626f0 --- /dev/null +++ b/applications/system/mfkey/mfkey_bs_verify.h @@ -0,0 +1,71 @@ +#ifndef MFKEY_BS_VERIFY_H +#define MFKEY_BS_VERIFY_H + +// Bit-sliced verification for all attack types (mfkey32, static_nested, +// static_encrypted). Processes 32 candidate LFSR states in parallel using +// SWAR (SIMD Within A Register) techniques. + +#include "mfkey.h" +#include +#include + +#define BS_BATCH_SIZE 32 + +typedef struct { + uint32_t odd[BS_BATCH_SIZE]; // Odd half-states (24-bit, lower bits used) + uint32_t even[BS_BATCH_SIZE]; // Even half-states (24-bit) + int count; // Current fill level (0-32) +} BsCandidateBatch; + +// Mirrored runway buffer: bits 0-23 mirrored to 24-47. +// Max read index: head (0-23) + max tap offset (23) = 46 < 48. +typedef struct { + uint32_t odd[48]; // 24 LFSR bits mirrored 2 times to avoid bounds checks + uint32_t even[48]; // Each element holds 32 bits (one per lane) + uint32_t odd_head; // Current head position (0-23 normalized) + uint32_t even_head; +} Crypto1BitSlice; + +// Initialize empty batch +static inline void bs_batch_init(BsCandidateBatch* batch) { + batch->count = 0; +} + +// Add candidate to batch +// Returns true if batch is now full (caller should verify and reset) +static inline bool bs_batch_add(BsCandidateBatch* batch, uint32_t odd, uint32_t even) { + if(batch->count < BS_BATCH_SIZE) { + batch->odd[batch->count] = odd; + batch->even[batch->count] = even; + batch->count++; + } + return batch->count >= BS_BATCH_SIZE; +} + +// Initialize bitsliced state from candidate batch (transpose scalar → SWAR) +// Call once before dispatching to any verification kernel +void bs_init_from_candidates(Crypto1BitSlice* bs, const BsCandidateBatch* batch); + +// Verify batch of up to 32 candidates against nonce data +// bs: pre-initialized bitsliced state (from bs_init_from_candidates) +// alive: lane mask with zero-states already rejected +// Returns bitmask where bit i is set if candidate i is valid +uint32_t bs_verify_batch_32(Crypto1BitSlice* bs, MfClassicNonce* nonce, uint32_t alive); + +// Extract key from valid lane (unified for all attack types) +// lane = __builtin_ctz(valid_mask) to get first valid lane +void bs_extract_key(const BsCandidateBatch* batch, int lane, MfClassicNonce* nonce); + +// Static nested verification: rollback uid_xor_nt1 → forward crypt uid_xor_nt0 +// Returns bitmask of valid lanes (first-match) +uint32_t bs_verify_batch_32_nested(Crypto1BitSlice* bs, MfClassicNonce* nonce, uint32_t alive); + +// Static encrypted verification: rollback uid_xor_nt0 + parity check +// Returns bitmask of ALL valid lanes (multi-result) +uint32_t bs_verify_batch_32_encrypted( + Crypto1BitSlice* bs, + const BsCandidateBatch* batch, + MfClassicNonce* nonce, + uint32_t alive); + +#endif // MFKEY_BS_VERIFY_H diff --git a/applications/system/mfkey/mfkey_dedup.h b/applications/system/mfkey/mfkey_dedup.h new file mode 100644 index 000000000..b6c193bd1 --- /dev/null +++ b/applications/system/mfkey/mfkey_dedup.h @@ -0,0 +1,141 @@ +#ifndef MFKEY_DEDUP_H +#define MFKEY_DEDUP_H + +#include "mfkey.h" +#include "crypto1.h" +#include +#include + +#define OPT_BARRIER(x) __asm__ volatile("" : "+r"(x)) + +// Golden ratio multiply-shift hash for 20-bit semi-states → 11-bit output +#define FIB_HASH_20BIT(x) (((x) * 2654435769u) >> 21) + +// Eliminates candidates before tree expansion by checking rounds 1-3 in advance. +// Returns 1 if any path survives to round 4, else 0. +static inline __attribute__((always_inline)) int + prefilter_rounds_1_3(uint32_t semi_state, int oks) { + OPT_BARRIER(oks); // Prevent hoisting of BIT(oks, round) extractions + // Precompute nibble bits for rounds 1-3 + // Round 1: nibble = (semi_state >> 15) & 0xF + // Round 2: nibble = (semi_state >> 14) & 0xF + // Round 3: nibble = (semi_state >> 13) & 0xF + uint32_t nib1 = ((0x0d938 >> ((semi_state >> 15) & 0xF)) & 1); + uint32_t nib2 = ((0x0d938 >> ((semi_state >> 14) & 0xF)) & 1); + uint32_t nib3 = ((0x0d938 >> ((semi_state >> 13) & 0xF)) & 1); + + // Round 1: 2 potential children -> 2-bit mask + uint32_t v = semi_state << 1; + int target = BIT(oks, 1); + uint32_t fp = filter_pair_with_nib(v, nib1); + int f0 = FILTER_F0(fp); + int f1 = FILTER_F1(fp); + + // r1_valid: bit 0 = v survives, bit 1 = v|1 survives + int r1_valid = ((f0 == target) << 0) | ((f1 == target) << 1); + if(!r1_valid) return 0; + + // Round 2: up to 4 grandchildren -> 4-bit mask + // Tracks exactly which grandchildren survive + target = BIT(oks, 2); + int r2_valid = 0; + + if(r1_valid & 1) { // v survived R1 + fp = filter_pair_with_nib(v << 1, nib2); + f0 = FILTER_F0(fp); + f1 = FILTER_F1(fp); + if(f0 == target) r2_valid |= 1; // v<<1 survives + if(f1 == target) r2_valid |= 2; // (v<<1)|1 survives + } + if(r1_valid & 2) { // v|1 survived R1 + fp = filter_pair_with_nib((v | 1) << 1, nib2); + f0 = FILTER_F0(fp); + f1 = FILTER_F1(fp); + if(f0 == target) r2_valid |= 4; // (v|1)<<1 survives + if(f1 == target) r2_valid |= 8; // ((v|1)<<1)|1 survives + } + + if(!r2_valid) return 0; + + // Round 3: only check children of actual R2 survivors + target = BIT(oks, 3); + + if(r2_valid & 1) { // v<<1 survived R2 + fp = filter_pair_with_nib(v << 2, nib3); + f0 = FILTER_F0(fp); + f1 = FILTER_F1(fp); + if(f0 == target || f1 == target) return 1; + } + if(r2_valid & 2) { // (v<<1)|1 survived R2 + fp = filter_pair_with_nib((v << 2) | 2, nib3); + f0 = FILTER_F0(fp); + f1 = FILTER_F1(fp); + if(f0 == target || f1 == target) return 1; + } + if(r2_valid & 4) { // (v|1)<<1 survived R2 + fp = filter_pair_with_nib((v | 1) << 2, nib3); + f0 = FILTER_F0(fp); + f1 = FILTER_F1(fp); + if(f0 == target || f1 == target) return 1; + } + if(r2_valid & 8) { // ((v|1)<<1)|1 survived R2 + fp = filter_pair_with_nib(((v | 1) << 2) | 2, nib3); + f0 = FILTER_F0(fp); + f1 = FILTER_F1(fp); + if(f0 == target || f1 == target) return 1; + } + + return 0; +} + +// 8x unrolled Duff's device for duplicate detection in packed 24-bit states +static inline __attribute__((always_inline)) bool scan_for_duplicate_8x( + const uint8_t* states, // Packed 24-bit state array + int count, // Number of entries to scan + uint32_t state_masked) // Target state with MSB masked off (& 0x00FFFFFF) +{ + if(count <= 0) return false; + + const uint8_t* p = states; + int n = (count + 7) / 8; // Number of 8-iteration chunks (rounded up) + + // Duff's Device: jump into unrolled loop based on remainder + switch(count % 8) { + case 0: + do { + if((*(uint32_t*)p & 0x00FFFFFF) == state_masked) return true; + p += 3; + __attribute__((fallthrough)); + case 7: + if((*(uint32_t*)p & 0x00FFFFFF) == state_masked) return true; + p += 3; + __attribute__((fallthrough)); + case 6: + if((*(uint32_t*)p & 0x00FFFFFF) == state_masked) return true; + p += 3; + __attribute__((fallthrough)); + case 5: + if((*(uint32_t*)p & 0x00FFFFFF) == state_masked) return true; + p += 3; + __attribute__((fallthrough)); + case 4: + if((*(uint32_t*)p & 0x00FFFFFF) == state_masked) return true; + p += 3; + __attribute__((fallthrough)); + case 3: + if((*(uint32_t*)p & 0x00FFFFFF) == state_masked) return true; + p += 3; + __attribute__((fallthrough)); + case 2: + if((*(uint32_t*)p & 0x00FFFFFF) == state_masked) return true; + p += 3; + __attribute__((fallthrough)); + case 1: + if((*(uint32_t*)p & 0x00FFFFFF) == state_masked) return true; + p += 3; + } while(--n > 0); + } + return false; +} + +#endif // MFKEY_DEDUP_H diff --git a/applications/system/mfkey/mfkey_recovery.c b/applications/system/mfkey/mfkey_recovery.c new file mode 100644 index 000000000..8ce52cffd --- /dev/null +++ b/applications/system/mfkey/mfkey_recovery.c @@ -0,0 +1,288 @@ +// MFKey Recovery - Sorting and LFSR state verification +// Extracted from mfkey_attack.c for better code organization + +#pragma GCC optimize("O3") + +#include "mfkey_recovery.h" +#include "crypto1.h" +#include "mfkey_bs_verify.h" +#include + +// External dependencies from mfkey.c +extern int sync_state(ProgramState* program_state); +extern void flush_key_buffer(ProgramState* program_state); +extern uint8_t MSB_LIMIT; + +// External from mfkey_attack.c +extern volatile bool g_abort_attack; +extern ProgramState* g_program_state; + +static inline __attribute__((always_inline)) int + binsearch(unsigned int data[], int start, int stop) { + unsigned int msb_val = data[stop] & 0xff000000; + + while(start != stop) { + int mid = start + ((stop - start) >> 1); + if(data[mid] >= msb_val) { + stop = mid; + } else { + start = mid + 1; + } + } + return start; +} + +// Radix sort: O(n) non-recursive replacement for quicksort +#define RADIX_BITS 8 +#define RADIX_SIZE (1 << RADIX_BITS) +#define RADIX_MASK (RADIX_SIZE - 1) + +unsigned int g_radix_temp[1280]; + +void radix_sort_32(unsigned int* arr, int low, int high, unsigned int* temp) { + int count = high - low + 1; + if(count <= 1) return; + + // Small arrays use insertion sort + if(count < 32) { + for(int i = low + 1; i <= high; i++) { + unsigned int key = arr[i]; + int j = i - 1; + while(j >= low && arr[j] > key) { + arr[j + 1] = arr[j]; + j--; + } + arr[j + 1] = key; + } + return; + } + + if(count > 1280) { + count = 1280; + high = low + count - 1; + } + + unsigned int hist[RADIX_SIZE]; + unsigned int* src = arr + low; + unsigned int* dst = temp; + + for(int pass = 0; pass < 4; pass++) { + int shift = pass * RADIX_BITS; + memset(hist, 0, sizeof(hist)); + for(int i = 0; i < count; i++) { + hist[(src[i] >> shift) & RADIX_MASK]++; + } + unsigned int total = 0; + for(int i = 0; i < RADIX_SIZE; i++) { + unsigned int c = hist[i]; + hist[i] = total; + total += c; + } + for(int i = 0; i < count; i++) { + int bucket = (src[i] >> shift) & RADIX_MASK; + dst[hist[bucket]++] = src[i]; + } + unsigned int* t = src; + src = dst; + dst = t; + } +} + +static inline __attribute__((always_inline)) void + update_contribution_odd(unsigned int data[], int item) { + unsigned int val = data[item]; + unsigned int p = val >> 25; + p = p << 1 | evenparity32(val & CONST_M1_1); + p = p << 1 | evenparity32(val & CONST_M2_1); + data[item] = (p << 24) | (val & 0xffffff); +} + +static inline __attribute__((always_inline)) void + update_contribution_even(unsigned int data[], int item) { + unsigned int val = data[item]; + unsigned int p = val >> 25; + p = p << 1 | evenparity32(val & CONST_M1_2); + p = p << 1 | evenparity32(val & CONST_M2_2); + data[item] = (p << 24) | (val & 0xffffff); +} + +static int __attribute__((hot)) extend_table_odd(unsigned int data[], int tbl, int end, int bit) { + for(data[tbl] <<= 1; tbl <= end; data[++tbl] <<= 1) { + int f0 = filter(data[tbl]); + int f1 = filter(data[tbl] | 1); + if((f0 ^ f1) != 0) { + data[tbl] |= f0 ^ bit; + update_contribution_odd(data, tbl); + } else if(f0 == bit) { + data[++end] = data[tbl + 1]; + data[tbl + 1] = data[tbl] | 1; + update_contribution_odd(data, tbl); + tbl++; + update_contribution_odd(data, tbl); + } else { + data[tbl--] = data[end--]; + } + } + return end; +} + +static int __attribute__((hot)) +extend_table_even(unsigned int data[], int tbl, int end, int bit, unsigned int in) { + in <<= 24; + for(data[tbl] <<= 1; tbl <= end; data[++tbl] <<= 1) { + int f0 = filter(data[tbl]); + int f1 = filter(data[tbl] | 1); + if((f0 ^ f1) != 0) { + data[tbl] |= f0 ^ bit; + update_contribution_even(data, tbl); + data[tbl] ^= in; + } else if(f0 == bit) { + data[++end] = data[tbl + 1]; + data[tbl + 1] = data[tbl] | 1; + update_contribution_even(data, tbl); + data[tbl++] ^= in; + update_contribution_even(data, tbl); + data[tbl] ^= in; + } else { + data[tbl--] = data[end--]; + } + } + return end; +} + +// Routes to correct bitsliced kernel by attack type. +// Returns: -1 = key found (mfkey32/static_nested), 0 = no match. +// For static_encrypted: buffers all valid keys, always returns 0. +static __attribute__((noinline)) int + bs_verify_dispatch(BsCandidateBatch* batch, MfClassicNonce* n) { + // Common: compute alive mask and reject zero states + uint32_t alive = (batch->count >= 32) ? 0xFFFFFFFF : ((1U << batch->count) - 1); + for(int i = 0; i < batch->count; i++) { + if(!(batch->odd[i] | batch->even[i])) { + alive &= ~(1U << i); + } + } + if(!alive) return 0; + + // Common: transpose scalar candidates → bitsliced SWAR state (once) + Crypto1BitSlice bs; + bs_init_from_candidates(&bs, batch); + + if(n->attack == mfkey32) { + uint32_t valid = bs_verify_batch_32(&bs, n, alive); + if(valid) { + int lane = __builtin_ctz(valid); + bs_extract_key(batch, lane, n); + return -1; + } + } else if(n->attack == static_nested) { + uint32_t valid = bs_verify_batch_32_nested(&bs, n, alive); + if(valid) { + int lane = __builtin_ctz(valid); + bs_extract_key(batch, lane, n); + return -1; + } + } else { + // static_encrypted: collect ALL valid keys + uint32_t valid = bs_verify_batch_32_encrypted(&bs, batch, n, alive); + while(valid) { + int lane = __builtin_ctz(valid); + valid &= valid - 1; + bs_extract_key(batch, lane, n); + // Buffer all valid keys for static_encrypted + g_program_state->num_candidates++; + g_program_state->key_buffer[g_program_state->key_buffer_count] = n->key; + g_program_state->key_idx_buffer[g_program_state->key_buffer_count] = n->key_idx; + g_program_state->key_buffer_count++; + if(g_program_state->key_buffer_count >= g_program_state->key_buffer_size) { + flush_key_buffer(g_program_state); + } + } + } + return 0; +} + +// 32-way parallel verification with recursive MSB-walk +int old_recover_bs( + unsigned int odd[], + int o_head, + int o_tail, + int oks, + unsigned int even[], + int e_head, + int e_tail, + int eks, + int rem, + int s, + MfClassicNonce* n, + unsigned int in, + int first_run) { + int o, e, i; + + if(rem == -1) { + BsCandidateBatch batch; + bs_batch_init(&batch); + + for(e = e_head; e <= e_tail; ++e) { + uint32_t e_val = (even[e] << 1) ^ evenparity32(even[e] & LF_POLY_EVEN) ^ (!!(in & 4)); + + for(o = o_head; o <= o_tail; ++o, ++s) { + uint32_t o_val = odd[o]; + uint32_t final_even = o_val; + uint32_t final_odd = e_val ^ evenparity32(o_val & LF_POLY_ODD); + + if(bs_batch_add(&batch, final_odd, final_even)) { + int result = bs_verify_dispatch(&batch, n); + if(result == -1) return -1; + if(g_abort_attack) return -2; + bs_batch_init(&batch); + } + } + } + + if(batch.count > 0) { + int result = bs_verify_dispatch(&batch, n); + if(result == -1) return -1; + } + + return s; + } + + if(first_run) { + // All elements share the same top byte (constructed as raw | msb_val), + // so sorting is a no-op and the MSB-walk finds exactly one group. + // Skip directly to recursion with first_run=0. + return old_recover_bs( + odd, o_head, o_tail, oks, even, e_head, e_tail, eks, rem, s, n, in, 0); + } + + for(i = 0; (i < 4) && (rem-- != 0); i++) { + oks >>= 1; + eks >>= 1; + in >>= 2; + o_tail = extend_table_odd(odd, o_head, o_tail, oks & 1); + if(o_head > o_tail) return s; + e_tail = extend_table_even(even, e_head, e_tail, eks & 1, in & 3); + if(e_head > e_tail) return s; + } + + // Sort by MSB for grouped cross-product intersection + radix_sort_32(odd, o_head, o_tail, g_radix_temp); + radix_sort_32(even, e_head, e_tail, g_radix_temp); + + while(o_tail >= o_head && e_tail >= e_head) { + if(((odd[o_tail] ^ even[e_tail]) >> 24) == 0) { + o_tail = binsearch(odd, o_head, o = o_tail); + e_tail = binsearch(even, e_head, e = e_tail); + s = old_recover_bs(odd, o_tail--, o, oks, even, e_tail--, e, eks, rem, s, n, in, 0); + if(s < 0) { + break; + } + } else if((odd[o_tail] ^ 0x80000000) > (even[e_tail] ^ 0x80000000)) { + o_tail = binsearch(odd, o_head, o_tail) - 1; + } else { + e_tail = binsearch(even, e_head, e_tail) - 1; + } + } + return s; +} diff --git a/applications/system/mfkey/mfkey_recovery.h b/applications/system/mfkey/mfkey_recovery.h new file mode 100644 index 000000000..257eac476 --- /dev/null +++ b/applications/system/mfkey/mfkey_recovery.h @@ -0,0 +1,31 @@ +#ifndef MFKEY_RECOVERY_H +#define MFKEY_RECOVERY_H + +#include "mfkey.h" +#include "crypto1.h" + +// Scratch buffer for radix sort. Also reused as ping-pong buffer by +// state_loop_r4 during expansion (phases don't overlap). +extern unsigned int g_radix_temp[1280]; + +// Radix sort for 24-bit packed states (O(n) non-recursive sorting) +void radix_sort_32(unsigned int* arr, int low, int high, unsigned int* temp); + +// Bitsliced recovery: 32-way parallel verification +// Returns: >0 = states checked, -1 = key found, -2 = aborted +int old_recover_bs( + unsigned int odd[], + int o_head, + int o_tail, + int oks, + unsigned int even[], + int e_head, + int e_tail, + int eks, + int rem, + int s, + MfClassicNonce* n, + unsigned int in, + int first_run); + +#endif // MFKEY_RECOVERY_H diff --git a/applications/system/mfkey/mfkey_state_expansion.c b/applications/system/mfkey/mfkey_state_expansion.c new file mode 100644 index 000000000..a3071886e --- /dev/null +++ b/applications/system/mfkey/mfkey_state_expansion.c @@ -0,0 +1,152 @@ +// MFKey State Expansion - LFSR tree search through rounds 1-12 +// Extracted from mfkey_attack.c for better code organization + +#pragma GCC optimize("O3") + +#include "mfkey_state_expansion.h" +#include "mfkey_recovery.h" +#include "crypto1.h" +#include + +#define OPT_BARRIER(x) __asm__ volatile("" : "+r"(x)) + +// Pre-fold xks_bit into the filter constant so BIT(adj, idx) == BIT(0xEC57E80A, idx) ^ xks_bit +#define ADJ_FILTER(xks, round) (0xEC57E80Au ^ (-(uint32_t)BIT(xks, round))) + +// In-place LFSR expansion for rounds 4-12, called after batch prelude completes rounds 0-3. +// fork_delta deferred past round 4 early-exit (~95% of calls exit at round 4). +__attribute__((hot)) int state_loop_r4( + unsigned int* states_buffer, + int count, // Number of active states in buffer + int xks, + int m1, + int m2, + unsigned int in, + int and_val) { + OPT_BARRIER(xks); // Prevent hoisting of BIT(xks, round) extractions + if(count == 0) return -1; + + // Round 4 (in-place, no parity update) + int states_tail = count - 1; + { + uint32_t adj = ADJ_FILTER(xks, 4); + for(int s = 0; s <= states_tail; ++s) { + unsigned int raw = states_buffer[s]; + OPT_BARRIER(raw); + unsigned int v = raw << 1; + uint32_t fp = filter_pair_xor(v, adj); + int f0_x = FILTER_F0(fp); + int f1_x = FILTER_F1(fp); + + if(__builtin_expect((f0_x ^ f1_x) != 0, 0)) { + // Single child survives + states_buffer[s] = v | f0_x; + } else if(__builtin_expect(f0_x == 0, 1)) { + // Both children survive — fork + states_buffer[++states_tail] = states_buffer[s + 1]; + states_buffer[s] = v; + s++; + states_buffer[s] = v | 1; + } else { + // Neither survives — eliminate + states_buffer[s--] = states_buffer[states_tail--]; + } + } + if(__builtin_expect(states_tail < 0, 1)) return -1; + } + + // Fork delta deferred past round 4 early-exit (~95% of calls don't reach here) + uint32_t fork_delta = ((m1 & 1) << 25) | ((m2 & 1) << 24) | 1; + + // Round 5 (unrolled, in-place) + { + uint32_t adj = ADJ_FILTER(xks, 5); + unsigned int r5_in = ((in >> 2) & and_val) << 24; + for(int s = 0; s <= states_tail; ++s) { + unsigned int raw = states_buffer[s]; + OPT_BARRIER(raw); + unsigned int v = raw << 1; + uint32_t fp = filter_pair_xor(v, adj); + int f0_x = FILTER_F0(fp); + int f1_x = FILTER_F1(fp); + + if(__builtin_expect((f0_x ^ f1_x) != 0, 0)) { + v |= f0_x; + OPT_BARRIER(v); + states_buffer[s] = update_contribution_reg(v, m1, m2) ^ r5_in; + } else if(__builtin_expect(f0_x == 0, 1)) { + states_buffer[++states_tail] = states_buffer[s + 1]; + OPT_BARRIER(v); + uint32_t p0 = update_contribution_reg(v, m1, m2) ^ r5_in; + states_buffer[s] = p0; + s++; + states_buffer[s] = p0 ^ fork_delta; + } else { + states_buffer[s--] = states_buffer[states_tail--]; + } + } + if(__builtin_expect(states_tail < 0, 0)) return -1; + } + + // Round 6 (unrolled, in-place) + { + uint32_t adj = ADJ_FILTER(xks, 6); + unsigned int r6_in = ((in >> 4) & and_val) << 24; + for(int s = 0; s <= states_tail; ++s) { + unsigned int raw = states_buffer[s]; + OPT_BARRIER(raw); + unsigned int v = raw << 1; + uint32_t fp = filter_pair_xor(v, adj); + int f0_x = FILTER_F0(fp); + int f1_x = FILTER_F1(fp); + + if(__builtin_expect((f0_x ^ f1_x) != 0, 0)) { + v |= f0_x; + OPT_BARRIER(v); + states_buffer[s] = update_contribution_reg(v, m1, m2) ^ r6_in; + } else if(__builtin_expect(f0_x == 0, 1)) { + states_buffer[++states_tail] = states_buffer[s + 1]; + OPT_BARRIER(v); + uint32_t p0 = update_contribution_reg(v, m1, m2) ^ r6_in; + states_buffer[s] = p0; + s++; + states_buffer[s] = p0 ^ fork_delta; + } else { + states_buffer[s--] = states_buffer[states_tail--]; + } + } + if(__builtin_expect(states_tail < 0, 0)) return -1; + } + + // Rounds 7-12 (loop, in-place) + for(int round = 7; round <= 12; ++round) { + uint32_t adj = ADJ_FILTER(xks, round); + unsigned int round_in = ((in >> (2 * (round - 4))) & and_val) << 24; + for(int s = 0; s <= states_tail; ++s) { + unsigned int raw = states_buffer[s]; + OPT_BARRIER(raw); + unsigned int v = raw << 1; + uint32_t fp = filter_pair_xor(v, adj); + int f0_x = FILTER_F0(fp); + int f1_x = FILTER_F1(fp); + + if(__builtin_expect((f0_x ^ f1_x) != 0, 0)) { + v |= f0_x; + OPT_BARRIER(v); + states_buffer[s] = update_contribution_reg(v, m1, m2) ^ round_in; + } else if(__builtin_expect(f0_x == 0, 1)) { + states_buffer[++states_tail] = states_buffer[s + 1]; + OPT_BARRIER(v); + uint32_t p0 = update_contribution_reg(v, m1, m2) ^ round_in; + states_buffer[s] = p0; + s++; + states_buffer[s] = p0 ^ fork_delta; + } else { + states_buffer[s--] = states_buffer[states_tail--]; + } + } + if(__builtin_expect(states_tail < 0, 0)) return -1; + } + + return states_tail; +} diff --git a/applications/system/mfkey/mfkey_state_expansion.h b/applications/system/mfkey/mfkey_state_expansion.h new file mode 100644 index 000000000..77dd82da4 --- /dev/null +++ b/applications/system/mfkey/mfkey_state_expansion.h @@ -0,0 +1,17 @@ +#ifndef MFKEY_STATE_EXPANSION_H +#define MFKEY_STATE_EXPANSION_H + +#include + +// LFSR state expansion for rounds 4-12 (rounds 0-3 handled by batch prelude). +// Returns final state count (states_tail), or -1 if all eliminated. +int state_loop_r4( + unsigned int* states_buffer, + int count, + int xks, + int m1, + int m2, + unsigned int in, + int and_val); + +#endif // MFKEY_STATE_EXPANSION_H From 8accdb435eb49280eadc825dfe89ce6fa3c70ae8 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 17 Feb 2026 01:11:28 +0300 Subject: [PATCH 134/160] upd changelog --- CHANGELOG.md | 51 +++------------------------------------------------ 1 file changed, 3 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e2adab8e..6a6f59fcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,54 +1,9 @@ ## Main changes - Current API: 87.6 -* SubGHz: **Cardin S449 protocol full support** (64bit keeloq) (with Add manually, and all button codes) (**use FSK12K modulation to read the remote**) (closes issues #735 #908) (by @xMasterX and @zero-mega (thanks!)) -* SubGHz: **Beninca ARC AES128 protocol full support** (128bit dynamic) (with Add manually, and 3 button codes) (resolves issue #596) (by @xMasterX and @zero-mega) -* SubGHz: **Treadmill37 protocol support** (37bit static) (by @xMasterX) -* SubGHz: **Jarolift protocol full support** (72bit dynamic) (with Add manually, and all button codes) (by @xMasterX & d82k & Steffen (bastelbudenbuben de)) -* SubGHz: **New modulation FSK with 12KHz deviation** -* SubGHz: **KingGates Stylo 4k - Add manually and button switch support** + refactoring of encoder -* SubGHz: **Stilmatic (R-Tech) - 12bit discr. fix & button 9 support** (two buttons hold simulation) (mapped on arrow keys) -* SubGHz: **Counter editor refactoring** (PR #939 | by @Dmitry422) -* SubGHz: **Alutech AT-4N & Nice Flor S turbo speedup** (PR #942 | by @Dmitry422) -* SubGHz: **Sommer fm2 in Add manually now uses FM12K modulation** (Sommer without fm2 tag uses FM476) (try this if regular option doesn't work for you) -* SubGHz: **Sommer - last button code 0x6 support** (mapped on arrow keys) -* SubGHz: **V2 Phoenix (Phox) added 2 counter modes support** (docs updated) -* SubGHz: Add 390MHz, 430.5MHz to default hopper list (6 elements like in OFW) (works well with Hopper RSSI level set for your enviroment) -* SubGHz: Fixed button mapping for **FAAC RC/XT** -* SubGHz: KeeLoq **display decrypted hop** in `Hop` instead of showing encrypted as is (encrypted non byte reversed hop is still displayed in `Key` field) -* SubGHz: **BFT KeeLoq** try decoding with **zero seed** too -* SubGHz: KeeLoq **display BFT programming mode TX** (when arrow button is held) -* SubGHz: KeeLoq **add counter mode 7 (sends 7 signals increasing counter with 0x3333 steps)** - may bypass counter on some receivers! -* SubGHz: Add signals button editor and real **remote simulation** (full signal transmit with just one click) (PR #956 #958 | by @Dmitry422) -* SubGHz: TX Power setting (PR #960 | by @LeeroysHub) -* Desktop: BT ON/OFF instead of Lock/Unlock action in desktop lock menu (To lock - hold Up button) (PR #965 | by @Dmitry422) (idea by Dezederix) -* Desktop: Holding back button to power off menu now allows to open power settings on left button (idea by Dezederix) -* JS: feat: add IR capabilities to the JS engine (PR #957 | by @LuisMayo) -* NFC: Handle PPS request in ISO14443-4 layer (by @WillyJL) -* NFC: Fixes to `READ_MULTI` and `GET_BLOCK_SECURITY` commands in ISO 15693-3 emulation (by @WillyJL & @aaronjamt) -* Archive: Allow folders to be pinned (by @WillyJL) -* Apps: Build tag (**12feb2026p3**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) +* SubGHz: Signal Settings Improvements (PR #968 | by @Dmitry422) +* Apps: Build tag (**17feb2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes -* Settings: Storage settings exit scenes properly if used via favourites (fixes issue #951) -* LCD: Backlight settings bug fix (PR #962 | by @Dmitry422) -* UI: Various small changes -* Desktop: Disable winter holidays anims -* OFW PR 4333: NFC: Fix sending 32+ byte ISO 15693-3 commands (by @WillyJL) -* NFC: Fix LED not blinking at SLIX unlock (closes issue #945) -* SubGHz: Added some RAM -* SubGHz: Fix documentation link for HT12A protocol (by @carlogrisetti) -* SubGHz: Improve docs on low level code (PR #949 | by @Dmitry422) -* SubGHz: Fix Alutech AT4N false positives -* SubGHz: Cleanup of extra local variables -* SubGHz: Replaced Cars ignore option with Revers RB2 protocol ignore option -* SubGHz: Moved Starline, ScherKhan, Kia decoders into external app -* SubGHz: Possible Sommer timings fix -* SubGHz: Various fixes -* SubGHz: Nice Flor S remove extra uint64 variable -* SubGHz: Rename Sommer(fsk476) to Sommer (Sommer keeloq works better with FM12K) + added backwards compatibility with older saved files -* Docs: Add full list of supported SubGHz protocols and their frequencies/modulations that can be used for reading remotes - [Docs Link](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSupportedSystems.md) -* Desktop: Show debug status (D) if clock is enabled and debug flag is on (PR #942 | by @Dmitry422) -* NFC: Fix some typos in Type4Tag protocol (by @WillyJL) -* Clangd: Add clangd parameters in IDE agnostic config file (by @WillyJL) +* MFKey: Update to v4.1 (by @noproto & @dchristle)

    #### Known NFC post-refactor regressions list: - Mifare Mini clones reading is broken (original mini working fine) (OFW) From 1dd8cfa00ab955a51e21b09d7930e7f08a39bc1a Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 22 Feb 2026 15:50:13 +0300 Subject: [PATCH 135/160] Fix USB HID keyboard LED state reporting OFW PR 4338 by Caballosanex --- targets/f7/furi_hal/furi_hal_usb_hid.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/targets/f7/furi_hal/furi_hal_usb_hid.c b/targets/f7/furi_hal/furi_hal_usb_hid.c index 04f2ae400..7820ae8d2 100644 --- a/targets/f7/furi_hal/furi_hal_usb_hid.c +++ b/targets/f7/furi_hal/furi_hal_usb_hid.c @@ -7,8 +7,9 @@ #include "usb.h" #include "usb_hid.h" -#define HID_EP_IN 0x81 -#define HID_EP_SZ 0x10 +#define HID_EP_IN 0x81 +#define HID_EP_OUT 0x01 +#define HID_EP_SZ 0x10 #define HID_INTERVAL 2 @@ -16,6 +17,7 @@ struct HidIntfDescriptor { struct usb_interface_descriptor hid; struct usb_hid_descriptor hid_desc; struct usb_endpoint_descriptor hid_ep_in; + struct usb_endpoint_descriptor hid_ep_out; }; struct HidConfigDescriptor { @@ -162,7 +164,7 @@ static const struct HidConfigDescriptor hid_cfg_desc = { .bDescriptorType = USB_DTYPE_INTERFACE, .bInterfaceNumber = 0, .bAlternateSetting = 0, - .bNumEndpoints = 1, + .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_HID, .bInterfaceSubClass = USB_HID_SUBCLASS_BOOT, .bInterfaceProtocol = USB_HID_PROTO_KEYBOARD, @@ -187,6 +189,15 @@ static const struct HidConfigDescriptor hid_cfg_desc = { .wMaxPacketSize = HID_EP_SZ, .bInterval = HID_INTERVAL, }, + .hid_ep_out = + { + .bLength = sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DTYPE_ENDPOINT, + .bEndpointAddress = HID_EP_OUT, + .bmAttributes = USB_EPTYPE_INTERRUPT, + .wMaxPacketSize = HID_EP_SZ, + .bInterval = HID_INTERVAL, + }, }, }; @@ -481,13 +492,17 @@ static usbd_respond hid_ep_config(usbd_device* dev, uint8_t cfg) { switch(cfg) { case 0: /* deconfiguring device */ + usbd_ep_deconfig(dev, HID_EP_OUT); usbd_ep_deconfig(dev, HID_EP_IN); + usbd_reg_endpoint(dev, HID_EP_OUT, 0); usbd_reg_endpoint(dev, HID_EP_IN, 0); return usbd_ack; case 1: /* configuring device */ usbd_ep_config(dev, HID_EP_IN, USB_EPTYPE_INTERRUPT, HID_EP_SZ); + usbd_ep_config(dev, HID_EP_OUT, USB_EPTYPE_INTERRUPT, HID_EP_SZ); usbd_reg_endpoint(dev, HID_EP_IN, hid_txrx_ep_callback); + usbd_reg_endpoint(dev, HID_EP_OUT, hid_txrx_ep_callback); usbd_ep_write(dev, HID_EP_IN, 0, 0); boot_protocol = false; /* BIOS will SET_PROTOCOL if it wants this */ return usbd_ack; From f01005580ab818fb7f3f29076b2ee2ea7aea0b36 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 22 Feb 2026 16:45:58 +0300 Subject: [PATCH 136/160] Make view_port_send_to_back public OFW PR 4320 by loftyinclination --- targets/f18/api_symbols.csv | 2 +- targets/f7/api_symbols.csv | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 38794afcc..ab29113fb 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1768,7 +1768,7 @@ Function,+,gui_remove_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, Function,+,gui_remove_view_port,void,"Gui*, ViewPort*" Function,+,gui_set_lockdown,void,"Gui*, _Bool" Function,+,gui_set_lockdown_inhibit,void,"Gui*, _Bool" -Function,-,gui_view_port_send_to_back,void,"Gui*, ViewPort*" +Function,+,gui_view_port_send_to_back,void,"Gui*, ViewPort*" Function,+,gui_view_port_send_to_front,void,"Gui*, ViewPort*" Function,-,hci_send_req,int,"hci_request*, uint8_t" Function,+,hex_char_to_hex_nibble,_Bool,"char, uint8_t*" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index e3159a17e..136786c7d 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -2093,7 +2093,7 @@ Function,+,gui_remove_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, Function,+,gui_remove_view_port,void,"Gui*, ViewPort*" Function,+,gui_set_lockdown,void,"Gui*, _Bool" Function,+,gui_set_lockdown_inhibit,void,"Gui*, _Bool" -Function,-,gui_view_port_send_to_back,void,"Gui*, ViewPort*" +Function,+,gui_view_port_send_to_back,void,"Gui*, ViewPort*" Function,+,gui_view_port_send_to_front,void,"Gui*, ViewPort*" Function,-,hci_send_req,int,"hci_request*, uint8_t" Function,+,hex_char_to_hex_nibble,_Bool,"char, uint8_t*" From ad1fb5a248886c20e1d0b0ec61211779d5fffc29 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 22 Feb 2026 16:47:53 +0300 Subject: [PATCH 137/160] upd changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a6f59fcd..7e8607072 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,10 @@ ## Main changes - Current API: 87.6 * SubGHz: Signal Settings Improvements (PR #968 | by @Dmitry422) -* Apps: Build tag (**17feb2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) +* OFW PR 4338: HID: Fix USB HID keyboard LED state reporting (by @Caballosanex) +* Apps: Build tag (**22feb2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes +* OFW PR 4320: API: Make view_port_send_to_back public (by @loftyinclination) * MFKey: Update to v4.1 (by @noproto & @dchristle)

    #### Known NFC post-refactor regressions list: From d61c98c97c41c1d87e6f4962ca18ebb4ca152a7d Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 22 Feb 2026 19:43:59 +0300 Subject: [PATCH 138/160] subghz keeloq genius btn fix, and change delta size --- lib/subghz/protocols/keeloq.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 0ed600ece..83e7fdc34 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -21,7 +21,7 @@ static bool bypass = false; static const SubGhzBlockConst subghz_protocol_keeloq_const = { .te_short = 400, .te_long = 800, - .te_delta = 140, + .te_delta = 180, .min_count_bit_for_found = 64, }; @@ -177,7 +177,8 @@ static bool subghz_protocol_keeloq_gen_data( } else if( (strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) || (strcmp(instance->manufacture_name, "Monarch") == 0) || - (strcmp(instance->manufacture_name, "NICE_Smilo") == 0)) { + (strcmp(instance->manufacture_name, "NICE_Smilo") == 0) || + (strcmp(instance->manufacture_name, "Genius_Bravo") == 0)) { klq_last_custom_btn = 0xB; } else if( (strcmp(instance->manufacture_name, "Novoferm") == 0) || From e681fd2be571523f251ff688351a9299aa533ad4 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 22 Feb 2026 19:44:36 +0300 Subject: [PATCH 139/160] update docs --- documentation/SubGHzSupportedSystems.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/documentation/SubGHzSupportedSystems.md b/documentation/SubGHzSupportedSystems.md index eed5ee420..1784b9db9 100644 --- a/documentation/SubGHzSupportedSystems.md +++ b/documentation/SubGHzSupportedSystems.md @@ -20,7 +20,7 @@ That list is only for default SubGHz app, apps like *Weather Station* have their - AN-Motors (Alutech) AT4 `433.92MHz` `AM650` (64 bits, Pseudo-Dynamic, KeeLoq based) - Ansonic `433MHz` `FM` (12 bits, Static) - BETT `433.92MHz` `AM650` (18 bits, Static) -- Beninca ARC (TOGO2VA) `433.92MHz` `AM650` (128 bits, Dynamic AES) (button code `0` emulates `hidden button` option on the remote) +- Beninca ARC (TOGO2VA) `433.92MHz` `AM650` (128 bits, Dynamic AES128) (button code `0` emulates `hidden button` option on the remote) - BFT Mitto `433.92MHz` `AM650` (64 bits, Dynamic, KeeLoq based with Seed) - CAME Atomo `433.92MHz, 868MHz` `AM650` (62 bits, Dynamic) - CAME TWEE `433.92MHz` `AM650` (54 bits, Static) @@ -32,11 +32,11 @@ That list is only for default SubGHz app, apps like *Weather Station* have their - Dickert MAHS `AM650` (36 bits, Static) - Doitrand `AM650` (37 bits, Dynamic) - Elplast/P-11B/3BK/E.C.A `433MHz` `AM650` (18 bits, Static) -- FAAC SLH `433.92MHz, 868MHz` `AM650` (64 bits, Dynamic) +- FAAC SLH `433.92MHz, 868.35MHz` `AM650` (64 bits, Dynamic) (+ Genius KILO TX2/4 JLC) - Gate TX `433.92MHz` `AM650` (64 bits, Static) - Hormann `868MHz` `AM650` (44 bits, Static) - HCS101 `AM650` (64 bits, Simple Dynamic, KeeLoq-like) -- IDO `433MHz` `AM650` (48 bits, Dynamic) +- iDO `433MHz` `AM650` (48 bits, Dynamic) (Decode only) - KingGates Stylo 4k `433.92MHz` `AM650` (89 bits, Dynamic, KeeLoq based) - Mastercode `AM650` (36 bits, Static) - Megacode `AM650` (24 bits, Static) @@ -49,7 +49,7 @@ That list is only for default SubGHz app, apps like *Weather Station* have their - V2 Phoenix (Phox) `433.92MHz` `AM650` (52 bits, Dynamic) (receivers have option to enable Static mode, making them ignore rolling part of the key) - Marantec `433.92MHz, 868MHz` `AM650` (49 bits, Static) - Marantec24 `868MHz` `AM650` (24 bits, Static) -- Somfy Keytis `433.92MHz, 868MHz` `AM650` (80 bits, Dynamic) +- Somfy Keytis `433.42MHz, 868MHz` `AM650` (80 bits, Dynamic) - ZKTeco `430.5MHz` `AM650` (24 bits, Static - Princeton based) - (Button codes (already mapped to arrow keys): `0x30 (UP)`, `0x03 (STOP)`, `0x0C (DOWN)`) - Linear `300MHz` `AM650` (10 bits, Static) - Linear Delta3 `AM650` (8 bits, Static) @@ -106,7 +106,7 @@ The following manufacturers have KeeLoq support in Unleashed firmware: - DTM Neo - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - simple learning) - Elmes Poland - `433.92MHz` `AM650` (KeeLoq, 64 bits) (normal learning) - FAAC RC,XT - `433.92MHz, 868MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) -- Genius Bravo - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) +- Genius Bravo - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) (Genius ECHO, Genius Bravo (Button code 0xB for prog. mode)) - Gibidi - `433.92MHz` `AM650` (KeeLoq, 64 bits) - GSN - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) - Hormann EcoStar - `433.92MHz` `AM650` (KeeLoq, 64 bits) (normal learning) From 56620ab62f3204756332fb445fe7a6afa0cff624 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 22 Feb 2026 19:44:57 +0300 Subject: [PATCH 140/160] subghz somfy keytis button switch and add manually support --- .../main/subghz/helpers/subghz_custom_event.h | 1 + .../main/subghz/helpers/subghz_gen_info.c | 11 +++- .../main/subghz/helpers/subghz_gen_info.h | 6 ++ .../helpers/subghz_txrx_create_protocol_key.c | 30 ++++++++++ .../helpers/subghz_txrx_create_protocol_key.h | 8 +++ .../subghz/scenes/subghz_scene_set_button.c | 5 ++ .../subghz/scenes/subghz_scene_set_counter.c | 16 +++++ .../subghz/scenes/subghz_scene_set_seed.c | 2 + .../subghz/scenes/subghz_scene_set_serial.c | 9 +++ .../subghz/scenes/subghz_scene_set_type.c | 13 +++- lib/subghz/protocols/somfy_keytis.c | 60 ++++++++++++++++--- 11 files changed, 150 insertions(+), 11 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index 011b53025..4242e552d 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -70,6 +70,7 @@ typedef enum { SetTypeFaacSLH_433, SetTypeBFTMitto, SetTypeSomfyTelis, + SetTypeSomfyKeytis, SetTypeKingGatesStylo4k, SetTypeBenincaARC, SetTypeJarolift, diff --git a/applications/main/subghz/helpers/subghz_gen_info.c b/applications/main/subghz/helpers/subghz_gen_info.c index bfa609e32..f9574d40d 100644 --- a/applications/main/subghz/helpers/subghz_gen_info.c +++ b/applications/main/subghz/helpers/subghz_gen_info.c @@ -523,6 +523,15 @@ void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType ty .somfy_telis.btn = 0x02, .somfy_telis.cnt = 0x03}; break; + case SetTypeSomfyKeytis: + gen_info = (GenInfo){ + .type = GenSomfyKeytis, + .mod = "AM650", + .freq = 433420000, + .somfy_keytis.serial = (key & 0x000FFFFF) | 0x0D500000, + .somfy_keytis.btn = 0x04, + .somfy_keytis.cnt = 0x03}; + break; case SetTypeKingGatesStylo4k: gen_info = (GenInfo){ .type = GenKingGatesStylo4k, @@ -636,7 +645,7 @@ void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType ty .mod = "AM650", .freq = 433920000, .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x06, + .keeloq.btn = 0x09, .keeloq.cnt = 0x03, .keeloq.manuf = "Genius_Bravo"}; break; diff --git a/applications/main/subghz/helpers/subghz_gen_info.h b/applications/main/subghz/helpers/subghz_gen_info.h index a680b7ba5..478039c45 100644 --- a/applications/main/subghz/helpers/subghz_gen_info.h +++ b/applications/main/subghz/helpers/subghz_gen_info.h @@ -10,6 +10,7 @@ typedef enum { GenKeeloqBFT, GenAlutechAt4n, GenSomfyTelis, + GenSomfyKeytis, GenKingGatesStylo4k, GenBenincaARC, GenJarolift, @@ -64,6 +65,11 @@ typedef struct { uint8_t btn; uint16_t cnt; } somfy_telis; + struct { + uint32_t serial; + uint8_t btn; + uint16_t cnt; + } somfy_keytis; struct { uint32_t serial; uint8_t btn; diff --git a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c index 27fb71f5b..72197c0c9 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c +++ b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c @@ -335,6 +335,36 @@ bool subghz_txrx_gen_somfy_telis_protocol( return res; } +bool subghz_txrx_gen_somfy_keytis_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt) { + SubGhzTxRx* txrx = context; + + bool res = false; + + txrx->transmitter = + subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_SOMFY_KEYTIS_NAME); + subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); + + if(txrx->transmitter && subghz_protocol_somfy_keytis_create_data( + subghz_transmitter_get_protocol_instance(txrx->transmitter), + txrx->fff_data, + serial, + btn, + cnt, + txrx->preset)) { + res = true; + } + + subghz_transmitter_free(txrx->transmitter); + + return res; +} + bool subghz_txrx_gen_kinggates_stylo_4k_protocol( void* context, const char* preset_name, diff --git a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h index 285770975..9cd75fad7 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h +++ b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h @@ -108,6 +108,14 @@ bool subghz_txrx_gen_somfy_telis_protocol( uint8_t btn, uint16_t cnt); +bool subghz_txrx_gen_somfy_keytis_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt); + bool subghz_txrx_gen_kinggates_stylo_4k_protocol( void* context, const char* preset_name, diff --git a/applications/main/subghz/scenes/subghz_scene_set_button.c b/applications/main/subghz/scenes/subghz_scene_set_button.c index d2ef60a91..9f96f03d2 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_button.c +++ b/applications/main/subghz/scenes/subghz_scene_set_button.c @@ -36,6 +36,10 @@ void subghz_scene_set_button_on_enter(void* context) { byte_ptr = &subghz->gen_info->somfy_telis.btn; byte_count = sizeof(subghz->gen_info->somfy_telis.btn); break; + case GenSomfyKeytis: + byte_ptr = &subghz->gen_info->somfy_keytis.btn; + byte_count = sizeof(subghz->gen_info->somfy_keytis.btn); + break; case GenKingGatesStylo4k: byte_ptr = &subghz->gen_info->kinggates_stylo_4k.btn; byte_count = sizeof(subghz->gen_info->kinggates_stylo_4k.btn); @@ -98,6 +102,7 @@ bool subghz_scene_set_button_on_event(void* context, SceneManagerEvent event) { case GenBenincaARC: case GenJarolift: case GenNiceFlorS: + case GenSomfyKeytis: case GenSecPlus2: scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCounter); break; diff --git a/applications/main/subghz/scenes/subghz_scene_set_counter.c b/applications/main/subghz/scenes/subghz_scene_set_counter.c index 8510d4aca..d9ad3a42c 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_counter.c +++ b/applications/main/subghz/scenes/subghz_scene_set_counter.c @@ -42,6 +42,10 @@ void subghz_scene_set_counter_on_enter(void* context) { byte_ptr = (uint8_t*)&subghz->gen_info->somfy_telis.cnt; byte_count = sizeof(subghz->gen_info->somfy_telis.cnt); break; + case GenSomfyKeytis: + byte_ptr = (uint8_t*)&subghz->gen_info->somfy_keytis.cnt; + byte_count = sizeof(subghz->gen_info->somfy_keytis.cnt); + break; case GenKingGatesStylo4k: byte_ptr = (uint8_t*)&subghz->gen_info->kinggates_stylo_4k.cnt; byte_count = sizeof(subghz->gen_info->kinggates_stylo_4k.cnt); @@ -125,6 +129,9 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { case GenSomfyTelis: subghz->gen_info->somfy_telis.cnt = __bswap16(subghz->gen_info->somfy_telis.cnt); break; + case GenSomfyKeytis: + subghz->gen_info->somfy_keytis.cnt = __bswap16(subghz->gen_info->somfy_keytis.cnt); + break; case GenKingGatesStylo4k: subghz->gen_info->kinggates_stylo_4k.cnt = __bswap16(subghz->gen_info->kinggates_stylo_4k.cnt); @@ -193,6 +200,15 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { subghz->gen_info->somfy_telis.btn, subghz->gen_info->somfy_telis.cnt); break; + case GenSomfyKeytis: + generated_protocol = subghz_txrx_gen_somfy_keytis_protocol( + subghz->txrx, + subghz->gen_info->mod, + subghz->gen_info->freq, + subghz->gen_info->somfy_keytis.serial, + subghz->gen_info->somfy_keytis.btn, + subghz->gen_info->somfy_keytis.cnt); + break; case GenKingGatesStylo4k: generated_protocol = subghz_txrx_gen_kinggates_stylo_4k_protocol( subghz->txrx, diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed.c b/applications/main/subghz/scenes/subghz_scene_set_seed.c index 36307f11f..1ba7d4c61 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed.c @@ -30,6 +30,7 @@ void subghz_scene_set_seed_on_enter(void* context) { case GenKeeloq: case GenAlutechAt4n: case GenSomfyTelis: + case GenSomfyKeytis: case GenKingGatesStylo4k: case GenBenincaARC: case GenJarolift: @@ -92,6 +93,7 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { case GenKeeloq: case GenAlutechAt4n: case GenSomfyTelis: + case GenSomfyKeytis: case GenKingGatesStylo4k: case GenBenincaARC: case GenJarolift: diff --git a/applications/main/subghz/scenes/subghz_scene_set_serial.c b/applications/main/subghz/scenes/subghz_scene_set_serial.c index f30b1a4a5..58fbbf026 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_serial.c +++ b/applications/main/subghz/scenes/subghz_scene_set_serial.c @@ -42,6 +42,10 @@ void subghz_scene_set_serial_on_enter(void* context) { byte_ptr = (uint8_t*)&subghz->gen_info->somfy_telis.serial; byte_count = sizeof(subghz->gen_info->somfy_telis.serial); break; + case GenSomfyKeytis: + byte_ptr = (uint8_t*)&subghz->gen_info->somfy_keytis.serial; + byte_count = sizeof(subghz->gen_info->somfy_keytis.serial); + break; case GenKingGatesStylo4k: byte_ptr = (uint8_t*)&subghz->gen_info->kinggates_stylo_4k.serial; byte_count = sizeof(subghz->gen_info->kinggates_stylo_4k.serial); @@ -122,6 +126,10 @@ bool subghz_scene_set_serial_on_event(void* context, SceneManagerEvent event) { subghz->gen_info->somfy_telis.serial = __bswap32(subghz->gen_info->somfy_telis.serial); break; + case GenSomfyKeytis: + subghz->gen_info->somfy_keytis.serial = + __bswap32(subghz->gen_info->somfy_keytis.serial); + break; case GenKingGatesStylo4k: subghz->gen_info->kinggates_stylo_4k.serial = __bswap32(subghz->gen_info->kinggates_stylo_4k.serial); @@ -159,6 +167,7 @@ bool subghz_scene_set_serial_on_event(void* context, SceneManagerEvent event) { case GenKeeloqBFT: case GenAlutechAt4n: case GenSomfyTelis: + case GenSomfyKeytis: case GenKingGatesStylo4k: case GenBenincaARC: case GenJarolift: diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 2be40602b..e696664f5 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -16,6 +16,7 @@ static const char* submenu_names[SetTypeMAX] = { [SetTypeFaacSLH_433] = "FAAC SLH 433MHz", [SetTypeBFTMitto] = "BFT Mitto 433MHz", [SetTypeSomfyTelis] = "Somfy Telis 433MHz", + [SetTypeSomfyKeytis] = "Somfy Keytis 433MHz", [SetTypeANMotorsAT4] = "AN-Motors AT4 433MHz", [SetTypeAlutechAT4N] = "Alutech AT4N 433MHz", [SetTypeRoger_433] = "Roger 433MHz", @@ -56,7 +57,7 @@ static const char* submenu_names[SetTypeMAX] = { [SetTypeCardinS449_433FM] = "KL: Cardin S449 433MHz", [SetTypeFAACRCXT_433_92] = "KL: FAAC RC,XT 433MHz", [SetTypeFAACRCXT_868] = "KL: FAAC RC,XT 868MHz", - [SetTypeGeniusBravo433] = "KL: Genius Bravo 433MHz", + [SetTypeGeniusBravo433] = "KL: Genius TX4RC 433MHz", [SetTypeNiceMHouse_433_92] = "KL: Mhouse 433MHz", [SetTypeNiceSmilo_433_92] = "KL: Nice Smilo 433MHz", [SetTypeNiceFlorS_433_92] = "Nice FloR-S 433MHz", @@ -190,6 +191,15 @@ bool subghz_scene_set_type_generate_protocol_from_infos(SubGhz* subghz) { gen_info.somfy_telis.btn, gen_info.somfy_telis.cnt); break; + case GenSomfyKeytis: + generated_protocol = subghz_txrx_gen_somfy_keytis_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.somfy_keytis.serial, + gen_info.somfy_keytis.btn, + gen_info.somfy_keytis.cnt); + break; case GenKingGatesStylo4k: generated_protocol = subghz_txrx_gen_kinggates_stylo_4k_protocol( subghz->txrx, @@ -296,6 +306,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { case GenKeeloqBFT: // Serial (u32), Button (u8), Counter (u16), Seed (u32) case GenAlutechAt4n: // Serial (u32), Button (u8), Counter (u16) case GenSomfyTelis: // Serial (u32), Button (u8), Counter (u16) + case GenSomfyKeytis: // Serial (u32), Button (u8), Counter (u16) case GenKingGatesStylo4k: // Serial (u32), Button (u8), Counter (u16) case GenBenincaARC: // Serial (u32), Button (u8), Counter (u32) case GenJarolift: // Serial (u32), Button (u4), Counter (u16) diff --git a/lib/subghz/protocols/somfy_keytis.c b/lib/subghz/protocols/somfy_keytis.c index 38873d064..e673ad0ae 100644 --- a/lib/subghz/protocols/somfy_keytis.c +++ b/lib/subghz/protocols/somfy_keytis.c @@ -7,6 +7,8 @@ #include "../blocks/generic.h" #include "../blocks/math.h" +#include "../blocks/custom_btn_i.h" + #define TAG "SubGhzProtocolSomfyKeytis" static const SubGhzBlockConst subghz_protocol_somfy_keytis_const = { @@ -122,17 +124,49 @@ void subghz_protocol_decoder_somfy_keytis_reset(void* context) { NULL); } +static void subghz_protocol_somfy_keytis_check_remote_controller(SubGhzBlockGeneric* instance); + +static uint8_t subghz_protocol_somfy_keytis_get_btn_code(void) { + uint8_t custom_btn_id = subghz_custom_btn_get(); + uint8_t original_btn_code = subghz_custom_btn_get_original(); + uint8_t btn = original_btn_code; + + // Set custom button + if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) { + // Restore original button code + btn = original_btn_code; + } else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) { + switch(original_btn_code) { + case 0x4: + btn = 0x3; + break; + case 0x3: + btn = 0x4; + break; + + default: + break; + } + } + + return btn; +} + static bool subghz_protocol_somfy_keytis_gen_data(SubGhzProtocolEncoderSomfyKeytis* instance, uint8_t btn) { - UNUSED(btn); - uint64_t data = instance->generic.data ^ (instance->generic.data >> 8); - instance->generic.btn = (data >> 48) & 0xF; - instance->generic.cnt = (data >> 24) & 0xFFFF; - instance->generic.serial = data & 0xFFFFFF; + //instance->generic.btn = (data >> 48) & 0xF; + //instance->generic.cnt = (data >> 24) & 0xFFFF; + //instance->generic.serial = data & 0xFFFFFF; + // Save original button for later use + if(subghz_custom_btn_get_original() == 0) { + subghz_custom_btn_set_original(btn); + } + + btn = subghz_protocol_somfy_keytis_get_btn_code(); // override button if we change it with signal settings button editor - if(subghz_block_generic_global_button_override_get(&instance->generic.btn)) - FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", instance->generic.btn); + if(subghz_block_generic_global_button_override_get(&btn)) + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", btn); // Check for OFEX (overflow experimental) mode if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { @@ -156,7 +190,7 @@ static bool } uint8_t frame[10]; - frame[0] = (0xA << 4) | instance->generic.btn; + frame[0] = (0xA << 4) | btn; frame[1] = 0xF << 4; frame[2] = instance->generic.cnt >> 8; frame[3] = instance->generic.cnt; @@ -178,7 +212,7 @@ static bool for(uint8_t i = 1; i < 7; i++) { frame[i] ^= frame[i - 1]; } - data = 0; + uint64_t data = 0; for(uint8_t i = 0; i < 7; ++i) { data <<= 8; data |= frame[i]; @@ -420,6 +454,8 @@ SubGhzProtocolStatus flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_somfy_keytis_check_remote_controller(&instance->generic); + subghz_protocol_encoder_somfy_keytis_get_upload(instance, instance->generic.btn); if(!flipper_format_rewind(flipper_format)) { @@ -711,6 +747,12 @@ static void subghz_protocol_somfy_keytis_check_remote_controller(SubGhzBlockGene instance->btn = (data >> 48) & 0xF; instance->cnt = (data >> 24) & 0xFFFF; instance->serial = data & 0xFFFFFF; + + // Save original button for later use + if(subghz_custom_btn_get_original() == 0) { + subghz_custom_btn_set_original(instance->btn); + } + subghz_custom_btn_set_max(1); } /** From 95debd82c2a40db7d189e2235fb517d5e40b7c85 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 22 Feb 2026 20:24:09 +0300 Subject: [PATCH 141/160] fix keytis variable usage --- lib/subghz/protocols/somfy_keytis.c | 44 +++++++++++++++++------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/lib/subghz/protocols/somfy_keytis.c b/lib/subghz/protocols/somfy_keytis.c index e673ad0ae..2825ea7a0 100644 --- a/lib/subghz/protocols/somfy_keytis.c +++ b/lib/subghz/protocols/somfy_keytis.c @@ -26,7 +26,6 @@ struct SubGhzProtocolDecoderSomfyKeytis { uint16_t header_count; ManchesterState manchester_saved_state; - uint32_t press_duration_counter; }; struct SubGhzProtocolEncoderSomfyKeytis { @@ -223,7 +222,7 @@ static bool data <<= 8; data |= frame[i]; } - instance->generic.data_2 = data; + instance->generic.seed = data; return true; } @@ -239,12 +238,25 @@ bool subghz_protocol_somfy_keytis_create_data( instance->generic.serial = serial; instance->generic.cnt = cnt; instance->generic.data_count_bit = 80; - bool res = subghz_protocol_somfy_keytis_gen_data(instance, btn); - if(res) { - return SubGhzProtocolStatusOk == - subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + subghz_protocol_somfy_keytis_gen_data(instance, btn); + + // Encode complete, now serialize + SubGhzProtocolStatus res = + subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + res = SubGhzProtocolStatusErrorParserOthers; } - return res; + + if((res == SubGhzProtocolStatusOk) && + !flipper_format_write_uint32( + flipper_format, "Duration_Counter", &instance->generic.seed, 1)) { + FURI_LOG_E(TAG, "Unable to add Duration_Counter"); + res = SubGhzProtocolStatusErrorParserOthers; + } + + return res == SubGhzProtocolStatusOk; } /** @@ -310,7 +322,7 @@ static bool subghz_protocol_encoder_somfy_keytis_get_upload( } for(uint8_t i = 24; i > 0; i--) { - if(bit_read(instance->generic.data_2, i - 1)) { + if(bit_read(instance->generic.seed, i - 1)) { if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) { instance->encoder.upload[index - 1].duration *= 2; // 00 instance->encoder.upload[index++] = level_duration_make( @@ -388,7 +400,7 @@ static bool subghz_protocol_encoder_somfy_keytis_get_upload( } for(uint8_t i = 24; i > 0; i--) { - if(bit_read(instance->generic.data_2, i - 1)) { + if(bit_read(instance->generic.seed, i - 1)) { if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) { instance->encoder.upload[index - 1].duration *= 2; // 00 instance->encoder.upload[index++] = level_duration_make( @@ -551,7 +563,7 @@ void subghz_protocol_decoder_somfy_keytis_feed(void* context, bool level, uint32 instance->decoder.parser_step = SomfyKeytisDecoderStepDecoderData; instance->decoder.decode_data = 0; instance->decoder.decode_count_bit = 0; - instance->press_duration_counter = 0; + instance->generic.seed = 0; manchester_advance( instance->manchester_saved_state, ManchesterEventReset, @@ -628,8 +640,7 @@ void subghz_protocol_decoder_somfy_keytis_feed(void* context, bool level, uint32 if(instance->decoder.decode_count_bit < 56) { instance->decoder.decode_data = (instance->decoder.decode_data << 1) | data; } else { - instance->press_duration_counter = (instance->press_duration_counter << 1) | - data; + instance->generic.seed = (instance->generic.seed << 1) | data; } instance->decoder.decode_count_bit++; @@ -797,7 +808,7 @@ SubGhzProtocolStatus subghz_protocol_decoder_somfy_keytis_serialize( subghz_block_generic_serialize(&instance->generic, flipper_format, preset); if((ret == SubGhzProtocolStatusOk) && !flipper_format_write_uint32( - flipper_format, "Duration_Counter", &instance->press_duration_counter, 1)) { + flipper_format, "Duration_Counter", &instance->generic.seed, 1)) { FURI_LOG_E(TAG, "Unable to add Duration_Counter"); ret = SubGhzProtocolStatusErrorParserOthers; } @@ -823,10 +834,7 @@ SubGhzProtocolStatus break; } if(!flipper_format_read_uint32( - flipper_format, - "Duration_Counter", - (uint32_t*)&instance->press_duration_counter, - 1)) { + flipper_format, "Duration_Counter", (uint32_t*)&instance->generic.seed, 1)) { FURI_LOG_E(TAG, "Missing Duration_Counter"); ret = SubGhzProtocolStatusErrorParserOthers; break; @@ -864,7 +872,7 @@ void subghz_protocol_decoder_somfy_keytis_get_string(void* context, FuriString* instance->generic.data_count_bit, (uint32_t)(instance->generic.data >> 32), (uint32_t)instance->generic.data, - instance->press_duration_counter, + instance->generic.seed, instance->generic.serial, instance->generic.cnt, instance->generic.btn, From 317838eaf4194013fb00c9b1bf20b46b102e84c1 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 22 Feb 2026 20:33:06 +0300 Subject: [PATCH 142/160] fix keytis key generation --- applications/main/subghz/helpers/subghz_gen_info.c | 2 +- lib/subghz/protocols/somfy_keytis.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_gen_info.c b/applications/main/subghz/helpers/subghz_gen_info.c index f9574d40d..bce3d6856 100644 --- a/applications/main/subghz/helpers/subghz_gen_info.c +++ b/applications/main/subghz/helpers/subghz_gen_info.c @@ -528,7 +528,7 @@ void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType ty .type = GenSomfyKeytis, .mod = "AM650", .freq = 433420000, - .somfy_keytis.serial = (key & 0x000FFFFF) | 0x0D500000, + .somfy_keytis.serial = (key & 0x0000FFFF) | 0x00D50000, .somfy_keytis.btn = 0x04, .somfy_keytis.cnt = 0x03}; break; diff --git a/lib/subghz/protocols/somfy_keytis.c b/lib/subghz/protocols/somfy_keytis.c index 2825ea7a0..cf03f4b4d 100644 --- a/lib/subghz/protocols/somfy_keytis.c +++ b/lib/subghz/protocols/somfy_keytis.c @@ -250,7 +250,7 @@ bool subghz_protocol_somfy_keytis_create_data( } if((res == SubGhzProtocolStatusOk) && - !flipper_format_write_uint32( + !flipper_format_insert_or_update_uint32( flipper_format, "Duration_Counter", &instance->generic.seed, 1)) { FURI_LOG_E(TAG, "Unable to add Duration_Counter"); res = SubGhzProtocolStatusErrorParserOthers; From 0c6140217832fd7c57e9c51faa2375283d1f0bb5 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 22 Feb 2026 22:44:44 +0300 Subject: [PATCH 143/160] keeloq bft mitto experiments --- lib/subghz/protocols/keeloq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 83e7fdc34..2ad023f24 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -803,6 +803,8 @@ void subghz_protocol_decoder_keeloq_reset(void* context) { // TODO instance->keystore->mfname = ""; instance->keystore->kl_type = 0; + // Reset seed? + instance->generic.seed = 0; } void subghz_protocol_decoder_keeloq_feed(void* context, bool level, uint32_t duration) { From a4ae9293217d2cb592210e77187fb69aacaf1453 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 22 Feb 2026 22:48:23 +0300 Subject: [PATCH 144/160] upd changelog --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e8607072..e65641fad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ ## Main changes - Current API: 87.6 -* SubGHz: Signal Settings Improvements (PR #968 | by @Dmitry422) +* SubGHz: **BFT Mitto fix decode bug** (seed was not resetting after one successful decode) +* SubGHz: **Somfy Keytis** button switch and **Add Manually support** +* SubGHz: **KeeLoq** change delta size +* SubGHz: **Genius Echo/Bravo** add 2 buttons hold simulation (0xB btn code) +* SubGHz: Signal **Settings Improvements** (PR #968 | by @Dmitry422) * OFW PR 4338: HID: Fix USB HID keyboard LED state reporting (by @Caballosanex) * Apps: Build tag (**22feb2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes From 9aacbf943c458df1db94c05c0c08cc87bbc93bb0 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 22 Feb 2026 22:52:25 +0300 Subject: [PATCH 145/160] upd docs --- documentation/SubGHzSupportedSystems.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/SubGHzSupportedSystems.md b/documentation/SubGHzSupportedSystems.md index 1784b9db9..69ec4d4ec 100644 --- a/documentation/SubGHzSupportedSystems.md +++ b/documentation/SubGHzSupportedSystems.md @@ -49,7 +49,7 @@ That list is only for default SubGHz app, apps like *Weather Station* have their - V2 Phoenix (Phox) `433.92MHz` `AM650` (52 bits, Dynamic) (receivers have option to enable Static mode, making them ignore rolling part of the key) - Marantec `433.92MHz, 868MHz` `AM650` (49 bits, Static) - Marantec24 `868MHz` `AM650` (24 bits, Static) -- Somfy Keytis `433.42MHz, 868MHz` `AM650` (80 bits, Dynamic) +- Somfy Keytis `433.42MHz, 868MHz` `AM650` (80 bits, Dynamic) (KeyGo 4 RTS 4 / Keytis NS 2RTS) - ZKTeco `430.5MHz` `AM650` (24 bits, Static - Princeton based) - (Button codes (already mapped to arrow keys): `0x30 (UP)`, `0x03 (STOP)`, `0x0C (DOWN)`) - Linear `300MHz` `AM650` (10 bits, Static) - Linear Delta3 `AM650` (8 bits, Static) From 485a705d5bebbe8bd583f832bd488591eed37f59 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 23 Feb 2026 04:21:24 +0300 Subject: [PATCH 146/160] subghz: bft force seed value --- lib/subghz/protocols/keeloq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 2ad023f24..421cfe560 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -1023,10 +1023,10 @@ static uint32_t subghz_protocol_keeloq_check_remote_controller_selector( case KEELOQ_LEARNING_SECURE: bool reset_seed_back = false; if((strcmp(furi_string_get_cstr(manufacture_code->name), "BFT") == 0)) { - if(instance->seed == 0) { - instance->seed = (fix & 0xFFFFFFF); - reset_seed_back = true; - } + //if(instance->seed == 0) { + instance->seed = (fix & 0xFFFFFFF); + reset_seed_back = true; + //} } man = subghz_protocol_keeloq_common_secure_learning( fix, instance->seed, manufacture_code->key); From 35474e3627a7c57a1d59906b113b2bb57b36b240 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 23 Feb 2026 04:30:26 +0300 Subject: [PATCH 147/160] subghz: bft experiments --- lib/subghz/protocols/keeloq.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 421cfe560..159dbc62a 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -1023,11 +1023,23 @@ static uint32_t subghz_protocol_keeloq_check_remote_controller_selector( case KEELOQ_LEARNING_SECURE: bool reset_seed_back = false; if((strcmp(furi_string_get_cstr(manufacture_code->name), "BFT") == 0)) { + // Try current seed from file if present + man = subghz_protocol_keeloq_common_secure_learning( + fix, instance->seed, manufacture_code->key); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); + if(subghz_protocol_keeloq_check_decrypt( + instance, decrypt, btn, end_serial)) { + *manufacture_name = furi_string_get_cstr(manufacture_code->name); + keystore->mfname = *manufacture_name; + return decrypt; + } + // Try seed from serial //if(instance->seed == 0) { instance->seed = (fix & 0xFFFFFFF); reset_seed_back = true; //} } + // Try seed from serial or zero seed man = subghz_protocol_keeloq_common_secure_learning( fix, instance->seed, manufacture_code->key); decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); From 556a2dd3f6012d6d0ae4abe20f0ebc1997e4ae13 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 28 Feb 2026 05:29:03 +0300 Subject: [PATCH 148/160] subghz: add ditec gol4 protocol by @xMasterX (MMX) & @zero-mega --- .../main/subghz/helpers/subghz_custom_event.h | 1 + .../main/subghz/helpers/subghz_gen_info.c | 9 + .../main/subghz/helpers/subghz_gen_info.h | 6 + .../helpers/subghz_txrx_create_protocol_key.c | 30 + .../helpers/subghz_txrx_create_protocol_key.h | 8 + .../subghz/scenes/subghz_scene_set_button.c | 5 + .../subghz/scenes/subghz_scene_set_counter.c | 16 + .../subghz/scenes/subghz_scene_set_seed.c | 2 + .../subghz/scenes/subghz_scene_set_serial.c | 9 + .../subghz/scenes/subghz_scene_set_type.c | 11 + lib/subghz/protocols/ditec_gol4.c | 729 ++++++++++++++++++ lib/subghz/protocols/ditec_gol4.h | 109 +++ lib/subghz/protocols/protocol_items.c | 1 + lib/subghz/protocols/protocol_items.h | 1 + lib/subghz/protocols/public_api.h | 18 + targets/f7/api_symbols.csv | 1 + 16 files changed, 956 insertions(+) create mode 100644 lib/subghz/protocols/ditec_gol4.c create mode 100644 lib/subghz/protocols/ditec_gol4.h diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index 4242e552d..ebb120929 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -74,6 +74,7 @@ typedef enum { SetTypeKingGatesStylo4k, SetTypeBenincaARC, SetTypeJarolift, + SetTypeDitecGOL4, SetTypeANMotorsAT4, SetTypeAlutechAT4N, SetTypePhoenix_V2_433, diff --git a/applications/main/subghz/helpers/subghz_gen_info.c b/applications/main/subghz/helpers/subghz_gen_info.c index bce3d6856..db3f2926a 100644 --- a/applications/main/subghz/helpers/subghz_gen_info.c +++ b/applications/main/subghz/helpers/subghz_gen_info.c @@ -559,6 +559,15 @@ void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType ty .jarolift.btn = 0x02, .jarolift.cnt = 0x03}; break; + case SetTypeDitecGOL4: + gen_info = (GenInfo){ + .type = GenDitecGOL4, + .mod = "AM650", + .freq = 433920000, + .ditec_gol4.serial = (key & 0x0000FFFF) | 0xCC090000, + .ditec_gol4.btn = 0x01, + .ditec_gol4.cnt = 0xC200}; + break; case SetTypeMotorline433: gen_info = (GenInfo){ .type = GenKeeloq, diff --git a/applications/main/subghz/helpers/subghz_gen_info.h b/applications/main/subghz/helpers/subghz_gen_info.h index 478039c45..60212801c 100644 --- a/applications/main/subghz/helpers/subghz_gen_info.h +++ b/applications/main/subghz/helpers/subghz_gen_info.h @@ -14,6 +14,7 @@ typedef enum { GenKingGatesStylo4k, GenBenincaARC, GenJarolift, + GenDitecGOL4, GenNiceFlorS, GenSecPlus1, GenSecPlus2, @@ -100,6 +101,11 @@ typedef struct { uint32_t serial; uint16_t cnt; } phoenix_v2; + struct { + uint32_t serial; + uint8_t btn; + uint16_t cnt; + } ditec_gol4; }; } GenInfo; diff --git a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c index 72197c0c9..11bb70ed9 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c +++ b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c @@ -455,6 +455,36 @@ bool subghz_txrx_gen_jarolift_protocol( return res; } +bool subghz_txrx_gen_ditec_gol4_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt) { + SubGhzTxRx* txrx = context; + + bool res = false; + + txrx->transmitter = + subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_DITEC_GOL4_NAME); + subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); + + if(txrx->transmitter && subghz_protocol_ditec_gol4_create_data( + subghz_transmitter_get_protocol_instance(txrx->transmitter), + txrx->fff_data, + serial, + btn, + cnt, + txrx->preset)) { + res = true; + } + + subghz_transmitter_free(txrx->transmitter); + + return res; +} + bool subghz_txrx_gen_secplus_v2_protocol( SubGhzTxRx* instance, const char* name_preset, diff --git a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h index 9cd75fad7..811724584 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h +++ b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h @@ -140,6 +140,14 @@ bool subghz_txrx_gen_jarolift_protocol( uint8_t btn, uint16_t cnt); +bool subghz_txrx_gen_ditec_gol4_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt); + bool subghz_txrx_gen_came_atomo_protocol( void* context, const char* preset_name, diff --git a/applications/main/subghz/scenes/subghz_scene_set_button.c b/applications/main/subghz/scenes/subghz_scene_set_button.c index 9f96f03d2..2006fdfa6 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_button.c +++ b/applications/main/subghz/scenes/subghz_scene_set_button.c @@ -52,6 +52,10 @@ void subghz_scene_set_button_on_enter(void* context) { byte_ptr = &subghz->gen_info->jarolift.btn; byte_count = sizeof(subghz->gen_info->jarolift.btn); break; + case GenDitecGOL4: + byte_ptr = &subghz->gen_info->ditec_gol4.btn; + byte_count = sizeof(subghz->gen_info->ditec_gol4.btn); + break; case GenNiceFlorS: byte_ptr = &subghz->gen_info->nice_flor_s.btn; byte_count = sizeof(subghz->gen_info->nice_flor_s.btn); @@ -101,6 +105,7 @@ bool subghz_scene_set_button_on_event(void* context, SceneManagerEvent event) { case GenKingGatesStylo4k: case GenBenincaARC: case GenJarolift: + case GenDitecGOL4: case GenNiceFlorS: case GenSomfyKeytis: case GenSecPlus2: diff --git a/applications/main/subghz/scenes/subghz_scene_set_counter.c b/applications/main/subghz/scenes/subghz_scene_set_counter.c index d9ad3a42c..be13499b8 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_counter.c +++ b/applications/main/subghz/scenes/subghz_scene_set_counter.c @@ -58,6 +58,10 @@ void subghz_scene_set_counter_on_enter(void* context) { byte_ptr = (uint8_t*)&subghz->gen_info->jarolift.cnt; byte_count = sizeof(subghz->gen_info->jarolift.cnt); break; + case GenDitecGOL4: + byte_ptr = (uint8_t*)&subghz->gen_info->ditec_gol4.cnt; + byte_count = sizeof(subghz->gen_info->ditec_gol4.cnt); + break; case GenNiceFlorS: byte_ptr = (uint8_t*)&subghz->gen_info->nice_flor_s.cnt; byte_count = sizeof(subghz->gen_info->nice_flor_s.cnt); @@ -142,6 +146,9 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { case GenJarolift: subghz->gen_info->jarolift.cnt = __bswap16(subghz->gen_info->jarolift.cnt); break; + case GenDitecGOL4: + subghz->gen_info->ditec_gol4.cnt = __bswap16(subghz->gen_info->ditec_gol4.cnt); + break; case GenNiceFlorS: subghz->gen_info->nice_flor_s.cnt = __bswap16(subghz->gen_info->nice_flor_s.cnt); break; @@ -236,6 +243,15 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { subghz->gen_info->jarolift.btn, subghz->gen_info->jarolift.cnt); break; + case GenDitecGOL4: + generated_protocol = subghz_txrx_gen_ditec_gol4_protocol( + subghz->txrx, + subghz->gen_info->mod, + subghz->gen_info->freq, + subghz->gen_info->ditec_gol4.serial, + subghz->gen_info->ditec_gol4.btn, + subghz->gen_info->ditec_gol4.cnt); + break; case GenNiceFlorS: generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( subghz->txrx, diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed.c b/applications/main/subghz/scenes/subghz_scene_set_seed.c index 1ba7d4c61..b3bd447e6 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed.c @@ -34,6 +34,7 @@ void subghz_scene_set_seed_on_enter(void* context) { case GenKingGatesStylo4k: case GenBenincaARC: case GenJarolift: + case GenDitecGOL4: case GenNiceFlorS: case GenSecPlus2: case GenPhoenixV2: @@ -97,6 +98,7 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { case GenKingGatesStylo4k: case GenBenincaARC: case GenJarolift: + case GenDitecGOL4: case GenNiceFlorS: case GenSecPlus2: case GenPhoenixV2: diff --git a/applications/main/subghz/scenes/subghz_scene_set_serial.c b/applications/main/subghz/scenes/subghz_scene_set_serial.c index 58fbbf026..ba105a804 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_serial.c +++ b/applications/main/subghz/scenes/subghz_scene_set_serial.c @@ -58,6 +58,10 @@ void subghz_scene_set_serial_on_enter(void* context) { byte_ptr = (uint8_t*)&subghz->gen_info->jarolift.serial; byte_count = sizeof(subghz->gen_info->jarolift.serial); break; + case GenDitecGOL4: + byte_ptr = (uint8_t*)&subghz->gen_info->ditec_gol4.serial; + byte_count = sizeof(subghz->gen_info->ditec_gol4.serial); + break; case GenNiceFlorS: byte_ptr = (uint8_t*)&subghz->gen_info->nice_flor_s.serial; byte_count = sizeof(subghz->gen_info->nice_flor_s.serial); @@ -137,6 +141,10 @@ bool subghz_scene_set_serial_on_event(void* context, SceneManagerEvent event) { case GenJarolift: subghz->gen_info->jarolift.serial = __bswap32(subghz->gen_info->jarolift.serial); break; + case GenDitecGOL4: + subghz->gen_info->ditec_gol4.serial = + __bswap32(subghz->gen_info->ditec_gol4.serial); + break; case GenBenincaARC: subghz->gen_info->beninca_arc.serial = __bswap32(subghz->gen_info->beninca_arc.serial); @@ -171,6 +179,7 @@ bool subghz_scene_set_serial_on_event(void* context, SceneManagerEvent event) { case GenKingGatesStylo4k: case GenBenincaARC: case GenJarolift: + case GenDitecGOL4: case GenNiceFlorS: case GenSecPlus2: scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetButton); diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index e696664f5..7ee72ea21 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -24,6 +24,7 @@ static const char* submenu_names[SetTypeMAX] = { [SetTypeKingGatesStylo4k] = "KingGates Stylo4k 433M.", [SetTypeBenincaARC] = "Beninca ARC 433MHz", [SetTypeJarolift] = "Jarolift 433MHz", + [SetTypeDitecGOL4] = "Ditec GOL4 433MHz", [SetTypeHCS101_433_92] = "KL: HCS101 433MHz", [SetTypeDoorHan_315_00] = "KL: DoorHan 315MHz", [SetTypeDoorHan_433_92] = "KL: DoorHan 433MHz", @@ -227,6 +228,15 @@ bool subghz_scene_set_type_generate_protocol_from_infos(SubGhz* subghz) { gen_info.jarolift.btn, gen_info.jarolift.cnt); break; + case GenDitecGOL4: + generated_protocol = subghz_txrx_gen_ditec_gol4_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.ditec_gol4.serial, + gen_info.ditec_gol4.btn, + gen_info.ditec_gol4.cnt); + break; case GenNiceFlorS: generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( subghz->txrx, @@ -310,6 +320,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { case GenKingGatesStylo4k: // Serial (u32), Button (u8), Counter (u16) case GenBenincaARC: // Serial (u32), Button (u8), Counter (u32) case GenJarolift: // Serial (u32), Button (u4), Counter (u16) + case GenDitecGOL4: // Serial (u32), Button (u4), Counter (u16) case GenNiceFlorS: // Serial (u32), Button (u8), Counter (u16) case GenSecPlus2: // Serial (u32), Button (u8), Counter (u32) case GenPhoenixV2: // Serial (u32), Counter (u16) diff --git a/lib/subghz/protocols/ditec_gol4.c b/lib/subghz/protocols/ditec_gol4.c new file mode 100644 index 000000000..c7ca600fa --- /dev/null +++ b/lib/subghz/protocols/ditec_gol4.c @@ -0,0 +1,729 @@ +#include "ditec_gol4.h" +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#include "../blocks/custom_btn_i.h" + +#define TAG "SubGhzProtocolDitecGOL4" + +#define GOL4_RAW_BYTES 7 + +static const SubGhzBlockConst subghz_protocol_ditec_gol4_const = { + .te_short = 400, + .te_long = 1100, + .te_delta = 200, + .min_count_bit_for_found = 54, +}; + +struct SubGhzProtocolDecoderDitecGOL4 { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; +}; + +struct SubGhzProtocolEncoderDitecGOL4 { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + DitecGOL4DecoderStepReset = 0, + DitecGOL4DecoderStepStartBit, + DitecGOL4DecoderStepSaveDuration, + DitecGOL4DecoderStepCheckDuration, +} DitecGOL4DecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_ditec_gol4_decoder = { + .alloc = subghz_protocol_decoder_ditec_gol4_alloc, + .free = subghz_protocol_decoder_ditec_gol4_free, + + .feed = subghz_protocol_decoder_ditec_gol4_feed, + .reset = subghz_protocol_decoder_ditec_gol4_reset, + + .get_hash_data = subghz_protocol_decoder_ditec_gol4_get_hash_data, + .serialize = subghz_protocol_decoder_ditec_gol4_serialize, + .deserialize = subghz_protocol_decoder_ditec_gol4_deserialize, + .get_string = subghz_protocol_decoder_ditec_gol4_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_ditec_gol4_encoder = { + .alloc = subghz_protocol_encoder_ditec_gol4_alloc, + .free = subghz_protocol_encoder_ditec_gol4_free, + + .deserialize = subghz_protocol_encoder_ditec_gol4_deserialize, + .stop = subghz_protocol_encoder_ditec_gol4_stop, + .yield = subghz_protocol_encoder_ditec_gol4_yield, +}; + +const SubGhzProtocol subghz_protocol_ditec_gol4 = { + .name = SUBGHZ_PROTOCOL_DITEC_GOL4_NAME, + .type = SubGhzProtocolTypeDynamic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_ditec_gol4_decoder, + .encoder = &subghz_protocol_ditec_gol4_encoder, +}; + +/** + * Defines the button value for the current btn_id + * Basic set | 0x1 | 0x2 | 0x4 | 0x8 | 0x0 PROG + * @return Button code + */ +static uint8_t subghz_protocol_ditec_gol4_get_btn_code(void); + +static uint8_t gol4_bit_reverse(uint8_t b) { + b &= 0xFF; + uint8_t result = 0; + for(uint8_t i = 0; i < 8; i++) { + result = (uint8_t)((result << 1) | (b & 1)); + b >>= 1; + } + return result; +} + +static uint8_t gol4_lcg_step(uint8_t seed, uint8_t steps) { + uint8_t x = seed & 0xFF; + steps &= 0xFF; + for(uint8_t i = 0; i < steps; i++) { + x = (uint8_t)((21 * x + 1) & 0xFF); + } + return x; +} + +static uint8_t gol4_lcg_inverse(uint8_t target, uint8_t steps) { + steps &= 0xFF; + if(steps == 0) return target & 0xFF; + return gol4_lcg_step(target, (uint8_t)(256 - steps)); +} + +static void gol4_decode_rotate_and_bitrev(uint8_t* raw) { + uint8_t carry = 0; + for(uint8_t r = 0; r < 3; r++) { + for(uint8_t i = 2; i < 7; i++) { + uint8_t new_carry = raw[i] & 1; + raw[i] = (uint8_t)(((raw[i] >> 1) | (carry << 7)) & 0xFF); + carry = new_carry; + } + } + + raw[0] = gol4_bit_reverse(raw[0]); + raw[1] = gol4_bit_reverse(raw[1]); + raw[3] = gol4_bit_reverse(raw[3]); + raw[4] = gol4_bit_reverse(raw[4]); + + uint8_t b2 = raw[2] & 0xDF; + b2 = (uint8_t)(((b2 << 4) | (b2 >> 4)) & 0xFF); + b2 = (uint8_t)((~b2) & 0xFF); + raw[2] = gol4_bit_reverse(b2); + + raw[5] = gol4_bit_reverse(raw[5]); + raw[6] = gol4_bit_reverse(raw[6]); +} + +static bool gol4_decode_lcg_xor(uint8_t* raw) { + if(raw[6] & 0x80) raw[5] ^= 1; + + uint8_t out5 = gol4_lcg_inverse(raw[5], 0xFE); + raw[5] = out5; + + uint8_t out6 = gol4_lcg_inverse(raw[6], raw[5]); + raw[6] = out6; + + raw[5] ^= 0xA7; + raw[6] ^= 0x69; + return true; +} + +static bool gol4_rolling_decode(uint8_t* raw) { + gol4_decode_rotate_and_bitrev(raw); + return gol4_decode_lcg_xor(raw); +} + +static bool gol4_encode_lcg_xor(uint8_t* raw) { + uint8_t dec5 = (uint8_t)(raw[5] ^ 0xA7); + uint8_t dec6 = (uint8_t)(raw[6] ^ 0x69); + + uint8_t enc6 = gol4_lcg_step(dec6, dec5); + uint8_t enc5 = gol4_lcg_step(dec5, 0xFE); + + if(enc6 & 0x80) enc5 ^= 1; + + raw[5] = enc5; + raw[6] = enc6; + return true; +} + +static void gol4_encode_bitrev_and_rotate(uint8_t* raw) { + raw[0] = gol4_bit_reverse(raw[0]); + raw[1] = gol4_bit_reverse(raw[1]); + raw[3] = gol4_bit_reverse(raw[3]); + raw[4] = gol4_bit_reverse(raw[4]); + + if(raw[2] == 0x0) { + raw[2] = 0xF0; + } + uint8_t b2 = gol4_bit_reverse(raw[2]); + b2 = (uint8_t)(~b2); + b2 = (uint8_t)(((b2 << 4) | (b2 >> 4)) & 0xFF); + b2 &= 0xDF; + raw[2] = b2; + + raw[5] = gol4_bit_reverse(raw[5]); + raw[6] = gol4_bit_reverse(raw[6]); + + uint8_t carry = 0; + for(uint8_t r = 0; r < 3; r++) { + for(int8_t i = 6; i >= 2; i--) { + uint8_t new_carry = (uint8_t)((raw[i] >> 7) & 1); + raw[i] = (uint8_t)(((raw[i] << 1) | carry) & 0xFF); + carry = new_carry; + } + } +} + +static bool gol4_rolling_encode(uint8_t* raw) { + if(!raw) return false; + if(!gol4_encode_lcg_xor(raw)) return false; + gol4_encode_bitrev_and_rotate(raw); + return true; +} + +static void bits_to_raw(const uint8_t* bits, uint8_t* raw) { + memset(raw, 0, GOL4_RAW_BYTES); + for(uint8_t i = 0; i < subghz_protocol_ditec_gol4_const.min_count_bit_for_found; i++) { + uint8_t byte_idx = i / 8; + uint8_t bit_idx = 7 - (i % 8); + if(bits[i]) raw[byte_idx] |= (1 << bit_idx); + } +} + +static void raw_to_bits(const uint8_t* raw, uint8_t* bits) { + for(uint8_t i = 0; i < subghz_protocol_ditec_gol4_const.min_count_bit_for_found; i++) { + uint8_t byte_idx = i / 8; + uint8_t bit_idx = 7 - (i % 8); + bits[i] = (uint8_t)((raw[byte_idx] >> bit_idx) & 1); + } +} + +static uint64_t bits_to_data(const uint8_t* bits) { + uint64_t data = 0; + for(uint8_t i = 0; i < subghz_protocol_ditec_gol4_const.min_count_bit_for_found; i++) { + data = (data << 1) | (uint64_t)(bits[i] & 1); + } + return data; +} + +static uint32_t serial_to_display(const uint8_t* s) { + if(!s) return 0; + return (uint32_t)((s[0] << 24) | (s[4] << 16) | (s[1] << 8) | s[3]); +} + +void* subghz_protocol_encoder_ditec_gol4_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderDitecGOL4* instance = malloc(sizeof(SubGhzProtocolEncoderDitecGOL4)); + + instance->base.protocol = &subghz_protocol_ditec_gol4; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 4; + instance->encoder.size_upload = 128; // 110 actual + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + return instance; +} + +void subghz_protocol_encoder_ditec_gol4_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderDitecGOL4* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderDitecGOL4 instance + */ +static void + subghz_protocol_encoder_ditec_gol4_get_upload(SubGhzProtocolEncoderDitecGOL4* instance) { + furi_assert(instance); + size_t index = 0; + + // Send key and GAP between repeats + //Send gap before data + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_ditec_gol4_const.te_long * 22); + // Start bit + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_ditec_gol4_const.te_short * 2); + + for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { + if(bit_read(instance->generic.data, i - 1)) { + // Send bit 1 + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_ditec_gol4_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_ditec_gol4_const.te_long); + } else { + // Send bit 0 + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_ditec_gol4_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_ditec_gol4_const.te_short); + } + } + + instance->encoder.size_upload = index; + return; +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_ditec_gol4_decode_key(SubGhzBlockGeneric* instance) { + // Ditec GOL4 Decoder + // 2025 - 2026.02 - @xMasterX (MMX) & @zero-mega + // + // RAW Samples + // 0xCCB2F83208122 - btn 1 = 0011001100101100 101111 100000110010000 01000000100100010 + // + // Programming mode: + // 0xCCB1F832103B9 - btn 0 = 0011001100101100 011111 100000110010000 10000001110111001 + // Regular buttons: + // 0xCCB2F8320ED66 - btn 1 = 0011001100101100 101111 100000110010000 01110110101100110 + // 0xCCB37832104A6 - btn 2 = 0011001100101100 110111 100000110010000 10000010010100110 + // 0xCCB3B8320DB4E - btn 4 = 0011001100101100 111011 100000110010000 01101101101001110 + // 0xCCB3D8320E855 - btn 8 = 0011001100101100 111101 100000110010000 01110100001010101 + // + // Regular buttons: + // Decoded array: CC 34 71 83 09 F8 C1 + // Decoded array: CC 34 71 83 09 F9 C1 + // Decoded array: CC 34 72 83 09 FA C1 + // Decoded array: CC 34 74 83 09 FB C1 + // Decoded array: CC 34 78 83 09 FC C1 + // Programming mode + // Decoded array: CC 34 F0 83 09 FD C1 + // Decoded array: CC 34 F0 83 09 FE C1 + // + uint8_t bits[subghz_protocol_ditec_gol4_const.min_count_bit_for_found]; + uint64_t data = instance->data; + for(int i = subghz_protocol_ditec_gol4_const.min_count_bit_for_found - 1; i >= 0; i--) { + bits[i] = (uint8_t)(data & 1); + data >>= 1; + } + uint8_t decrypted[GOL4_RAW_BYTES]; + bits_to_raw(bits, decrypted); + + if(gol4_rolling_decode(decrypted)) { + uint8_t temp_serial[5]; + memcpy(temp_serial, decrypted, 5); + instance->serial = serial_to_display(temp_serial); + instance->btn = decrypted[2] & 0x0F; + instance->cnt = (uint16_t)((decrypted[5] | (decrypted[6] << 8)) & 0xFFFF); + // Save original button for later use + if(subghz_custom_btn_get_original() == 0) { + subghz_custom_btn_set_original(instance->btn); + } + subghz_custom_btn_set_max(4); + } +} + +static void subghz_protocol_ditec_gol4_encode_key(SubGhzBlockGeneric* instance) { + // Encoder crypto part: + // + // TODO: Current issue - last bit at original remote sometimes 0 but we encode as 1, or vice versa. + // This does not affect decoding but may have issue on real receiver + // + uint8_t decrypted[GOL4_RAW_BYTES]; + + // Save original button for later use + if(subghz_custom_btn_get_original() == 0) { + subghz_custom_btn_set_original(instance->btn); + } + + instance->btn = subghz_protocol_ditec_gol4_get_btn_code(); + + // override button if we change it with signal settings button editor + if(subghz_block_generic_global_button_override_get(&instance->btn)) + FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", instance->btn); + + // Check for OFEX (overflow experimental) mode + if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { + // standart counter mode. PULL data from subghz_block_generic_global variables + if(!subghz_block_generic_global_counter_override_get(&instance->cnt)) { + // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value + if((instance->cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { + instance->cnt = 0; + } else { + instance->cnt += furi_hal_subghz_get_rolling_counter_mult(); + } + } + } else { + if((instance->cnt + 0x1) > 0xFFFF) { + instance->cnt = 0; + } else if(instance->cnt >= 0x1 && instance->cnt != 0xFFFE) { + instance->cnt = 0xFFFE; + } else { + instance->cnt++; + } + } + + decrypted[0] = (uint8_t)((instance->serial >> 24) & 0xFF); + decrypted[4] = (uint8_t)((instance->serial >> 16) & 0xFF); + decrypted[1] = (uint8_t)((instance->serial >> 8) & 0xFF); + decrypted[3] = (uint8_t)(instance->serial & 0xFF); + decrypted[2] = (uint8_t)(instance->btn & 0x0F); + + uint16_t counter = (uint16_t)(instance->cnt & 0xFFFF); + decrypted[5] = (uint8_t)(counter & 0xFF); + decrypted[6] = (uint8_t)((counter >> 8) & 0xFF); + + gol4_rolling_encode(decrypted); + + uint8_t bits[subghz_protocol_ditec_gol4_const.min_count_bit_for_found]; + raw_to_bits(decrypted, bits); + instance->data = bits_to_data(bits); +} + +SubGhzProtocolStatus + subghz_protocol_encoder_ditec_gol4_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderDitecGOL4* instance = context; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; + do { + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_ditec_gol4_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { + break; + } + // Optional parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_ditec_gol4_decode_key(&instance->generic); + subghz_protocol_ditec_gol4_encode_key(&instance->generic); + subghz_protocol_encoder_ditec_gol4_get_upload(instance); + + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data >> i * 8) & 0xFF; + } + if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to update Key"); + break; + } + + instance->encoder.is_running = true; + } while(false); + + return ret; +} + +void subghz_protocol_encoder_ditec_gol4_stop(void* context) { + SubGhzProtocolEncoderDitecGOL4* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_ditec_gol4_yield(void* context) { + SubGhzProtocolEncoderDitecGOL4* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_ditec_gol4_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderDitecGOL4* instance = malloc(sizeof(SubGhzProtocolDecoderDitecGOL4)); + instance->base.protocol = &subghz_protocol_ditec_gol4; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_ditec_gol4_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderDitecGOL4* instance = context; + free(instance); +} + +void subghz_protocol_decoder_ditec_gol4_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderDitecGOL4* instance = context; + instance->decoder.parser_step = DitecGOL4DecoderStepReset; +} + +void subghz_protocol_decoder_ditec_gol4_feed(void* context, bool level, uint32_t duration) { + furi_check(context); + SubGhzProtocolDecoderDitecGOL4* instance = context; + + switch(instance->decoder.parser_step) { + case DitecGOL4DecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_ditec_gol4_const.te_long * 22) < + (subghz_protocol_ditec_gol4_const.te_long * 4))) { + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + instance->decoder.parser_step = DitecGOL4DecoderStepStartBit; + } + break; + + case DitecGOL4DecoderStepStartBit: + if((level) && (DURATION_DIFF(duration, subghz_protocol_ditec_gol4_const.te_short * 2) < + subghz_protocol_ditec_gol4_const.te_delta)) { + instance->decoder.parser_step = DitecGOL4DecoderStepSaveDuration; + } else { + instance->decoder.parser_step = DitecGOL4DecoderStepReset; + } + break; + + case DitecGOL4DecoderStepSaveDuration: + if(!level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = DitecGOL4DecoderStepCheckDuration; + } else { + instance->decoder.parser_step = DitecGOL4DecoderStepReset; + } + break; + + case DitecGOL4DecoderStepCheckDuration: + if(level) { + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_ditec_gol4_const.te_short) < + subghz_protocol_ditec_gol4_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_ditec_gol4_const.te_long) < + subghz_protocol_ditec_gol4_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = DitecGOL4DecoderStepSaveDuration; + } else if( + (DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_ditec_gol4_const.te_long) < + subghz_protocol_ditec_gol4_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_ditec_gol4_const.te_short) < + subghz_protocol_ditec_gol4_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = DitecGOL4DecoderStepSaveDuration; + } + } else { + if(DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_ditec_gol4_const.te_long * 20) < + (subghz_protocol_ditec_gol4_const.te_long * 3)) { + if(instance->decoder.decode_count_bit == + subghz_protocol_ditec_gol4_const.min_count_bit_for_found) { + // 54 bits received, save and continue + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = + subghz_protocol_ditec_gol4_const.min_count_bit_for_found; + + if(instance->base.callback) { + instance->base.callback(&instance->base, instance->base.context); + } + } + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + instance->decoder.parser_step = DitecGOL4DecoderStepReset; + } else { + instance->decoder.parser_step = DitecGOL4DecoderStepReset; + } + } + break; + } +} + +uint8_t subghz_protocol_decoder_ditec_gol4_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderDitecGOL4* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +SubGhzProtocolStatus subghz_protocol_decoder_ditec_gol4_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolDecoderDitecGOL4* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +SubGhzProtocolStatus + subghz_protocol_decoder_ditec_gol4_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderDitecGOL4* instance = context; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_ditec_gol4_const.min_count_bit_for_found); +} + +bool subghz_protocol_ditec_gol4_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolEncoderDitecGOL4* instance = context; + instance->generic.btn = btn; + instance->generic.serial = serial; + instance->generic.cnt = cnt; + instance->generic.data_count_bit = subghz_protocol_ditec_gol4_const.min_count_bit_for_found; + + subghz_protocol_ditec_gol4_encode_key(&instance->generic); + + return SubGhzProtocolStatusOk == + subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +static uint8_t subghz_protocol_ditec_gol4_get_btn_code(void) { + uint8_t custom_btn_id = subghz_custom_btn_get(); + uint8_t original_btn_code = subghz_custom_btn_get_original(); + uint8_t btn = original_btn_code; + + // Set custom button + if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) { + // Restore original button code + btn = original_btn_code; + } else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) { + switch(original_btn_code) { + case 0x1: + btn = 0x2; + break; + case 0x2: + btn = 0x1; + break; + case 0x4: + btn = 0x1; + break; + case 0x8: + btn = 0x1; + break; + case 0x0: + btn = 0x1; + break; + + default: + break; + } + } else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) { + switch(original_btn_code) { + case 0x1: + btn = 0x4; + break; + case 0x2: + btn = 0x4; + break; + case 0x4: + btn = 0x2; + break; + case 0x8: + btn = 0x4; + break; + case 0x0: + btn = 0x4; + break; + + default: + break; + } + } else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_LEFT) { + switch(original_btn_code) { + case 0x1: + btn = 0x8; + break; + case 0x2: + btn = 0x8; + break; + case 0x4: + btn = 0x8; + break; + case 0x8: + btn = 0x2; + break; + case 0x0: + btn = 0x2; + break; + + default: + break; + } + } else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_RIGHT) { + switch(original_btn_code) { + case 0x1: + btn = 0x0; + break; + case 0x2: + btn = 0x0; + break; + case 0x4: + btn = 0x0; + break; + case 0x8: + btn = 0x0; + break; + case 0x0: + btn = 0x8; + break; + + default: + break; + } + } + + return btn; +} + +void subghz_protocol_decoder_ditec_gol4_get_string(void* context, FuriString* output) { + furi_assert(context); + SubGhzProtocolDecoderDitecGOL4* instance = context; + + subghz_protocol_ditec_gol4_decode_key(&instance->generic); + + // push protocol data to global variable + subghz_block_generic_global.cnt_is_available = true; + subghz_block_generic_global.cnt_length_bit = 16; + subghz_block_generic_global.current_cnt = instance->generic.cnt; + + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + // + + furi_string_cat_printf( + output, + "%s %db\r\n" + "Key:0x%0lX%08lX\r\n" + "Serial:0x%08lX\r\n" + "Btn:%01X %s\r\n" + "Cnt:%04lX", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data >> 32), + (uint32_t)(instance->generic.data & 0xFFFFFFFF), + instance->generic.serial, + instance->generic.btn, + (instance->generic.btn == 0x0) ? "- Prog" : "", + instance->generic.cnt); +} diff --git a/lib/subghz/protocols/ditec_gol4.h b/lib/subghz/protocols/ditec_gol4.h new file mode 100644 index 000000000..e45e1d73c --- /dev/null +++ b/lib/subghz/protocols/ditec_gol4.h @@ -0,0 +1,109 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_DITEC_GOL4_NAME "Ditec GOL4" + +typedef struct SubGhzProtocolDecoderDitecGOL4 SubGhzProtocolDecoderDitecGOL4; +typedef struct SubGhzProtocolEncoderDitecGOL4 SubGhzProtocolEncoderDitecGOL4; + +extern const SubGhzProtocolDecoder subghz_protocol_ditec_gol4_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_ditec_gol4_encoder; +extern const SubGhzProtocol subghz_protocol_ditec_gol4; + +/** + * Allocate SubGhzProtocolEncoderDitecGOL4. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderDitecGOL4* pointer to a SubGhzProtocolEncoderDitecGOL4 instance + */ +void* subghz_protocol_encoder_ditec_gol4_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderDitecGOL4. + * @param context Pointer to a SubGhzProtocolEncoderDitecGOL4 instance + */ +void subghz_protocol_encoder_ditec_gol4_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderDitecGOL4 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return status + */ +SubGhzProtocolStatus + subghz_protocol_encoder_ditec_gol4_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderDitecGOL4 instance + */ +void subghz_protocol_encoder_ditec_gol4_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderDitecGOL4 instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_ditec_gol4_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderDitecGOL4. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderDitecGOL4* pointer to a SubGhzProtocolDecoderDitecGOL4 instance + */ +void* subghz_protocol_decoder_ditec_gol4_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderDitecGOL4. + * @param context Pointer to a SubGhzProtocolDecoderDitecGOL4 instance + */ +void subghz_protocol_decoder_ditec_gol4_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderDitecGOL4. + * @param context Pointer to a SubGhzProtocolDecoderDitecGOL4 instance + */ +void subghz_protocol_decoder_ditec_gol4_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderDitecGOL4 instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_ditec_gol4_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderDitecGOL4 instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_ditec_gol4_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderDitecGOL4. + * @param context Pointer to a SubGhzProtocolDecoderDitecGOL4 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return status + */ +SubGhzProtocolStatus subghz_protocol_decoder_ditec_gol4_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data SubGhzProtocolDecoderDitecGOL4. + * @param context Pointer to a SubGhzProtocolDecoderDitecGOL4 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return status + */ +SubGhzProtocolStatus + subghz_protocol_decoder_ditec_gol4_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderDitecGOL4 instance + * @param output Resulting text + */ +void subghz_protocol_decoder_ditec_gol4_get_string(void* context, FuriString* output); diff --git a/lib/subghz/protocols/protocol_items.c b/lib/subghz/protocols/protocol_items.c index 14d54b8d3..d4390fd7f 100644 --- a/lib/subghz/protocols/protocol_items.c +++ b/lib/subghz/protocols/protocol_items.c @@ -28,6 +28,7 @@ const SubGhzProtocol* const subghz_protocol_registry_items[] = { &subghz_protocol_feron, &subghz_protocol_roger, &subghz_protocol_elplast, &subghz_protocol_treadmill37, &subghz_protocol_beninca_arc, &subghz_protocol_jarolift, + &subghz_protocol_ditec_gol4, }; const SubGhzProtocolRegistry subghz_protocol_registry = { diff --git a/lib/subghz/protocols/protocol_items.h b/lib/subghz/protocols/protocol_items.h index 2c36260ed..a2067f4e8 100644 --- a/lib/subghz/protocols/protocol_items.h +++ b/lib/subghz/protocols/protocol_items.h @@ -56,3 +56,4 @@ #include "treadmill37.h" #include "beninca_arc.h" #include "jarolift.h" +#include "ditec_gol4.h" diff --git a/lib/subghz/protocols/public_api.h b/lib/subghz/protocols/public_api.h index 7539352dc..43bef118b 100644 --- a/lib/subghz/protocols/public_api.h +++ b/lib/subghz/protocols/public_api.h @@ -249,6 +249,24 @@ bool subghz_protocol_jarolift_create_data( uint16_t cnt, SubGhzRadioPreset* preset); +/** + * Key generation from simple data. + * @param context Pointer to a SubGhzProtocolEncoderDitecGOL4 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param serial Serial number + * @param btn Button number, 8 bit + * @param cnt Counter value, 16 bit + * @param preset Modulation, SubGhzRadioPreset + * @return true On success + */ +bool subghz_protocol_ditec_gol4_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + SubGhzRadioPreset* preset); + typedef struct SubGhzProtocolDecoderBinRAW SubGhzProtocolDecoderBinRAW; void subghz_protocol_decoder_bin_raw_data_input_rssi( diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 136786c7d..bb03dcbb6 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -3721,6 +3721,7 @@ Function,+,subghz_protocol_decoder_raw_feed,void,"void*, _Bool, uint32_t" Function,+,subghz_protocol_decoder_raw_free,void,void* Function,+,subghz_protocol_decoder_raw_get_string,void,"void*, FuriString*" Function,+,subghz_protocol_decoder_raw_reset,void,void* +Function,+,subghz_protocol_ditec_gol4_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*" Function,+,subghz_protocol_encoder_raw_alloc,void*,SubGhzEnvironment* Function,+,subghz_protocol_encoder_raw_deserialize,SubGhzProtocolStatus,"void*, FlipperFormat*" Function,+,subghz_protocol_encoder_raw_free,void,void* From 851303d191971bb5d9457f69242293a734152a29 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 28 Feb 2026 06:01:15 +0300 Subject: [PATCH 149/160] upd changelog --- CHANGELOG.md | 1 + documentation/SubGHzSupportedSystems.md | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e65641fad..9cbcc36fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## Main changes - Current API: 87.6 +* SubGHz: Add **Ditec GOL4** protocol (with programming mode, button switch, add manually) (by @xMasterX (MMX) & @zero-mega) * SubGHz: **BFT Mitto fix decode bug** (seed was not resetting after one successful decode) * SubGHz: **Somfy Keytis** button switch and **Add Manually support** * SubGHz: **KeeLoq** change delta size diff --git a/documentation/SubGHzSupportedSystems.md b/documentation/SubGHzSupportedSystems.md index 69ec4d4ec..3284bc060 100644 --- a/documentation/SubGHzSupportedSystems.md +++ b/documentation/SubGHzSupportedSystems.md @@ -21,10 +21,11 @@ That list is only for default SubGHz app, apps like *Weather Station* have their - Ansonic `433MHz` `FM` (12 bits, Static) - BETT `433.92MHz` `AM650` (18 bits, Static) - Beninca ARC (TOGO2VA) `433.92MHz` `AM650` (128 bits, Dynamic AES128) (button code `0` emulates `hidden button` option on the remote) -- BFT Mitto `433.92MHz` `AM650` (64 bits, Dynamic, KeeLoq based with Seed) +- BFT Mitto `433.92MHz` `AM650` (64 bits, Dynamic, KeeLoq based with Seed taken from serial) - CAME Atomo `433.92MHz, 868MHz` `AM650` (62 bits, Dynamic) - CAME TWEE `433.92MHz` `AM650` (54 bits, Static) - CAME `433.92MHz, 868MHz` `AM650` (12, 24 bits, Static) +- Ditec GOL4 `433.92MHz` `AM650` (54 bits, Dynamic) (should be compatible with BIXLG4, BIXLS2, BIXLP2) - (right arrow emulates button `0` (hidden button)) - Prastel `433.92MHz, 868MHz` `AM650` (25, 42 bits, Static) - Airforce `433.92MHz, 868MHz` `AM650` (18 bits, Static) - Chamberlain Code `AM650` (10 bits, Static) From 6085dc08426ae4b505a6466a6166a57eda9548b8 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 28 Feb 2026 15:20:41 +0300 Subject: [PATCH 150/160] ditec fix missing parity bits --- lib/subghz/protocols/ditec_gol4.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/subghz/protocols/ditec_gol4.c b/lib/subghz/protocols/ditec_gol4.c index c7ca600fa..c046ae770 100644 --- a/lib/subghz/protocols/ditec_gol4.c +++ b/lib/subghz/protocols/ditec_gol4.c @@ -88,6 +88,14 @@ static uint8_t gol4_bit_reverse(uint8_t b) { return result; } +static uint8_t gol4_bit_parity(uint8_t b) { + uint8_t p = 0; + for(uint8_t i = 0; i < 8; i++) { + if((b >> i) & 1u) p ^= 1u; + } + return p; +} + static uint8_t gol4_lcg_step(uint8_t seed, uint8_t steps) { uint8_t x = seed & 0xFF; steps &= 0xFF; @@ -178,6 +186,9 @@ static void gol4_encode_bitrev_and_rotate(uint8_t* raw) { raw[5] = gol4_bit_reverse(raw[5]); raw[6] = gol4_bit_reverse(raw[6]); + uint8_t p5 = gol4_bit_parity(raw[5]); + uint8_t p6 = gol4_bit_parity(raw[6]); + uint8_t carry = 0; for(uint8_t r = 0; r < 3; r++) { for(int8_t i = 6; i >= 2; i--) { @@ -186,6 +197,8 @@ static void gol4_encode_bitrev_and_rotate(uint8_t* raw) { carry = new_carry; } } + + raw[6] = (p5 == p6) ? (uint8_t)(raw[6] & 0xFBu) : (uint8_t)(raw[6] | 0x04u); } static bool gol4_rolling_encode(uint8_t* raw) { From 1c1fe6d74e62482bd5d26da5c0eaa5196a55ce47 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Sat, 28 Feb 2026 22:16:02 +0100 Subject: [PATCH 151/160] FBT: Save 2KB flash on flipper_application --- firmware.scons | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware.scons b/firmware.scons index e53fd8edf..378b196a2 100644 --- a/firmware.scons +++ b/firmware.scons @@ -67,7 +67,7 @@ env = ENV.Clone( }, "flipper_application": { "CCFLAGS": [ - "-Og", + "-Os", ], "CPPDEFINES": [ "NDEBUG", From c98fa215da6d824462017c9bd2c4cd67be2adffb Mon Sep 17 00:00:00 2001 From: WillyJL Date: Sat, 28 Feb 2026 23:41:19 +0100 Subject: [PATCH 152/160] FBT: Use LTO for firmware dfu --nobuild --- firmware.scons | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/firmware.scons b/firmware.scons index 378b196a2..bbd4a54a4 100644 --- a/firmware.scons +++ b/firmware.scons @@ -216,6 +216,14 @@ sources.extend( ) ) +# Link-Time Optimization for firmware dfu only, we are desperately out of flash space +if ENV["COMPACT"]: + fwenv.Append( + CCFLAGS=[ + "-flto", + ], + ) + # Debug # print(fwenv.Dump()) From 3c1cbe39d07b90020abc00767bf6c6de8a5edb4f Mon Sep 17 00:00:00 2001 From: WillyJL Date: Sun, 1 Mar 2026 01:28:12 +0100 Subject: [PATCH 153/160] Fix #include'd C files by mistake --- applications/main/subghz/scenes/subghz_scene_transmitter.c | 1 - targets/f7/furi_hal/furi_hal_bt.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index f22cd3e24..16ba681c8 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -5,7 +5,6 @@ #include -#include #include "applications/main/subghz/helpers/subghz_txrx_i.h" #include "lib/subghz/blocks/generic.h" diff --git a/targets/f7/furi_hal/furi_hal_bt.c b/targets/f7/furi_hal/furi_hal_bt.c index f1881f94f..4c619c2b8 100644 --- a/targets/f7/furi_hal/furi_hal_bt.c +++ b/targets/f7/furi_hal/furi_hal_bt.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include From 0ac1b9b52dbdee802c3ec10aadace6f4cbc7cd00 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Sun, 1 Mar 2026 01:28:52 +0100 Subject: [PATCH 154/160] Sub-GHz: Add function used by app to API --- lib/subghz/protocols/marantec.h | 8 -------- lib/subghz/protocols/public_api.h | 8 ++++++++ targets/f7/api_symbols.csv | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/subghz/protocols/marantec.h b/lib/subghz/protocols/marantec.h index 3d4679afb..6b77d0511 100644 --- a/lib/subghz/protocols/marantec.h +++ b/lib/subghz/protocols/marantec.h @@ -107,11 +107,3 @@ SubGhzProtocolStatus * @param output Resulting text */ void subghz_protocol_decoder_marantec_get_string(void* context, FuriString* output); - -/** - * Calculate CRC8 for Marantec protocol. - * @param data Pointer to the data buffer - * @param len Length of the data buffer - * @return CRC8 value - */ -uint8_t subghz_protocol_marantec_crc8(uint8_t* data, size_t len); diff --git a/lib/subghz/protocols/public_api.h b/lib/subghz/protocols/public_api.h index d9ee062d0..1a3c097fb 100644 --- a/lib/subghz/protocols/public_api.h +++ b/lib/subghz/protocols/public_api.h @@ -284,6 +284,14 @@ bool subghz_protocol_secplus_v1_check_fixed(uint32_t fixed); // TODO: Remake in proper way void faac_slh_reset_prog_mode(void); +/** + * Calculate CRC8 for Marantec protocol. + * @param data Pointer to the data buffer + * @param len Length of the data buffer + * @return CRC8 value + */ +uint8_t subghz_protocol_marantec_crc8(uint8_t* data, size_t len); + #ifdef __cplusplus } #endif diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index c30ae0357..1634dff7e 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -3740,6 +3740,7 @@ Function,+,subghz_protocol_jarolift_create_data,_Bool,"void*, FlipperFormat*, ui Function,+,subghz_protocol_keeloq_bft_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, uint32_t, const char*, SubGhzRadioPreset*" Function,+,subghz_protocol_keeloq_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, const char*, SubGhzRadioPreset*" Function,+,subghz_protocol_kinggates_stylo_4k_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*" +Function,+,subghz_protocol_marantec_crc8,uint8_t,"uint8_t*, size_t" Function,+,subghz_protocol_nice_flor_s_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*, _Bool" Function,+,subghz_protocol_phoenix_v2_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint16_t, SubGhzRadioPreset*" Function,+,subghz_protocol_raw_file_encoder_worker_set_callback_end,void,"SubGhzProtocolEncoderRAW*, SubGhzProtocolEncoderRAWCallbackEnd, void*" From 514f88983f08c742fefee174ccd4988731dd21ff Mon Sep 17 00:00:00 2001 From: WillyJL Date: Sun, 1 Mar 2026 01:29:39 +0100 Subject: [PATCH 155/160] FBT: Allow apps to specify custom cflags --nobuild --- CHANGELOG.md | 1 + scripts/fbt/appmanifest.py | 1 + scripts/fbt_tools/fbt_extapps.py | 5 +++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a646c655..03fb85a3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - UL: Somfy Keytis button switch and Add Manually support (by @xMasterX) - UL: Genius Echo/Bravo add 2 buttons hold simulation (0xB btn code) (by @xMasterX) - UL: JS: Add IR capabilities to the JS engine (by @LuisMayo) +- FBT: Allow apps to specify custom cflags (by @WillyJL) - UL: Docs: Add [full list of supported SubGHz protocols](https://github.com/Next-Flip/Momentum-Firmware/blob/dev/documentation/SubGHzSupportedSystems.md) and their frequencies/modulations that can be used for reading remotes (by @xMasterX) ### Updated: diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index 4f6a2416c..9b576fb28 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -68,6 +68,7 @@ class FlipperApplication: # .fap-specific sources: List[str] = field(default_factory=lambda: ["*.c*"]) + cflags: List[str] = field(default_factory=list) fap_version: Union[str, Tuple[int]] = "0.1" fap_icon: Optional[str] = None fap_libs: List[str] = field(default_factory=list) diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index 2aa2da30d..0cd33d3a9 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -57,6 +57,7 @@ class AppBuilder: FAP_WORK_DIR=self.app_work_dir, ) self.app_env.Append( + CCFLAGS=self.app.cflags, CPPDEFINES=[ ("FAP_VERSION", f'\\"{".".join(map(str, self.app.fap_version))}\\"'), *self.app.cdefines, @@ -89,7 +90,7 @@ class AppBuilder: fap_icons = self.app_env.CompileIcons( self.app_work_dir, self.app._appdir.Dir(self.app.fap_icon_assets), - icon_bundle_name=f"{self.app.fap_icon_assets_symbol or self.app.appid }_icons", + icon_bundle_name=f"{self.app.fap_icon_assets_symbol or self.app.appid}_icons", add_include=True, ) self.app_env.Alias("_fap_icons", fap_icons) @@ -420,7 +421,7 @@ def _validate_app_imports(target, source, env): if env.get("_CHECK_APP"): raise UserError(warning_msg) else: - SCons.Warnings.warn(SCons.Warnings.LinkWarning, warning_msg), + SCons.Warnings.warn(SCons.Warnings.LinkWarning, warning_msg) def GetExtAppByIdOrPath(env, app_dir): From 8236079122d9a48681946567f30f60f9bdf834c8 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 1 Mar 2026 19:12:19 +0300 Subject: [PATCH 156/160] subghz keeloq fix anmotors and hcs101 display --- CHANGELOG.md | 1 + lib/subghz/protocols/keeloq.c | 66 +++++++++++++++++++++++++++-------- 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cbcc36fe..714c3e88f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * SubGHz: **KeeLoq** change delta size * SubGHz: **Genius Echo/Bravo** add 2 buttons hold simulation (0xB btn code) * SubGHz: Signal **Settings Improvements** (PR #968 | by @Dmitry422) +* SubGHz: KeeLoq **fix display** of **AN-Motors** and **HCS101** keys * OFW PR 4338: HID: Fix USB HID keyboard LED state reporting (by @Caballosanex) * Apps: Build tag (**22feb2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 159dbc62a..2bf173994 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -1567,7 +1567,8 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output SubGhzProtocolDecoderKeeloq* instance = context; uint32_t hopdecrypt = 0; - + // Try to get decrypt for display if mf is known, if not it will be 0 and display will be without decrypt part since it might come already decrypted like in HCS101 or AN-Motors + // Or we might have Unknown MF hopdecrypt = subghz_protocol_keeloq_check_remote_controller( &instance->generic, instance->keystore, &instance->manufacture_name); @@ -1579,16 +1580,56 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output uint32_t code_found_reverse_hi = code_found_reverse >> 32; uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; - if(strcmp(instance->manufacture_name, "BFT") == 0) { - // push protocol data to global variable + // Allow button edit + subghz_block_generic_global.btn_is_available = true; + subghz_block_generic_global.current_btn = instance->generic.btn; + subghz_block_generic_global.btn_length_bit = 4; + + if(strcmp(instance->manufacture_name, "AN-Motors") == 0) { + // No counter only pseudo counter + subghz_block_generic_global.cnt_is_available = false; + furi_string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%08lX%08lX\r\n" + "Fix:0x%08lX PsCn:%04lX\r\n" + "Hop:0x%08lX Btn:%01X\r\n" + "MF:%s", + instance->generic.protocol_name, + instance->generic.data_count_bit, + code_found_hi, + code_found_lo, + code_found_reverse_hi, + instance->generic.cnt, + code_found_reverse_lo, + instance->generic.btn, + instance->manufacture_name); + } else if(strcmp(instance->manufacture_name, "HCS101") == 0) { + // Counter is present but not encrypted + subghz_block_generic_global.cnt_is_available = true; + subghz_block_generic_global.cnt_length_bit = 16; + subghz_block_generic_global.current_cnt = instance->generic.cnt; + furi_string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%08lX%08lX\r\n" + "Fix:0x%08lX Cnt:%04lX\r\n" + "Hop:0x%08lX Btn:%01X\r\n" + "MF:%s", + instance->generic.protocol_name, + instance->generic.data_count_bit, + code_found_hi, + code_found_lo, + code_found_reverse_hi, + instance->generic.cnt, + code_found_reverse_lo, + instance->generic.btn, + instance->manufacture_name); + } else if(strcmp(instance->manufacture_name, "BFT") == 0) { + // Allow counter edit subghz_block_generic_global.cnt_is_available = true; subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; - - subghz_block_generic_global.btn_is_available = true; - subghz_block_generic_global.current_btn = instance->generic.btn; - subghz_block_generic_global.btn_length_bit = 4; - // ProgMode prog_mode = subghz_custom_btn_get_prog_mode(); if(prog_mode == PROG_MODE_KEELOQ_BFT) { @@ -1629,10 +1670,9 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output instance->generic.seed); } } else if(strcmp(instance->manufacture_name, "Unknown") == 0) { - subghz_block_generic_global.btn_is_available = true; - subghz_block_generic_global.current_btn = instance->generic.btn; - subghz_block_generic_global.btn_length_bit = 4; + // No counter info with unknown MF instance->generic.cnt = 0x0; + subghz_block_generic_global.cnt_is_available = false; furi_string_cat_printf( output, "%s %dbit\r\n" @@ -1649,12 +1689,10 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output instance->generic.btn, instance->manufacture_name); } else { + // All other known MF with counter info, allow counter edit subghz_block_generic_global.cnt_is_available = true; subghz_block_generic_global.cnt_length_bit = 16; subghz_block_generic_global.current_cnt = instance->generic.cnt; - subghz_block_generic_global.btn_is_available = true; - subghz_block_generic_global.current_btn = instance->generic.btn; - subghz_block_generic_global.btn_length_bit = 4; furi_string_cat_printf( output, "%s %dbit\r\n" From 1854c9d19081e03952ca894448679d623e10bab0 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Sun, 1 Mar 2026 22:36:17 +0100 Subject: [PATCH 157/160] Update apps --nobuild --- CHANGELOG.md | 19 ++++++++++++++----- applications/external | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03fb85a3f..0ccc28a35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,18 +25,27 @@ ### Updated: - Apps: + - XERO: MFKey: 4.1 with 40% faster key recovery, improved memory efficiency (by @dchristle), new SEN dictionary for 10x faster recovery (by @noproto) + - UL: Update Sub-GHz apps for FM12K modulation (by @xMasterX) - CAN Tools: Parity with DBC format, support importing DBC files (by @MatthewKuKanich) - - ESP Flasher: Bump Marauder 1.9.1 (by @justcallmekoko), Marauder 1.9.0 support (by @H4W9) - - FlipSocial: Autocomplete, keyboard improvements, bugfixes (by @jblanked) + - ESP Flasher: Bump Marauder 1.10.2 (by @justcallmekoko) + - ESP32 WiFi Marauder: Marauder 1.10.0 support (by @justcallmekoko), Marauder 1.9.0 support (by @H4W9) + - FlipLibrary: Added Fahrenheit, current weather, and wind speed/direction (by @H4W9) + - FlipSocial: Autocomplete, keyboard improvements, explore and profile view enhancements, bugfixes (by @jblanked) + - FlipWeather: Added Fahrenheit, current weather, and wind speed/direction (by @H4W9) + - Flipper Blackhat: TUI command (by @o7-machinehum) - Geometry Dash: Major refactor, bugfixes and performance improvements, rename from Geometry Flip (by @gooseprjkt) - HC-SR04 Distance Sensor: Option to change measure units (by @Tyl3rA) - IconEdit: Save/Send animations, settings tab with canvas scale and cursor guides, bugfixes (by @rdefeo) - - NFC Login: Code refactor, bugfixes, renamed from NFC PC Login (by @Play2BReal) + - INA2xx INA Meter: Fixed application freezing when the sensor is not connected (by @cepetr) + - NFC Login: Code refactor, bugfixes, renamed from NFC PC Login, restore BLE profile on app exit (by @Play2BReal) + - Picopass: Option to Create credential without a card (by @redteamlife) - Seader: SAM ATR3 support, better IFSC/IFSD handling, various improvements (by @bettse) - - Seos Compatible: Seos write support, various improvements (by @aaronjamt) + - Seos Compatible: Seos write support, various improvements (by @aaronjamt), support switching key sets (by @pcunning), code refactoring, various bugfixes (by @bettse) - Sub-GHz Scheduler: Added new interval times, bugfixes and improvements (by @shalebridge) + - Tetris: Various bugfixes (by @Bricktech2000) - Unitemp: Numerous improvements from @MLAB-project fork (by @MLAB-project) - - UL: Update Sub-GHz apps for FM12K modulation (by @xMasterX) + - XRemote: Add dolphin xp and crash bugfix (by @teohumeau) - Sub-GHz: - UL: Counter editor refactoring (by @Dmitry422) - UL: Alutech AT-4N & Nice Flor S turbo speedup (by @Dmitry422) diff --git a/applications/external b/applications/external index e9230bc08..9b2d6a5b1 160000 --- a/applications/external +++ b/applications/external @@ -1 +1 @@ -Subproject commit e9230bc089ae26094a9cba4614815c36532fc964 +Subproject commit 9b2d6a5b1b9726105868b250ae3c65af5ac229f0 From ccc621ad581498b51b47cb2c23c67a35a382415e Mon Sep 17 00:00:00 2001 From: WillyJL Date: Sun, 1 Mar 2026 23:04:11 +0100 Subject: [PATCH 158/160] Apps: Add UL-C Bruteforce, UL-C Relay. ULCFkey (by noproto) --nobuild --- CHANGELOG.md | 6 +++++- applications/external | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ce989538..b49924038 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ ### Added: - Apps: - - NFC: ISO 15693-3 NFC Writer (by @ch4istO) + - NFC: + - ISO 15693-3 NFC Writer (by @ch4istO) + - UL-C Bruteforce (by @noproto) + - UL-C Relay (by @noproto) + - ULCFkey (by @noproto) - Sub-GHz: ProtoPirate (by @RocketGod-git & @xMasterX & @zero-mega et al.) - Sub-GHz: - UL: Cardin S449 protocol full support (64bit keeloq) (with Add manually, and all button codes) (use FSK12K modulation to read the remote) (by @xMasterX & @zero-mega) diff --git a/applications/external b/applications/external index 9b2d6a5b1..f71049f74 160000 --- a/applications/external +++ b/applications/external @@ -1 +1 @@ -Subproject commit 9b2d6a5b1b9726105868b250ae3c65af5ac229f0 +Subproject commit f71049f74a390e2934f30ca31579cbf25a628847 From 1b61a39a3757fc8455920cbcb1f0f0fe92aaa517 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Sun, 1 Mar 2026 23:27:16 +0100 Subject: [PATCH 159/160] Apps: Add Flipper Wedge (by dangerous-tac0s) --nobuild --- CHANGELOG.md | 1 + applications/external | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b49924038..16fadee0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - UL-C Relay (by @noproto) - ULCFkey (by @noproto) - Sub-GHz: ProtoPirate (by @RocketGod-git & @xMasterX & @zero-mega et al.) + - Tools: Flipper Wedge (by @dangerous-tac0s) - Sub-GHz: - UL: Cardin S449 protocol full support (64bit keeloq) (with Add manually, and all button codes) (use FSK12K modulation to read the remote) (by @xMasterX & @zero-mega) - UL: Beninca ARC AES128 protocol full support (128bit dynamic) (with Add manually, and 2 button codes) (by @xMasterX & @zero-mega) diff --git a/applications/external b/applications/external index f71049f74..850a3234d 160000 --- a/applications/external +++ b/applications/external @@ -1 +1 @@ -Subproject commit f71049f74a390e2934f30ca31579cbf25a628847 +Subproject commit 850a3234d9a7596b4e21951733e8e04b6e2afa7c From 7a614a368391de0284ef52e916839ed6b0f6e7a8 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Mon, 2 Mar 2026 00:33:23 +0100 Subject: [PATCH 160/160] Apps: Add Checkers (by H4W9) --- CHANGELOG.md | 1 + applications/external | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16fadee0f..ac9cbf8c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ### Added: - Apps: + - Games: Checkers (by @H4W9) - NFC: - ISO 15693-3 NFC Writer (by @ch4istO) - UL-C Bruteforce (by @noproto) diff --git a/applications/external b/applications/external index 850a3234d..8c980b149 160000 --- a/applications/external +++ b/applications/external @@ -1 +1 @@ -Subproject commit 850a3234d9a7596b4e21951733e8e04b6e2afa7c +Subproject commit 8c980b1498ecfdfe9995e1d39b644235680ecc47