diff --git a/CHANGELOG.md b/CHANGELOG.md index 550ee7e90..1ef441d65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,8 @@ - USB: Portal Of Flipper (by @Bettse & @sanjay900) - Sub-GHz: - UL: Add ReversRB2/RB2M Protocol full support with add manually (by @xMasterX) + - UL: Add Feron static 32-bit protocol full support (by @xMasterX) + - UL: Various bugfixes and experimental options, rolling counter overflow (by @xMasterX) - OFW: Added support for 42-bit Prastel variation (by @pmazzini) - RFID: - OFW: EM4305 support (by @Astrrra) @@ -102,6 +104,7 @@ - Split NfcProtocolSupport handlers into plugins for ~23kb less RAM usage (#396 by @Willy-JL) - Enable Asset Packs in NFC app again due to reduced RAM usage (#396 by @Willy-JL) - Improve loading of parser plugins (by @Willy-JL) + - UL: Use default UL/UL-C pwd/key as default value for key input (by @mishamyte) - OFW: Added naming for DESFire cards + fix MF3ICD40 cards unable to be read (by @Demae) - OFW: FeliCa Protocol Expose Read Block API and Allow Specifying Service (by @zinongli) - OFW: Enable MFUL sync poller to be provided with passwords (by @GMMan) diff --git a/applications/main/bad_usb/helpers/ducky_script.c b/applications/main/bad_usb/helpers/ducky_script.c index 47e19fe0d..5e1eaaa6f 100644 --- a/applications/main/bad_usb/helpers/ducky_script.c +++ b/applications/main/bad_usb/helpers/ducky_script.c @@ -453,7 +453,7 @@ static int32_t bad_usb_worker(void* context) { if(bad_usb->hid->is_connected(bad_usb->hid_inst)) { worker_state = BadUsbStateIdle; // Ready to run } else { - worker_state = BadUsbStateNotConnected; // USB not connected + worker_state = BadUsbStateNotConnected; // Not connected } } else { worker_state = BadUsbStateScriptError; // Script preload error diff --git a/applications/main/nfc/helpers/mf_ultralight_auth.c b/applications/main/nfc/helpers/mf_ultralight_auth.c index e97649cb3..fccf50cdd 100644 --- a/applications/main/nfc/helpers/mf_ultralight_auth.c +++ b/applications/main/nfc/helpers/mf_ultralight_auth.c @@ -18,9 +18,11 @@ void mf_ultralight_auth_free(MfUltralightAuth* instance) { void mf_ultralight_auth_reset(MfUltralightAuth* instance) { furi_assert(instance); + uint32_t default_password = MF_ULTRALIGHT_DEFAULT_PASSWORD; + instance->type = MfUltralightAuthTypeNone; - memset(&instance->password, 0, sizeof(MfUltralightAuthPassword)); - memset(&instance->tdes_key, 0, sizeof(MfUltralightC3DesAuthKey)); + memcpy(&instance->password, &default_password, sizeof(MfUltralightAuthPassword)); + memcpy(&instance->tdes_key, MF_ULTRALIGHT_C_DEFAULT_KEY, sizeof(MfUltralightC3DesAuthKey)); memset(&instance->pack, 0, sizeof(MfUltralightAuthPack)); } diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index af3fd62eb..5b54d38db 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -3,16 +3,37 @@ #include #include #include +#include +#include +#include +#include +#include #include #include #define FLAG_EVENT (1 << 10) +#define NFC_MAX_BUFFER_SIZE (256) +#define NFC_BASE_PROTOCOL_MAX (3) +#define POLLER_DONE (1 << 0) +#define POLLER_ERR (1 << 1) +static NfcProtocol BASE_PROTOCOL[NFC_BASE_PROTOCOL_MAX] = { + NfcProtocolIso14443_4a, + NfcProtocolIso14443_4b, + NfcProtocolIso15693_3}; +typedef struct ApduContext { + BitBuffer* tx_buffer; + BitBuffer* rx_buffer; + bool ready; + FuriThreadId thread_id; +} ApduContext; + static void nfc_cli_print_usage(void) { printf("Usage:\r\n"); printf("nfc \r\n"); printf("Cmd list:\r\n"); + printf("\tapdu\t - Send APDU and print response \r\n"); if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { printf("\tfield\t - turn field on\r\n"); } @@ -41,6 +62,144 @@ static void nfc_cli_field(PipeSide* pipe, FuriString* args) { furi_hal_nfc_release(); } +static NfcCommand trx_callback(NfcGenericEvent event, void* context) { + furi_check(context); + ApduContext* apdu_context = (ApduContext*)context; + + if(apdu_context->ready) { + apdu_context->ready = false; + if(NfcProtocolIso14443_4a == event.protocol) { + Iso14443_4aError err = iso14443_4a_poller_send_block( + event.instance, apdu_context->tx_buffer, apdu_context->rx_buffer); + if(Iso14443_4aErrorNone == err) { + furi_thread_flags_set(apdu_context->thread_id, POLLER_DONE); + return NfcCommandContinue; + } else { + furi_thread_flags_set(apdu_context->thread_id, POLLER_ERR); + return NfcCommandStop; + } + } else if(NfcProtocolIso14443_4b == event.protocol) { + Iso14443_4bError err = iso14443_4b_poller_send_block( + event.instance, apdu_context->tx_buffer, apdu_context->rx_buffer); + if(Iso14443_4bErrorNone == err) { + furi_thread_flags_set(apdu_context->thread_id, POLLER_DONE); + return NfcCommandContinue; + } else { + furi_thread_flags_set(apdu_context->thread_id, POLLER_ERR); + return NfcCommandStop; + } + } else if(NfcProtocolIso15693_3 == event.protocol) { + Iso15693_3Error err = iso15693_3_poller_send_frame( + event.instance, + apdu_context->tx_buffer, + apdu_context->rx_buffer, + ISO15693_3_FDT_POLL_FC); + if(Iso15693_3ErrorNone == err) { + furi_thread_flags_set(apdu_context->thread_id, POLLER_DONE); + return NfcCommandContinue; + } else { + furi_thread_flags_set(apdu_context->thread_id, POLLER_ERR); + return NfcCommandStop; + } + } else { + // should never reach here + furi_crash("Unknown protocol"); + } + } else { + furi_delay_ms(100); + } + + return NfcCommandContinue; +} + +static void nfc_cli_apdu(PipeSide* pipe, FuriString* args) { + UNUSED(pipe); + Nfc* nfc = NULL; + NfcPoller* poller = NULL; + FuriString* data = furi_string_alloc(); + uint8_t* req_buffer = NULL; + uint8_t* resp_buffer = NULL; + size_t apdu_size = 0; + size_t resp_size = 0; + NfcProtocol current_protocol = NfcProtocolInvalid; + + do { + if(0 == args_get_first_word_length(args)) { + printf( + "Use like `nfc apdu 00a404000e325041592e5359532e444446303100 00a4040008a0000003010102` \r\n"); + break; + } + nfc = nfc_alloc(); + + printf("detecting tag\r\n"); + for(int i = 0; i < NFC_BASE_PROTOCOL_MAX; i++) { + poller = nfc_poller_alloc(nfc, BASE_PROTOCOL[i]); + bool is_detected = nfc_poller_detect(poller); + nfc_poller_free(poller); + if(is_detected) { + current_protocol = BASE_PROTOCOL[i]; + printf("detected tag:%d\r\n", BASE_PROTOCOL[i]); + break; + } + } + if(NfcProtocolInvalid == current_protocol) { + nfc_free(nfc); + printf("Can not find any tag\r\n"); + break; + } + poller = nfc_poller_alloc(nfc, current_protocol); + ApduContext* apdu_context = malloc(sizeof(ApduContext)); + apdu_context->tx_buffer = bit_buffer_alloc(NFC_MAX_BUFFER_SIZE); + apdu_context->rx_buffer = bit_buffer_alloc(NFC_MAX_BUFFER_SIZE); + apdu_context->ready = false; + apdu_context->thread_id = furi_thread_get_current_id(); + + nfc_poller_start(poller, trx_callback, apdu_context); + while(args_read_string_and_trim(args, data)) { + bit_buffer_reset(apdu_context->tx_buffer); + bit_buffer_reset(apdu_context->rx_buffer); + apdu_size = furi_string_size(data) / 2; + req_buffer = malloc(apdu_size); + + hex_chars_to_uint8(furi_string_get_cstr(data), req_buffer); + printf("Sending APDU:%s to Tag\r\n", furi_string_get_cstr(data)); + bit_buffer_copy_bytes(apdu_context->tx_buffer, req_buffer, apdu_size); + apdu_context->ready = true; + uint32_t flags = furi_thread_flags_wait(POLLER_DONE, FuriFlagWaitAny, 3000); + if(0 == (flags & POLLER_DONE)) { + printf("Error or Timeout"); + free(req_buffer); + break; + } + furi_assert(apdu_context->ready == false); + resp_size = bit_buffer_get_size_bytes(apdu_context->rx_buffer) * 2; + if(!resp_size) { + printf("No response\r\n"); + free(req_buffer); + continue; + } + resp_buffer = malloc(resp_size); + uint8_to_hex_chars( + bit_buffer_get_data(apdu_context->rx_buffer), resp_buffer, resp_size); + resp_buffer[resp_size] = 0; + printf("Response: %s\r\n", resp_buffer); + + free(req_buffer); + free(resp_buffer); + } + + nfc_poller_stop(poller); + nfc_poller_free(poller); + nfc_free(nfc); + + bit_buffer_free(apdu_context->tx_buffer); + bit_buffer_free(apdu_context->rx_buffer); + free(apdu_context); + } while(false); + + furi_string_free(data); +} + static void execute(PipeSide* pipe, FuriString* args, void* context) { UNUSED(context); FuriString* cmd; @@ -51,6 +210,10 @@ static void execute(PipeSide* pipe, FuriString* args, void* context) { nfc_cli_print_usage(); break; } + if(furi_string_cmp_str(cmd, "apdu") == 0) { + nfc_cli_apdu(pipe, args); + break; + } if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { if(furi_string_cmp_str(cmd, "field") == 0) { nfc_cli_field(pipe, args); diff --git a/applications/main/subghz/scenes/subghz_scene_radio_settings.c b/applications/main/subghz/scenes/subghz_scene_radio_settings.c index 5031731eb..240b18233 100644 --- a/applications/main/subghz/scenes/subghz_scene_radio_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_radio_settings.c @@ -36,7 +36,7 @@ const char* const gps_text[GPS_COUNT] = { "115200", }; -#define DEBUG_COUNTER_COUNT 13 +#define DEBUG_COUNTER_COUNT 16 const char* const debug_counter_text[DEBUG_COUNTER_COUNT] = { "+1", "+2", @@ -44,21 +44,26 @@ const char* const debug_counter_text[DEBUG_COUNTER_COUNT] = { "+4", "+5", "+10", - "0", + "+50", + "OVFL", + "No", "-1", "-2", "-3", "-4", "-5", "-10", + "-50", }; -const uint32_t debug_counter_val[DEBUG_COUNTER_COUNT] = { +const int32_t debug_counter_val[DEBUG_COUNTER_COUNT] = { 1, 2, 3, 4, 5, 10, + 50, + 65535, 0, -1, -2, @@ -66,6 +71,7 @@ const uint32_t debug_counter_val[DEBUG_COUNTER_COUNT] = { -4, -5, -10, + -50, }; static void subghz_scene_radio_settings_set_device(VariableItem* item) { @@ -149,7 +155,7 @@ void subghz_scene_radio_settings_on_enter(void* context) { SubGhz* subghz = context; VariableItemList* variable_item_list = subghz->variable_item_list; - uint8_t value_index; + int32_t value_index; VariableItem* item; uint8_t value_count_device = RADIO_DEVICE_COUNT; @@ -196,7 +202,7 @@ void subghz_scene_radio_settings_on_enter(void* context) { furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) ? DEBUG_COUNTER_COUNT : 3, subghz_scene_receiver_config_set_debug_counter, subghz); - value_index = value_index_uint32( + value_index = value_index_int32( furi_hal_subghz_get_rolling_counter_mult(), debug_counter_val, furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) ? DEBUG_COUNTER_COUNT : 3); diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 451ebd0f2..0702f1d0a 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -96,7 +96,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { subghz_txrx_stop(subghz->txrx); if(subghz_custom_btn_get() != SUBGHZ_CUSTOM_BTN_OK) { subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); - int8_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); + 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)); diff --git a/applications/main/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c index 0ab1b0174..7847917ec 100644 --- a/applications/main/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -816,7 +816,6 @@ void subghz_cli_command_tx_from_file(PipeSide* pipe, FuriString* args, void* con subghz_devices_deinit(); // Reset custom settings subghz_environment_reset_keeloq(environment); - faac_slh_reset_prog_mode(); subghz_custom_btns_reset(); // Free environment subghz_environment_free(environment); @@ -1117,7 +1116,8 @@ static void subghz_cli_command_chat(PipeSide* pipe, FuriString* args) { } static void execute(PipeSide* pipe, FuriString* args, void* context) { - FuriString* cmd = furi_string_alloc(); + FuriString* cmd; + cmd = furi_string_alloc(); do { if(!args_read_string_and_trim(args, cmd)) { diff --git a/applications/services/gui/modules/submenu.c b/applications/services/gui/modules/submenu.c index e2be131b0..12b1ab4db 100644 --- a/applications/services/gui/modules/submenu.c +++ b/applications/services/gui/modules/submenu.c @@ -501,7 +501,10 @@ void submenu_process_ok(Submenu* submenu, InputType input_type) { }, true); - if(!item || item->locked) return; + if(!item) return; + if(item->locked) { + return; + } if(!item->has_extended_events && input_type == InputTypeShort && item->callback) { item->callback(item->callback_context, item->index); diff --git a/applications/services/gui/modules/submenu.h b/applications/services/gui/modules/submenu.h index beabf4adf..0a4d714b7 100644 --- a/applications/services/gui/modules/submenu.h +++ b/applications/services/gui/modules/submenu.h @@ -54,22 +54,6 @@ void submenu_add_item( SubmenuItemCallback callback, void* callback_context); -/** Add item to submenu with extended press events - * - * @param submenu Submenu instance - * @param label menu item label - * @param index menu item index, used for callback, may be - * the same with other items - * @param callback menu item extended callback - * @param callback_context menu item callback context - */ -void submenu_add_item_ex( - Submenu* submenu, - const char* label, - uint32_t index, - SubmenuItemCallbackEx callback, - void* callback_context); - /** Add lockable item to submenu * * @param submenu Submenu instance @@ -90,6 +74,22 @@ void submenu_add_lockable_item( bool locked, const char* locked_message); +/** Add item to submenu with extended press events + * + * @param submenu Submenu instance + * @param label menu item label + * @param index menu item index, used for callback, may be + * the same with other items + * @param callback menu item extended callback + * @param callback_context menu item callback context + */ +void submenu_add_item_ex( + Submenu* submenu, + const char* label, + uint32_t index, + SubmenuItemCallbackEx callback, + void* callback_context); + /** Change label of an existing item * * @param submenu Submenu instance diff --git a/applications/services/input/input.c b/applications/services/input/input.c index b4587e417..fb6eb7a25 100644 --- a/applications/services/input/input.c +++ b/applications/services/input/input.c @@ -7,10 +7,10 @@ #include #include #include +#include #include #include #include -#include #define INPUT_DEBOUNCE_TICKS_HALF (INPUT_DEBOUNCE_TICKS / 2) #define INPUT_PRESS_TICKS 150 @@ -155,8 +155,10 @@ int32_t input_srv(void* p) { // Send Press/Release event event.type = pin_states[i].state ? InputTypePress : InputTypeRelease; furi_pubsub_publish(event_pubsub, &event); - // do vibro if user setup vibro touch level in Settings-Input. + // vibro signal if user setup vibro touch level in Settings-Input. if(settings->vibro_touch_level) { + //delay 1 ticks for compatibility with rgb_backlight_mod + furi_delay_tick(1); furi_hal_vibro_on(true); furi_delay_tick(settings->vibro_touch_level); furi_hal_vibro_on(false); diff --git a/applications/services/input/input_settings.c b/applications/services/input/input_settings.c index 3cd1711a9..d48990847 100644 --- a/applications/services/input/input_settings.c +++ b/applications/services/input/input_settings.c @@ -29,7 +29,6 @@ void input_settings_load(InputSettings* settings) { sizeof(InputSettings), INPUT_SETTINGS_MAGIC, INPUT_SETTINGS_VER); - // if config previous version - load it and inicialize new settings } // in case of another config version we exit from useless cycle to next step } while(false); diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index 1bae573a5..d94c000e4 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -388,13 +388,18 @@ static void power_handle_reboot(PowerBootMode mode) { //start furi timer for autopoweroff static void power_start_auto_poweroff_timer(Power* power) { + if(furi_timer_is_running(power->auto_poweroff_timer)) { + furi_timer_stop(power->auto_poweroff_timer); + } furi_timer_start( power->auto_poweroff_timer, furi_ms_to_ticks(power->settings.auto_poweroff_delay_ms)); } //stop furi timer for autopoweroff static void power_stop_auto_poweroff_timer(Power* power) { - furi_timer_stop(power->auto_poweroff_timer); + if(furi_timer_is_running(power->auto_poweroff_timer)) { + furi_timer_stop(power->auto_poweroff_timer); + } } static uint32_t power_is_running_auto_poweroff_timer(Power* power) { diff --git a/applications/settings/application.fam b/applications/settings/application.fam index 1d6db35a7..2ad4aa030 100644 --- a/applications/settings/application.fam +++ b/applications/settings/application.fam @@ -6,6 +6,7 @@ App( "passport", "system_settings", "clock_settings", + "input_settings", "about", ], ) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index caf25ceee..191deeda6 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -38,6 +38,7 @@ extern "C" { #define MF_ULTRALIGHT_TEARING_FLAG_NUM (3) #define MF_ULTRALIGHT_AUTH_PASSWORD_SIZE (4) #define MF_ULTRALIGHT_AUTH_PACK_SIZE (2) +#define MF_ULTRALIGHT_DEFAULT_PASSWORD (0xffffffffUL) #define MF_ULTRALIGHT_C_AUTH_RESPONSE_SIZE (9) #define MF_ULTRALIGHT_C_AUTH_DES_KEY_SIZE (16) @@ -47,6 +48,11 @@ extern "C" { #define MF_ULTRALIGHT_C_AUTH_RND_A_BLOCK_OFFSET (0) #define MF_ULTRALIGHT_C_AUTH_RND_B_BLOCK_OFFSET (8) #define MF_ULTRALIGHT_C_ENCRYPTED_PACK_SIZE (MF_ULTRALIGHT_C_AUTH_DATA_SIZE + 1) +#define MF_ULTRALIGHT_C_DEFAULT_KEY \ + (uint8_t[]) { \ + 0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, \ + 0x46 \ + } typedef enum { MfUltralightErrorNone, diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index b35c49aea..6880a0c43 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -11,8 +11,6 @@ extern "C" { #define MF_ULTRALIGHT_POLLER_STANDARD_FWT_FC (60000) #define MF_ULTRALIGHT_MAX_BUFF_SIZE (64) -#define MF_ULTRALIGHT_DEFAULT_PASSWORD (0xffffffffUL) - #define MF_ULTRALIGHT_IS_NTAG_I2C(type) \ (((type) == MfUltralightTypeNTAGI2C1K) || ((type) == MfUltralightTypeNTAGI2C2K) || \ ((type) == MfUltralightTypeNTAGI2CPlus1K) || ((type) == MfUltralightTypeNTAGI2CPlus2K)) diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 091a726ed..a9fb5b012 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -281,7 +281,7 @@ static bool subghz_protocol_alutech_at_4n_gen_data( } else { instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } - } else if(instance->generic.cnt >= 0xFFFF) { + } else if((instance->generic.cnt >= 0xFFFF) && (furi_hal_subghz_get_rolling_counter_mult() != 0)) { instance->generic.cnt = 0; } crc = subghz_protocol_alutech_at_4n_decrypt_data_crc((uint8_t)(instance->generic.cnt & 0xFF)); diff --git a/lib/subghz/protocols/came_atomo.c b/lib/subghz/protocols/came_atomo.c index eb3500c7b..ddbf477b2 100644 --- a/lib/subghz/protocols/came_atomo.c +++ b/lib/subghz/protocols/came_atomo.c @@ -193,7 +193,7 @@ static void subghz_protocol_encoder_came_atomo_get_upload( } else { instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } - } else if(instance->generic.cnt >= 0xFFFF) { + } else if((instance->generic.cnt >= 0xFFFF) && (furi_hal_subghz_get_rolling_counter_mult() != 0)) { instance->generic.cnt = 0; } diff --git a/lib/subghz/protocols/faac_slh.c b/lib/subghz/protocols/faac_slh.c index 1f577b60d..4868c3dd7 100644 --- a/lib/subghz/protocols/faac_slh.c +++ b/lib/subghz/protocols/faac_slh.c @@ -142,9 +142,40 @@ static bool subghz_protocol_faac_slh_gen_data(SubGhzProtocolEncoderFaacSLH* inst data_prg[0] = 0x00; if(allow_zero_seed || (instance->generic.seed != 0x0)) { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + if(!(furi_hal_subghz_get_rolling_counter_mult() >= 0xFFFF)) { + if(instance->generic.cnt < 0xFFFFF) { + 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 if( + (instance->generic.cnt >= 0xFFFFF) && + (furi_hal_subghz_get_rolling_counter_mult() != 0)) { + instance->generic.cnt = 0; + } + } else { + instance->generic.cnt += 1; + } + if(temp_counter_backup != 0x0) { - temp_counter_backup += furi_hal_subghz_get_rolling_counter_mult(); + if(!(furi_hal_subghz_get_rolling_counter_mult() >= 0xFFFF)) { + if(temp_counter_backup < 0xFFFFF) { + 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 if( + (temp_counter_backup >= 0xFFFFF) && + (furi_hal_subghz_get_rolling_counter_mult() != 0)) { + temp_counter_backup = 0; + } + } else { + temp_counter_backup += 1; + } } } @@ -195,7 +226,9 @@ static bool subghz_protocol_faac_slh_gen_data(SubGhzProtocolEncoderFaacSLH* inst (temp_fix_backup != 0x0) && !faac_prog_mode) { instance->generic.serial = temp_fix_backup >> 4; instance->generic.btn = temp_fix_backup & 0xF; - instance->generic.cnt = temp_counter_backup; + if(temp_counter_backup != 0x0) { + instance->generic.cnt = temp_counter_backup; + } } uint32_t fix = instance->generic.serial << 4 | instance->generic.btn; uint32_t hop = 0; @@ -209,7 +242,32 @@ static bool subghz_protocol_faac_slh_gen_data(SubGhzProtocolEncoderFaacSLH* inst } if(allow_zero_seed || (instance->generic.seed != 0x0)) { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + if(!(furi_hal_subghz_get_rolling_counter_mult() >= 0xFFFF)) { + if(instance->generic.cnt < 0xFFFFF) { + 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 if( + (instance->generic.cnt >= 0xFFFFF) && + (furi_hal_subghz_get_rolling_counter_mult() != 0)) { + instance->generic.cnt = 0; + } + } else { + if(instance->generic.cnt < 0xFFFFF) { + if((instance->generic.cnt + 0xFFFFF) > 0xFFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += 0xFFFFF; + } + } else if( + (instance->generic.cnt >= 0xFFFFF) && + (furi_hal_subghz_get_rolling_counter_mult() != 0)) { + instance->generic.cnt = 0; + } + } } if((instance->generic.cnt % 2) == 0) { @@ -250,7 +308,7 @@ bool subghz_protocol_faac_slh_create_data( const char* manufacture_name, SubGhzRadioPreset* preset) { furi_assert(context); - // roguemaster don't steal!!! + // OwO SubGhzProtocolEncoderFaacSLH* instance = context; instance->generic.serial = serial; instance->generic.btn = btn; diff --git a/lib/subghz/protocols/feron.c b/lib/subghz/protocols/feron.c new file mode 100644 index 000000000..7e5f12bea --- /dev/null +++ b/lib/subghz/protocols/feron.c @@ -0,0 +1,352 @@ +#include "feron.h" +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocolFeron" + +static const SubGhzBlockConst subghz_protocol_feron_const = { + .te_short = 350, + .te_long = 750, + .te_delta = 150, + .min_count_bit_for_found = 32, +}; + +struct SubGhzProtocolDecoderFeron { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; +}; + +struct SubGhzProtocolEncoderFeron { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + FeronDecoderStepReset = 0, + FeronDecoderStepSaveDuration, + FeronDecoderStepCheckDuration, +} FeronDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_feron_decoder = { + .alloc = subghz_protocol_decoder_feron_alloc, + .free = subghz_protocol_decoder_feron_free, + + .feed = subghz_protocol_decoder_feron_feed, + .reset = subghz_protocol_decoder_feron_reset, + + .get_hash_data = NULL, + .get_hash_data_long = subghz_protocol_decoder_feron_get_hash_data, + .serialize = subghz_protocol_decoder_feron_serialize, + .deserialize = subghz_protocol_decoder_feron_deserialize, + .get_string = subghz_protocol_decoder_feron_get_string, + .get_string_brief = NULL, +}; + +const SubGhzProtocolEncoder subghz_protocol_feron_encoder = { + .alloc = subghz_protocol_encoder_feron_alloc, + .free = subghz_protocol_encoder_feron_free, + + .deserialize = subghz_protocol_encoder_feron_deserialize, + .stop = subghz_protocol_encoder_feron_stop, + .yield = subghz_protocol_encoder_feron_yield, +}; + +const SubGhzProtocol subghz_protocol_feron = { + .name = SUBGHZ_PROTOCOL_FERON_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_feron_decoder, + .encoder = &subghz_protocol_feron_encoder, +}; + +void* subghz_protocol_encoder_feron_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderFeron* instance = malloc(sizeof(SubGhzProtocolEncoderFeron)); + + instance->base.protocol = &subghz_protocol_feron; + 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_feron_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderFeron* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderFeron instance + */ +static void subghz_protocol_encoder_feron_get_upload(SubGhzProtocolEncoderFeron* 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_feron_const.te_long); + if(i == 1) { + //Send 500/500 and gap if bit was last + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_feron_const.te_short + 150); + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_feron_const.te_short + 150); + // Gap + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_feron_const.te_long * 6); + } else { + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_feron_const.te_short); + } + } else { + // Send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_feron_const.te_short); + if(i == 1) { + //Send 500/500 and gap if bit was last + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_feron_const.te_short + 150); + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_feron_const.te_short + 150); + // Gap + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_feron_const.te_long * 6); + } else { + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_feron_const.te_long); + } + } + } + + instance->encoder.size_upload = index; + return; +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_feron_check_remote_controller(SubGhzBlockGeneric* instance) { + instance->serial = instance->data >> 16; +} + +SubGhzProtocolStatus + subghz_protocol_encoder_feron_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderFeron* instance = context; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; + do { + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_feron_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_feron_check_remote_controller(&instance->generic); + subghz_protocol_encoder_feron_get_upload(instance); + instance->encoder.is_running = true; + } while(false); + + return ret; +} + +void subghz_protocol_encoder_feron_stop(void* context) { + SubGhzProtocolEncoderFeron* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_feron_yield(void* context) { + SubGhzProtocolEncoderFeron* 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_feron_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderFeron* instance = malloc(sizeof(SubGhzProtocolDecoderFeron)); + instance->base.protocol = &subghz_protocol_feron; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_feron_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderFeron* instance = context; + free(instance); +} + +void subghz_protocol_decoder_feron_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderFeron* instance = context; + instance->decoder.parser_step = FeronDecoderStepReset; +} + +void subghz_protocol_decoder_feron_feed(void* context, bool level, volatile uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderFeron* instance = context; + + // Feron Decoder + // 2025.04 - @xMasterX (MMX) + + // Key samples + /* + 0110001100111000 1000010101111010 - ON + 0110001100111000 1000010001111011 - OFF + + 0110001100111000 1000011001111001 - brightness up + 0110001100111000 1000011101111000 - brightness down + + 0110001100111000 1000001001111101 - scroll mode command + + ------------------------------------------ + 0110001100111000 0111000010001111 - R + 0110001100111000 0001101011100101 - B + 0110001100111000 0100000010111111 - G + */ + + switch(instance->decoder.parser_step) { + case FeronDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_feron_const.te_long * 6) < + subghz_protocol_feron_const.te_delta * 4)) { + //Found GAP + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + instance->decoder.parser_step = FeronDecoderStepSaveDuration; + } + break; + case FeronDecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = FeronDecoderStepCheckDuration; + } else { + instance->decoder.parser_step = FeronDecoderStepReset; + } + break; + case FeronDecoderStepCheckDuration: + if(!level) { + // Bit 0 is short and long timing = 350us HIGH (te_last) and 750us LOW + if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_feron_const.te_short) < + subghz_protocol_feron_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_feron_const.te_long) < + subghz_protocol_feron_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = FeronDecoderStepSaveDuration; + // Bit 1 is long and short timing = 750us HIGH (te_last) and 350us LOW + } else if( + (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_feron_const.te_long) < + subghz_protocol_feron_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_feron_const.te_short) < + subghz_protocol_feron_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = FeronDecoderStepSaveDuration; + } else if( + // End of the key 500Low(we are here)/500High us + DURATION_DIFF( + duration, (uint16_t)(subghz_protocol_feron_const.te_short + (uint16_t)150)) < + subghz_protocol_feron_const.te_delta) { + if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_feron_const.te_short) < + subghz_protocol_feron_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + } + if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_feron_const.te_long) < + subghz_protocol_feron_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + } + // If got 32 bits key reading is finished + if(instance->decoder.decode_count_bit == + subghz_protocol_feron_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 = FeronDecoderStepReset; + } else { + instance->decoder.parser_step = FeronDecoderStepReset; + } + } else { + instance->decoder.parser_step = FeronDecoderStepReset; + } + break; + } +} + +uint32_t subghz_protocol_decoder_feron_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderFeron* instance = context; + return subghz_protocol_blocks_get_hash_data_long( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +SubGhzProtocolStatus subghz_protocol_decoder_feron_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolDecoderFeron* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +SubGhzProtocolStatus + subghz_protocol_decoder_feron_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderFeron* instance = context; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, subghz_protocol_feron_const.min_count_bit_for_found); +} + +void subghz_protocol_decoder_feron_get_string(void* context, FuriString* output) { + furi_assert(context); + SubGhzProtocolDecoderFeron* instance = context; + + subghz_protocol_feron_check_remote_controller(&instance->generic); + + furi_string_cat_printf( + output, + "%s %db\r\n" + "Key: 0x%08lX\r\n" + "Serial: 0x%04lX\r\n" + "Command: 0x%04lX\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data & 0xFFFFFFFF), + instance->generic.serial, + (uint32_t)(instance->generic.data & 0xFFFF)); +} diff --git a/lib/subghz/protocols/feron.h b/lib/subghz/protocols/feron.h new file mode 100644 index 000000000..9b7e6587f --- /dev/null +++ b/lib/subghz/protocols/feron.h @@ -0,0 +1,109 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_FERON_NAME "Feron" + +typedef struct SubGhzProtocolDecoderFeron SubGhzProtocolDecoderFeron; +typedef struct SubGhzProtocolEncoderFeron SubGhzProtocolEncoderFeron; + +extern const SubGhzProtocolDecoder subghz_protocol_feron_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_feron_encoder; +extern const SubGhzProtocol subghz_protocol_feron; + +/** + * Allocate SubGhzProtocolEncoderFeron. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderFeron* pointer to a SubGhzProtocolEncoderFeron instance + */ +void* subghz_protocol_encoder_feron_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderFeron. + * @param context Pointer to a SubGhzProtocolEncoderFeron instance + */ +void subghz_protocol_encoder_feron_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderFeron instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return status + */ +SubGhzProtocolStatus + subghz_protocol_encoder_feron_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderFeron instance + */ +void subghz_protocol_encoder_feron_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderFeron instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_feron_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderFeron. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderFeron* pointer to a SubGhzProtocolDecoderFeron instance + */ +void* subghz_protocol_decoder_feron_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderFeron. + * @param context Pointer to a SubGhzProtocolDecoderFeron instance + */ +void subghz_protocol_decoder_feron_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderFeron. + * @param context Pointer to a SubGhzProtocolDecoderFeron instance + */ +void subghz_protocol_decoder_feron_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderFeron instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_feron_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderFeron instance + * @return hash Hash sum + */ +uint32_t subghz_protocol_decoder_feron_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderFeron. + * @param context Pointer to a SubGhzProtocolDecoderFeron 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_feron_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data SubGhzProtocolDecoderFeron. + * @param context Pointer to a SubGhzProtocolDecoderFeron instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return status + */ +SubGhzProtocolStatus + subghz_protocol_decoder_feron_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderFeron instance + * @param output Resulting text + */ +void subghz_protocol_decoder_feron_get_string(void* context, FuriString* output); diff --git a/lib/subghz/protocols/hay21.c b/lib/subghz/protocols/hay21.c index 3945fcea7..2d6f14983 100644 --- a/lib/subghz/protocols/hay21.c +++ b/lib/subghz/protocols/hay21.c @@ -153,6 +153,9 @@ static void subghz_protocol_encoder_hay21_get_upload(SubGhzProtocolEncoderHay21* } else { instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } + if(furi_hal_subghz_get_rolling_counter_mult() >= 0xF) { + instance->generic.cnt = 0xF; + } } else if(instance->generic.cnt >= 0xF) { instance->generic.cnt = 0; } diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 4d458bc10..48d6b0e53 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -192,7 +192,9 @@ static bool subghz_protocol_keeloq_gen_data( } else { instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } - } else if(instance->generic.cnt >= 0xFFFF) { + } else if( + (instance->generic.cnt >= 0xFFFF) && + (furi_hal_subghz_get_rolling_counter_mult() != 0)) { instance->generic.cnt = 0; } } diff --git a/lib/subghz/protocols/kinggates_stylo_4k.c b/lib/subghz/protocols/kinggates_stylo_4k.c index 7e7488f00..d93363618 100644 --- a/lib/subghz/protocols/kinggates_stylo_4k.c +++ b/lib/subghz/protocols/kinggates_stylo_4k.c @@ -163,7 +163,7 @@ static bool subghz_protocol_kinggates_stylo_4k_gen_data( } else { instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } - } else if(instance->generic.cnt >= 0xFFFF) { + } else if((instance->generic.cnt >= 0xFFFF) && (furi_hal_subghz_get_rolling_counter_mult() != 0)) { instance->generic.cnt = 0; } diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index 4ba15d261..301e03f47 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -161,7 +161,7 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload( } else { instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } - } else if(instance->generic.cnt >= 0xFFFF) { + } else if((instance->generic.cnt >= 0xFFFF) && (furi_hal_subghz_get_rolling_counter_mult() != 0)) { instance->generic.cnt = 0; } uint64_t decrypt = ((uint64_t)instance->generic.serial << 16) | instance->generic.cnt; diff --git a/lib/subghz/protocols/protocol_items.c b/lib/subghz/protocols/protocol_items.c index 20d00b686..9f0f7307e 100644 --- a/lib/subghz/protocols/protocol_items.c +++ b/lib/subghz/protocols/protocol_items.c @@ -81,6 +81,7 @@ const SubGhzProtocol* const subghz_protocol_registry_items[] = { &subghz_protocol_hollarm, &subghz_protocol_hay21, &subghz_protocol_revers_rb2, + &subghz_protocol_feron, }; const SubGhzProtocolRegistry subghz_protocol_registry = { diff --git a/lib/subghz/protocols/protocol_items.h b/lib/subghz/protocols/protocol_items.h index f682f8468..3047151ec 100644 --- a/lib/subghz/protocols/protocol_items.h +++ b/lib/subghz/protocols/protocol_items.h @@ -82,3 +82,4 @@ #include "hollarm.h" #include "hay21.h" #include "revers_rb2.h" +#include "feron.h" diff --git a/lib/subghz/protocols/somfy_keytis.c b/lib/subghz/protocols/somfy_keytis.c index 05a01c32f..da2b730a2 100644 --- a/lib/subghz/protocols/somfy_keytis.c +++ b/lib/subghz/protocols/somfy_keytis.c @@ -138,7 +138,7 @@ static bool } else { instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } - } else if(instance->generic.cnt >= 0xFFFF) { + } else if((instance->generic.cnt >= 0xFFFF) && (furi_hal_subghz_get_rolling_counter_mult() != 0)) { instance->generic.cnt = 0; } diff --git a/lib/subghz/protocols/somfy_telis.c b/lib/subghz/protocols/somfy_telis.c index 39859092d..78f53378a 100644 --- a/lib/subghz/protocols/somfy_telis.c +++ b/lib/subghz/protocols/somfy_telis.c @@ -132,7 +132,7 @@ static bool subghz_protocol_somfy_telis_gen_data( } else { instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } - } else if(instance->generic.cnt >= 0xFFFF) { + } else if((instance->generic.cnt >= 0xFFFF) && (furi_hal_subghz_get_rolling_counter_mult() != 0)) { instance->generic.cnt = 0; } diff --git a/lib/subghz/protocols/star_line.c b/lib/subghz/protocols/star_line.c index ade320e6a..a2efefeb6 100644 --- a/lib/subghz/protocols/star_line.c +++ b/lib/subghz/protocols/star_line.c @@ -138,7 +138,7 @@ static bool } else { instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } - } else if(instance->generic.cnt >= 0xFFFF) { + } else if((instance->generic.cnt >= 0xFFFF) && (furi_hal_subghz_get_rolling_counter_mult() != 0)) { instance->generic.cnt = 0; } uint32_t fix = btn << 24 | instance->generic.serial; diff --git a/lib/subghz/subghz_setting.c b/lib/subghz/subghz_setting.c index 63e034d61..31b538766 100644 --- a/lib/subghz/subghz_setting.c +++ b/lib/subghz/subghz_setting.c @@ -282,6 +282,7 @@ void subghz_setting_load(SubGhzSetting* instance, const char* file_path) { FURI_LOG_E(TAG, "Rewind error"); break; } + furi_string_reset(temp_str); while(flipper_format_read_string(fff_data_file, "Custom_preset_name", temp_str)) { FURI_LOG_I(TAG, "Custom preset loaded %s", furi_string_get_cstr(temp_str)); subghz_setting_load_custom_preset( diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index d8ed76c05..a15edc125 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1749,7 +1749,7 @@ Function,+,furi_hal_subghz_flush_rx,void, Function,+,furi_hal_subghz_flush_tx,void, Function,+,furi_hal_subghz_get_data_gpio,const GpioPin*, Function,+,furi_hal_subghz_get_lqi,uint8_t, -Function,+,furi_hal_subghz_get_rolling_counter_mult,int8_t, +Function,+,furi_hal_subghz_get_rolling_counter_mult,int32_t, Function,+,furi_hal_subghz_get_rssi,float, Function,+,furi_hal_subghz_idle,void, Function,-,furi_hal_subghz_init,void, @@ -1768,7 +1768,7 @@ Function,+,furi_hal_subghz_set_async_mirror_pin,void,const GpioPin* Function,+,furi_hal_subghz_set_frequency,uint32_t,uint32_t Function,+,furi_hal_subghz_set_frequency_and_path,uint32_t,uint32_t Function,+,furi_hal_subghz_set_path,void,FuriHalSubGhzPath -Function,+,furi_hal_subghz_set_rolling_counter_mult,void,int8_t +Function,+,furi_hal_subghz_set_rolling_counter_mult,void,int32_t Function,+,furi_hal_subghz_shutdown,void, Function,+,furi_hal_subghz_sleep,void, Function,+,furi_hal_subghz_start_async_rx,void,"FuriHalSubGhzCaptureCallback, void*" @@ -3586,7 +3586,7 @@ Function,+,subghz_keystore_get_data,SubGhzKeyArray_t*,SubGhzKeystore* Function,+,subghz_keystore_load,_Bool,"SubGhzKeystore*, const char*" Function,+,subghz_keystore_raw_encrypted_save,_Bool,"const char*, const char*, uint8_t*" Function,+,subghz_keystore_raw_get_data,_Bool,"const char*, size_t, uint8_t*, size_t" -Function,-,subghz_keystore_reset_kl,void,SubGhzKeystore* +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_blocks_add_bit,void,"SubGhzBlockDecoder*, uint8_t" diff --git a/targets/f7/furi_hal/furi_hal_subghz.c b/targets/f7/furi_hal/furi_hal_subghz.c index fcfdf5ba8..dbb52e8ce 100644 --- a/targets/f7/furi_hal/furi_hal_subghz.c +++ b/targets/f7/furi_hal/furi_hal_subghz.c @@ -52,7 +52,7 @@ typedef struct { volatile SubGhzRegulation regulation; const GpioPin* async_mirror_pin; - int8_t rolling_counter_mult; + int32_t rolling_counter_mult; bool extended_range : 1; bool bypass_region : 1; } FuriHalSubGhz; @@ -66,11 +66,11 @@ volatile FuriHalSubGhz furi_hal_subghz = { .bypass_region = false, }; -int8_t furi_hal_subghz_get_rolling_counter_mult(void) { +int32_t furi_hal_subghz_get_rolling_counter_mult(void) { return furi_hal_subghz.rolling_counter_mult; } -void furi_hal_subghz_set_rolling_counter_mult(int8_t mult) { +void furi_hal_subghz_set_rolling_counter_mult(int32_t mult) { furi_hal_subghz.rolling_counter_mult = mult; } diff --git a/targets/f7/furi_hal/furi_hal_subghz.h b/targets/f7/furi_hal/furi_hal_subghz.h index c0c0c88c7..a524de74c 100644 --- a/targets/f7/furi_hal/furi_hal_subghz.h +++ b/targets/f7/furi_hal/furi_hal_subghz.h @@ -183,14 +183,14 @@ SubGhzTx furi_hal_subghz_check_tx(uint32_t value); bool furi_hal_subghz_is_tx_allowed(uint32_t value); /** Get the current rolling protocols counter ++/-- value - * @return int8_t current value + * @return int32_t current value */ -int8_t furi_hal_subghz_get_rolling_counter_mult(void); +int32_t furi_hal_subghz_get_rolling_counter_mult(void); /** Set the current rolling protocols counter ++/-- value - * @param mult int8_t = -1, -10, -100, 0, 1, 10, 100 + * @param mult int32_t = -1, -10, -50, 0, 1, 10, 50 */ -void furi_hal_subghz_set_rolling_counter_mult(int8_t mult); +void furi_hal_subghz_set_rolling_counter_mult(int32_t mult); /** Set frequency * diff --git a/targets/furi_hal_include/furi_hal_version.h b/targets/furi_hal_include/furi_hal_version.h index 1ac799067..17dd7064c 100644 --- a/targets/furi_hal_include/furi_hal_version.h +++ b/targets/furi_hal_include/furi_hal_version.h @@ -14,11 +14,12 @@ extern "C" { #endif -#define FURI_HAL_VERSION_NAME_LENGTH 8 -#define FURI_HAL_VERSION_ARRAY_NAME_LENGTH (FURI_HAL_VERSION_NAME_LENGTH + 1) -#define FURI_HAL_BT_ADV_NAME_LENGTH (18 + 1) // 18 characters + null terminator -#define FURI_HAL_VERSION_DEVICE_NAME_LENGTH \ - (1 + FURI_HAL_BT_ADV_NAME_LENGTH) // Used for custom BT name, BLE symbol + name +#define FURI_HAL_VERSION_NAME_LENGTH (8) +#define FURI_HAL_VERSION_ARRAY_NAME_LENGTH (FURI_HAL_VERSION_NAME_LENGTH + 1) +/** 31b BLE Adv - 3b flags - 2b name prefix - 4b service uuid - 3b tx power = 19, + 1b null terminator (not present in packet) */ +#define FURI_HAL_BT_ADV_NAME_LENGTH (20) +/** BLE symbol + name */ +#define FURI_HAL_VERSION_DEVICE_NAME_LENGTH (1 + FURI_HAL_BT_ADV_NAME_LENGTH) /** OTP Versions enum */ typedef enum {