From be942ef7b2b480b85efe85680eaa1ff6ed83d7c0 Mon Sep 17 00:00:00 2001 From: Daniel <71837281+darmiel@users.noreply.github.com> Date: Fri, 12 Aug 2022 01:55:19 +0200 Subject: [PATCH 01/78] feat[unirfremix]: allow protocols other than raw --- applications/unirfremix/unirfremix_app.c | 175 ++++++++++++++--------- 1 file changed, 104 insertions(+), 71 deletions(-) diff --git a/applications/unirfremix/unirfremix_app.c b/applications/unirfremix/unirfremix_app.c index 000b20ef1c..c7858e38e6 100644 --- a/applications/unirfremix/unirfremix_app.c +++ b/applications/unirfremix/unirfremix_app.c @@ -12,6 +12,8 @@ #include #include +#include + #define UNIRFMAP_FOLDER "/ext/unirf" #define UNIRFMAP_EXTENSION ".txt" @@ -469,11 +471,46 @@ static void unirfremix_end_send(UniRFRemix* app) { app->processing = 0; } -static void unirfremix_send_signal( +static FuriHalSubGhzPreset str_to_preset(string_t preset) { + if(string_cmp_str(preset, "FuriHalSubGhzPresetOok270Async") == 0) { + return FuriHalSubGhzPresetOok270Async; + } + if(string_cmp_str(preset, "FuriHalSubGhzPresetOok650Async") == 0) { + return FuriHalSubGhzPresetOok650Async; + } + if(string_cmp_str(preset, "FuriHalSubGhzPreset2FSKDev238Async") == 0) { + return FuriHalSubGhzPreset2FSKDev238Async; + } + if(string_cmp_str(preset, "FuriHalSubGhzPreset2FSKDev476Async") == 0) { + return FuriHalSubGhzPreset2FSKDev476Async; + } + if(string_cmp_str(preset, "FuriHalSubGhzPresetMSK99_97KbAsync") == 0) { + return FuriHalSubGhzPresetMSK99_97KbAsync; + } + if(string_cmp_str(preset, "FuriHalSubGhzPresetMSK99_97KbAsync") == 0) { + return FuriHalSubGhzPresetMSK99_97KbAsync; + } + return FuriHalSubGhzPresetCustom; +} + +static bool unirfremix_send_sub( UniRFRemix* app, - uint32_t frequency, - string_t signal, - string_t protocol) { + FlipperFormat* fff_file, + FlipperFormat* fff_data, + string_t protocol, + string_t preset, + const char* path) { + // + if(!flipper_format_file_open_existing(fff_file, path)) { + FURI_LOG_E(TAG, "Could not open file %s", path); + return false; + } + + uint32_t frequency = 0; + if(!flipper_format_read_uint32(fff_file, "Frequency", &frequency, 1)) { + FURI_LOG_W(TAG, "Cannot read frequency. Defaulting to 433.92 MHz"); + frequency = 433920000; + } if(!furi_hal_subghz_is_tx_allowed(frequency)) { printf( "In your settings, only reception on this frequency (%lu) is allowed,\r\n" @@ -481,100 +518,96 @@ static void unirfremix_send_signal( frequency); app->tx_not_allowed = true; unirfremix_end_send(app); - return; + return false; } else { app->tx_not_allowed = false; } - for(int x = 1; x <= app->repeat; x++) { - frequency = frequency ? frequency : 433920000; - FURI_LOG_E(TAG, "file to send: %s", string_get_cstr(signal)); - string_t flipper_format_string; - - if(strcmp(string_get_cstr(protocol), "RAW") == 0) { - string_init_printf(flipper_format_string, "File_name: %s", string_get_cstr(signal)); - } else { - unirfremix_end_send(app); - } - NotificationApp* notification = furi_record_open("notification"); - - FlipperFormat* flipper_format = flipper_format_string_alloc(); - Stream* stream = flipper_format_get_raw_stream(flipper_format); - stream_clean(stream); - stream_write_cstring(stream, string_get_cstr(flipper_format_string)); - - SubGhzEnvironment* environment = subghz_environment_alloc(); - SubGhzTransmitter* transmitter = - subghz_transmitter_alloc_init(environment, string_get_cstr(protocol)); - subghz_transmitter_deserialize(transmitter, flipper_format); + if(!flipper_format_read_string(fff_file, "Preset", preset)) { + FURI_LOG_W(TAG, "Could not read Preset. Defaulting to Ook650Async"); + string_set(preset, "FuriHalSubGhzPresetOok650Async"); + } - furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); - furi_hal_subghz_set_frequency_and_path(frequency); + if(!flipper_format_read_string(fff_file, "Protocol", protocol)) { + FURI_LOG_W(TAG, "Could not read Protocol. Defaulting to RAW"); + string_set(protocol, "RAW"); + } - //printf("Transmitting at %lu, repeat %d.\r\n", frequency, x); + if(!string_cmp_str(protocol, "RAW")) { + subghz_protocol_raw_gen_fff_data(fff_data, path); + } else { + stream_copy_full( + flipper_format_get_raw_stream(fff_file), flipper_format_get_raw_stream(fff_data)); + } + flipper_format_free(fff_file); - furi_hal_power_suppress_charge_enter(); - furi_hal_subghz_start_async_tx(subghz_transmitter_yield, transmitter); + SubGhzEnvironment* environment = subghz_environment_alloc(); + SubGhzTransmitter* transmitter = + subghz_transmitter_alloc_init(environment, string_get_cstr(protocol)); - while(!(furi_hal_subghz_is_async_tx_complete())) { - notification_message(notification, &sequence_blink_magenta_10); - //printf("Sending..."); - fflush(stdout); - furi_delay_ms(333); - } + subghz_transmitter_deserialize(transmitter, fff_data); - furi_record_close("notification"); + furi_hal_subghz_reset(); + furi_hal_subghz_load_preset(str_to_preset(preset)); - furi_hal_subghz_stop_async_tx(); - furi_hal_subghz_sleep(); + frequency = furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_power_suppress_charge_exit(); + furi_hal_power_suppress_charge_enter(); + furi_hal_subghz_start_async_tx(subghz_transmitter_yield, transmitter); - flipper_format_free(flipper_format); - subghz_transmitter_free(transmitter); - subghz_environment_free(environment); + FURI_LOG_I(TAG, "Sending..."); + while(!furi_hal_subghz_is_async_tx_complete()) { + fflush(stdout); + furi_delay_ms(333); } + FURI_LOG_I(TAG, " Done!"); - unirfremix_end_send(app); -} - -static void unirfremix_process_signal(UniRFRemix* app, string_t signal) { - view_port_update(app->view_port); + furi_hal_subghz_stop_async_tx(); + furi_hal_subghz_sleep(); - FURI_LOG_I(TAG, "signal = %s", string_get_cstr(signal)); + furi_hal_power_suppress_charge_exit(); - if(strlen(string_get_cstr(signal)) > 12) { - string_t file_name; - string_init(file_name); + subghz_transmitter_free(transmitter); + return true; +} - string_t protocol; - string_init(protocol); +static void unirfremix_send_signal(UniRFRemix* app, Storage* storage, string_t signal) { + FURI_LOG_I(TAG, "Sending: %s", string_get_cstr(signal)); - uint32_t frequency_str; + FlipperFormat* fff_data = flipper_format_string_alloc(); - string_set(file_name, string_get_cstr(signal)); + string_t preset, protocol; + string_init(preset); + string_init(protocol); - Storage* storage = furi_record_open("storage"); - FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); + for(int x = 0; x < app->repeat; ++x) { + FlipperFormat* fff_file = flipper_format_file_alloc(storage); + bool res = unirfremix_send_sub( + app, fff_file, fff_data, protocol, preset, string_get_cstr(signal)); - flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name)); + if(!res) { // errored + flipper_format_free(fff_file); + break; + } + } - flipper_format_read_uint32(fff_data_file, "Frequency", (uint32_t*)&frequency_str, 1); + string_clear(preset); + string_clear(protocol); - if(!flipper_format_read_string(fff_data_file, "Protocol", protocol)) { - FURI_LOG_I(TAG, "Could not read Protocol"); - string_set(protocol, "RAW"); - } + flipper_format_free(fff_data); - flipper_format_free(fff_data_file); - furi_record_close("storage"); + unirfremix_end_send(app); +} - FURI_LOG_I(TAG, "%lu", frequency_str); +static void unirfremix_process_signal(UniRFRemix* app, string_t signal) { + view_port_update(app->view_port); - string_clear(file_name); + FURI_LOG_I(TAG, "signal = %s", string_get_cstr(signal)); - unirfremix_send_signal(app, frequency_str, signal, protocol); + if(strlen(string_get_cstr(signal)) > 12) { + Storage* storage = furi_record_open(RECORD_STORAGE); + unirfremix_send_signal(app, storage, signal); + furi_record_close(RECORD_STORAGE); } else if(strlen(string_get_cstr(signal)) < 10) { unirfremix_end_send(app); } From 36784f95c8f393e31bc048d1bc648f58db1e9a46 Mon Sep 17 00:00:00 2001 From: Daniel <71837281+darmiel@users.noreply.github.com> Date: Sun, 14 Aug 2022 23:26:49 +0200 Subject: [PATCH 02/78] refactor[unirf]: dynamic protocol updates --- applications/unirfremix/unirfremix_app.c | 365 ++++++++++++++++------- 1 file changed, 249 insertions(+), 116 deletions(-) diff --git a/applications/unirfremix/unirfremix_app.c b/applications/unirfremix/unirfremix_app.c index c7858e38e6..eeb96028f5 100644 --- a/applications/unirfremix/unirfremix_app.c +++ b/applications/unirfremix/unirfremix_app.c @@ -13,6 +13,8 @@ #include #include +#include +#include #define UNIRFMAP_FOLDER "/ext/unirf" #define UNIRFMAP_EXTENSION ".txt" @@ -27,6 +29,8 @@ typedef struct { ViewPort* view_port; Gui* gui; + SubGhzSetting* setting; + string_t up_file; string_t down_file; string_t left_file; @@ -68,6 +72,20 @@ typedef struct { } UniRFRemix; +typedef struct { + uint32_t frequency; + string_t name; + + uint8_t* data; + size_t data_size; +} UniRFPreset; + +UniRFPreset* unirf_preset_alloc(void) { + UniRFPreset* preset = malloc(sizeof(UniRFPreset)); + string_init(preset->name); + return preset; +} + static char* char_to_str(char* str, int i) { char* converted = malloc(sizeof(char) * i + 1); memcpy(converted, str, i); @@ -104,37 +122,6 @@ static const char* int_to_char(int number) { } } -/*Decided not to use this -//check name for special characters and length -static char* check_special(char* filename) -{ - char stripped[11]; - - //grab length of string - int len = strlen(filename); - - int c = 0; - int i; - - //remove special characters - for (i = 0; i < len; i++) - { - if (isalnum((unsigned)filename[i])) - { - if(c < 11) - { - stripped[c] = filename[i]; - c++; - } - } - } - - stripped[c] = '\0'; - - return char_to_str(stripped, 10); -} -*/ - //get filename without path static char* extract_filename(const char* name, int len) { string_t tmp; @@ -156,7 +143,7 @@ static char* extract_filename(const char* name, int len) { */ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { - Storage* storage = furi_record_open("storage"); + Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); app->file_result = 3; @@ -352,7 +339,7 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { } flipper_format_free(fff_data_file); - furi_record_close("storage"); + furi_record_close(RECORD_STORAGE); //File Existence Check //Check each file definition if not already set to "N/A" @@ -374,7 +361,7 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { //if button is still enabled, check that file exists if(app->up_enabled == 1) { string_set(file_name, app->up_file); - storage = furi_record_open("storage"); + storage = furi_record_open(RECORD_STORAGE); fff_data_file = flipper_format_file_alloc(storage); if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) { @@ -388,12 +375,12 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { //close the file flipper_format_free(fff_data_file); - furi_record_close("storage"); + furi_record_close(RECORD_STORAGE); } if(app->down_enabled == 1) { string_set(file_name, app->down_file); - storage = furi_record_open("storage"); + storage = furi_record_open(RECORD_STORAGE); fff_data_file = flipper_format_file_alloc(storage); if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) { @@ -405,12 +392,12 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { } flipper_format_free(fff_data_file); - furi_record_close("storage"); + furi_record_close(RECORD_STORAGE); } if(app->left_enabled == 1) { string_set(file_name, app->left_file); - storage = furi_record_open("storage"); + storage = furi_record_open(RECORD_STORAGE); fff_data_file = flipper_format_file_alloc(storage); if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) { @@ -422,12 +409,12 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { } flipper_format_free(fff_data_file); - furi_record_close("storage"); + furi_record_close(RECORD_STORAGE); } if(app->right_enabled == 1) { string_set(file_name, app->right_file); - storage = furi_record_open("storage"); + storage = furi_record_open(RECORD_STORAGE); fff_data_file = flipper_format_file_alloc(storage); if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) { @@ -439,12 +426,12 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { } flipper_format_free(fff_data_file); - furi_record_close("storage"); + furi_record_close(RECORD_STORAGE); } if(app->ok_enabled == 1) { string_set(file_name, app->ok_file); - storage = furi_record_open("storage"); + storage = furi_record_open(RECORD_STORAGE); fff_data_file = flipper_format_file_alloc(storage); if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) { @@ -456,7 +443,7 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { } flipper_format_free(fff_data_file); - furi_record_close("storage"); + furi_record_close(RECORD_STORAGE); } if(app->file_blank == 5) { @@ -471,34 +458,141 @@ static void unirfremix_end_send(UniRFRemix* app) { app->processing = 0; } -static FuriHalSubGhzPreset str_to_preset(string_t preset) { - if(string_cmp_str(preset, "FuriHalSubGhzPresetOok270Async") == 0) { - return FuriHalSubGhzPresetOok270Async; - } - if(string_cmp_str(preset, "FuriHalSubGhzPresetOok650Async") == 0) { - return FuriHalSubGhzPresetOok650Async; - } - if(string_cmp_str(preset, "FuriHalSubGhzPreset2FSKDev238Async") == 0) { - return FuriHalSubGhzPreset2FSKDev238Async; - } - if(string_cmp_str(preset, "FuriHalSubGhzPreset2FSKDev476Async") == 0) { - return FuriHalSubGhzPreset2FSKDev476Async; - } - if(string_cmp_str(preset, "FuriHalSubGhzPresetMSK99_97KbAsync") == 0) { - return FuriHalSubGhzPresetMSK99_97KbAsync; +bool unirf_set_preset(UniRFPreset* p, const char* preset) { + if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { + string_set(p->name, "AM270"); + } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { + string_set(p->name, "AM650"); + } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) { + string_set(p->name, "FM238"); + } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { + string_set(p->name, "FM476"); + } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) { + string_set(p->name, "CUSTOM"); + } else { + FURI_LOG_E(TAG, "Unsupported preset"); + return false; } - if(string_cmp_str(preset, "FuriHalSubGhzPresetMSK99_97KbAsync") == 0) { - return FuriHalSubGhzPresetMSK99_97KbAsync; + return true; +} + +bool unirf_key_load( + UniRFPreset* preset, + FlipperFormat* fff_file, + FlipperFormat* fff_data, + SubGhzSetting* setting, + SubGhzReceiver* receiver, + const char* path) { + // + if(!flipper_format_rewind(fff_file)) { + FURI_LOG_E(TAG, "Rewind error"); + return NULL; } - return FuriHalSubGhzPresetCustom; + + string_t temp_str; + string_init(temp_str); + + bool res = false; + + do { + // load frequency from file + uint32_t frequency = 0; + if(!flipper_format_read_uint32(fff_file, "Frequency", &frequency, 1)) { + FURI_LOG_W(TAG, "Cannot read frequency. Defaulting to 433.92 MHz"); + frequency = 433920000; + } + preset->frequency = frequency; + + // load preset from file + if(!flipper_format_read_string(fff_file, "Preset", temp_str)) { + FURI_LOG_W(TAG, "Could not read Preset. Defaulting to Ook650Async"); + string_set(temp_str, "FuriHalSubGhzPresetOok650Async"); + } + if(!unirf_set_preset(preset, string_get_cstr(temp_str))) { + FURI_LOG_E(TAG, "Could not set preset"); + break; + } + if(!strcmp(string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) { + // TODO: check if preset is custom + } + size_t preset_index = + subghz_setting_get_inx_preset_by_name(setting, string_get_cstr(preset->name)); + FURI_LOG_I(TAG, "Preset index: %d", preset_index); + preset->data = subghz_setting_get_preset_data(setting, preset_index); + FURI_LOG_I(TAG, "Preset data: %p", preset->data); + preset->data_size = subghz_setting_get_preset_data_size(setting, preset_index); + FURI_LOG_I(TAG, "Preset data size: %d", preset->data_size); + + // load protocol from file + if(!flipper_format_read_string(fff_file, "Protocol", temp_str)) { + FURI_LOG_W(TAG, "Could not read Protocol."); + break; + } + if(!string_cmp_str(temp_str, "RAW")) { + FURI_LOG_I(TAG, "RAW protocol"); + subghz_protocol_raw_gen_fff_data(fff_data, path); + } else { + FURI_LOG_E(TAG, "Other protocol"); + stream_copy_full( + flipper_format_get_raw_stream(fff_file), flipper_format_get_raw_stream(fff_data)); + } + SubGhzProtocolDecoderBase* decoder_res = + subghz_receiver_search_decoder_base_by_name(receiver, string_get_cstr(temp_str)); + if(decoder_res) { + if(!subghz_protocol_decoder_base_deserialize(decoder_res, fff_data)) { + break; + } + } else { + FURI_LOG_E(TAG, "Protocol %s not found", string_get_cstr(temp_str)); + } + + res = true; + } while(0); + + string_clear(temp_str); + + return res; +} + +// method modified from subghz_i.c +bool unirf_save_protocol_to_file(FlipperFormat* fff_file, const char* dev_file_name) { + furi_assert(fff_file); + furi_assert(dev_file_name); + + Storage* storage = furi_record_open(RECORD_STORAGE); + Stream* flipper_format_stream = flipper_format_get_raw_stream(fff_file); + + bool saved = false; + string_t file_dir; + string_init(file_dir); + + path_extract_dirname(dev_file_name, file_dir); + do { + flipper_format_delete_key(fff_file, "Repeat"); + flipper_format_delete_key(fff_file, "Manufacture"); + + if(!storage_simply_mkdir(storage, string_get_cstr(file_dir))) { + break; + } + + if(!storage_simply_remove(storage, dev_file_name)) { + break; + } + //ToDo check Write + stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); + stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); + + saved = true; + } while(0); + string_clear(file_dir); + furi_record_close(RECORD_STORAGE); + return saved; } static bool unirfremix_send_sub( UniRFRemix* app, FlipperFormat* fff_file, FlipperFormat* fff_data, - string_t protocol, - string_t preset, const char* path) { // if(!flipper_format_file_open_existing(fff_file, path)) { @@ -506,68 +600,106 @@ static bool unirfremix_send_sub( return false; } - uint32_t frequency = 0; - if(!flipper_format_read_uint32(fff_file, "Frequency", &frequency, 1)) { - FURI_LOG_W(TAG, "Cannot read frequency. Defaulting to 433.92 MHz"); - frequency = 433920000; - } - if(!furi_hal_subghz_is_tx_allowed(frequency)) { - printf( - "In your settings, only reception on this frequency (%lu) is allowed,\r\n" - "the actual operation of the unirf app is not possible\r\n ", - frequency); - app->tx_not_allowed = true; - unirfremix_end_send(app); + SubGhzEnvironment* environment = subghz_environment_alloc(); + SubGhzReceiver* subghz_receiver = subghz_receiver_alloc_init(environment); + + UniRFPreset* preset = unirf_preset_alloc(); + if(!unirf_key_load(preset, fff_file, fff_data, app->setting, subghz_receiver, path)) { + FURI_LOG_E(TAG, "Could not load key"); return false; - } else { - app->tx_not_allowed = false; } + FURI_LOG_I(TAG, "Loaded preset."); + + // TODO: reimplement this later: + /* + if(!furi_hal_subghz_is_tx_allowed(frequency)) { + printf( + "In your settings, only reception on this frequency (%lu) is allowed,\r\n" + "the actual operation of the unirf app is not possible\r\n ", + frequency); + app->tx_not_allowed = true; + unirfremix_end_send(app); + return false; + } else { + app->tx_not_allowed = false; + } + */ - if(!flipper_format_read_string(fff_file, "Preset", preset)) { - FURI_LOG_W(TAG, "Could not read Preset. Defaulting to Ook650Async"); - string_set(preset, "FuriHalSubGhzPresetOok650Async"); - } + string_t temp_str; + string_init(temp_str); - if(!flipper_format_read_string(fff_file, "Protocol", protocol)) { - FURI_LOG_W(TAG, "Could not read Protocol. Defaulting to RAW"); - string_set(protocol, "RAW"); - } + do { + if(!flipper_format_rewind(fff_file)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } - if(!string_cmp_str(protocol, "RAW")) { - subghz_protocol_raw_gen_fff_data(fff_data, path); - } else { - stream_copy_full( - flipper_format_get_raw_stream(fff_file), flipper_format_get_raw_stream(fff_data)); - } - flipper_format_free(fff_file); + if(!flipper_format_read_string(fff_file, "Protocol", temp_str)) { + FURI_LOG_E(TAG, "Could not read Protocol"); + break; + } - SubGhzEnvironment* environment = subghz_environment_alloc(); - SubGhzTransmitter* transmitter = - subghz_transmitter_alloc_init(environment, string_get_cstr(protocol)); + uint32_t repeat = 200; + if(!flipper_format_insert_or_update_uint32(fff_file, "Repeat", &repeat, 1)) { + FURI_LOG_E(TAG, "Unable to insert or update Repeat"); + break; + } - subghz_transmitter_deserialize(transmitter, fff_data); + SubGhzTransmitter* transmitter = + subghz_transmitter_alloc_init(environment, string_get_cstr(temp_str)); + FURI_LOG_I(TAG, "Got transmitter for %s", string_get_cstr(temp_str)); - furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(str_to_preset(preset)); + if(transmitter) { + subghz_transmitter_deserialize(transmitter, fff_data); - frequency = furi_hal_subghz_set_frequency_and_path(frequency); + furi_hal_subghz_reset(); + furi_hal_subghz_idle(); + furi_hal_subghz_load_custom_preset(preset->data); + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); - furi_hal_power_suppress_charge_enter(); - furi_hal_subghz_start_async_tx(subghz_transmitter_yield, transmitter); + furi_hal_subghz_set_frequency_and_path(preset->frequency); + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_write(&gpio_cc1101_g0, true); - FURI_LOG_I(TAG, "Sending..."); - while(!furi_hal_subghz_is_async_tx_complete()) { - fflush(stdout); - furi_delay_ms(333); - } - FURI_LOG_I(TAG, " Done!"); + furi_hal_power_suppress_charge_enter(); + + if(furi_hal_subghz_tx()) { + furi_hal_subghz_start_async_tx(subghz_transmitter_yield, transmitter); + + FURI_LOG_I(TAG, "Sending..."); + while(!furi_hal_subghz_is_async_tx_complete()) { + // fflush(stdout); + furi_delay_ms(33); + } + FURI_LOG_I(TAG, " Done!"); - furi_hal_subghz_stop_async_tx(); - furi_hal_subghz_sleep(); + furi_hal_subghz_stop_async_tx(); - furi_hal_power_suppress_charge_exit(); + subghz_transmitter_stop(transmitter); + subghz_transmitter_free(transmitter); - subghz_transmitter_free(transmitter); + FURI_LOG_I(TAG, "Checking if protocol is dynamic"); + const SubGhzProtocol* registry_protocol = + subghz_protocol_registry_get_by_name(string_get_cstr(temp_str)); + if(registry_protocol && registry_protocol->type == SubGhzProtocolTypeDynamic) { + FURI_LOG_I(TAG, " Protocol is dynamic. Updating Repeat"); + unirf_save_protocol_to_file(fff_file, path); + } + } else { + FURI_LOG_E(TAG, "Sending not allowed"); + } + + FURI_LOG_I(TAG, "Cleaning up."); + furi_hal_subghz_idle(); + furi_hal_subghz_sleep(); + furi_hal_power_suppress_charge_exit(); + } + } while(0); + + string_clear(temp_str); + unirfremix_end_send(app); + + subghz_environment_free(environment); return true; } @@ -582,8 +714,7 @@ static void unirfremix_send_signal(UniRFRemix* app, Storage* storage, string_t s for(int x = 0; x < app->repeat; ++x) { FlipperFormat* fff_file = flipper_format_file_alloc(storage); - bool res = unirfremix_send_sub( - app, fff_file, fff_data, protocol, preset, string_get_cstr(signal)); + bool res = unirfremix_send_sub(app, fff_file, fff_data, string_get_cstr(signal)); if(!res) { // errored flipper_format_free(fff_file); @@ -709,7 +840,6 @@ static void render_callback(Canvas* canvas, void* ctx) { static void input_callback(InputEvent* input_event, void* ctx) { UniRFRemix* app = ctx; - furi_message_queue_put(app->input_queue, input_event, 0); } @@ -728,6 +858,9 @@ UniRFRemix* unirfremix_alloc() { app->gui = furi_record_open(RECORD_GUI); gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen); + app->setting = subghz_setting_alloc(); + subghz_setting_load(app->setting, EXT_PATH("subghz/assets/setting_user")); + return app; } @@ -780,11 +913,11 @@ int32_t unirfremix_app(void* p) { app->file_result = 3; - Storage* storage = furi_record_open("storage"); + Storage* storage = furi_record_open(RECORD_STORAGE); if(!storage_simply_mkdir(storage, UNIRFMAP_FOLDER)) { FURI_LOG_E(TAG, "Could not create folder %s", UNIRFMAP_FOLDER); } - furi_record_close("storage"); + furi_record_close(RECORD_STORAGE); string_set_str(app->file_path, UNIRFMAP_FOLDER); From 33fbf268b79c216516b59ad87524e68259004e9e Mon Sep 17 00:00:00 2001 From: Daniel <71837281+darmiel@users.noreply.github.com> Date: Sun, 14 Aug 2022 23:52:05 +0200 Subject: [PATCH 03/78] fix[unirf]: close fff_file --- applications/unirfremix/unirfremix_app.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/applications/unirfremix/unirfremix_app.c b/applications/unirfremix/unirfremix_app.c index eeb96028f5..7d99794829 100644 --- a/applications/unirfremix/unirfremix_app.c +++ b/applications/unirfremix/unirfremix_app.c @@ -529,10 +529,10 @@ bool unirf_key_load( break; } if(!string_cmp_str(temp_str, "RAW")) { - FURI_LOG_I(TAG, "RAW protocol"); + FURI_LOG_I(TAG, "-> RAW protocol"); subghz_protocol_raw_gen_fff_data(fff_data, path); } else { - FURI_LOG_E(TAG, "Other protocol"); + FURI_LOG_I(TAG, "-> Other protocol"); stream_copy_full( flipper_format_get_raw_stream(fff_file), flipper_format_get_raw_stream(fff_data)); } @@ -572,10 +572,12 @@ bool unirf_save_protocol_to_file(FlipperFormat* fff_file, const char* dev_file_n flipper_format_delete_key(fff_file, "Manufacture"); if(!storage_simply_mkdir(storage, string_get_cstr(file_dir))) { + FURI_LOG_E(TAG, "(save) Cannot mkdir"); break; } if(!storage_simply_remove(storage, dev_file_name)) { + FURI_LOG_E(TAG, "(save) Cannot remove"); break; } //ToDo check Write @@ -583,6 +585,7 @@ bool unirf_save_protocol_to_file(FlipperFormat* fff_file, const char* dev_file_n stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); saved = true; + FURI_LOG_I(TAG, "(save) OK Save"); } while(0); string_clear(file_dir); furi_record_close(RECORD_STORAGE); @@ -628,6 +631,7 @@ static bool unirfremix_send_sub( string_t temp_str; string_init(temp_str); + bool res = false; do { if(!flipper_format_rewind(fff_file)) { FURI_LOG_E(TAG, "Rewind error"); @@ -678,6 +682,8 @@ static bool unirfremix_send_sub( subghz_transmitter_stop(transmitter); subghz_transmitter_free(transmitter); + flipper_format_file_close(fff_file); + FURI_LOG_I(TAG, "Checking if protocol is dynamic"); const SubGhzProtocol* registry_protocol = subghz_protocol_registry_get_by_name(string_get_cstr(temp_str)); @@ -694,13 +700,15 @@ static bool unirfremix_send_sub( furi_hal_subghz_sleep(); furi_hal_power_suppress_charge_exit(); } + + res = true; } while(0); string_clear(temp_str); unirfremix_end_send(app); subghz_environment_free(environment); - return true; + return res; } static void unirfremix_send_signal(UniRFRemix* app, Storage* storage, string_t signal) { From 3aed4de1b4961ecabb0d529aaa5b674dd6f72913 Mon Sep 17 00:00:00 2001 From: Daniel <71837281+darmiel@users.noreply.github.com> Date: Mon, 15 Aug 2022 20:52:04 +0200 Subject: [PATCH 04/78] fix[unirf]: passed wrong FlipperFormat --- applications/unirfremix/unirfremix_app.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/applications/unirfremix/unirfremix_app.c b/applications/unirfremix/unirfremix_app.c index 7d99794829..f1f21c32c6 100644 --- a/applications/unirfremix/unirfremix_app.c +++ b/applications/unirfremix/unirfremix_app.c @@ -542,6 +542,8 @@ bool unirf_key_load( if(!subghz_protocol_decoder_base_deserialize(decoder_res, fff_data)) { break; } + subghz_protocol_decoder_base_get_string(decoder_res, temp_str); + FURI_LOG_I(TAG, "Protocol-Des: %s", string_get_cstr(temp_str)); } else { FURI_LOG_E(TAG, "Protocol %s not found", string_get_cstr(temp_str)); } @@ -661,6 +663,7 @@ static bool unirfremix_send_sub( furi_hal_subghz_load_custom_preset(preset->data); furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_subghz_idle(); furi_hal_subghz_set_frequency_and_path(preset->frequency); furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); furi_hal_gpio_write(&gpio_cc1101_g0, true); @@ -689,7 +692,7 @@ static bool unirfremix_send_sub( subghz_protocol_registry_get_by_name(string_get_cstr(temp_str)); if(registry_protocol && registry_protocol->type == SubGhzProtocolTypeDynamic) { FURI_LOG_I(TAG, " Protocol is dynamic. Updating Repeat"); - unirf_save_protocol_to_file(fff_file, path); + unirf_save_protocol_to_file(fff_data, path); } } else { FURI_LOG_E(TAG, "Sending not allowed"); From 71c27de8cc32bd17e2c46a2cd3b42e6bf8a489e8 Mon Sep 17 00:00:00 2001 From: Daniel <71837281+darmiel@users.noreply.github.com> Date: Fri, 19 Aug 2022 03:38:35 +0200 Subject: [PATCH 05/78] fix[unirf]: load environment mf codes --- applications/unirfremix/unirfremix_app.c | 35 ++++++++++++++---------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/applications/unirfremix/unirfremix_app.c b/applications/unirfremix/unirfremix_app.c index f1f21c32c6..b3c010f92c 100644 --- a/applications/unirfremix/unirfremix_app.c +++ b/applications/unirfremix/unirfremix_app.c @@ -78,6 +78,8 @@ typedef struct { uint8_t* data; size_t data_size; + + SubGhzProtocolDecoderBase* decoder; } UniRFPreset; UniRFPreset* unirf_preset_alloc(void) { @@ -517,11 +519,8 @@ bool unirf_key_load( } size_t preset_index = subghz_setting_get_inx_preset_by_name(setting, string_get_cstr(preset->name)); - FURI_LOG_I(TAG, "Preset index: %d", preset_index); preset->data = subghz_setting_get_preset_data(setting, preset_index); - FURI_LOG_I(TAG, "Preset data: %p", preset->data); preset->data_size = subghz_setting_get_preset_data_size(setting, preset_index); - FURI_LOG_I(TAG, "Preset data size: %d", preset->data_size); // load protocol from file if(!flipper_format_read_string(fff_file, "Protocol", temp_str)) { @@ -529,21 +528,18 @@ bool unirf_key_load( break; } if(!string_cmp_str(temp_str, "RAW")) { - FURI_LOG_I(TAG, "-> RAW protocol"); subghz_protocol_raw_gen_fff_data(fff_data, path); } else { - FURI_LOG_I(TAG, "-> Other protocol"); stream_copy_full( flipper_format_get_raw_stream(fff_file), flipper_format_get_raw_stream(fff_data)); } - SubGhzProtocolDecoderBase* decoder_res = + + preset->decoder = subghz_receiver_search_decoder_base_by_name(receiver, string_get_cstr(temp_str)); - if(decoder_res) { - if(!subghz_protocol_decoder_base_deserialize(decoder_res, fff_data)) { + if(preset->decoder) { + if(!subghz_protocol_decoder_base_deserialize(preset->decoder, fff_data)) { break; } - subghz_protocol_decoder_base_get_string(decoder_res, temp_str); - FURI_LOG_I(TAG, "Protocol-Des: %s", string_get_cstr(temp_str)); } else { FURI_LOG_E(TAG, "Protocol %s not found", string_get_cstr(temp_str)); } @@ -606,6 +602,13 @@ static bool unirfremix_send_sub( } SubGhzEnvironment* environment = subghz_environment_alloc(); + subghz_environment_load_keystore(environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); + subghz_environment_load_keystore(environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); + subghz_environment_set_came_atomo_rainbow_table_file_name( + environment, EXT_PATH("subghz/assets/came_atomo")); + subghz_environment_set_nice_flor_s_rainbow_table_file_name( + environment, EXT_PATH("subghz/assets/nice_flor_s")); + SubGhzReceiver* subghz_receiver = subghz_receiver_alloc_init(environment); UniRFPreset* preset = unirf_preset_alloc(); @@ -687,6 +690,10 @@ static bool unirfremix_send_sub( flipper_format_file_close(fff_file); + subghz_protocol_decoder_base_deserialize(preset->decoder, fff_data); + subghz_protocol_decoder_base_get_string(preset->decoder, temp_str); + FURI_LOG_I(TAG, "Decoded: %s", string_get_cstr(temp_str)); + FURI_LOG_I(TAG, "Checking if protocol is dynamic"); const SubGhzProtocol* registry_protocol = subghz_protocol_registry_get_by_name(string_get_cstr(temp_str)); @@ -714,8 +721,8 @@ static bool unirfremix_send_sub( return res; } -static void unirfremix_send_signal(UniRFRemix* app, Storage* storage, string_t signal) { - FURI_LOG_I(TAG, "Sending: %s", string_get_cstr(signal)); +static void unirfremix_send_signal(UniRFRemix* app, Storage* storage, const char* path) { + FURI_LOG_I(TAG, "Sending: %s", path); FlipperFormat* fff_data = flipper_format_string_alloc(); @@ -725,7 +732,7 @@ static void unirfremix_send_signal(UniRFRemix* app, Storage* storage, string_t s for(int x = 0; x < app->repeat; ++x) { FlipperFormat* fff_file = flipper_format_file_alloc(storage); - bool res = unirfremix_send_sub(app, fff_file, fff_data, string_get_cstr(signal)); + bool res = unirfremix_send_sub(app, fff_file, fff_data, path); if(!res) { // errored flipper_format_free(fff_file); @@ -748,7 +755,7 @@ static void unirfremix_process_signal(UniRFRemix* app, string_t signal) { if(strlen(string_get_cstr(signal)) > 12) { Storage* storage = furi_record_open(RECORD_STORAGE); - unirfremix_send_signal(app, storage, signal); + unirfremix_send_signal(app, storage, string_get_cstr(signal)); furi_record_close(RECORD_STORAGE); } else if(strlen(string_get_cstr(signal)) < 10) { unirfremix_end_send(app); From fdb181b1586f69af7a39c5a99ba5cad255127d0b Mon Sep 17 00:00:00 2001 From: Max Andreev Date: Fri, 19 Aug 2022 14:31:45 +0300 Subject: [PATCH 06/78] Fix BT Remote 'stay' button on first launch bug (#1626) --- applications/bt/bt_hid_app/bt_hid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/applications/bt/bt_hid_app/bt_hid.c b/applications/bt/bt_hid_app/bt_hid.c index b6f00e9394..3189042c0e 100755 --- a/applications/bt/bt_hid_app/bt_hid.c +++ b/applications/bt/bt_hid_app/bt_hid.c @@ -134,7 +134,8 @@ BtHid* bt_hid_app_alloc() { app->view_dispatcher, BtHidViewMouse, bt_hid_mouse_get_view(app->bt_hid_mouse)); // TODO switch to menu after Media is done - view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewKeynote); + app->view_id = BtHidViewKeynote; + view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); return app; } From 0a6d775fa7935039de8c81ce669f084c003996d0 Mon Sep 17 00:00:00 2001 From: Anna Prosvetova Date: Sun, 21 Aug 2022 14:51:04 +0200 Subject: [PATCH 07/78] Github: Update CODEOWNERS (#1631) --- .github/CODEOWNERS | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 71acb5f14b..ea165de2f7 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -17,7 +17,6 @@ /applications/gui/ @skotopes @DrZlo13 @hedger /applications/ibutton/ @skotopes @DrZlo13 @hedger @gsurkov /applications/infrared/ @skotopes @DrZlo13 @hedger @gsurkov -/applications/infrared_monitor/ @skotopes @DrZlo13 @hedger @gsurkov /applications/input/ @skotopes @DrZlo13 @hedger /applications/lfrfid/ @skotopes @DrZlo13 @hedger /applications/lfrfid_debug/ @skotopes @DrZlo13 @hedger @@ -46,11 +45,11 @@ /debug/ @skotopes @DrZlo13 @hedger # Docker -/docker/ @skotopes @DrZlo13 @hedger @aprosvetova -/docker-compose.yml @skotopes @DrZlo13 @hedger @aprosvetova +/docker/ @skotopes @DrZlo13 @hedger @drunkbatya +/docker-compose.yml @skotopes @DrZlo13 @hedger @drunkbatya # Documentation -/documentation/ @skotopes @DrZlo13 @hedger @aprosvetova +/documentation/ @skotopes @DrZlo13 @hedger @drunkbatya # Firmware targets /firmware/ @skotopes @DrZlo13 @hedger @@ -84,8 +83,5 @@ /lib/u8g2/ @skotopes @DrZlo13 @hedger /lib/update_util/ @skotopes @DrZlo13 @hedger -# Make tools -/make/ @skotopes @DrZlo13 @hedger @aprosvetova - # Helper scripts /scripts/ @skotopes @DrZlo13 @hedger From cfc0383b96c0f386a20bd142fb72b650b36e9fea Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Mon, 22 Aug 2022 19:19:03 +0300 Subject: [PATCH 08/78] Archive: dont start browser worker on favourites tab (#1628) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../archive/helpers/archive_browser.c | 28 +++++++++++++------ .../archive/helpers/archive_browser.h | 1 - .../archive/views/archive_browser_view.c | 9 ++---- .../archive/views/archive_browser_view.h | 1 + 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/applications/archive/helpers/archive_browser.c b/applications/archive/helpers/archive_browser.c index 54759dadc9..2dfb9484b8 100644 --- a/applications/archive/helpers/archive_browser.c +++ b/applications/archive/helpers/archive_browser.c @@ -77,14 +77,24 @@ static void archive_long_load_cb(void* context) { }); } -void archive_file_browser_set_callbacks(ArchiveBrowserView* browser) { +static void archive_file_browser_set_path( + ArchiveBrowserView* browser, + string_t path, + const char* filter_ext, + bool skip_assets) { furi_assert(browser); - - file_browser_worker_set_callback_context(browser->worker, browser); - file_browser_worker_set_folder_callback(browser->worker, archive_folder_open_cb); - file_browser_worker_set_list_callback(browser->worker, archive_list_load_cb); - file_browser_worker_set_item_callback(browser->worker, archive_list_item_cb); - file_browser_worker_set_long_load_callback(browser->worker, archive_long_load_cb); + if(!browser->worker_running) { + browser->worker = file_browser_worker_alloc(path, filter_ext, skip_assets); + file_browser_worker_set_callback_context(browser->worker, browser); + file_browser_worker_set_folder_callback(browser->worker, archive_folder_open_cb); + file_browser_worker_set_list_callback(browser->worker, archive_list_load_cb); + file_browser_worker_set_item_callback(browser->worker, archive_list_item_cb); + file_browser_worker_set_long_load_callback(browser->worker, archive_long_load_cb); + browser->worker_running = true; + } else { + furi_assert(browser->worker); + file_browser_worker_set_config(browser->worker, path, filter_ext, skip_assets); + } } bool archive_is_item_in_array(ArchiveBrowserViewModel* model, uint32_t idx) { @@ -438,8 +448,8 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) { tab = archive_get_tab(browser); if(archive_is_dir_exists(browser->path)) { bool skip_assets = (strcmp(archive_get_tab_ext(tab), "*") == 0) ? false : true; - file_browser_worker_set_config( - browser->worker, browser->path, archive_get_tab_ext(tab), skip_assets); + archive_file_browser_set_path( + browser, browser->path, archive_get_tab_ext(tab), skip_assets); tab_empty = false; // Empty check will be performed later } else { tab_empty = true; diff --git a/applications/archive/helpers/archive_browser.h b/applications/archive/helpers/archive_browser.h index d6c79817a2..ad64a98453 100644 --- a/applications/archive/helpers/archive_browser.h +++ b/applications/archive/helpers/archive_browser.h @@ -87,4 +87,3 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key); void archive_enter_dir(ArchiveBrowserView* browser, string_t name); void archive_leave_dir(ArchiveBrowserView* browser); void archive_refresh_dir(ArchiveBrowserView* browser); -void archive_file_browser_set_callbacks(ArchiveBrowserView* browser); diff --git a/applications/archive/views/archive_browser_view.c b/applications/archive/views/archive_browser_view.c index 810d5c8f78..174071ad49 100644 --- a/applications/archive/views/archive_browser_view.c +++ b/applications/archive/views/archive_browser_view.c @@ -370,18 +370,15 @@ ArchiveBrowserView* browser_alloc() { return true; }); - browser->worker = file_browser_worker_alloc(browser->path, "*", false); - archive_file_browser_set_callbacks(browser); - - file_browser_worker_set_callback_context(browser->worker, browser); - return browser; } void browser_free(ArchiveBrowserView* browser) { furi_assert(browser); - file_browser_worker_free(browser->worker); + if(browser->worker_running) { + file_browser_worker_free(browser->worker); + } with_view_model( browser->view, (ArchiveBrowserViewModel * model) { diff --git a/applications/archive/views/archive_browser_view.h b/applications/archive/views/archive_browser_view.h index 2de04a166c..5c649c389d 100644 --- a/applications/archive/views/archive_browser_view.h +++ b/applications/archive/views/archive_browser_view.h @@ -74,6 +74,7 @@ typedef enum { struct ArchiveBrowserView { View* view; BrowserWorker* worker; + bool worker_running; ArchiveBrowserViewCallback callback; void* context; string_t path; From 4e1470cef2bf9ffca3b17ae38cbbce0e7a1f9eb2 Mon Sep 17 00:00:00 2001 From: Lesha Lomalkin Date: Mon, 22 Aug 2022 19:24:08 +0300 Subject: [PATCH 09/78] slideshow.py: add return code on error (#1636) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * slideshow.py: add return code on error * Scripts: remove dead code Co-authored-by: Lesha Lomalkin Co-authored-by: あく --- scripts/slideshow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/slideshow.py b/scripts/slideshow.py index 7626a6aca0..8a9541a7c1 100644 --- a/scripts/slideshow.py +++ b/scripts/slideshow.py @@ -36,7 +36,7 @@ def pack(self): file_idx += 1 except Exception as e: self.logger.error(e) - break + return 3 widths = set(img.width for img in images) heights = set(img.height for img in images) From 84e2e321b432c6073d7aa82cf80105960bd58938 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Mon, 22 Aug 2022 19:36:45 +0300 Subject: [PATCH 10/78] RPC: more asserts and checks (#1606) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/rpc/rpc.c | 280 ++----------------------- applications/rpc/rpc_app.c | 1 + applications/rpc/rpc_cli.c | 16 +- applications/rpc/rpc_debug.c | 260 +++++++++++++++++++++++ applications/rpc/rpc_gpio.c | 5 - applications/rpc/rpc_i.h | 4 +- applications/rpc/rpc_storage.c | 8 + applications/rpc/rpc_system.c | 4 + applications/unit_tests/rpc/rpc_test.c | 2 +- 9 files changed, 299 insertions(+), 281 deletions(-) create mode 100644 applications/rpc/rpc_debug.c diff --git a/applications/rpc/rpc.c b/applications/rpc/rpc.c index f241a67869..d767a928d6 100644 --- a/applications/rpc/rpc.c +++ b/applications/rpc/rpc.c @@ -80,13 +80,11 @@ struct Rpc { FuriMutex* busy_mutex; }; -static bool content_callback(pb_istream_t* stream, const pb_field_t* field, void** arg); - static void rpc_close_session_process(const PB_Main* request, void* context) { furi_assert(request); + furi_assert(context); RpcSession* session = (RpcSession*)context; - furi_assert(session); rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK); furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever); @@ -98,264 +96,6 @@ static void rpc_close_session_process(const PB_Main* request, void* context) { furi_mutex_release(session->callbacks_mutex); } -static size_t rpc_sprintf_msg_file( - string_t str, - const char* prefix, - const PB_Storage_File* msg_file, - size_t msg_files_size) { - size_t cnt = 0; - - for(size_t i = 0; i < msg_files_size; ++i, ++msg_file) { - string_cat_printf( - str, - "%s[%c] size: %5ld", - prefix, - msg_file->type == PB_Storage_File_FileType_DIR ? 'd' : 'f', - msg_file->size); - - if(msg_file->name) { - string_cat_printf(str, " \'%s\'", msg_file->name); - } - - if(msg_file->data && msg_file->data->size) { - string_cat_printf( - str, - " (%d):\'%.*s%s\'", - msg_file->data->size, - MIN(msg_file->data->size, 30), - msg_file->data->bytes, - msg_file->data->size > 30 ? "..." : ""); - } - - string_cat_printf(str, "\r\n"); - } - - return cnt; -} - -void rpc_print_data(const char* prefix, uint8_t* buffer, size_t size) { - string_t str; - string_init(str); - string_reserve(str, 100 + size * 5); - - string_cat_printf(str, "\r\n%s DEC(%d): {", prefix, size); - for(size_t i = 0; i < size; ++i) { - string_cat_printf(str, "%d, ", buffer[i]); - } - string_cat_printf(str, "}\r\n"); - - printf("%s", string_get_cstr(str)); - string_reset(str); - string_reserve(str, 100 + size * 3); - - string_cat_printf(str, "%s HEX(%d): {", prefix, size); - for(size_t i = 0; i < size; ++i) { - string_cat_printf(str, "%02X", buffer[i]); - } - string_cat_printf(str, "}\r\n\r\n"); - - printf("%s", string_get_cstr(str)); - string_clear(str); -} - -void rpc_print_message(const PB_Main* message) { - string_t str; - string_init(str); - - string_cat_printf( - str, - "PB_Main: {\r\n\tresult: %d cmd_id: %ld (%s)\r\n", - message->command_status, - message->command_id, - message->has_next ? "has_next" : "last"); - switch(message->which_content) { - default: - /* not implemented yet */ - string_cat_printf(str, "\tNOT_IMPLEMENTED (%d) {\r\n", message->which_content); - break; - case PB_Main_stop_session_tag: - string_cat_printf(str, "\tstop_session {\r\n"); - break; - case PB_Main_app_start_request_tag: { - string_cat_printf(str, "\tapp_start {\r\n"); - const char* name = message->content.app_start_request.name; - const char* args = message->content.app_start_request.args; - if(name) { - string_cat_printf(str, "\t\tname: %s\r\n", name); - } - if(args) { - string_cat_printf(str, "\t\targs: %s\r\n", args); - } - break; - } - case PB_Main_app_lock_status_request_tag: { - string_cat_printf(str, "\tapp_lock_status_request {\r\n"); - break; - } - case PB_Main_app_lock_status_response_tag: { - string_cat_printf(str, "\tapp_lock_status_response {\r\n"); - bool lock_status = message->content.app_lock_status_response.locked; - string_cat_printf(str, "\t\tlocked: %s\r\n", lock_status ? "true" : "false"); - break; - } - case PB_Main_storage_md5sum_request_tag: { - string_cat_printf(str, "\tmd5sum_request {\r\n"); - const char* path = message->content.storage_md5sum_request.path; - if(path) { - string_cat_printf(str, "\t\tpath: %s\r\n", path); - } - break; - } - case PB_Main_storage_md5sum_response_tag: { - string_cat_printf(str, "\tmd5sum_response {\r\n"); - const char* path = message->content.storage_md5sum_response.md5sum; - if(path) { - string_cat_printf(str, "\t\tmd5sum: %s\r\n", path); - } - break; - } - case PB_Main_system_ping_request_tag: - string_cat_printf(str, "\tping_request {\r\n"); - break; - case PB_Main_system_ping_response_tag: - string_cat_printf(str, "\tping_response {\r\n"); - break; - case PB_Main_system_device_info_request_tag: - string_cat_printf(str, "\tdevice_info_request {\r\n"); - break; - case PB_Main_system_device_info_response_tag: - string_cat_printf(str, "\tdevice_info_response {\r\n"); - string_cat_printf( - str, - "\t\t%s: %s\r\n", - message->content.system_device_info_response.key, - message->content.system_device_info_response.value); - break; - case PB_Main_storage_mkdir_request_tag: - string_cat_printf(str, "\tmkdir {\r\n"); - break; - case PB_Main_storage_delete_request_tag: { - string_cat_printf(str, "\tdelete {\r\n"); - const char* path = message->content.storage_delete_request.path; - if(path) { - string_cat_printf(str, "\t\tpath: %s\r\n", path); - } - break; - } - case PB_Main_empty_tag: - string_cat_printf(str, "\tempty {\r\n"); - break; - case PB_Main_storage_info_request_tag: { - string_cat_printf(str, "\tinfo_request {\r\n"); - const char* path = message->content.storage_info_request.path; - if(path) { - string_cat_printf(str, "\t\tpath: %s\r\n", path); - } - break; - } - case PB_Main_storage_info_response_tag: { - string_cat_printf(str, "\tinfo_response {\r\n"); - string_cat_printf( - str, "\t\ttotal_space: %lu\r\n", message->content.storage_info_response.total_space); - string_cat_printf( - str, "\t\tfree_space: %lu\r\n", message->content.storage_info_response.free_space); - break; - } - case PB_Main_storage_stat_request_tag: { - string_cat_printf(str, "\tstat_request {\r\n"); - const char* path = message->content.storage_stat_request.path; - if(path) { - string_cat_printf(str, "\t\tpath: %s\r\n", path); - } - break; - } - case PB_Main_storage_stat_response_tag: { - string_cat_printf(str, "\tstat_response {\r\n"); - if(message->content.storage_stat_response.has_file) { - const PB_Storage_File* msg_file = &message->content.storage_stat_response.file; - rpc_sprintf_msg_file(str, "\t\t\t", msg_file, 1); - } - break; - } - case PB_Main_storage_list_request_tag: { - string_cat_printf(str, "\tlist_request {\r\n"); - const char* path = message->content.storage_list_request.path; - if(path) { - string_cat_printf(str, "\t\tpath: %s\r\n", path); - } - break; - } - case PB_Main_storage_read_request_tag: { - string_cat_printf(str, "\tread_request {\r\n"); - const char* path = message->content.storage_read_request.path; - if(path) { - string_cat_printf(str, "\t\tpath: %s\r\n", path); - } - break; - } - case PB_Main_storage_write_request_tag: { - string_cat_printf(str, "\twrite_request {\r\n"); - const char* path = message->content.storage_write_request.path; - if(path) { - string_cat_printf(str, "\t\tpath: %s\r\n", path); - } - if(message->content.storage_write_request.has_file) { - const PB_Storage_File* msg_file = &message->content.storage_write_request.file; - rpc_sprintf_msg_file(str, "\t\t\t", msg_file, 1); - } - break; - } - case PB_Main_storage_read_response_tag: - string_cat_printf(str, "\tread_response {\r\n"); - if(message->content.storage_read_response.has_file) { - const PB_Storage_File* msg_file = &message->content.storage_read_response.file; - rpc_sprintf_msg_file(str, "\t\t\t", msg_file, 1); - } - break; - case PB_Main_storage_list_response_tag: { - const PB_Storage_File* msg_file = message->content.storage_list_response.file; - size_t msg_file_count = message->content.storage_list_response.file_count; - string_cat_printf(str, "\tlist_response {\r\n"); - rpc_sprintf_msg_file(str, "\t\t", msg_file, msg_file_count); - break; - } - case PB_Main_storage_rename_request_tag: { - string_cat_printf(str, "\trename_request {\r\n"); - string_cat_printf( - str, "\t\told_path: %s\r\n", message->content.storage_rename_request.old_path); - string_cat_printf( - str, "\t\tnew_path: %s\r\n", message->content.storage_rename_request.new_path); - break; - } - case PB_Main_gui_start_screen_stream_request_tag: - string_cat_printf(str, "\tstart_screen_stream {\r\n"); - break; - case PB_Main_gui_stop_screen_stream_request_tag: - string_cat_printf(str, "\tstop_screen_stream {\r\n"); - break; - case PB_Main_gui_screen_frame_tag: - string_cat_printf(str, "\tscreen_frame {\r\n"); - break; - case PB_Main_gui_send_input_event_request_tag: - string_cat_printf(str, "\tsend_input_event {\r\n"); - string_cat_printf( - str, "\t\tkey: %d\r\n", message->content.gui_send_input_event_request.key); - string_cat_printf( - str, "\t\type: %d\r\n", message->content.gui_send_input_event_request.type); - break; - case PB_Main_gui_start_virtual_display_request_tag: - string_cat_printf(str, "\tstart_virtual_display {\r\n"); - break; - case PB_Main_gui_stop_virtual_display_request_tag: - string_cat_printf(str, "\tstop_virtual_display {\r\n"); - break; - } - string_cat_printf(str, "\t}\r\n}\r\n"); - printf("%s", string_get_cstr(str)); - - string_clear(str); -} - void rpc_session_set_context(RpcSession* session, void* context) { furi_assert(session); @@ -409,6 +149,9 @@ void rpc_session_set_terminated_callback( size_t rpc_session_feed(RpcSession* session, uint8_t* encoded_bytes, size_t size, TickType_t timeout) { furi_assert(session); + furi_assert(encoded_bytes); + furi_assert(size > 0); + size_t bytes_sent = xStreamBufferSend(session->stream, encoded_bytes, size, timeout); furi_thread_flags_set(furi_thread_get_id(session->thread), RpcEvtNewData); @@ -422,6 +165,8 @@ size_t rpc_session_get_available_size(RpcSession* session) { } bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) { + furi_assert(istream); + furi_assert(buf); RpcSession* session = istream->state; furi_assert(session); furi_assert(istream->bytes_left); @@ -462,16 +207,17 @@ bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) { } #if SRV_RPC_DEBUG - rpc_print_data("INPUT", buf, bytes_received); + rpc_debug_print_data("INPUT", buf, bytes_received); #endif return (count == bytes_received); } -static bool content_callback(pb_istream_t* stream, const pb_field_t* field, void** arg) { +static bool rpc_pb_content_callback(pb_istream_t* stream, const pb_field_t* field, void** arg) { furi_assert(stream); RpcSession* session = stream->state; furi_assert(session); + furi_assert(field); RpcHandler* handler = RpcHandlerDict_get(session->handlers, field->tag); @@ -502,7 +248,7 @@ static int32_t rpc_session_worker(void* context) { if(pb_decode_ex(&istream, &PB_Main_msg, session->decoded_message, PB_DECODE_DELIMITED)) { #if SRV_RPC_DEBUG FURI_LOG_I(TAG, "INPUT:"); - rpc_print_message(session->decoded_message); + rpc_debug_print_message(session->decoded_message); #endif RpcHandler* handler = RpcHandlerDict_get(session->handlers, session->decoded_message->which_content); @@ -610,7 +356,7 @@ RpcSession* rpc_session_open(Rpc* rpc) { RpcHandlerDict_init(session->handlers); session->decoded_message = malloc(sizeof(PB_Main)); - session->decoded_message->cb_content.funcs.decode = content_callback; + session->decoded_message->cb_content.funcs.decode = rpc_pb_content_callback; session->decoded_message->cb_content.arg = session; session->system_contexts = malloc(COUNT_OF(rpc_systems) * sizeof(void*)); @@ -678,7 +424,7 @@ void rpc_send(RpcSession* session, PB_Main* message) { #if SRV_RPC_DEBUG FURI_LOG_I(TAG, "OUTPUT:"); - rpc_print_message(message); + rpc_debug_print_message(message); #endif bool result = pb_encode_ex(&ostream, &PB_Main_msg, message, PB_ENCODE_DELIMITED); @@ -690,7 +436,7 @@ void rpc_send(RpcSession* session, PB_Main* message) { pb_encode_ex(&ostream, &PB_Main_msg, message, PB_ENCODE_DELIMITED); #if SRV_RPC_DEBUG - rpc_print_data("OUTPUT", buffer, ostream.bytes_written); + rpc_debug_print_data("OUTPUT", buffer, ostream.bytes_written); #endif furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever); diff --git a/applications/rpc/rpc_app.c b/applications/rpc/rpc_app.c index 555cec8cf0..b8b34170e5 100644 --- a/applications/rpc/rpc_app.c +++ b/applications/rpc/rpc_app.c @@ -299,6 +299,7 @@ void* rpc_system_app_alloc(RpcSession* session) { void rpc_system_app_free(void* context) { RpcAppSystem* rpc_app = context; + furi_assert(rpc_app); RpcSession* session = rpc_app->session; furi_assert(session); diff --git a/applications/rpc/rpc_cli.c b/applications/rpc/rpc_cli.c index efc672193d..8cb0f76acd 100644 --- a/applications/rpc/rpc_cli.c +++ b/applications/rpc/rpc_cli.c @@ -14,23 +14,23 @@ typedef struct { #define CLI_READ_BUFFER_SIZE 64 -static void rpc_send_bytes_callback(void* context, uint8_t* bytes, size_t bytes_len) { +static void rpc_cli_send_bytes_callback(void* context, uint8_t* bytes, size_t bytes_len) { furi_assert(context); furi_assert(bytes); - furi_assert(bytes_len); + furi_assert(bytes_len > 0); CliRpc* cli_rpc = context; cli_write(cli_rpc->cli, bytes, bytes_len); } -static void rpc_session_close_callback(void* context) { +static void rpc_cli_session_close_callback(void* context) { furi_assert(context); CliRpc* cli_rpc = context; cli_rpc->session_close_request = true; } -static void rpc_session_terminated_callback(void* context) { +static void rpc_cli_session_terminated_callback(void* context) { furi_check(context); CliRpc* cli_rpc = context; @@ -39,6 +39,8 @@ static void rpc_session_terminated_callback(void* context) { void rpc_cli_command_start_session(Cli* cli, string_t args, void* context) { UNUSED(args); + furi_assert(cli); + furi_assert(context); Rpc* rpc = context; uint32_t mem_before = memmgr_get_free_heap(); @@ -55,9 +57,9 @@ void rpc_cli_command_start_session(Cli* cli, string_t args, void* context) { CliRpc cli_rpc = {.cli = cli, .session_close_request = false}; cli_rpc.terminate_semaphore = furi_semaphore_alloc(1, 0); rpc_session_set_context(rpc_session, &cli_rpc); - rpc_session_set_send_bytes_callback(rpc_session, rpc_send_bytes_callback); - rpc_session_set_close_callback(rpc_session, rpc_session_close_callback); - rpc_session_set_terminated_callback(rpc_session, rpc_session_terminated_callback); + rpc_session_set_send_bytes_callback(rpc_session, rpc_cli_send_bytes_callback); + rpc_session_set_close_callback(rpc_session, rpc_cli_session_close_callback); + rpc_session_set_terminated_callback(rpc_session, rpc_cli_session_terminated_callback); uint8_t* buffer = malloc(CLI_READ_BUFFER_SIZE); size_t size_received = 0; diff --git a/applications/rpc/rpc_debug.c b/applications/rpc/rpc_debug.c new file mode 100644 index 0000000000..9c04bd89a5 --- /dev/null +++ b/applications/rpc/rpc_debug.c @@ -0,0 +1,260 @@ +#include "rpc_i.h" +#include + +static size_t rpc_debug_print_file_msg( + string_t str, + const char* prefix, + const PB_Storage_File* msg_file, + size_t msg_files_size) { + size_t cnt = 0; + + for(size_t i = 0; i < msg_files_size; ++i, ++msg_file) { + string_cat_printf( + str, + "%s[%c] size: %5ld", + prefix, + msg_file->type == PB_Storage_File_FileType_DIR ? 'd' : 'f', + msg_file->size); + + if(msg_file->name) { + string_cat_printf(str, " \'%s\'", msg_file->name); + } + + if(msg_file->data && msg_file->data->size) { + string_cat_printf( + str, + " (%d):\'%.*s%s\'", + msg_file->data->size, + MIN(msg_file->data->size, 30), + msg_file->data->bytes, + msg_file->data->size > 30 ? "..." : ""); + } + + string_cat_printf(str, "\r\n"); + } + + return cnt; +} + +void rpc_debug_print_data(const char* prefix, uint8_t* buffer, size_t size) { + string_t str; + string_init(str); + string_reserve(str, 100 + size * 5); + + string_cat_printf(str, "\r\n%s DEC(%d): {", prefix, size); + for(size_t i = 0; i < size; ++i) { + string_cat_printf(str, "%d, ", buffer[i]); + } + string_cat_printf(str, "}\r\n"); + + printf("%s", string_get_cstr(str)); + string_reset(str); + string_reserve(str, 100 + size * 3); + + string_cat_printf(str, "%s HEX(%d): {", prefix, size); + for(size_t i = 0; i < size; ++i) { + string_cat_printf(str, "%02X", buffer[i]); + } + string_cat_printf(str, "}\r\n\r\n"); + + printf("%s", string_get_cstr(str)); + string_clear(str); +} + +void rpc_debug_print_message(const PB_Main* message) { + string_t str; + string_init(str); + + string_cat_printf( + str, + "PB_Main: {\r\n\tresult: %d cmd_id: %ld (%s)\r\n", + message->command_status, + message->command_id, + message->has_next ? "has_next" : "last"); + switch(message->which_content) { + default: + /* not implemented yet */ + string_cat_printf(str, "\tNOT_IMPLEMENTED (%d) {\r\n", message->which_content); + break; + case PB_Main_stop_session_tag: + string_cat_printf(str, "\tstop_session {\r\n"); + break; + case PB_Main_app_start_request_tag: { + string_cat_printf(str, "\tapp_start {\r\n"); + const char* name = message->content.app_start_request.name; + const char* args = message->content.app_start_request.args; + if(name) { + string_cat_printf(str, "\t\tname: %s\r\n", name); + } + if(args) { + string_cat_printf(str, "\t\targs: %s\r\n", args); + } + break; + } + case PB_Main_app_lock_status_request_tag: { + string_cat_printf(str, "\tapp_lock_status_request {\r\n"); + break; + } + case PB_Main_app_lock_status_response_tag: { + string_cat_printf(str, "\tapp_lock_status_response {\r\n"); + bool lock_status = message->content.app_lock_status_response.locked; + string_cat_printf(str, "\t\tlocked: %s\r\n", lock_status ? "true" : "false"); + break; + } + case PB_Main_storage_md5sum_request_tag: { + string_cat_printf(str, "\tmd5sum_request {\r\n"); + const char* path = message->content.storage_md5sum_request.path; + if(path) { + string_cat_printf(str, "\t\tpath: %s\r\n", path); + } + break; + } + case PB_Main_storage_md5sum_response_tag: { + string_cat_printf(str, "\tmd5sum_response {\r\n"); + const char* path = message->content.storage_md5sum_response.md5sum; + if(path) { + string_cat_printf(str, "\t\tmd5sum: %s\r\n", path); + } + break; + } + case PB_Main_system_ping_request_tag: + string_cat_printf(str, "\tping_request {\r\n"); + break; + case PB_Main_system_ping_response_tag: + string_cat_printf(str, "\tping_response {\r\n"); + break; + case PB_Main_system_device_info_request_tag: + string_cat_printf(str, "\tdevice_info_request {\r\n"); + break; + case PB_Main_system_device_info_response_tag: + string_cat_printf(str, "\tdevice_info_response {\r\n"); + string_cat_printf( + str, + "\t\t%s: %s\r\n", + message->content.system_device_info_response.key, + message->content.system_device_info_response.value); + break; + case PB_Main_storage_mkdir_request_tag: + string_cat_printf(str, "\tmkdir {\r\n"); + break; + case PB_Main_storage_delete_request_tag: { + string_cat_printf(str, "\tdelete {\r\n"); + const char* path = message->content.storage_delete_request.path; + if(path) { + string_cat_printf(str, "\t\tpath: %s\r\n", path); + } + break; + } + case PB_Main_empty_tag: + string_cat_printf(str, "\tempty {\r\n"); + break; + case PB_Main_storage_info_request_tag: { + string_cat_printf(str, "\tinfo_request {\r\n"); + const char* path = message->content.storage_info_request.path; + if(path) { + string_cat_printf(str, "\t\tpath: %s\r\n", path); + } + break; + } + case PB_Main_storage_info_response_tag: { + string_cat_printf(str, "\tinfo_response {\r\n"); + string_cat_printf( + str, "\t\ttotal_space: %lu\r\n", message->content.storage_info_response.total_space); + string_cat_printf( + str, "\t\tfree_space: %lu\r\n", message->content.storage_info_response.free_space); + break; + } + case PB_Main_storage_stat_request_tag: { + string_cat_printf(str, "\tstat_request {\r\n"); + const char* path = message->content.storage_stat_request.path; + if(path) { + string_cat_printf(str, "\t\tpath: %s\r\n", path); + } + break; + } + case PB_Main_storage_stat_response_tag: { + string_cat_printf(str, "\tstat_response {\r\n"); + if(message->content.storage_stat_response.has_file) { + const PB_Storage_File* msg_file = &message->content.storage_stat_response.file; + rpc_debug_print_file_msg(str, "\t\t\t", msg_file, 1); + } + break; + } + case PB_Main_storage_list_request_tag: { + string_cat_printf(str, "\tlist_request {\r\n"); + const char* path = message->content.storage_list_request.path; + if(path) { + string_cat_printf(str, "\t\tpath: %s\r\n", path); + } + break; + } + case PB_Main_storage_read_request_tag: { + string_cat_printf(str, "\tread_request {\r\n"); + const char* path = message->content.storage_read_request.path; + if(path) { + string_cat_printf(str, "\t\tpath: %s\r\n", path); + } + break; + } + case PB_Main_storage_write_request_tag: { + string_cat_printf(str, "\twrite_request {\r\n"); + const char* path = message->content.storage_write_request.path; + if(path) { + string_cat_printf(str, "\t\tpath: %s\r\n", path); + } + if(message->content.storage_write_request.has_file) { + const PB_Storage_File* msg_file = &message->content.storage_write_request.file; + rpc_debug_print_file_msg(str, "\t\t\t", msg_file, 1); + } + break; + } + case PB_Main_storage_read_response_tag: + string_cat_printf(str, "\tread_response {\r\n"); + if(message->content.storage_read_response.has_file) { + const PB_Storage_File* msg_file = &message->content.storage_read_response.file; + rpc_debug_print_file_msg(str, "\t\t\t", msg_file, 1); + } + break; + case PB_Main_storage_list_response_tag: { + const PB_Storage_File* msg_file = message->content.storage_list_response.file; + size_t msg_file_count = message->content.storage_list_response.file_count; + string_cat_printf(str, "\tlist_response {\r\n"); + rpc_debug_print_file_msg(str, "\t\t", msg_file, msg_file_count); + break; + } + case PB_Main_storage_rename_request_tag: { + string_cat_printf(str, "\trename_request {\r\n"); + string_cat_printf( + str, "\t\told_path: %s\r\n", message->content.storage_rename_request.old_path); + string_cat_printf( + str, "\t\tnew_path: %s\r\n", message->content.storage_rename_request.new_path); + break; + } + case PB_Main_gui_start_screen_stream_request_tag: + string_cat_printf(str, "\tstart_screen_stream {\r\n"); + break; + case PB_Main_gui_stop_screen_stream_request_tag: + string_cat_printf(str, "\tstop_screen_stream {\r\n"); + break; + case PB_Main_gui_screen_frame_tag: + string_cat_printf(str, "\tscreen_frame {\r\n"); + break; + case PB_Main_gui_send_input_event_request_tag: + string_cat_printf(str, "\tsend_input_event {\r\n"); + string_cat_printf( + str, "\t\tkey: %d\r\n", message->content.gui_send_input_event_request.key); + string_cat_printf( + str, "\t\type: %d\r\n", message->content.gui_send_input_event_request.type); + break; + case PB_Main_gui_start_virtual_display_request_tag: + string_cat_printf(str, "\tstart_virtual_display {\r\n"); + break; + case PB_Main_gui_stop_virtual_display_request_tag: + string_cat_printf(str, "\tstop_virtual_display {\r\n"); + break; + } + string_cat_printf(str, "\t}\r\n}\r\n"); + printf("%s", string_get_cstr(str)); + + string_clear(str); +} diff --git a/applications/rpc/rpc_gpio.c b/applications/rpc/rpc_gpio.c index 614e775a1c..09e7385052 100644 --- a/applications/rpc/rpc_gpio.c +++ b/applications/rpc/rpc_gpio.c @@ -57,7 +57,6 @@ static void rpc_system_gpio_set_pin_mode(const PB_Main* request, void* context) furi_assert(request->which_content == PB_Main_gpio_set_pin_mode_tag); RpcSession* session = context; - furi_assert(session); PB_Gpio_SetPinMode cmd = request->content.gpio_set_pin_mode; const GpioPin* pin = rpc_pin_to_hal_pin(cmd.pin); @@ -77,7 +76,6 @@ static void rpc_system_gpio_write_pin(const PB_Main* request, void* context) { furi_assert(request->which_content == PB_Main_gpio_write_pin_tag); RpcSession* session = context; - furi_assert(session); PB_Gpio_WritePin cmd = request->content.gpio_write_pin; const GpioPin* pin = rpc_pin_to_hal_pin(cmd.pin); @@ -105,7 +103,6 @@ static void rpc_system_gpio_read_pin(const PB_Main* request, void* context) { furi_assert(request->which_content == PB_Main_gpio_read_pin_tag); RpcSession* session = context; - furi_assert(session); PB_Gpio_ReadPin cmd = request->content.gpio_read_pin; const GpioPin* pin = rpc_pin_to_hal_pin(cmd.pin); @@ -133,7 +130,6 @@ void rpc_system_gpio_get_pin_mode(const PB_Main* request, void* context) { furi_assert(request->which_content == PB_Main_gpio_get_pin_mode_tag); RpcSession* session = context; - furi_assert(session); PB_Gpio_GetPinMode cmd = request->content.gpio_get_pin_mode; const GpioPin* pin = rpc_pin_to_hal_pin(cmd.pin); @@ -170,7 +166,6 @@ void rpc_system_gpio_set_input_pull(const PB_Main* request, void* context) { furi_assert(request->which_content == PB_Main_gpio_set_input_pull_tag); RpcSession* session = context; - furi_assert(session); PB_Gpio_SetInputPull cmd = request->content.gpio_set_input_pull; const GpioPin* pin = rpc_pin_to_hal_pin(cmd.pin); diff --git a/applications/rpc/rpc_i.h b/applications/rpc/rpc_i.h index e512ad3976..9ffd054a0c 100644 --- a/applications/rpc/rpc_i.h +++ b/applications/rpc/rpc_i.h @@ -35,7 +35,9 @@ void rpc_system_gui_free(void* ctx); void* rpc_system_gpio_alloc(RpcSession* session); void rpc_system_gpio_free(void* ctx); -void rpc_print_message(const PB_Main* message); +void rpc_debug_print_message(const PB_Main* message); +void rpc_debug_print_data(const char* prefix, uint8_t* buffer, size_t size); + void rpc_cli_command_start_session(Cli* cli, string_t args, void* context); PB_CommandStatus rpc_system_storage_get_error(FS_Error fs_error); diff --git a/applications/rpc/rpc_storage.c b/applications/rpc/rpc_storage.c index ad6191b2fd..1b545b4141 100644 --- a/applications/rpc/rpc_storage.c +++ b/applications/rpc/rpc_storage.c @@ -37,6 +37,7 @@ static void rpc_system_storage_reset_state( RpcSession* session, bool send_error) { furi_assert(rpc_storage); + furi_assert(session); if(rpc_storage->state != RpcStorageStateIdle) { if(send_error) { @@ -177,6 +178,8 @@ static void rpc_system_storage_stat_process(const PB_Main* request, void* contex } static void rpc_system_storage_list_root(const PB_Main* request, void* context) { + furi_assert(request); + furi_assert(context); RpcStorageSystem* rpc_storage = context; RpcSession* session = rpc_storage->session; furi_assert(session); @@ -411,6 +414,8 @@ static void rpc_system_storage_write_process(const PB_Main* request, void* conte } static bool rpc_system_storage_is_dir_is_empty(Storage* fs_api, const char* path) { + furi_assert(fs_api); + furi_assert(path); FileInfo fileinfo; bool is_dir_is_empty = true; FS_Error error = storage_common_stat(fs_api, path, &fileinfo); @@ -605,6 +610,7 @@ static void rpc_system_storage_rename_process(const PB_Main* request, void* cont static void rpc_system_storage_backup_create_process(const PB_Main* request, void* context) { furi_assert(request); furi_assert(request->which_content == PB_Main_storage_backup_create_request_tag); + furi_assert(context); FURI_LOG_D(TAG, "BackupCreate"); @@ -626,6 +632,7 @@ static void rpc_system_storage_backup_create_process(const PB_Main* request, voi static void rpc_system_storage_backup_restore_process(const PB_Main* request, void* context) { furi_assert(request); furi_assert(request->which_content == PB_Main_storage_backup_restore_request_tag); + furi_assert(context); FURI_LOG_D(TAG, "BackupRestore"); @@ -695,6 +702,7 @@ void* rpc_system_storage_alloc(RpcSession* session) { } void rpc_system_storage_free(void* context) { + furi_assert(context); RpcStorageSystem* rpc_storage = context; RpcSession* session = rpc_storage->session; furi_assert(session); diff --git a/applications/rpc/rpc_system.c b/applications/rpc/rpc_system.c index 0538aa64dc..1681bb17e8 100644 --- a/applications/rpc/rpc_system.c +++ b/applications/rpc/rpc_system.c @@ -77,6 +77,7 @@ static void rpc_system_system_device_info_callback( furi_assert(key); furi_assert(value); RpcSystemContext* ctx = context; + furi_assert(ctx); furi_assert(key); furi_assert(value); @@ -233,6 +234,7 @@ static void rpc_system_system_power_info_callback( furi_assert(key); furi_assert(value); RpcSystemContext* ctx = context; + furi_assert(ctx); furi_assert(key); furi_assert(value); @@ -297,6 +299,8 @@ static void rpc_system_system_update_request_process(const PB_Main* request, voi #endif void* rpc_system_system_alloc(RpcSession* session) { + furi_assert(session); + RpcHandler rpc_handler = { .message_handler = NULL, .decode_submessage = NULL, diff --git a/applications/unit_tests/rpc/rpc_test.c b/applications/unit_tests/rpc/rpc_test.c index d31311af6c..6ee2aed652 100644 --- a/applications/unit_tests/rpc/rpc_test.c +++ b/applications/unit_tests/rpc/rpc_test.c @@ -215,7 +215,7 @@ static void test_rpc_print_message_list(MsgList_t msg_list) { MsgList_reverse(msg_list); for M_EACH(msg, msg_list, MsgList_t) { - rpc_print_message(msg); + rpc_debug_print_message(msg); } MsgList_reverse(msg_list); #else From df4755bc065bc7e4a313d5273b39106081c08fe7 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Mon, 22 Aug 2022 19:41:41 +0300 Subject: [PATCH 11/78] [FL-2727] BLE Remote UI fixes #1609 Co-authored-by: Aleksandr Kutuzov --- applications/bt/bt_hid_app/bt_hid.c | 5 ++-- .../bt/bt_hid_app/views/bt_hid_keynote.c | 7 +++-- .../bt/bt_hid_app/views/bt_hid_media.c | 14 +++++++++ .../bt/bt_hid_app/views/bt_hid_mouse.c | 27 ++++++++++++------ .../icons/BLE/BLE_HID/Left_mouse_icon_9x9.png | Bin 0 -> 3622 bytes .../BLE/BLE_HID/Ok_btn_pressed_13x13.png | Bin 0 -> 3625 bytes .../BLE/BLE_HID/Right_mouse_icon_9x9.png | Bin 0 -> 3622 bytes 7 files changed, 40 insertions(+), 13 deletions(-) mode change 100755 => 100644 applications/bt/bt_hid_app/bt_hid.c create mode 100644 assets/icons/BLE/BLE_HID/Left_mouse_icon_9x9.png create mode 100644 assets/icons/BLE/BLE_HID/Ok_btn_pressed_13x13.png create mode 100644 assets/icons/BLE/BLE_HID/Right_mouse_icon_9x9.png diff --git a/applications/bt/bt_hid_app/bt_hid.c b/applications/bt/bt_hid_app/bt_hid.c old mode 100755 new mode 100644 index 3189042c0e..0827bd0ad0 --- a/applications/bt/bt_hid_app/bt_hid.c +++ b/applications/bt/bt_hid_app/bt_hid.c @@ -89,8 +89,7 @@ BtHid* bt_hid_app_alloc() { app->submenu, "Keynote", BtHidSubmenuIndexKeynote, bt_hid_submenu_callback, app); submenu_add_item( app->submenu, "Keyboard", BtHidSubmenuIndexKeyboard, bt_hid_submenu_callback, app); - submenu_add_item( - app->submenu, "Media Player", BtHidSubmenuIndexMedia, bt_hid_submenu_callback, app); + submenu_add_item(app->submenu, "Media", BtHidSubmenuIndexMedia, bt_hid_submenu_callback, app); submenu_add_item(app->submenu, "Mouse", BtHidSubmenuIndexMouse, bt_hid_submenu_callback, app); view_set_previous_callback(submenu_get_view(app->submenu), bt_hid_exit); view_dispatcher_add_view( @@ -134,7 +133,7 @@ BtHid* bt_hid_app_alloc() { app->view_dispatcher, BtHidViewMouse, bt_hid_mouse_get_view(app->bt_hid_mouse)); // TODO switch to menu after Media is done - app->view_id = BtHidViewKeynote; + app->view_id = BtHidViewSubmenu; view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); return app; diff --git a/applications/bt/bt_hid_app/views/bt_hid_keynote.c b/applications/bt/bt_hid_app/views/bt_hid_keynote.c index 60a1ebc087..ea4ee16fa4 100755 --- a/applications/bt/bt_hid_app/views/bt_hid_keynote.c +++ b/applications/bt/bt_hid_app/views/bt_hid_keynote.c @@ -43,7 +43,10 @@ static void bt_hid_keynote_draw_callback(Canvas* canvas, void* context) { } canvas_set_font(canvas, FontPrimary); elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Keynote"); + + canvas_draw_icon(canvas, 68, 2, &I_Pin_back_arrow_10x8); canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned(canvas, 127, 3, AlignRight, AlignTop, "Hold to exit"); // Up canvas_draw_icon(canvas, 21, 24, &I_Button_18x18); @@ -97,8 +100,8 @@ static void bt_hid_keynote_draw_callback(Canvas* canvas, void* context) { elements_slightly_rounded_box(canvas, 66, 47, 60, 13); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 110, 49, &I_Ok_btn_9x9); - elements_multiline_text_aligned(canvas, 76, 56, AlignLeft, AlignBottom, "Back"); + canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8); + elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Back"); } static void bt_hid_keynote_process(BtHidKeynote* bt_hid_keynote, InputEvent* event) { diff --git a/applications/bt/bt_hid_app/views/bt_hid_media.c b/applications/bt/bt_hid_app/views/bt_hid_media.c index b384f47cf1..258ea0a404 100755 --- a/applications/bt/bt_hid_app/views/bt_hid_media.c +++ b/applications/bt/bt_hid_app/views/bt_hid_media.c @@ -49,7 +49,9 @@ static void bt_hid_media_draw_callback(Canvas* canvas, void* context) { // Up if(model->up_pressed) { + canvas_set_bitmap_mode(canvas, 1); canvas_draw_icon(canvas, 93, 9, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } canvas_draw_icon(canvas, 96, 12, &I_Volup_8x6); @@ -57,7 +59,9 @@ static void bt_hid_media_draw_callback(Canvas* canvas, void* context) { // Down if(model->down_pressed) { + canvas_set_bitmap_mode(canvas, 1); canvas_draw_icon(canvas, 93, 41, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } canvas_draw_icon(canvas, 96, 45, &I_Voldwn_6x6); @@ -65,7 +69,9 @@ static void bt_hid_media_draw_callback(Canvas* canvas, void* context) { // Left if(model->left_pressed) { + canvas_set_bitmap_mode(canvas, 1); canvas_draw_icon(canvas, 77, 25, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } bt_hid_media_draw_arrow(canvas, 82, 31, CanvasDirectionRightToLeft); @@ -74,7 +80,9 @@ static void bt_hid_media_draw_callback(Canvas* canvas, void* context) { // Right if(model->right_pressed) { + canvas_set_bitmap_mode(canvas, 1); canvas_draw_icon(canvas, 109, 25, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } bt_hid_media_draw_arrow(canvas, 112, 31, CanvasDirectionLeftToRight); @@ -89,6 +97,12 @@ static void bt_hid_media_draw_callback(Canvas* canvas, void* context) { bt_hid_media_draw_arrow(canvas, 96, 31, CanvasDirectionLeftToRight); canvas_draw_line(canvas, 100, 29, 100, 33); canvas_draw_line(canvas, 102, 29, 102, 33); + canvas_set_color(canvas, ColorBlack); + + // Exit + canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); } static void bt_hid_media_process_press(BtHidMedia* bt_hid_media, InputEvent* event) { diff --git a/applications/bt/bt_hid_app/views/bt_hid_mouse.c b/applications/bt/bt_hid_app/views/bt_hid_mouse.c index fb1537a2c9..f9d84f9fbd 100644 --- a/applications/bt/bt_hid_app/views/bt_hid_mouse.c +++ b/applications/bt/bt_hid_app/views/bt_hid_mouse.c @@ -36,7 +36,11 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) { canvas_set_font(canvas, FontSecondary); if(model->left_mouse_held == true) { - elements_multiline_text_aligned(canvas, 0, 60, AlignLeft, AlignBottom, "Selecting..."); + elements_multiline_text_aligned(canvas, 0, 62, AlignLeft, AlignBottom, "Selecting..."); + } else { + canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); } // Keypad circles @@ -44,7 +48,9 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) { // Up if(model->up_pressed) { + canvas_set_bitmap_mode(canvas, 1); canvas_draw_icon(canvas, 81, 9, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } canvas_draw_icon(canvas, 84, 10, &I_Pin_arrow_up7x9); @@ -52,7 +58,9 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) { // Down if(model->down_pressed) { + canvas_set_bitmap_mode(canvas, 1); canvas_draw_icon(canvas, 81, 41, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } canvas_draw_icon(canvas, 84, 43, &I_Pin_arrow_down_7x9); @@ -60,7 +68,9 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) { // Left if(model->left_pressed) { + canvas_set_bitmap_mode(canvas, 1); canvas_draw_icon(canvas, 65, 25, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } canvas_draw_icon(canvas, 67, 28, &I_Pin_arrow_left_9x7); @@ -68,7 +78,9 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) { // Right if(model->right_pressed) { + canvas_set_bitmap_mode(canvas, 1); canvas_draw_icon(canvas, 97, 25, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } canvas_draw_icon(canvas, 99, 28, &I_Pin_arrow_right_9x7); @@ -76,18 +88,17 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) { // Ok if(model->left_mouse_pressed) { - canvas_draw_icon(canvas, 81, 25, &I_Pressed_Button_13x13); - canvas_set_color(canvas, ColorWhite); + canvas_draw_icon(canvas, 81, 25, &I_Ok_btn_pressed_13x13); + } else { + canvas_draw_icon(canvas, 83, 27, &I_Left_mouse_icon_9x9); } - canvas_draw_icon(canvas, 83, 27, &I_Ok_btn_9x9); - canvas_set_color(canvas, ColorBlack); // Back if(model->right_mouse_pressed) { - canvas_draw_icon(canvas, 108, 48, &I_Pressed_Button_13x13); - canvas_set_color(canvas, ColorWhite); + canvas_draw_icon(canvas, 108, 48, &I_Ok_btn_pressed_13x13); + } else { + canvas_draw_icon(canvas, 110, 50, &I_Right_mouse_icon_9x9); } - canvas_draw_icon(canvas, 110, 50, &I_Ok_btn_9x9); } static void bt_hid_mouse_process(BtHidMouse* bt_hid_mouse, InputEvent* event) { diff --git a/assets/icons/BLE/BLE_HID/Left_mouse_icon_9x9.png b/assets/icons/BLE/BLE_HID/Left_mouse_icon_9x9.png new file mode 100644 index 0000000000000000000000000000000000000000..c533d85729f9b778cba33227141c90dea298f5e3 GIT binary patch literal 3622 zcmaJ@c{r4N`+r3CEm@Lu#*i&$%-EXASZ2m<2%{NkG0Yf~#*8sFmJ*e%IwWO{sO(Ec zjfApgNr;l2Y)KB@EO8Rvao*E;e}DXXpX+&^@ArFO_vdqe?&Z0zC-#V=wS?$iQ2+oW zY;CYEyj5iT5$5N;d!4?40YKD}hQS=M#b7{87Q=^jh5`UV0~xMVyz7iSYIS58Z66bU z%bwvPCk%2yUkjH_P}f!wk+zFb$?lhPuG?j4DWKGn6~iAF7k*vNSx5Y;XrIue%DuSD z_hYWUULOm+@Asj4^;7%i(_Yi*;-!r8PN7<1@gy64XTxyu0`&e}A1^mIHjPa}%p*kA zn1Hl!IawueLzNF$3o|h}2(A@+0q_OA6B7n%ap|>s`=Ym`zMxZ&^MzmGt7Rt~vKJ1Q z1Hpin=S1B>;G~d3#L&M|1&Cjf;M%pvu`sfzFj z1F4ToZvY@GL5`R0(ne5+WNAl-Q5;wDlq z3x?A-?;V&I@I5J(b$0cdPnneYQy^<*fUv~eu8n2(jmrN1smaMcyGFDJ={4cPCbj-l zEn(x#pJ66HR#!g07*~scpNOy)So>K2X4xTUU*}DcD_%pN;;nyFh;98)eg|%}^{OOl z%T74U1jJ#}t}nrJz_I9?TCWatZ;{7Gb=LV!M-72Tr%m}n6Lj-Wc=La=*N`T%YsXgs zV6lo(_g+(&Kiv27SSM#|!ED1i>i`h$V|z0I08V1nAo$niX3fF?fX#}~eq^DvT(?K3 zR&Zb4&Y?Q7AD%{6&}xnKXlb-4IeZ_>Q>*wAS~IHsk+QZY^u4*VL9MfIR3cLnQt$Rm z62+AIP7=&h~e|PN>q&#R!EIpQ>n8Nkh!J?YK@U~2HPhX+Q3|{ z;z4dU%8Mx04n*{EtLF)aTLAc_A5qoTuv-yj&Zzg|PcfDG#(S?=-4lCDX2a6r<+IY? zvYzZkT{p^}ep}=#H4tx#Y1XU#yhljC@r)j%sR8}?kd8>AciUrdv3OC_-bY7^`Kw}A zygMIr1Y{yCYekF%IA{=Qzl9Caf#}$0lMmXbX0U5O#8`y?igUdNI5FS;iTd+he>U#% zg2SSTHae;wWa4*2r9)#djmBy+u^6~U<&7P-k00Q>WxB1p{asXNbPCc9Z1$=qwhoZ} z%7hTNbU+7NA}2E@8z%K9l_pgdJw!9S%mW^*xsGePygqHGI3+!0FeOMyfm^uUPjea0 z&&KaEj6a4h$>zE|bdJv7ZE!XX(SBLp);_1?-tBjLeHDCHX%9cMpYIyJz27nUEup(@ z#`<&eXZ~f5xI~oP<>nZwregXYp*>VZ&Yp)U4!Mf&t|>O-^^9S&DbuM^sSG!wHdp(+ zT*7P7+jh6rZ!2j-@dbssg(HPxZcA=$`1pd8t`|zJ-1J>13Pj!~6}c5=9GP`ha-|j= z&W|pn<}>hS55n9xVg=nB92%T351g|epPHy{0*QGmmIvvm_(>E+osBSTRDaywfBu|y zRmz5P)iqRMK{f)TZ>LWvcUijSVnU}m2c6CH{L2Fz~Dc8WE5=J@h zSD2KXL@cr?axSu-tuZQ{%ge~Ev8-}mkC3!zw$nJSVNH$i*qJfy+V47?Cz>aZLm^j6 zA%%W9O4(Id&P)Hi`IO8TC&M!x7M|3%dt1+Mv^dNO;}k)CI;{%zh9(e7 zdLLEfa0*vR3ks&+Oj&m)Oeai?N8lswr`{OXR-YeYsz5~9rFm@&k?U9e#1O9mr++tALh9Be#b={ zZCuFBKN6}9gVkQ?=jcpTUePGHQSBh%Fr1FelutVcqQgRzYnoX&5F5+PDNgr9qOGs;Y5VGk3J=RkIGOom5aSvDm$o< zEO)U_b0}y^DVp*6W$MtaCj~`~mE=yJZl9S?Bf6O$l1YWhpOPj0CHe=RNQ@qRGPm;0 zauAx_t~pqBnTx5s|I*}HH6^dLqy4ZM{sDd&{~d2M-#z@4)Vt>2HLny}{mtNyo8%lTGBfGM2RCkV6K_Jn}0({Rg&9V`MyWF8-;g? z|8Q{DTC(}K7n>Oi99;<`3Af+xG>xk=vB8rwt0JST`z4SA=dOnqj|si|?VK`I8G0I> zwwPv>?wYpl;pOq%>5XaEhc6=`Kdc9Tle%MI;vQ_bgm0w{%v^exNL}o_o^dkea8VKC3fInZ_N%%QeAY<+nccWFk<*HA^9k)mN)4qw>RHERBth zwyJ)P#(YV&Q}wB3^Er!t%y4v%naAc(-@?$v)3uzerLH0CRl&&1otp_O@lu$b@u~4` zQ4&$JnTJdfh;cL4#>|gAOeeWhJyT)x-ey~=f;=>At!K8kqbsE=J9#lV@g@Cy&c>J8 zS;dEgP4!LtU$h44!%i+AU7xGt3~`hf?vF}2O`Zo`)ZFs@^YM!7+r0He#l*xd0sfSw z9}9-JF7f^=71@?VwkyMj%^|TUfCZW1MFH8;NmPmpg+vYxXr-6{0KX;;Ph=Bu4oGhX z9YWgnfdtW+JTw59m<2IO-hLD|$csXy`J=!KRWHFH8W{y97~=GBObo@BW)s4qxQ005 zy+i!G5oEBLDaa%U$s?ds*d$O8{fvJgG6)6!ixsqKLR7APj>= z0U1MJy54$vdLUy2ghD34z4U!Z-Z~(-9vlXR@or;Xm@yKrkAxvWe_vo;Ko;2t>4LTT zI~?zX0{gPrOe7S_;cy@veF%d^g~AXB1XK?Wg~N4u9=d_S{%lf^u79BFPX;U{(3?eL zvS|!|&^9BC+f`KWG(Vj?jt3W?2N;TeoGKMQ%pm%(NP`ZAaxxIP31 z(!`OxY5v<5t-l~R9MaZ5kWKRUrr2UpU>*sCMk6CJ2$%uJ=#V~4&&mJ>v&33pF^AAt zI2vON*M}kC#y_!GhWA-I#h?8XOa3p`;Fs9#fuJ*ak+BpO?Hq+{#bVGwe`SrN{aOp` zmwbO?$-mYD|0Nd669e7u?f>cZPZMu|wzvNbFYoZr_*49OGtc4;_gwK*74O3kIpTn~ zjj{=6BfNKE{3D{aXVoTAUm;Mb1;5j7# literal 0 HcmV?d00001 diff --git a/assets/icons/BLE/BLE_HID/Ok_btn_pressed_13x13.png b/assets/icons/BLE/BLE_HID/Ok_btn_pressed_13x13.png new file mode 100644 index 0000000000000000000000000000000000000000..6b46ba3a8243811986234686c4289f23d5de535c GIT binary patch literal 3625 zcmaJ@XH-+!7QPHfZz4rNoDdKYAt9lekWiA)n?R5t77_>{Vn_(lP!vI=DFY(X1wo}3 z6%<84X#!FOq&E=|(E;92gpu~b%sB7;nD_3w_nve1+TXXoz0W>totP7L<|2Y}f&c)B zSX$s5_r|@CpPTbH)s?gZ06|kK7JI@Hiv=;5bT8@!G5`dOWI9psPV>^}^@&xCb#&+* zYr3NpKgbbtGgLA`MO{%q+$vfzXIRRie!rk8K_zR)VcF)&~UC~C9|TNuZ~|h*+SbvH&nO~b9n!U@Rp|LsTqiIn4mHP z5a+M(RP^6g;sQ28P^e?zI=)u`S3sW-KTv0zQKxk%YFF$FChas==yk3-R>E;>{!mH4 zI4BO22N;`ig=VIzI04x_fP1?KX&N}83An3X{nQ79W^SYfa{+F56s5Sb69CWwax@O` zHULVxPu?&E2wH%omvs{Y7}5l^EM2@TfXB~)x-M~{a)4hL&~k{5I12Ct1MaO#N&&$2 zG(gg9*#-66u`=;Fbxx(y%28Fy2-7e(eoa3<7Z=E3wJuAUW0HErpNQ$kkcPlCS$LR^ z*oT!40LV^|;$*wB9nd9O*43pKS1Ec<^UG`AT`-9>y))Zg%rFLkDOO0&js~o>j1#f+Z;+4CbVD~!F`nC9H78XlgVnHjQb!nhIJT(0a;8qU?Z zY+v|21huuk_Tkk>`~ZN<4pV<@BEMRHP@|6b zQ2oBKdZ8_Mz3Uj|rUr~SM$j|#5Yzo=$u*2xWancAb$94{V+EZ$2k*#4hA5=L`GqK& zA@-ffpH;6`6DGi8(#n5;s5lbMMY=&yisP3_i`Y=Cx8RYusSJ7>E$INZPSCZ0Io`m7 zoGlcV(afI^QK!vbCK$8=@M~LOLRj({8$;1!-=?JUOl*km%9=1Y9Cq+${I_WC?e5%$i5{ z6E=@Tm}#AW9uFG>A|5ueAlMM>hAav|hm>{pj|k`sa9?+5Pz5IzSU**Hx&Qa3gCsaC zieRCkG$0Xw04g3Fjcw9bmWaW^RjY3OWclPFzE`5xtk>63X)yr%yQ_ z;*JLBSZl;g=1k*^_Kf_D;osVrg_|f_kO;WvPTV z!6d6Bl_Ys}D88^LuV|u3$a%%N9UotK*6B)_nX|UjbfLie5|fB2Q`Zx!dQcDg&3-Wxi={T7o>rcwHPf0OsPL*Ns#x28v0Y4e zw5`fJnrC2RVAIms(RsgfAWb&|4I6~dWz1y^W=uYJKNWCFqq3m#1=+HE=2V{RVr7kQ z#3_VpF2VWKnF_Pg%+ezR)uq+>`}3>p677n!1}Ke>f2(|3S@>M`@$3-qXjvt#@(Phc zlA%0*Q`WecSetm|<&|Hy(R?CN!=l9srxZf`pE4zpCy^8BU3V9auDn@Io`+Hh-QwLt z+S8Q>+K)C-Go3Q}%qcRID*y16=$kRt*V-W|hL8;T=JD3r87tPB-sIhw;I`@udxoZ2rYiz}SaG32e61tb96Rzhv^y{9tK5w^gq-ULrn8aRH+V$KG+U)`ILyvG# zxMRXh!rXq^+z7g?_&UxAIZFOkKD=NOn_XohWfFg_^xABFsiJr5ueVAS*XL5Z61u3O z5hp@E54__eej?s%3=vk1h>CEDG>T(H6XbeeDZ1>QF|7Y2?mI3SH<3Ys*&`llTIs4A z7D3LVM)Y6myfkWtc)51;6EX>w7pxBvyIBXNR(4GIkuFtkUnCwd5bTK%xyvW2>B z(CuFnYIFmY-)QG*%vN1jExc7@BVse2fy|OlzXYPe(a2g@`0a#SewZRf+r&!B7s@BE zOYJ4(i1M8`zBivk4=3@x^{Kd3vd>jhuo9E^8GlM`P@S)wLU!?b-5Jw{NG{Gg*16D8 z(KdQZ|L)Sg-35sTiK*L_xslc`nhJzZwI$~f1XyNYV-sV#htsJa+->=Y%#yiFj z9Q$f6+VbllzAlt^81+k z=>5vzIghT%^J4U+m*T9cUen#1a|SgAU8k2{u$Ie5XAii%a7llJJV*P&`hwa??6YsF zzFVDMR(0B^YB8wxS+LjoynL2^*Z68};BV5q1N~VD^my$`5Pkj4`r4%QcnDKZZ5p#QfD<9kK*{zZ#vvYr^y-Y?L8nV&J?JzD zanA=5Kx1&w0Dv+IU=Tfg$Se?vOriRs!AsSz!62$98tkHLt7Xf;lD(-GK}@n!kR9G5 z$j1ZW2{tkWp#qQ`0vee`1O?D8`1&IQ(BMCKk(~LS843pd;llDkgZ~souss37(wStC zJ_M%ep{1n-(nmnZoDNfCx0YnBA2GQEf>W8DP?f-YB(f;=KXE~Dp zqxT<){qcbeGSrdmPru0Y;Ow23(q1SA63ZkLS#&0zPQUP@kSDz9EV{opodJStLtr2^ zTcQWmch7S44~VTT($d$TMfCL`TjJ1Q4he)x^+f98FuE`;eI1yVnJx@wiZj7sk7ICf z3|1em4MV{7e_(NRkBc<2FY5=^^FLS){(oTi8iK~)M8=Vs)JtSfGbWt|`Xg&3^&hlg z5ilLB-f;wnPv@Vt{E7Aa2Q7bLP5vhq$`J$I+uQ%z>mMdg1MN-!ZeGsf@AfDAa(bT0 zY3`!iXF2z3K;VQ8-jp-$h5$Pu0Q7Lr69@cE tNU_5F5@tDqw>z-XxMyOWnyrgG{91sV9boy3dsxXH+S1exSB7!F_HPPcG0^}3 literal 0 HcmV?d00001 diff --git a/assets/icons/BLE/BLE_HID/Right_mouse_icon_9x9.png b/assets/icons/BLE/BLE_HID/Right_mouse_icon_9x9.png new file mode 100644 index 0000000000000000000000000000000000000000..446d7176c8dc3ce478572f4a044a7e32b326bc72 GIT binary patch literal 3622 zcmaJ@XH-+!7QP75n@AB6Cj_Jk2?@=_gp!2b1cC&y5FmtzAt6LVQKU!{2Sk)A2r9j( zpdbQDlPVw}y-5?%0p3uAk@mvOIPd*}R+k1F9+3x|HZ(so6H=Bupj;vWfZuSsJsEF5FNt0sU&UBN1>d!x z*-7w%>@YFG;_-^Aa(trZQF2*B61H^*jEuNsS~8h(_@J1++G=89I*%er`Kc?A@fiXvLda|NDkjVwOw7a=Z1E?2)w_-?q4eu^{Msu0-SlI;aInz>dIRK=%l z#e8CMskc_(+2Cl*9hJAodUoBXCe$`L^(M4|rx*1&0^`;5&be`ZvrrNxFl(pQ0bsd` zR`)@fmowNiY_f~ByQIHul6edW_AtBS0|4i73J`o-nSL`b0N^r1RG%8ktkxY;tK~jY zw|}%wV9Q1421cQ=9wUn3cMm?oa8W4=#VAK~Je5^-fqpQM)vC4ij7XphL+Tw~3Zv;F z--)~#b;{Ktd|ZYtya$PL!%-ZrHwp5wyizIQ8*+7~Tw*Z_pw=jHTd+mEwkgc+CLZKq zD!Ytk>_bGJHGUO;vIT&LZbej^!0v{W+M+)QzQ9)I=^nme{7~S%I}?@~Cz+Y{p7H!J z`j$@C-1|aLk>NN!Y_mq~=R-W2jh8eaO%0f5C)D^7+}fXkiv$as4nI9z#90-+=GOI$ z#U&PERLiHs#lnDyM-5F0mIUiT(>%}-1+4?ae7by`H*D*bzzKO4&lO)C_@nWVD;yR{ zFjbT97mGUx6%CBSHtH&fMPuPgmAChqJ$sDr5$iGT@wStnSIbY+GCeGx&^qkyRmy|7 zs|GsW5kExGmGrvhxd99drEn(Q=WWgzB({=@2GXsd&i#kd6Umc zpE*}qf*$*4l54r__+M@_SZ^`9W?Ey^Z7m`7CIE9pZaPqV^7XMnHO0= z&ZFV=9|t*YM{_$hST@*TAKPX=yD(kd1QKwQF7s29^AakIxE!M0sQ9d7=;{^Ks^o3i zsu*-Zeij0&X|Cy5X18+JL!W0l*=OTE)0%HiIX7t~=;pZilFF2dOpcaiC5&{|s~|Bc zkx*z_Xj^FVwMM68AvZmz#;D3^Gep?1*<9(Yk_kDkbAS4r{gC}wE`P416&kr#0x9sy zmdUEZvEF#+E+%KZJ|CQ6Ny{DgubKOPnL~VMc$gL=+XkqomYBAN$ zsxn6<=cMIH%jS-E9S=MDQ?%32umSj7+FaT|+C+uR8NV}X<$2{VNoJ)pXL6ht%d5S^ z&mf$#2@Yq@l^GYO7a!}dDz3^skXvb;U|pEePi}bndwFYleuebY*+K4+l5%SKH6qzn zid^xwq+v0kCgIwvYrk%zd4wW|gbQWQ$Oid7XNV(DBga!a?=R|Kd%K!A4{Xam}ra8c1V&QBu%DitfgkgoVn(6ZZe=}Ej_I)t$rbI zeF%B|k zbckVy^S;fEfU9zEV)cBcD-9(K<3fu=XX}dPJX?OdT`adgm)sfONf8b| z74*6PJrD5{F{U9%P$@hz+%ZBwmL5eo+zm_8W_6EZeJ60=af!I`G&0Nv@kHHRTUD0KWoonUs!;s^qwTB759>Gj0c!b;>+`jo(Qpj0xn#=Ry;wpD(O^Ga7*= zbtsQig_UC~AH6}ntS05Qc6OZ9$3Moe;=ki{7JJ5C5C=BAyBB2wtG{Xe);Ho@y}qs2 z`g+8H!@;W0qmQ&{wpq5WUlLs~zmd2}Jy&c^^;u}sQl0;+k?j2#q}Tm zY9ieH%j=!=C6>C7j*!Ez_nW5V={WzH`E|aD^`k<_;VZWSizaz`f4L${mW5u#q%Nl# zr`e}&I=ec*vU#W1-T!4gV9R9W7m@o~C?|jO6?`jYcs{f@fxO&xEB#*jwIIkJqb?&4 z%LC`!IwvlQ(3W0_GADbCc4OvFR-f!VyZn;5Tsks)(D9{X>J#Jz>KEo0)J{ULO>@=# zs??IovtE^p0W~iIJ=W)CGITq~R%`r!m)z~|%Rr#VYE}Yh>u=ZBCM3s#7)sln?Nvi8 zrN!cEo9YXz1`CEm*s;hyednFg!KKmb7i(FWE8U|e>)hdCT|4n>aU$6LaVc@_5ke7P zGfwCs5L5b$?fI=-Y?phNVusYt!=3gLDM@J1M&H+g&hF&ytfb|ngg4Zy+1p=gze+zD zX{v8J`nuIm6Lx;}^yWexYm_Cs^k_oFX67pBy7I2)AJ5k8-{)>7NGBxha&acFY%OWu z4Q2mVN;8cJOnaIKlSO2Z07G}0D+y#qC6Y;YB%-^&Pb&!p0G!GcJb_8DvP8Pks1V|w z55$j3XQKfCrSC^4x_Ob9AXgHZ;*AC`RlNa&DDG&mqqdcX6&*|Rq?iUUNcI8Nc((vA zH-tM_Uk`-xL$V2|BqkB$N4@0ji}XW-|Kvro_j_h281$zL(+ds$OBBKC6bMUWkU+W+ zn7W&Wh6YF%0U@~);jWqn zx>3CMEGmCOtgMh`-o8wtw;Ra}hX%7rAQXx_5{rOoVRcUE!ZeJvU@#+`Ar5;2gM(wR zx^PVx0 Date: Mon, 22 Aug 2022 19:53:51 +0300 Subject: [PATCH 12/78] [FL-2737] Dolphin level thresholds update #1610 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/dolphin/helpers/dolphin_state.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/dolphin/helpers/dolphin_state.c b/applications/dolphin/helpers/dolphin_state.c index 76f38a5fd4..95e2f42f49 100644 --- a/applications/dolphin/helpers/dolphin_state.c +++ b/applications/dolphin/helpers/dolphin_state.c @@ -14,8 +14,8 @@ #define DOLPHIN_STATE_PATH INT_PATH(DOLPHIN_STATE_FILE_NAME) #define DOLPHIN_STATE_HEADER_MAGIC 0xD0 #define DOLPHIN_STATE_HEADER_VERSION 0x01 -#define LEVEL2_THRESHOLD 735 -#define LEVEL3_THRESHOLD 2940 +#define LEVEL2_THRESHOLD 300 +#define LEVEL3_THRESHOLD 1800 #define BUTTHURT_MAX 14 #define BUTTHURT_MIN 0 From 9829145d8cfd41053aa66c4f7cb19238464c0449 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 22 Aug 2022 20:06:17 +0300 Subject: [PATCH 13/78] fbt: fixed include paths; added PVS-Studio configuration (#1615) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fbt: fixed include paths for generated version header * lib: STM32CubeWB: refactored & cleaned up WPAN include paths * hal: linter fixes for new headers * fbt: added version_json target * Added .pvsconfig; split common_defines.h into 2 files * Added PVS-Studio basic configuration files; updated .gitignore Co-authored-by: あく --- .gitignore | 4 + .pvsconfig | 22 +++ .pvsoptions | 1 + applications/bt/bt_cli.c | 2 +- firmware.scons | 2 + firmware/SConscript | 5 + firmware/targets/f7/Inc/stm32.h | 32 +--- firmware/targets/f7/ble_glue/app_conf.h | 5 +- firmware/targets/f7/ble_glue/app_debug.c | 11 +- .../targets/f7/ble_glue/battery_service.c | 2 +- firmware/targets/f7/ble_glue/ble_app.c | 6 +- firmware/targets/f7/ble_glue/ble_const.h | 115 ++++++++++++++ firmware/targets/f7/ble_glue/ble_glue.c | 10 +- firmware/targets/f7/ble_glue/compiler.h | 150 ++++++++++++++++++ .../targets/f7/ble_glue/dev_info_service.c | 2 +- firmware/targets/f7/ble_glue/gap.c | 2 +- firmware/targets/f7/ble_glue/hid_service.c | 2 +- firmware/targets/f7/ble_glue/hw_ipcc.c | 2 +- firmware/targets/f7/ble_glue/osal.h | 63 ++++++++ firmware/targets/f7/ble_glue/serial_service.c | 2 +- firmware/targets/f7/furi_hal/furi_hal_bt.c | 5 +- .../targets/f7/furi_hal/furi_hal_crypto.c | 2 +- firmware/targets/f7/furi_hal/furi_hal_flash.c | 4 +- firmware/targets/f7/furi_hal/furi_hal_info.c | 2 +- .../targets/f7/furi_hal/furi_hal_version.c | 2 +- furi/core/common_defines.h | 87 +--------- furi/core/core_defines.h | 97 +++++++++++ furi/core/record.h | 3 +- lib/STM32CubeWB.scons | 19 +-- lib/toolbox/SConscript | 3 +- 30 files changed, 507 insertions(+), 157 deletions(-) create mode 100644 .pvsconfig create mode 100644 .pvsoptions create mode 100644 firmware/targets/f7/ble_glue/ble_const.h create mode 100644 firmware/targets/f7/ble_glue/compiler.h create mode 100644 firmware/targets/f7/ble_glue/osal.h create mode 100644 furi/core/core_defines.h diff --git a/.gitignore b/.gitignore index 21f391743e..38a31bf01b 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,7 @@ build/ # openocd output file openocd.log + +# PVS Studio temporary files +.PVS-Studio/ +PVS-Studio.log diff --git a/.pvsconfig b/.pvsconfig new file mode 100644 index 0000000000..d17eaa5a03 --- /dev/null +++ b/.pvsconfig @@ -0,0 +1,22 @@ +# MLib macros we can't do much about. +//-V:M_EACH:1048,1044 +//-V:ARRAY_DEF:760,747,568,776,729,712,654 +//-V:LIST_DEF:760,747,568,712,729,654,776 +//-V:BPTREE_DEF2:779,1086,557,773,512 +//-V:DICT_DEF2:779,524,776,760,1044,1001,729,590,568,747,685 +//-V:ALGO_DEF:1048,747,1044 + +# Non-severe malloc/null pointer deref warnings +//-V::522:2,3 + +# Warning about headers with copyleft license +//-V::1042 + +# Potentially null argument warnings +//-V:memset:575 +//-V:memcpy:575 +//-V:strcpy:575 +//-V:strchr:575 + +# For loop warning on M_FOREACH +//-V:for:1044 diff --git a/.pvsoptions b/.pvsoptions new file mode 100644 index 0000000000..6715f87189 --- /dev/null +++ b/.pvsoptions @@ -0,0 +1 @@ +--rules-config .pvsconfig -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/micro-ecc -e lib/microtar -e lib/mlib -e lib/qrcode -e lib/ST25RFAL002 -e lib/STM32CubeWB -e lib/u8g2 -e toolchain/ diff --git a/applications/bt/bt_cli.c b/applications/bt/bt_cli.c index 3aa1bc7523..79500fac48 100644 --- a/applications/bt/bt_cli.c +++ b/applications/bt/bt_cli.c @@ -3,7 +3,7 @@ #include #include -#include "ble.h" +#include #include "bt_settings.h" #include "bt_service/bt.h" diff --git a/firmware.scons b/firmware.scons index 863b35fca9..745543070c 100644 --- a/firmware.scons +++ b/firmware.scons @@ -244,6 +244,8 @@ if should_gen_cdb_and_link_dir(fwenv, BUILD_TARGETS): # without filtering, both updater & firmware commands would be generated fwenv.Replace(COMPILATIONDB_PATH_FILTER=fwenv.subst("*${FW_FLAVOR}*")) AlwaysBuild(fwcdb) + Precious(fwcdb) + NoClean(fwcdb) Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_cdb", fwcdb) fw_artifacts.append(fwcdb) diff --git a/firmware/SConscript b/firmware/SConscript index 8dade34e11..3530ed8278 100644 --- a/firmware/SConscript +++ b/firmware/SConscript @@ -3,6 +3,11 @@ Import("env") env.Append(LINT_SOURCES=["firmware"]) libenv = env.Clone(FW_LIB_NAME="flipper${TARGET_HW}") +libenv.Append( + CPPPATH=[ + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl", + ] +) libenv.ApplyLibFlags() diff --git a/firmware/targets/f7/Inc/stm32.h b/firmware/targets/f7/Inc/stm32.h index 83dda96e27..8e5cc379b5 100644 --- a/firmware/targets/f7/Inc/stm32.h +++ b/firmware/targets/f7/Inc/stm32.h @@ -16,36 +16,6 @@ /* bit value */ #define _BV(bit) (0x01 << (bit)) -#if defined(STM32F0) -#include "STM32F0xx/Include/stm32f0xx.h" -#elif defined(STM32F1) -#include "STM32F1xx/Include/stm32f1xx.h" -#elif defined(STM32F2) -#include "STM32F2xx/Include/stm32f2xx.h" -#elif defined(STM32F3) -#include "STM32F3xx/Include/stm32f3xx.h" -#elif defined(STM32F4) -#include "STM32F4xx/Include/stm32f4xx.h" -#elif defined(STM32F7) -#include "STM32F7xx/Include/stm32f7xx.h" -#elif defined(STM32H7) -#include "STM32H7xx/Include/stm32h7xx.h" -#elif defined(STM32L0) -#include "STM32L0xx/Include/stm32l0xx.h" -#elif defined(STM32L1) -#include "STM32L1xx/Include/stm32l1xx.h" -#elif defined(STM32L4) -#include "STM32L4xx/Include/stm32l4xx.h" -#elif defined(STM32L5) -#include "STM32L5xx/Include/stm32l5xx.h" -#elif defined(STM32G0) -#include "STM32G0xx/Include/stm32g0xx.h" -#elif defined(STM32G4) -#include "STM32G4xx/Include/stm32g4xx.h" -#elif defined(STM32WB) -#include "STM32WBxx/Include/stm32wbxx.h" -#else -#error "STM32 family not defined" -#endif +#include "stm32wbxx.h" #endif // _STM32_H_ diff --git a/firmware/targets/f7/ble_glue/app_conf.h b/firmware/targets/f7/ble_glue/app_conf.h index 1d7474da5c..aaa755a362 100644 --- a/firmware/targets/f7/ble_glue/app_conf.h +++ b/firmware/targets/f7/ble_glue/app_conf.h @@ -1,9 +1,10 @@ #pragma once -#include "hw.h" #include "hw_conf.h" #include "hw_if.h" -#include "ble_bufsize.h" + +#include +#include #define CFG_TX_POWER (0x19) /* +0dBm */ diff --git a/firmware/targets/f7/ble_glue/app_debug.c b/firmware/targets/f7/ble_glue/app_debug.c index e480ea364a..d84588540a 100644 --- a/firmware/targets/f7/ble_glue/app_debug.c +++ b/firmware/targets/f7/ble_glue/app_debug.c @@ -1,10 +1,11 @@ -#include "utilities_common.h" - #include "app_common.h" #include "app_debug.h" -#include "shci.h" -#include "tl.h" -#include "dbg_trace.h" +#include +#include +#include +#include +#include + #include typedef PACKED_STRUCT { diff --git a/firmware/targets/f7/ble_glue/battery_service.c b/firmware/targets/f7/ble_glue/battery_service.c index a95f918728..8c371efadb 100644 --- a/firmware/targets/f7/ble_glue/battery_service.c +++ b/firmware/targets/f7/ble_glue/battery_service.c @@ -1,6 +1,6 @@ #include "battery_service.h" #include "app_common.h" -#include "ble.h" +#include #include #include diff --git a/firmware/targets/f7/ble_glue/ble_app.c b/firmware/targets/f7/ble_glue/ble_app.c index 4d3c96e13c..3cf02009fc 100644 --- a/firmware/targets/f7/ble_glue/ble_app.c +++ b/firmware/targets/f7/ble_glue/ble_app.c @@ -1,8 +1,8 @@ #include "ble_app.h" -#include "hci_tl.h" -#include "ble.h" -#include "shci.h" +#include +#include +#include #include "gap.h" #include diff --git a/firmware/targets/f7/ble_glue/ble_const.h b/firmware/targets/f7/ble_glue/ble_const.h new file mode 100644 index 0000000000..0e4c8b398d --- /dev/null +++ b/firmware/targets/f7/ble_glue/ble_const.h @@ -0,0 +1,115 @@ +/***************************************************************************** + * @file ble_const.h + * @author MDG + * @brief This file contains the definitions which are compiler dependent. + ***************************************************************************** + * @attention + * + * Copyright (c) 2018-2022 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ***************************************************************************** + */ + +#ifndef BLE_CONST_H__ +#define BLE_CONST_H__ + +#include +#include +#include +#include +#include "osal.h" + +/* Default BLE variant */ +#ifndef BASIC_FEATURES +#define BASIC_FEATURES 0 +#endif +#ifndef SLAVE_ONLY +#define SLAVE_ONLY 0 +#endif +#ifndef LL_ONLY +#define LL_ONLY 0 +#endif +#ifndef BEACON_ONLY +#define BEACON_ONLY 0 +#endif + +/* Size of command/events buffers: + * + * To change the size of commands and events parameters used in the + * auto-generated files, you need to update 2 defines: + * + * - BLE_CMD_MAX_PARAM_LEN + * - BLE_EVT_MAX_PARAM_LEN + * + * These 2 defines are set below with default values and can be changed. + * + * To compute the value to support a characteristic of 512 bytes for a specific + * command or an event, you need to look in "ble_types.h". + * + * Here are 2 examples, one with a command and one with an event: + * + * - aci_gatt_update_char_value_ext_cp0 + * ---------------------------------- + * + * we have in the structure: + * + * uint8_t Value[(BLE_CMD_MAX_PARAM_LEN- 12)/sizeof(uint8_t)]; + * + * so to support a 512 byte value, we need to have + * + * BLE_CMD_MAX_PARAM_LEN at least equal to: 512 + 12 = 524 + * + * - aci_gatt_read_handle_value_rp0 + * ------------------------------ + * + * we have in the structure: + * + * uint8_t Value[((BLE_EVT_MAX_PARAM_LEN - 3) - 5)/sizeof(uint8_t)]; + * + * so to support a 512 byte value, we need to have + * + * BLE_EVT_MAX_PARAM_LEN at least equal to: 512 + 3 + 5 = 520 + * + * If you need several events or commands with 512-size values, you need to + * take the maximum values for BLE_EVT_MAX_PARAM_LEN and BLE_CMD_MAX_PARAM_LEN. + * + */ + +/* Maximum parameter size of BLE commands. + * Change this value if needed. */ +#define BLE_CMD_MAX_PARAM_LEN HCI_COMMAND_MAX_PARAM_LEN + +/* Maximum parameter size of BLE responses/events. + * Change this value if needed. */ +#define BLE_EVT_MAX_PARAM_LEN HCI_EVENT_MAX_PARAM_LEN + +/* Callback function to send command and receive response */ +struct hci_request { + uint16_t ogf; + uint16_t ocf; + int event; + void* cparam; + int clen; + void* rparam; + int rlen; +}; +extern int hci_send_req(struct hci_request* req, uint8_t async); + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#endif /* BLE_CONST_H__ */ diff --git a/firmware/targets/f7/ble_glue/ble_glue.c b/firmware/targets/f7/ble_glue/ble_glue.c index 585a898202..87af5f2a89 100644 --- a/firmware/targets/f7/ble_glue/ble_glue.c +++ b/firmware/targets/f7/ble_glue/ble_glue.c @@ -1,14 +1,14 @@ #include "ble_glue.h" #include "app_common.h" #include "ble_app.h" -#include "ble.h" -#include "tl.h" -#include "shci.h" -#include "shci_tl.h" +#include + +#include +#include +#include #include "app_debug.h" #include -#include #define TAG "Core2" diff --git a/firmware/targets/f7/ble_glue/compiler.h b/firmware/targets/f7/ble_glue/compiler.h new file mode 100644 index 0000000000..1c39628197 --- /dev/null +++ b/firmware/targets/f7/ble_glue/compiler.h @@ -0,0 +1,150 @@ +/***************************************************************************** + * @file compiler.h + * @author MDG + * @brief This file contains the definitions which are compiler dependent. + ***************************************************************************** + * @attention + * + * Copyright (c) 2018-2022 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ***************************************************************************** + */ + +#ifndef COMPILER_H__ +#define COMPILER_H__ + +/** + * @brief This is the section dedicated to IAR toolchain + */ +#if defined(__ICCARM__) || defined(__IAR_SYSTEMS_ASM__) + +#ifndef __WEAK +#define __WEAK __weak +#endif + +#define QUOTE_(a) #a + +/** + * @brief PACKED + * Use the PACKED macro for variables that needs to be packed. + * Usage: PACKED(struct) myStruct_s + * PACKED(union) myStruct_s + */ +#define PACKED(decl) __packed decl + +/** + * @brief SECTION + * Use the SECTION macro to assign data or code in a specific section. + * Usage: SECTION(".my_section") + */ +#define SECTION(name) _Pragma(QUOTE_(location = name)) + +/** + * @brief ALIGN_DEF + * Use the ALIGN_DEF macro to specify the alignment of a variable. + * Usage: ALIGN_DEF(4) + */ +#define ALIGN_DEF(v) _Pragma(QUOTE_(data_alignment = v)) + +/** + * @brief NO_INIT + * Use the NO_INIT macro to declare a not initialized variable. + * Usage: NO_INIT(int my_no_init_var) + * Usage: NO_INIT(uint16_t my_no_init_array[10]) + */ +#define NO_INIT(var) __no_init var + +/** + * @brief This is the section dedicated to GNU toolchain + */ +#else +#ifdef __GNUC__ + +#ifndef __WEAK +#define __WEAK __attribute__((weak)) +#endif + +/** + * @brief PACKED + * Use the PACKED macro for variables that needs to be packed. + * Usage: PACKED(struct) myStruct_s + * PACKED(union) myStruct_s + */ +#define PACKED(decl) decl __attribute__((packed)) + +/** + * @brief SECTION + * Use the SECTION macro to assign data or code in a specific section. + * Usage: SECTION(".my_section") + */ +#define SECTION(name) __attribute__((section(name))) + +/** + * @brief ALIGN_DEF + * Use the ALIGN_DEF macro to specify the alignment of a variable. + * Usage: ALIGN_DEF(4) + */ +#define ALIGN_DEF(N) __attribute__((aligned(N))) + +/** + * @brief NO_INIT + * Use the NO_INIT macro to declare a not initialized variable. + * Usage: NO_INIT(int my_no_init_var) + * Usage: NO_INIT(uint16_t my_no_init_array[10]) + */ +#define NO_INIT(var) var __attribute__((section(".noinit"))) + +/** + * @brief This is the section dedicated to Keil toolchain + */ +#else +#ifdef __CC_ARM + +#ifndef __WEAK +#define __WEAK __weak +#endif + +/** + * @brief PACKED + * Use the PACKED macro for variables that needs to be packed. + * Usage: PACKED(struct) myStruct_s + * PACKED(union) myStruct_s + */ +#define PACKED(decl) decl __attribute__((packed)) + +/** + * @brief SECTION + * Use the SECTION macro to assign data or code in a specific section. + * Usage: SECTION(".my_section") + */ +#define SECTION(name) __attribute__((section(name))) + +/** + * @brief ALIGN_DEF + * Use the ALIGN_DEF macro to specify the alignment of a variable. + * Usage: ALIGN_DEF(4) + */ +#define ALIGN_DEF(N) __attribute__((aligned(N))) + +/** + * @brief NO_INIT + * Use the NO_INIT macro to declare a not initialized variable. + * Usage: NO_INIT(int my_no_init_var) + * Usage: NO_INIT(uint16_t my_no_init_array[10]) + */ +#define NO_INIT(var) var __attribute__((section("NoInit"))) + +#else + +#error Neither ICCARM, CC ARM nor GNUC C detected. Define your macros. + +#endif +#endif +#endif + +#endif /* COMPILER_H__ */ diff --git a/firmware/targets/f7/ble_glue/dev_info_service.c b/firmware/targets/f7/ble_glue/dev_info_service.c index d6d1e479ef..ecfa08b175 100755 --- a/firmware/targets/f7/ble_glue/dev_info_service.c +++ b/firmware/targets/f7/ble_glue/dev_info_service.c @@ -1,6 +1,6 @@ #include "dev_info_service.h" #include "app_common.h" -#include "ble.h" +#include #include #include diff --git a/firmware/targets/f7/ble_glue/gap.c b/firmware/targets/f7/ble_glue/gap.c index 7154b9b119..62db30feea 100644 --- a/firmware/targets/f7/ble_glue/gap.c +++ b/firmware/targets/f7/ble_glue/gap.c @@ -1,6 +1,6 @@ #include "gap.h" -#include "ble.h" +#include #include #include diff --git a/firmware/targets/f7/ble_glue/hid_service.c b/firmware/targets/f7/ble_glue/hid_service.c index 0efe1747b6..d0ca9685ab 100644 --- a/firmware/targets/f7/ble_glue/hid_service.c +++ b/firmware/targets/f7/ble_glue/hid_service.c @@ -1,6 +1,6 @@ #include "hid_service.h" #include "app_common.h" -#include "ble.h" +#include #include diff --git a/firmware/targets/f7/ble_glue/hw_ipcc.c b/firmware/targets/f7/ble_glue/hw_ipcc.c index ccdb0736e8..64dd9ef9b7 100644 --- a/firmware/targets/f7/ble_glue/hw_ipcc.c +++ b/firmware/targets/f7/ble_glue/hw_ipcc.c @@ -19,7 +19,7 @@ /* Includes ------------------------------------------------------------------*/ #include "app_common.h" -#include "mbox_def.h" +#include /* Global variables ---------------------------------------------------------*/ /* Private defines -----------------------------------------------------------*/ diff --git a/firmware/targets/f7/ble_glue/osal.h b/firmware/targets/f7/ble_glue/osal.h new file mode 100644 index 0000000000..e5e0c4f689 --- /dev/null +++ b/firmware/targets/f7/ble_glue/osal.h @@ -0,0 +1,63 @@ +/***************************************************************************** + * @file osal.h + * @author MDG + * @brief This header file defines the OS abstraction layer used by + * the BLE stack. OSAL defines the set of functions which needs to be + * ported to target operating system and target platform. + * Actually, only memset, memcpy and memcmp wrappers are defined. + ***************************************************************************** + * @attention + * + * Copyright (c) 2018-2022 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ***************************************************************************** + */ + +#ifndef OSAL_H__ +#define OSAL_H__ + +/** + * This function copies size number of bytes from a + * memory location pointed by src to a destination + * memory location pointed by dest + * + * @param[in] dest Destination address + * @param[in] src Source address + * @param[in] size size in the bytes + * + * @return Address of the destination + */ + +extern void* Osal_MemCpy(void* dest, const void* src, unsigned int size); + +/** + * This function sets first number of bytes, specified + * by size, to the destination memory pointed by ptr + * to the specified value + * + * @param[in] ptr Destination address + * @param[in] value Value to be set + * @param[in] size Size in the bytes + * + * @return Address of the destination + */ + +extern void* Osal_MemSet(void* ptr, int value, unsigned int size); + +/** + * This function compares n bytes of two regions of memory + * + * @param[in] s1 First buffer to compare. + * @param[in] s2 Second buffer to compare. + * @param[in] size Number of bytes to compare. + * + * @return 0 if the two buffers are equal, 1 otherwise + */ +extern int Osal_MemCmp(const void* s1, const void* s2, unsigned int size); + +#endif /* OSAL_H__ */ diff --git a/firmware/targets/f7/ble_glue/serial_service.c b/firmware/targets/f7/ble_glue/serial_service.c index 91e12dd688..eb58ae0ec3 100644 --- a/firmware/targets/f7/ble_glue/serial_service.c +++ b/firmware/targets/f7/ble_glue/serial_service.c @@ -1,6 +1,6 @@ #include "serial_service.h" #include "app_common.h" -#include "ble.h" +#include #include diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt.c b/firmware/targets/f7/furi_hal/furi_hal_bt.c index 47ed5992e3..1a2b436d28 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt.c @@ -1,7 +1,8 @@ #include -#include + +#include +#include #include -#include #include #include diff --git a/firmware/targets/f7/furi_hal/furi_hal_crypto.c b/firmware/targets/f7/furi_hal/furi_hal_crypto.c index b3c68e2d01..dbd8c58c2a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_crypto.c +++ b/firmware/targets/f7/furi_hal/furi_hal_crypto.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include #define TAG "FuriHalCrypto" diff --git a/firmware/targets/f7/furi_hal/furi_hal_flash.c b/firmware/targets/f7/furi_hal/furi_hal_flash.c index ac141db045..9e05dc1238 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_flash.c +++ b/firmware/targets/f7/furi_hal/furi_hal_flash.c @@ -1,8 +1,8 @@ #include #include #include -#include -#include +#include +#include #include diff --git a/firmware/targets/f7/furi_hal/furi_hal_info.c b/firmware/targets/f7/furi_hal/furi_hal_info.c index 1f75ea331e..25ea42bb6d 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_info.c +++ b/firmware/targets/f7/furi_hal/furi_hal_info.c @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/firmware/targets/f7/furi_hal/furi_hal_version.c b/firmware/targets/f7/furi_hal/furi_hal_version.c index 0d87c80731..697d659311 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_version.c +++ b/firmware/targets/f7/furi_hal/furi_hal_version.c @@ -6,7 +6,7 @@ #include #include -#include "ble.h" +#include #define TAG "FuriHalVersion" diff --git a/furi/core/common_defines.h b/furi/core/common_defines.h index c211ad7ee7..31be7fff07 100644 --- a/furi/core/common_defines.h +++ b/furi/core/common_defines.h @@ -1,5 +1,6 @@ #pragma once +#include "core_defines.h" #include #include #include @@ -10,92 +11,6 @@ extern "C" { #include -#ifndef MAX -#define MAX(a, b) \ - ({ \ - __typeof__(a) _a = (a); \ - __typeof__(b) _b = (b); \ - _a > _b ? _a : _b; \ - }) -#endif - -#ifndef MIN -#define MIN(a, b) \ - ({ \ - __typeof__(a) _a = (a); \ - __typeof__(b) _b = (b); \ - _a < _b ? _a : _b; \ - }) -#endif - -#ifndef ROUND_UP_TO -#define ROUND_UP_TO(a, b) \ - ({ \ - __typeof__(a) _a = (a); \ - __typeof__(b) _b = (b); \ - _a / _b + !!(_a % _b); \ - }) -#endif - -#ifndef CLAMP -#define CLAMP(x, upper, lower) (MIN(upper, MAX(x, lower))) -#endif - -#ifndef COUNT_OF -#define COUNT_OF(x) (sizeof(x) / sizeof(x[0])) -#endif - -#ifndef FURI_SWAP -#define FURI_SWAP(x, y) \ - do { \ - typeof(x) SWAP = x; \ - x = y; \ - y = SWAP; \ - } while(0) -#endif - -#ifndef PLACE_IN_SECTION -#define PLACE_IN_SECTION(x) __attribute__((section(x))) -#endif - -#ifndef ALIGN -#define ALIGN(n) __attribute__((aligned(n))) -#endif - -#ifndef __weak -#define __weak __attribute__((weak)) -#endif - -#ifndef UNUSED -#define UNUSED(X) (void)(X) -#endif - -#ifndef STRINGIFY -#define STRINGIFY(x) #x -#endif - -#ifndef TOSTRING -#define TOSTRING(x) STRINGIFY(x) -#endif - -#ifndef REVERSE_BYTES_U32 -#define REVERSE_BYTES_U32(x) \ - ((((x)&0x000000FF) << 24) | (((x)&0x0000FF00) << 8) | (((x)&0x00FF0000) >> 8) | \ - (((x)&0xFF000000) >> 24)) -#endif - -#ifndef FURI_BIT -#define FURI_BIT(x, n) (((x) >> (n)) & 1) -#endif - -#ifndef FURI_BIT_SET -#define FURI_BIT_SET(x, n) ((x) |= (1 << (n))) -#endif - -#ifndef FURI_BIT_CLEAR -#define FURI_BIT_CLEAR(x, n) ((x) &= ~(1 << (n))) -#endif - #ifndef FURI_IS_IRQ_MASKED #define FURI_IS_IRQ_MASKED() (__get_PRIMASK() != 0U) #endif diff --git a/furi/core/core_defines.h b/furi/core/core_defines.h new file mode 100644 index 0000000000..9ed05b2107 --- /dev/null +++ b/furi/core/core_defines.h @@ -0,0 +1,97 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#define FURI_RETURNS_NONNULL __attribute__((returns_nonnull)) + +#ifndef MAX +#define MAX(a, b) \ + ({ \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + _a > _b ? _a : _b; \ + }) +#endif + +#ifndef MIN +#define MIN(a, b) \ + ({ \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + _a < _b ? _a : _b; \ + }) +#endif + +#ifndef ROUND_UP_TO +#define ROUND_UP_TO(a, b) \ + ({ \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + _a / _b + !!(_a % _b); \ + }) +#endif + +#ifndef CLAMP +#define CLAMP(x, upper, lower) (MIN(upper, MAX(x, lower))) +#endif + +#ifndef COUNT_OF +#define COUNT_OF(x) (sizeof(x) / sizeof(x[0])) +#endif + +#ifndef FURI_SWAP +#define FURI_SWAP(x, y) \ + do { \ + typeof(x) SWAP = x; \ + x = y; \ + y = SWAP; \ + } while(0) +#endif + +#ifndef PLACE_IN_SECTION +#define PLACE_IN_SECTION(x) __attribute__((section(x))) +#endif + +#ifndef ALIGN +#define ALIGN(n) __attribute__((aligned(n))) +#endif + +#ifndef __weak +#define __weak __attribute__((weak)) +#endif + +#ifndef UNUSED +#define UNUSED(X) (void)(X) +#endif + +#ifndef STRINGIFY +#define STRINGIFY(x) #x +#endif + +#ifndef TOSTRING +#define TOSTRING(x) STRINGIFY(x) +#endif + +#ifndef REVERSE_BYTES_U32 +#define REVERSE_BYTES_U32(x) \ + ((((x)&0x000000FF) << 24) | (((x)&0x0000FF00) << 8) | (((x)&0x00FF0000) >> 8) | \ + (((x)&0xFF000000) >> 24)) +#endif + +#ifndef FURI_BIT +#define FURI_BIT(x, n) (((x) >> (n)) & 1) +#endif + +#ifndef FURI_BIT_SET +#define FURI_BIT_SET(x, n) ((x) |= (1 << (n))) +#endif + +#ifndef FURI_BIT_CLEAR +#define FURI_BIT_CLEAR(x, n) ((x) &= ~(1 << (n))) +#endif + +#ifdef __cplusplus +} +#endif diff --git a/furi/core/record.h b/furi/core/record.h index cb4bd199f8..4819123e27 100644 --- a/furi/core/record.h +++ b/furi/core/record.h @@ -6,6 +6,7 @@ #pragma once #include +#include "core_defines.h" #ifdef __cplusplus extern "C" { @@ -51,7 +52,7 @@ bool furi_record_destroy(const char* name); * @note Thread safe. Open and close must be executed from the same * thread. Suspends caller thread till record is available */ -void* furi_record_open(const char* name); +FURI_RETURNS_NONNULL void* furi_record_open(const char* name); /** Close record * diff --git a/lib/STM32CubeWB.scons b/lib/STM32CubeWB.scons index 02618ae73a..80d06b5fcc 100644 --- a/lib/STM32CubeWB.scons +++ b/lib/STM32CubeWB.scons @@ -2,19 +2,10 @@ Import("env") env.Append( CPPPATH=[ - "#/lib/STM32CubeWB/Drivers/CMSIS/Device/ST", "#/lib/STM32CubeWB/Drivers/CMSIS/Device/ST/STM32WBxx/Include", "#/lib/STM32CubeWB/Drivers/CMSIS/Include", "#/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc", - "#/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/Legacy", "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN", - "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble", - "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core", - "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/template", - "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread", - "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci", - "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl", - "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities", ], CPPDEFINES=[ "STM32WB", @@ -33,6 +24,16 @@ if env["RAM_EXEC"]: libenv = env.Clone(FW_LIB_NAME="stm32cubewb") +libenv.Append( + CPPPATH=[ + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities", + ] +) libenv.ApplyLibFlags() sources = libenv.GlobRecursive( diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index 26c233d98b..e4f2cbd020 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -29,6 +29,7 @@ build_version = libenv.VersionBuilder( fw_version_json = libenv.InstallAs( "${BUILD_DIR}/${FIRMWARE_BUILD_CFG}.json", "version.json" ) +Alias("version_json", fw_version_json) env.Append(FW_VERSION_JSON=fw_version_json) # Default(fw_version_json) @@ -40,7 +41,7 @@ if not version_depends: sources = libenv.GlobRecursive("*.c") -libenv.Append(CPPPATH=["."]) +libenv.Append(CPPPATH=[libenv.Dir(".")]) lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) From 8992f8ac3633702947177021cd845f8947ef91c2 Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 22 Aug 2022 20:14:31 +0300 Subject: [PATCH 14/78] Fix mifare ultralight/ntag unlock #1624 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- lib/nfc/nfc_worker.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 45bbc5f41a..f07ea616ce 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -545,6 +545,16 @@ void nfc_worker_mf_ultralight_read_auth(NfcWorker* nfc_worker) { } data->auth_success = mf_ultralight_authenticate(&tx_rx, key, &pack); + + if(!data->auth_success) { + // Reset card + furi_hal_nfc_sleep(); + if(!furi_hal_nfc_activate_nfca(300, NULL)) { + nfc_worker->callback(NfcWorkerEventFail, nfc_worker->context); + break; + } + } + mf_ul_read_card(&tx_rx, &reader, data); if(data->auth_success) { MfUltralightConfigPages* config_pages = mf_ultralight_get_config_pages(data); From 9317ded1a96b6ed3e78e094bb8cbd4f72e5eadbb Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Mon, 22 Aug 2022 20:54:01 +0300 Subject: [PATCH 15/78] [FL-2749] New power off screen #1637 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/power/power_service/power.c | 14 +++--- applications/power/power_service/power_api.c | 4 +- applications/power/power_service/power_i.h | 5 +- .../power_service/views/power_unplug_usb.c | 43 ++++++++++++++++++ .../power_service/views/power_unplug_usb.h | 11 +++++ .../icons/Power/Unplug_bg_bottom_128x10.png | Bin 0 -> 5355 bytes assets/icons/Power/Unplug_bg_top_128x14.png | Bin 0 -> 5945 bytes 7 files changed, 67 insertions(+), 10 deletions(-) create mode 100644 applications/power/power_service/views/power_unplug_usb.c create mode 100644 applications/power/power_service/views/power_unplug_usb.h create mode 100644 assets/icons/Power/Unplug_bg_bottom_128x10.png create mode 100644 assets/icons/Power/Unplug_bg_top_128x14.png diff --git a/applications/power/power_service/power.c b/applications/power/power_service/power.c index 9036ae1ce3..3a2c6cf3b1 100644 --- a/applications/power/power_service/power.c +++ b/applications/power/power_service/power.c @@ -55,13 +55,14 @@ Power* power_alloc() { // Gui power->view_dispatcher = view_dispatcher_alloc(); - power->popup = popup_alloc(); - popup_set_header( - power->popup, "Disconnect USB for safe\nshutdown", 64, 26, AlignCenter, AlignTop); - view_dispatcher_add_view(power->view_dispatcher, PowerViewPopup, popup_get_view(power->popup)); power->power_off = power_off_alloc(); view_dispatcher_add_view( power->view_dispatcher, PowerViewOff, power_off_get_view(power->power_off)); + power->power_unplug_usb = power_unplug_usb_alloc(); + view_dispatcher_add_view( + power->view_dispatcher, + PowerViewUnplugUsb, + power_unplug_usb_get_view(power->power_unplug_usb)); view_dispatcher_attach_to_gui( power->view_dispatcher, power->gui, ViewDispatcherTypeFullscreen); @@ -78,8 +79,9 @@ void power_free(Power* power) { // Gui view_dispatcher_remove_view(power->view_dispatcher, PowerViewOff); power_off_free(power->power_off); - view_dispatcher_remove_view(power->view_dispatcher, PowerViewPopup); - popup_free(power->popup); + view_dispatcher_remove_view(power->view_dispatcher, PowerViewUnplugUsb); + power_unplug_usb_free(power->power_unplug_usb); + view_port_free(power->battery_view_port); // State diff --git a/applications/power/power_service/power_api.c b/applications/power/power_service/power_api.c index d26fb3b4f0..8185b7cd52 100644 --- a/applications/power/power_service/power_api.c +++ b/applications/power/power_service/power_api.c @@ -8,8 +8,8 @@ void power_off(Power* power) { furi_hal_power_off(); // Notify user if USB is plugged view_dispatcher_send_to_front(power->view_dispatcher); - view_dispatcher_switch_to_view(power->view_dispatcher, PowerViewPopup); - furi_delay_ms(10); + view_dispatcher_switch_to_view(power->view_dispatcher, PowerViewUnplugUsb); + furi_delay_ms(100); furi_halt("Disconnect USB for safe shutdown"); } diff --git a/applications/power/power_service/power_i.h b/applications/power/power_service/power_i.h index c7181d0a1a..66ced885b1 100755 --- a/applications/power/power_service/power_i.h +++ b/applications/power/power_service/power_i.h @@ -8,6 +8,7 @@ #include #include "views/power_off.h" +#include "views/power_unplug_usb.h" #include @@ -21,8 +22,8 @@ typedef enum { struct Power { ViewDispatcher* view_dispatcher; - Popup* popup; PowerOff* power_off; + PowerUnplugUsb* power_unplug_usb; ViewPort* battery_view_port; Gui* gui; @@ -42,6 +43,6 @@ struct Power { }; typedef enum { - PowerViewPopup, PowerViewOff, + PowerViewUnplugUsb, } PowerView; diff --git a/applications/power/power_service/views/power_unplug_usb.c b/applications/power/power_service/views/power_unplug_usb.c new file mode 100644 index 0000000000..6d14be22c7 --- /dev/null +++ b/applications/power/power_service/views/power_unplug_usb.c @@ -0,0 +1,43 @@ +#include "power_unplug_usb.h" +#include +#include + +struct PowerUnplugUsb { + View* view; +}; + +static void power_unplug_usb_draw_callback(Canvas* canvas, void* _model) { + UNUSED(_model); + + canvas_set_color(canvas, ColorBlack); + canvas_draw_icon(canvas, 0, 0, &I_Unplug_bg_top_128x14); + canvas_draw_box(canvas, 0, 14, 128, (64 - 10 - 14)); + canvas_draw_icon(canvas, 0, (64 - 10), &I_Unplug_bg_bottom_128x10); + + canvas_set_color(canvas, ColorWhite); + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned( + canvas, 64, 32, AlignCenter, AlignCenter, "It's now safe to unplug\nUSB cable"); +} + +PowerUnplugUsb* power_unplug_usb_alloc() { + PowerUnplugUsb* power_unplug_usb = malloc(sizeof(PowerUnplugUsb)); + + power_unplug_usb->view = view_alloc(); + view_set_context(power_unplug_usb->view, power_unplug_usb); + view_set_draw_callback(power_unplug_usb->view, power_unplug_usb_draw_callback); + view_set_input_callback(power_unplug_usb->view, NULL); + + return power_unplug_usb; +} + +void power_unplug_usb_free(PowerUnplugUsb* power_unplug_usb) { + furi_assert(power_unplug_usb); + view_free(power_unplug_usb->view); + free(power_unplug_usb); +} + +View* power_unplug_usb_get_view(PowerUnplugUsb* power_unplug_usb) { + furi_assert(power_unplug_usb); + return power_unplug_usb->view; +} diff --git a/applications/power/power_service/views/power_unplug_usb.h b/applications/power/power_service/views/power_unplug_usb.h new file mode 100644 index 0000000000..e85c6d03b9 --- /dev/null +++ b/applications/power/power_service/views/power_unplug_usb.h @@ -0,0 +1,11 @@ +#pragma once + +typedef struct PowerUnplugUsb PowerUnplugUsb; + +#include + +PowerUnplugUsb* power_unplug_usb_alloc(); + +void power_unplug_usb_free(PowerUnplugUsb* power_unplug_usb); + +View* power_unplug_usb_get_view(PowerUnplugUsb* power_unplug_usb); diff --git a/assets/icons/Power/Unplug_bg_bottom_128x10.png b/assets/icons/Power/Unplug_bg_bottom_128x10.png new file mode 100644 index 0000000000000000000000000000000000000000..35d73ba76ea10724f02119ac7c7413c6ec7d6d3f GIT binary patch literal 5355 zcmeHKc~lcu7mtVn0nv(}RVp#iD%HuJkPL)HK#3X%i!3VWWHJdMD@ib66O0>+h>BVf z5L8qU3M!y1qV_|<6^pyLp;8wV#08humTwYV@U-WA$8)~^XU>`A&0T))-ru|LzPxmv z|I88C@mLH7GlJvi6NLVzq7T-5IQpGr8ybhfn06`%;K>r=54XZr4WH9YZMGWU71>&*+nu8nyi+sUR&&B)^ZK2foU zl6Q8~thtiLn$A_nJ;I`} z6rSL5JlW&$!{6Ezg=5$@C-4ZdEA7Y6jVY};u;)@t*jLW70nUr7fkoaT5v}ilQ&ys$cxLF?%V?j5acfjUzR8I#-?9BFqD2uUK~HMH}aa z&99gC(eoqi`-*Q54yBg#TV2Zy~7HOOFCHJ$J4j0n>oZPsMw@% zZ}zUcu)oxaQKQgHI>=yZy{XBpQA2X?=7gSb}8IQc5cey&_v)JU#y$&qVI^e)$J70JDHvIKu$J~8(09GFep1%gW z(w$nK72ZiM+&z7JetFw7*A8upxiUNZfs0u<@K_iVFVNB{!jyV4_}I=K99i+SuXbW=5f5eKQunH-Q_2*WBWCE+8n5( zEHjNMDDk)R@wKnP`j(7}SrPi(9KxUaA4YI8GIw;$Q})99x;pNbmn|#9nJ-CYf-L8H zzx4juSb*=w>}hF8%x=)8@`%*4UE|DXHyOd{wVO{?WJFe)Lzv{WNmHn&H|G>PCAC~( znO3RZi{Suldn5dY&qIP75VHRW07`3ZLM50QwIuHerAsPs$lS$=jP{+m_aY1x!5EJn@ zqlres#)orxIB$gt!O;jb0txWdi5FAw?pU0gN+1M-d}h3dK;PK-XpKe*5{X)^mY}5) z6eTw_9 zlPS5}kMMH!dlpbWh&o6~BojzPnT$BtL#^>$jDoxm=pQ}QA?SHd3_{e3I2DZeE=J@U z$H5Q+_@lovP9-&_BY=sB6p^8(YIIieXH(APaCsj+3>1jOGNsWACHpf=jac}Jtj}UI zXpHF$4g_`oi2IrKhun?Es1=tB`Y7NyLwFn?Hr_BlC{Vy+0cadTLOzv2MQ8xTr|7BUfu6IgA*fP;i16#X$rV7G1~?0tku$(3nCxz#<9A z0H4I5@kw-s3xx~~f(THF(W-=`gQGG)2~a2si%O@!LIwaagj9egAn^efnMDC$ghh3M zUcy?7ipo-a(*#!a^OcEWS@gWAl=aXT8BA^R}Ofn1$Tn4J? zBf454)Mz0U;w3_PM7cuC)5sNWigBTwKaWKljTlw|B@7@jfxi<*e4jAU&@(<{>_+?> zCvHZAK}`nr8<3&R3+;u(kInEsXK1|t=I8xd{F_tYa9=0+B7VQp^_8wKV&IF6zgE{* zy1s~kFEajGUH><_u%E6|h#dVFq(v`F?Ryu+q8F{<{Mj>oj8`tqTknPxbY!9Qi%?@Q zmNtfG2xd$EI8x<`S?WZWr_iqttv6Yg$&cd4(I zGg~J*H#IwP$FfzI1I&{q>hC?}>v?~e;f5-yLH|iSALd>;oc*e{=<= G^#294V-(;3 literal 0 HcmV?d00001 diff --git a/assets/icons/Power/Unplug_bg_top_128x14.png b/assets/icons/Power/Unplug_bg_top_128x14.png new file mode 100644 index 0000000000000000000000000000000000000000..bafa2c4947082eff8f59d48d119e9ca01ece9729 GIT binary patch literal 5945 zcmeHKcTiK?){lxbDPB;nfF%Y+5JGxLazm3229TnmbCMh&lq4jf2?&bv07a1^qEs(J zE+SY!k)l@-QA8{VHY^trq$$!xk#_>td2i+$XTJBJnK?OUuf5i9uk~ANwfKZC3+|F?y|xA9?xUt995XIZm%o$sX}rWUb~x$J zu@laH!Idgg8CxulbdC*Aw|rP>dg1nD?@Z!zqZDtGe5s_u7J?C~((h9gb;pVbPtEXg zDbpAu#g5yG7LkLK_6d1=&O~KYlMfWWThZJ%4mXtS(J8xQk+sH@ZZFZhiV+)wG6F9I z$F6w)u~zzZZnKY_wV-9EptbLn@dUSKq`O$qBc;q--I>)%YFfF*9@edsV`#YOK#M2R z+ip53^FXbAP~(j6kh1%F1E-MPM_>EZRyZtg!-5mnXNya7uv-)C;W z=k4kT;ofM$MW#@<(D33E?Z)M6@_wziH^(3JR}_s)PQ^rjB2}nLp7?W6NflP>rMWd_ z)_GU7a&9*L!o_Z-S5(Qk#N#@x1#wCMvPaEbE-meIn&l-P_jc{12U1AcHm&lU z?IXt{&ASW;?N^5zNsV%v8>f}3O#)M0Y}UsX3HkmV9=0c|T>h%xPjTlQZ|^vQM%Fzi4R@N;&?6P7c=FQ9 z=RQcovg1d!^R?ELVK$Bsf2+@N?v=Z8&jqn>uaohn4ZXT!bQ^w8&RMilsYqtS2|?H~ zoMgN?vsC4Ir)OWI2se2tqPFPcRrl$N7EimU`q>{c&sWg@c$P46>!Ix)g@Eg#1LSma z=TKPC^52W;>bA_j6^^Q5*GlY%+> zk8C^dUSXM~^{VM^r@VjjqbAer%p>GO|4anjzkaCAt)bk+Xb9=l)GC9qEIP z1QD{-6}LFgVsn-1q0M%k%#+2g-Ghf7nc=1BHU0ZWQ=j!^Nb17RkM8o#5&7UwneRxo zq4^|D*U^II4xSEI97tQ2d)W7Is?GbHzeXo#2FAI{bsDK%B}_xi9-d@r^mYZYisLmO`@ESNU0Q*=59gKC z=+cQ+Zy0XYB`sPBml?NU8#iI=-&Gj@u9h;gXZD;9D*fY9xULW3k54K0y~icIue9|a z_B(XL&T9X8dyPmMu2}izp`Fu7JimLF5M#S*lt!Kqts7i!Tva+YZQ)bBohouK|tgkgWy7H(cQQIOur$$Mq zn>-}(L|x08qx#RD8^N0U6ejkk%(~q@ud}^$t4iz9tkL$2uDF(!f84Mg4qatZe2_=T z4A5&#?KF;29coHV+#he7EK+aZbH!Ie>tt?<+JkGU4onWOlxrFIv3_8@RyjY=h2mJ0 zcm0T&Z5-@L$UfOV5PrYhs(Q=6M3u|xPNi*>c`Rye63woCb=ffcvegWknHJinnPl1g zMyR)B2-B%Gec~4GY)-aZRZo>ZYyq&aIdgPSc3{$u*cP}@UZUsk^4C>kcsJV;y=M*^ z)sv#+^i($fgHALClM;|jk*lSBoSC(~hdgjJj;N~N9 zTM;gD?uxIYG6#dy$JEg~uLZh=rbHDDt_fd#zB#MOI#D_#K_JS@xJowO@-Ap3U)9~7 zdAsb?i@RG65Z@<vpFTEU{Y0Cs5DyW8F$cVAR$Wal*5N(a%Ewu zW5AM^mtQPXnaWl^ZKDyEVQgztDbG(D*+}sIAnk~MzAWl=T&7pDpOkBfzHNt8Lks?E%l!vn|%QdG`Fl0xC`oTi2uQzJAyLlf2UZOlsRNKyEUDc6t*h2jjWS#6A6=! zobmW4YQ$c?eSl*y*#>9t^f%H`~!O<;7%Ysg-}_E?RuH>? zHNg)9hb!I2HdH3*Czj|3$B!C@>|PFLPUS?j6fIFQ;(NZEN)cQJclueh2m|s+n{-tk z)7i|ectV$Um#DNa1I40lC38bMnq4~THpBv?k_ufxZVy_CepP8*qJx9E4EXT=HW`Yx zieu%P$#;qub|iVoUa;}$rW-F-V?9v(Bz38_Y9w9R%aNoYyhv(olD<>51Rt<}G-i;L zq70vs^XNmy9#?3IPV)+6-_zG=cdVA4ZzcHF?!K}(_ zuhH#+Z(fcquyWdVL;b~zr7MsQ6E(MMO^51dqKY3qS9A;E=b|+>YC)%y2sU&Iq0=@~ znA~7JfW>8idJ(}q=#&D3QH>&a05cF2!Wp0+n`3}@TYCusXR{0t+Xyr?jb{q_v#qxC zL8t9@&dlwBOfm~$WGG9Gpg;h@pb&sZ1P5^hln4XF94-a=7K>2`_?(I`&;UWFIlxW1 zd=QS;!|S1u<`L{LEW%J0PUW+FDUN0qpCO=@0m5G>VtyFX(wgS*)j~{xA3K;gX9bb{gQk$}`;Dw0d=vM~h4Z~5 zkoi~KAGE*3KBo+6(P$JiE;Cf@p0$|)LOec&#bvTtl(|okg~4Dk3|}OOBao4J0*QqL zaCj1ug+&8IEQ^G}GqK-6S#tzJfWrjEP!PBt8^U2=7+5lfNkrlSeGrK!>tm4shD1b? z31kKVL}LH|1iyo@=d+=z1cJWzN({w<6pKl*;PQh3D4pzJzz;<6IDT^-V!|mV4%P+;tRDKC#32X}`a%WRVgMg6Bcjj_~3=m?M;9|?K-85)Au>c`p1_(h26ph7F&?E{L>x>~&@I(p*ql3m# z(BJ8ES#00P|4UmudEnIflv}X{(D;#aqWKx+1cuDF=9@w6xv2z)&rJ#nz?=_30EB_8 zIX@w+`7WkE!0`j2)#G!yevz~PODPcb0VvxfEE4BSBq8xQ3Jb?B-?A;svdRsIQCRXU-sh|Chhdx%giW0f+w@8wnnZH;RfeLu* z%u_B{JiDNkMQV@;i@PZoz3X=Uee?Hp<&3+QGDcEUcPk Date: Mon, 22 Aug 2022 22:01:42 +0400 Subject: [PATCH 16/78] [FL-2757] SubGhz: add protocol Magellen (#1633) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: add decoder Paradox Wireless * SubGhz: fix syntax * SubGhz: rename paradox_wireless -> magellen, add encoder Magellen, parse event * SuBghz: add unit_test Magellen Co-authored-by: あく --- applications/unit_tests/subghz/subghz_test.c | 17 +- assets/unit_tests/subghz/magellen.sub | 7 + assets/unit_tests/subghz/magellen_raw.sub | 8 + assets/unit_tests/subghz/test_random_raw.sub | 11 + lib/subghz/protocols/magellen.c | 444 +++++++++++++++++++ lib/subghz/protocols/magellen.h | 107 +++++ lib/subghz/protocols/registry.c | 2 +- lib/subghz/protocols/registry.h | 1 + 8 files changed, 595 insertions(+), 2 deletions(-) create mode 100644 assets/unit_tests/subghz/magellen.sub create mode 100644 assets/unit_tests/subghz/magellen_raw.sub create mode 100644 lib/subghz/protocols/magellen.c create mode 100644 lib/subghz/protocols/magellen.h diff --git a/applications/unit_tests/subghz/subghz_test.c b/applications/unit_tests/subghz/subghz_test.c index f91d27234a..04f442f6c4 100644 --- a/applications/unit_tests/subghz/subghz_test.c +++ b/applications/unit_tests/subghz/subghz_test.c @@ -13,7 +13,7 @@ #define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo") #define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s") #define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub") -#define TEST_RANDOM_COUNT_PARSE 188 +#define TEST_RANDOM_COUNT_PARSE 196 #define TEST_TIMEOUT 10000 static SubGhzEnvironment* environment_handler; @@ -412,6 +412,13 @@ MU_TEST(subghz_decoder_honeywell_wdb_test) { "Test decoder " SUBGHZ_PROTOCOL_HONEYWELL_WDB_NAME " error\r\n"); } +MU_TEST(subghz_decoder_magellen_test) { + mu_assert( + subghz_decoder_test( + EXT_PATH("unit_tests/subghz/magellen_raw.sub"), SUBGHZ_PROTOCOL_MAGELLEN_NAME), + "Test decoder " SUBGHZ_PROTOCOL_MAGELLEN_NAME " error\r\n"); +} + //test encoders MU_TEST(subghz_encoder_princeton_test) { mu_assert( @@ -515,6 +522,12 @@ MU_TEST(subghz_encoder_honeywell_wdb_test) { "Test encoder " SUBGHZ_PROTOCOL_HONEYWELL_WDB_NAME " error\r\n"); } +MU_TEST(subghz_encoder_magellen_test) { + mu_assert( + subghz_encoder_test(EXT_PATH("unit_tests/subghz/magellen.sub")), + "Test encoder " SUBGHZ_PROTOCOL_MAGELLEN_NAME " error\r\n"); +} + MU_TEST(subghz_random_test) { mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n"); } @@ -552,6 +565,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_decoder_doitrand_test); MU_RUN_TEST(subghz_decoder_phoenix_v2_test); MU_RUN_TEST(subghz_decoder_honeywell_wdb_test); + MU_RUN_TEST(subghz_decoder_magellen_test); MU_RUN_TEST(subghz_encoder_princeton_test); MU_RUN_TEST(subghz_encoder_came_test); @@ -570,6 +584,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_encoder_doitrand_test); MU_RUN_TEST(subghz_encoder_phoenix_v2_test); MU_RUN_TEST(subghz_encoder_honeywell_wdb_test); + MU_RUN_TEST(subghz_encoder_magellen_test); MU_RUN_TEST(subghz_random_test); subghz_test_deinit(); diff --git a/assets/unit_tests/subghz/magellen.sub b/assets/unit_tests/subghz/magellen.sub new file mode 100644 index 0000000000..3317fd4bce --- /dev/null +++ b/assets/unit_tests/subghz/magellen.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz Key File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: Magellen +Bit: 32 +Key: 00 00 00 00 37 AE 48 28 diff --git a/assets/unit_tests/subghz/magellen_raw.sub b/assets/unit_tests/subghz/magellen_raw.sub new file mode 100644 index 0000000000..0d70576bab --- /dev/null +++ b/assets/unit_tests/subghz/magellen_raw.sub @@ -0,0 +1,8 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: RAW +RAW_Data: 29262 361 -68 2635 -66 24113 -66 1131 -100 4157 -66 26253 -130 621 -18438 99 -298 231 -66 197 -496 753 -230 7503 -16526 65 -396 65 -296 99 -196 293 -64 429 -132 397 -66 329 -66 37701 -66 13475 -100 54967 -64 18209 -18340 97 -462 197 -98 587 -232 97 -100 259 -98 197 -262 297 -64 557 -100 599 -100 333 -234 42493 -13212 6449 -206 173 -214 217 -176 195 -218 181 -218 181 -182 217 -182 217 -176 187 -214 215 -180 217 -182 217 -182 217 -178 185 -424 1177 -388 387 -240 381 -214 181 -398 211 -380 419 -176 217 -394 203 -394 205 -380 189 -402 421 -168 219 -398 393 -190 191 -398 205 -406 185 -402 381 -212 215 -362 241 -378 421 -176 377 -218 197 -378 427 -210 393 -172 429 -172 397 -212 217 -362 389 -228 197 -372 417 -204 395 -210 181 -398 391 -192 201 -216888 761 -200 299 -166 695 -132 15435 -66 5611 -66 21049 -66 4947 -66 2355 -66 1921 -100 2223 -100 2107 -100 397 -98 3643 -66 5301 -98 14205 -66 37371 -246 175 -216 179 -216 177 -224 149 -246 159 -228 181 -212 201 -204 159 -244 151 -254 169 -214 181 -210 197 -182 181 -454 1141 -444 357 -228 361 -246 177 -396 209 -412 367 -188 187 -434 201 -394 185 -406 193 -402 377 -238 181 -386 381 -234 153 -424 205 -412 157 -412 383 -240 181 -398 203 -392 385 -236 371 -212 179 -400 383 -240 359 -210 375 -220 381 -246 175 -394 383 -240 181 -398 363 -222 379 -246 175 -394 383 -204 217 -182856 99 -66 99 -300 133 -402 65 -198 99 -328 65 -100 491 -164 593 -100 3547 -64 361 -66 789 -68 2521 -66 22883 -66 2659 -98 3309 -130 3789 -100 9689 -17178 99 -1388 65 -266 197 -100 131 -134 99 -232 627 -130 233 -66 1949 -100 14567 -198 165 -256 181 -208 159 -214 183 -220 163 -244 149 -246 159 -236 181 -254 141 -226 151 -246 157 -228 181 -212 201 -400 1163 -428 379 -230 355 -244 177 -396 207 -412 367 -222 157 -418 189 -410 207 -412 171 -430 357 -226 165 -404 413 -204 181 -428 173 -428 169 -426 353 -236 173 -414 173 -408 381 -244 337 -222 201 -408 397 -208 393 -204 395 -208 359 -246 177 -394 387 -200 205 -380 415 -202 395 -208 181 -432 357 -226 169 -195084 65 -300 763 -66 297 -364 593 -68 2883 -66 1357 -68 363 -98 3841 -66 3119 -66 5153 -66 4023 -268 143 -246 133 -290 141 -250 139 -254 141 -226 181 -248 137 -254 143 -252 139 -252 143 -230 181 -250 139 -254 145 -436 1135 -448 349 -240 347 -254 157 -434 167 -426 377 -226 157 -434 167 -426 155 -440 163 -434 375 -206 215 -380 381 -234 153 +RAW_Data: -424 205 -412 159 -412 381 -240 181 -398 203 -392 387 -236 369 -212 179 -400 383 -240 359 -244 339 -222 381 -246 175 -394 383 -240 181 -398 363 -222 381 -244 175 -392 383 -240 181 -184002 99 -360 63 -330 65 -132 129 -232 97 -198 295 -328 6031 -66 831 -132 3417 -66 2187 -64 2183 -100 6535 -66 1127 -66 2569 -66 2031 -66 2271 -66 2183 -66 3815 -66 3803 -66 493 -66 1909 -66 1627 -98 4805 -17512 67 -2164 131 -498 265 -430 163 -98 97 -64 99 -230 99 -100 229 -230 165 -196 63 -132 99 -66 927 -66 14955 -66 19621 -68 2627 -66 14305 -68 23247 -66 2891 -66 3941 -66 3021 -212 173 -242 181 -218 181 -214 181 -208 157 -250 141 -248 181 -218 179 -214 179 -210 159 -250 179 -214 181 -218 181 -404 1153 -404 389 -244 375 -192 181 -436 161 -414 383 -240 181 -398 205 -392 201 -394 205 -394 365 -246 177 -396 383 -204 217 -398 171 -426 167 -428 353 -242 173 -420 173 -408 373 -220 403 -208 175 -422 381 -194 399 -228 357 -246 355 -210 215 -400 387 -208 181 -398 391 -226 353 -246 177 -398 383 -204 217 -185098 163 -166 525 -98 293 -100 63 -66 229 -66 1183 -66 1507 -66 3089 -98 30187 -66 2847 -19112 133 -364 131 -394 97 -166 295 -66 229 -164 227 -66 263 -130 623 -98 2071 -66 493 -66 787 -98 691 -64 10249 -132 3879 -66 1949 -66 3453 -198 23157 -66 2845 -100 1193 -66 1587 -100 3797 -98 3187 -100 3319 -66 22119 -98 5513 -226 155 -244 153 -256 131 -248 151 -246 159 -262 121 -274 133 -272 127 -244 153 -254 167 -248 145 -244 133 -252 177 -398 1169 -418 381 -238 359 -242 141 -430 169 -426 357 -274 139 -422 171 -442 173 -428 167 -426 353 -236 171 -416 379 -226 149 -436 161 -438 173 -406 381 -234 153 -424 205 -380 389 -244 359 -206 215 -384 381 -246 335 -224 383 -246 355 -244 179 -404 385 -206 181 -432 359 -226 355 -246 175 -398 383 -240 181 -179760 97 -168 727 -66 97 -332 1389 -66 2793 -66 4955 -100 12453 -100 2425 -66 21965 -66 3809 -68 1683 -66 3095 -66 2153 -64 999 -208 173 -220 181 -214 191 -196 181 -212 183 -220 191 -212 181 -214 191 -198 181 -212 181 -222 191 -212 181 -214 191 -416 1167 -424 369 -220 373 -210 209 -390 207 -376 403 -190 187 -418 189 -408 209 -412 173 -428 357 -226 169 -404 399 -208 179 -412 209 -396 169 -428 355 -230 201 -378 205 -406 381 -244 339 -222 193 -400 413 -204 393 -208 347 -220 401 -210 175 -422 383 -202 217 -398 365 -222 377 -246 175 -390 385 -204 217 -179890 165 -1552 131 -164 65 +RAW_Data: -1448 361 -17056 131 -134 233 -1462 131 -166 953 -100 261 -164 5077 -272 137 -268 143 -252 141 -248 143 -246 159 -252 141 -244 143 -290 107 -276 145 -244 131 -250 179 -248 143 -252 141 -414 1165 -424 373 -236 359 -242 145 -434 169 -428 355 -230 169 -442 173 -434 157 -406 193 -402 379 -238 181 -422 335 -252 157 -434 167 -428 185 -406 381 -208 211 -390 207 -410 381 -200 373 -236 171 -414 383 -202 393 -210 379 -220 373 -208 211 -390 383 -204 217 -398 365 -220 379 -244 175 -394 381 -240 181 -161030 97 -166 167 -930 593 -2670 1091 -132 229 -98 461 -164 1649 -66 6311 -100 44723 -16832 67 -2656 131 -132 99 -132 263 -100 399 -68 893 -18950 99 -164 165 -198 525 -998 335 -66 565 -66 1057 -17880 97 -360 195 -262 131 -332 625 -98 197 -230 455 -98 9343 -16498 67 -368 131 -598 65 -1066 333 -300 789 -130 757 -66 87207 -16554 97 -3520 97 -786 591 -64 461 -98 21495 -66 24811 -18448 131 -296 491 -134 163 -760 1091 -230 893 -66 927 -68 4581 -68 32965 -64 45217 -17292 131 -1684 231 -132 327 -64 163 -330 263 -230 25751 diff --git a/assets/unit_tests/subghz/test_random_raw.sub b/assets/unit_tests/subghz/test_random_raw.sub index 0a7d529ce6..06dfb9b4b6 100644 --- a/assets/unit_tests/subghz/test_random_raw.sub +++ b/assets/unit_tests/subghz/test_random_raw.sub @@ -128,3 +128,14 @@ RAW_Data: 161 -302 147 -320 331 -162 171 -314 161 -312 163 -300 175 -296 195 -31 RAW_Data: 163 -300 175 -298 169 -318 177 -290 191 -298 165 -314 161 -310 189 -284 185 -292 189 -298 193 -284 189 -310 163 -312 497 -460 145 -320 325 -170 169 -290 333 -162 171 -314 307 -158 317 -168 169 -290 333 -162 171 -314 281 -182 159 -296 189 -300 165 -312 309 -182 313 -168 143 -318 331 -162 301 -148 319 -196 139 -314 165 -336 137 -338 135 -338 161 -312 159 -294 327 -160 173 -314 163 -312 159 -312 163 -300 175 -302 195 -312 163 -312 159 -312 163 -300 175 -298 169 -318 175 -292 189 -300 165 -312 161 -312 187 -284 185 -292 189 -300 193 -284 187 -312 161 -314 471 -486 167 -314 313 -152 159 -300 335 -162 169 -308 321 -156 329 -170 127 -318 321 -176 155 -300 333 -164 169 -302 165 -314 161 -310 329 -168 299 -166 151 -328 311 -154 331 -168 299 -178 143 -318 153 -322 167 -332 149 -320 151 -318 165 -304 321 -156 181 -290 189 -300 173 -294 177 -294 189 -302 173 -294 177 -294 189 -302 173 -294 177 -318 193 -278 173 -294 179 -292 191 -302 173 -294 177 -294 189 -302 173 -320 177 -294 195 -278 175 -318 491 -460 163 -314 333 -158 159 -294 327 -160 171 -316 311 -180 307 -170 141 -318 331 -162 143 -316 309 -182 157 -294 189 -302 165 -312 309 -182 313 -168 141 -318 331 -164 299 -148 321 -194 141 -314 165 -334 137 -338 135 -338 161 -312 159 -294 329 -158 173 -314 163 -310 161 -306 173 -314 165 -304 193 -284 187 -286 189 -276 197 -294 193 -310 163 -312 161 -310 163 -300 175 -296 193 -310 165 -284 187 -310 163 -300 175 -300 169 -318 177 -316 483 -466 187 -292 341 -134 171 -308 319 -150 179 -300 333 -164 309 -162 171 -316 313 -152 153 -316 327 -160 171 -316 163 -310 161 -312 307 -166 337 -136 171 -322 305 -164 299 -174 301 -194 141 -318 165 -336 137 -338 161 -310 163 -300 149 -320 331 -162 171 -314 161 -312 163 -300 173 -296 195 -310 163 -312 159 -312 163 -312 159 -296 189 -302 165 -312 189 -284 189 -284 185 -294 189 -296 165 -314 161 -310 189 -284 187 -294 189 -298 193 -284 485 -494 167 -298 321 -150 177 -312 313 -168 171 -290 333 -162 299 -176 151 -316 325 -162 171 -316 289 -176 151 -314 189 -296 165 -314 309 -182 305 -170 141 -318 333 -162 299 -150 319 -194 141 -314 165 -334 137 -340 133 -338 161 -302 149 -320 329 -164 171 -286 187 -312 163 -300 173 -298 193 -310 163 -312 159 -312 163 -312 159 -296 189 -302 191 -286 187 -284 189 -312 159 -292 191 -296 165 -314 161 -310 189 -284 187 -292 RAW_Data: 189 -300 193 -284 485 -494 167 -298 321 -150 177 -300 327 -150 167 -328 305 -160 319 -168 171 -290 333 -162 171 -314 281 -184 159 -296 189 -300 165 -314 307 -184 311 -170 141 -318 333 -162 299 -150 319 -194 139 -314 167 -334 135 -340 133 -338 163 -312 159 -294 327 -158 173 -314 163 -312 159 -312 165 -298 177 -302 193 -314 163 -310 161 -312 163 -300 173 -300 167 -318 177 -292 189 -300 165 -312 161 -312 187 -284 185 -292 189 -300 191 -286 187 -284 189 -300 487 -484 149 -320 333 -138 171 -322 321 -154 151 -316 327 -160 311 -164 173 -312 307 -160 161 -298 355 -132 173 -314 163 -310 161 -312 335 -170 311 -164 143 -322 307 -164 323 -150 301 -196 141 -318 165 -334 137 -338 161 -312 161 -302 147 -320 331 -162 173 -312 161 -312 163 -300 173 -298 195 -310 163 -312 159 -312 163 -312 159 -296 189 -300 193 -284 189 -284 189 -284 185 -294 189 -296 165 -314 161 -312 189 -284 185 -294 189 -298 193 -286 485 -468 193 -296 323 -150 147 -340 313 -168 171 -292 331 -164 299 -174 151 -316 325 -160 173 -316 289 -176 149 -316 189 -294 165 -314 309 -182 307 -170 141 -318 331 -164 299 -148 321 -194 139 -314 167 -306 165 -338 133 -338 163 -312 159 -294 327 -160 173 -314 163 -312 161 -310 165 -300 175 -300 169 -318 177 -290 189 -298 165 -314 187 -284 189 -312 159 -294 189 -298 165 -314 161 -310 161 -306 173 -316 193 -280 191 -312 159 -312 163 -300 515 -460 161 -312 305 -190 135 -328 329 -134 201 -286 309 -182 311 -168 143 -318 331 -162 143 -316 309 -182 157 -294 189 -300 165 -312 309 -184 311 -168 143 -318 331 -162 301 -148 319 -196 139 -314 165 -334 137 -340 159 -312 163 -300 149 -318 331 -162 173 -312 161 -312 163 -300 175 -296 195 -310 163 -312 159 -312 163 -300 173 -296 193 -312 163 -312 159 -312 163 -312 161 -298 189 -300 165 -312 161 -312 189 -312 159 -292 191 -300 191 -286 485 -468 193 -298 323 -148 147 -342 323 -160 173 -314 289 -176 297 -196 139 -314 331 -162 143 -314 311 -180 157 -292 191 -300 165 -312 311 -182 309 -170 141 -318 333 -162 299 -150 319 -194 141 -314 165 -334 137 -338 161 -312 161 -312 159 -294 329 -158 173 -314 163 -310 161 -312 165 -298 175 -304 193 -312 163 -310 161 -310 163 -302 173 -300 169 -318 175 -292 189 -300 165 -312 161 -310 189 -278 173 -316 195 -280 191 -312 159 -312 163 -300 515 -460 163 -310 305 -190 137 -328 329 -134 199 -288 309 -182 311 -168 143 -318 RAW_Data: 331 -162 143 -316 309 -182 157 -292 191 -300 165 -312 309 -182 313 -168 141 -318 331 -164 299 -174 295 -194 141 -314 165 -334 137 -340 133 -338 163 -312 159 -292 327 -160 171 -316 163 -310 161 -312 165 -298 175 -304 193 -312 163 -312 159 -312 163 -300 175 -300 169 -316 177 -292 189 -298 167 -312 161 -310 189 -278 173 -316 193 -282 191 -312 159 -312 163 -300 515 -460 163 -310 305 -190 137 -326 331 -132 201 -286 309 -184 309 -170 141 -318 333 -162 143 -314 311 -180 159 -294 189 -300 165 -312 309 -184 311 -168 143 -318 331 -162 301 -148 319 -196 139 -314 165 -336 135 -340 159 -312 163 -300 149 -320 329 -164 171 -314 159 -312 163 -300 175 -296 195 -310 163 -312 159 -312 163 -300 175 -294 195 -310 163 -312 161 -310 163 -300 175 -298 169 -318 153 -314 191 -296 193 -286 187 -284 189 -312 161 -294 509 -468 159 -298 335 -162 169 -304 323 -150 175 -300 335 -162 311 -160 173 -316 313 -152 151 -316 327 -160 171 -316 163 -312 159 -312 307 -168 335 -138 169 -322 305 -164 299 -176 299 -194 141 -316 167 -334 137 -340 159 -312 161 -302 147 -320 331 -162 173 -312 161 -312 163 -300 175 -296 193 -310 165 -310 161 -312 161 -302 173 -296 195 -310 163 -312 161 -310 163 -300 175 -298 169 -318 177 -290 189 -296 193 -286 187 -310 163 -300 175 -296 501 -484 161 -288 347 -154 151 -316 325 -160 173 -314 313 -152 301 -196 141 -314 331 -162 143 -316 309 -182 157 -294 189 -300 165 -314 309 -182 311 -168 143 -318 331 -162 301 -148 319 -196 139 -314 165 -336 137 -338 133 -338 163 -312 159 -294 327 -158 173 -316 161 -312 159 -312 163 -298 177 -302 193 -314 163 -312 159 -312 163 -300 175 -298 169 -318 177 -290 191 -298 165 -314 161 -310 189 -284 193 -292 179 -308 167 -314 161 -312 189 -302 481 -460 173 -320 303 -168 169 -294 331 -164 171 -314 307 -160 319 -168 169 -292 331 -162 143 -342 283 -182 159 -294 189 -302 165 -312 309 -184 311 -168 143 -318 331 -162 299 -150 319 -194 141 -314 165 -336 135 -340 133 -338 163 -312 159 -294 327 -158 173 -316 161 -312 159 -312 165 -298 177 -302 193 -312 163 -312 161 -310 163 -314 161 -296 189 -302 165 -312 187 -284 189 -284 185 -294 189 -296 165 -314 187 -284 189 -302 173 -294 195 -310 491 -458 163 -318 319 -156 153 -314 327 -160 171 -316 311 -152 327 -170 141 -316 331 -164 143 -314 309 -182 157 -294 189 -300 165 -314 309 -182 311 -168 143 -316 333 -162 299 -150 +RAW_Data: 15041 -66 15883 -66 12643 -66 12681 -66 3413 -68 2713 -68 33389 -66 1445 -66 1279 -68 1027 -66 6911 -98 25229 -66 3967 -100 3019 -100 6131 -66 955 -66 3605 -66 12411 -98 1419 -66 3593 -68 2753 -66 2457 -66 6007 -66 627 -100 1597 -66 3071 -98 22749 -66 333 -66 12829 -66 4313 -132 855 -66 44097 -64 20391 -98 29999 -66 3539 -98 557 -66 1489 -100 4081 -100 3857 -64 2895 -132 2261 -166 3089 -66 2429 -68 34467 -66 3585 -66 3087 -66 3329 -132 5287 -66 1063 -98 15259 -100 2535 -66 995 -66 13057 -100 24233 -68 531 -100 26415 -66 1761 -100 2717 -66 4071 -100 12191 -66 23367 -68 2323 -66 19809 -248 245 -1388 255 -242 275 -1358 273 -1370 277 -246 277 -1368 275 -246 275 -1362 275 -244 275 -1364 275 -244 275 -1362 275 -244 275 -1328 273 -278 273 -1358 275 -246 275 -238 263 -1384 275 -246 273 -1358 275 -244 273 -1358 275 -246 275 -1360 275 -1344 277 -246 275 -1358 275 -244 275 -234 263 -1382 277 -1344 277 -246 279 -1362 275 -246 271 -234 261 -1380 275 -246 273 -1360 275 -246 275 -1366 277 -1340 277 -248 279 -238 263 -1382 275 -1344 277 -246 279 -1364 277 -244 275 -234 263 -1382 277 -244 273 -1358 275 -1344 277 -248 279 -1368 275 -244 273 -1360 239 -280 271 -1358 275 -244 275 -1358 275 -174 269 -10298 289 -2660 267 -238 299 -1356 275 -244 275 -1356 275 -1344 277 -248 277 -1360 275 -246 275 -1328 309 -244 273 -1358 277 -244 275 -1356 275 -246 273 -1326 309 -244 275 -1356 275 -246 273 -234 263 -1380 277 -246 273 -1326 309 -244 273 -1356 277 -246 277 -1358 275 -1338 279 -248 279 -1364 275 -246 273 -234 261 -1380 277 -1344 279 -250 277 -1330 309 -244 273 -232 261 -1384 275 -246 273 -1356 275 -248 275 -1360 275 -1340 279 -248 277 -236 263 -1380 277 -1342 279 -248 279 -1366 275 -246 273 -234 263 -1380 275 -246 275 -1358 275 -1340 279 -248 281 -1336 309 -244 273 -1358 275 -246 273 -1360 275 -244 273 -1358 275 -176 267 -10306 257 -2646 299 -234 301 -1354 277 -246 275 -1356 277 -1340 279 -250 279 -1332 309 -244 275 -1358 275 -248 273 -1326 309 -246 273 -1326 309 -244 275 -1356 277 -248 275 -1328 309 -246 273 -234 261 -1382 277 -246 277 -1326 309 -244 275 -1358 277 -246 277 -1356 277 -1346 277 -250 277 -1358 277 -246 275 -234 263 -1382 279 -1346 279 -248 281 -1330 307 -246 273 -236 261 -1380 277 -246 277 -1360 277 -246 277 -1360 275 -1344 279 -248 279 -236 263 -1384 277 -1340 279 -250 281 -1338 307 -246 271 -234 261 -1384 277 -246 275 -1356 277 -1340 279 -250 283 -1336 309 -246 273 -1356 277 -246 273 -1360 277 -246 +RAW_Data: 275 -1328 309 -174 269 -10296 289 -2648 267 -238 299 -1356 277 -246 275 -1324 307 -1342 279 -250 277 -1330 309 -244 275 -1362 277 -244 275 -1356 275 -248 273 -1328 309 -244 273 -1328 309 -244 275 -1360 277 -246 275 -234 259 -1384 277 -246 275 -1360 275 -246 273 -1358 277 -248 277 -1362 275 -1344 277 -248 277 -1328 307 -246 273 -236 261 -1384 277 -1348 279 -248 279 -1360 277 -246 273 -234 263 -1388 275 -246 275 -1360 277 -248 279 -1368 277 -1344 279 -248 279 -240 265 -1386 275 -1342 279 -286 247 -1372 275 -248 275 -238 265 -1386 277 -248 275 -1360 275 -1344 277 -286 247 -1374 275 -246 275 -1362 277 -246 275 -1360 277 -248 275 -1326 307 -174 269 -10290 287 -2654 269 -236 301 -1352 275 -248 273 -1326 311 -1340 277 -248 277 -1328 309 -244 273 -1358 275 -244 275 -1326 309 -244 273 -1356 277 -244 273 -1356 275 -246 275 -1358 275 -244 275 -234 261 -1382 277 -246 273 -1358 275 -246 273 -1360 277 -246 273 -1324 309 -1340 277 -248 277 -1328 307 -246 271 -234 259 -1382 277 -1346 279 -248 277 -1330 309 -244 271 -232 259 -1382 277 -244 275 -1356 277 -248 273 -1354 277 -1342 277 -248 275 -236 261 -1380 277 -1344 277 -248 279 -1330 307 -246 273 -234 261 -1378 277 -246 273 -1356 277 -1342 277 -248 277 -1330 309 -244 273 -1322 307 -246 273 -1326 309 -244 273 -1322 309 -176 267 -10298 257 -2682 265 -236 299 -1324 309 -248 273 -1324 311 -1342 277 -246 279 -1360 277 -244 275 -1362 275 -244 275 -1358 275 -244 275 -1360 275 -246 273 -1360 275 -244 277 -1360 275 -246 273 -234 263 -1384 275 -246 273 -1358 275 -246 275 -1360 277 -246 277 -1356 277 -1342 279 -248 277 -1364 275 -244 275 -234 261 -1384 275 -1344 277 -250 279 -1366 275 -246 273 -236 263 -1384 277 -246 275 -1358 277 -246 277 -1362 277 -1342 279 -248 279 -236 265 -1382 277 -1346 277 -248 281 -1366 275 -246 275 -234 265 -1384 275 -246 273 -1358 277 -1344 279 -248 279 -1364 275 -244 275 -1324 309 -246 273 -1324 307 -246 273 -1326 309 -174 267 -118796 133 -100 131 -892 329 -166 199 -132 131 -166 99 -100 265 -264 4663 -134 4889 -100 365 -98 5921 -100 5903 -68 4877 -98 2953 -98 1645 -64 1687 -66 981 -98 10769 -66 18319 -66 4831 -66 13301 -66 893 -132 5967 -100 15949 -66 3749 -66 497 -100 625 -66 1147 -66 469 -66 1261 -66 3651 -100 265 -100 26741 -68 6873 -66 4485 -100 2667 -68 3159 -68 2857 -132 2655 -66 12903 -66 1277 -66 1711 -66 787 -100 1327 -198 727 -64 1677 -100 1187 -66 1019 -66 891 -66 4303 -100 11297 -66 3923 -254 253 -1380 247 -292 253 -1344 +RAW_Data: 277 -1346 277 -250 279 -1364 275 -244 275 -1362 275 -244 275 -1356 275 -246 273 -1358 241 -278 273 -1356 275 -246 273 -1360 275 -246 273 -234 263 -1382 275 -244 273 -1358 275 -246 273 -1360 275 -246 273 -1358 275 -1340 277 -248 277 -1362 275 -246 273 -234 261 -1380 277 -1344 277 -248 279 -1362 275 -244 273 -236 261 -1380 275 -244 275 -1360 275 -246 275 -1358 275 -1346 277 -246 275 -236 263 -1384 275 -1342 277 -248 277 -1364 277 -244 273 -234 261 -1378 277 -246 273 -1356 277 -1340 277 -248 281 -1334 307 -246 271 -1356 275 -246 273 -1358 275 -244 273 -1326 309 -174 267 -10296 257 -2650 297 -232 263 -1384 277 -244 273 -1358 275 -1340 279 -248 279 -1328 309 -244 275 -1328 307 -244 273 -1356 275 -244 275 -1358 275 -246 273 -1324 309 -244 275 -1328 307 -244 273 -234 261 -1382 275 -246 273 -1326 309 -244 273 -1358 275 -246 273 -1358 275 -1338 279 -248 279 -1330 309 -244 273 -232 261 -1380 277 -1344 279 -248 279 -1330 309 -244 271 -234 261 -1382 275 -246 273 -1358 277 -244 275 -1330 309 -1338 277 -246 277 -236 263 -1380 277 -1342 277 -248 279 -1364 275 -246 273 -232 261 -1380 275 -248 275 -1328 307 -1338 277 -248 279 -1334 309 -244 271 -1358 275 -244 275 -1324 307 -246 271 -1328 309 -174 265 -10270 291 -2640 297 -232 297 -1350 277 -248 275 -1326 309 -1340 277 -248 277 -1328 309 -244 273 -1358 275 -246 273 -1326 309 -244 273 -1354 275 -246 273 -1330 307 -244 273 -1358 275 -246 273 -234 263 -1380 275 -246 273 -1358 275 -246 273 -1360 275 -244 273 -1358 275 -1340 277 -248 279 -1364 275 -244 273 -232 261 -1380 277 -1342 279 -250 279 -1332 307 -244 271 -234 261 -1378 277 -246 273 -1358 275 -248 275 -1360 275 -1340 277 -248 275 -236 263 -1382 277 -1344 277 -246 277 -1364 275 -246 273 -234 259 -1380 275 -246 273 -1362 275 -1342 275 -248 277 -1334 309 -244 271 -1356 275 -244 275 -1326 307 -244 273 -1356 275 -176 267 -10290 289 -2644 267 -238 301 -1320 309 -246 273 -1324 309 -1340 277 -248 277 -1328 307 -246 273 -1326 307 -246 273 -1324 309 -246 273 -1322 309 -246 273 -1322 307 -246 275 -1326 309 -246 273 -234 259 -1382 275 -246 275 -1322 309 -246 273 -1326 309 -246 273 -1326 309 -1340 277 -248 275 -1326 309 -246 273 -232 261 -1380 279 -1346 277 -250 277 -1328 309 -244 271 -232 261 -1380 277 -246 273 -1358 275 -248 273 -1328 307 -1340 277 -248 277 -236 261 -1380 277 -1344 277 -248 279 -1328 309 -244 275 -232 261 -1378 277 -248 273 -1326 309 -1344 277 -248 277 -1358 277 -246 273 -1328 307 -244 271 -1324 309 -244 +RAW_Data: 273 -1324 309 -174 267 -10270 289 -2638 297 -234 297 -1352 275 -248 275 -1328 307 -1340 277 -248 275 -1330 309 -244 273 -1358 275 -244 275 -1326 309 -244 271 -1356 275 -244 275 -1326 307 -246 273 -1326 309 -244 273 -234 261 -1378 275 -248 275 -1326 309 -244 271 -1356 277 -248 273 -1328 309 -1338 277 -248 277 -1328 309 -244 271 -232 261 -1380 277 -1348 279 -248 277 -1328 307 -246 271 -234 259 -1384 275 -244 275 -1356 277 -246 275 -1326 309 -1344 275 -248 275 -236 261 -1378 277 -1342 277 -250 279 -1334 309 -244 271 -232 261 -1380 277 -246 273 -1326 307 -1344 277 -248 277 -1328 309 -246 273 -1326 309 -244 271 -1324 309 -244 273 -1324 307 -176 267 -10288 287 -2618 299 -236 299 -1354 277 -244 273 -1326 307 -1340 279 -248 275 -1328 309 -244 275 -1326 309 -246 273 -1324 307 -246 273 -1322 309 -244 273 -1322 309 -244 275 -1328 309 -246 273 -232 261 -1380 277 -246 275 -1324 309 -244 273 -1356 277 -246 275 -1324 309 -1340 279 -246 277 -1328 309 -244 273 -232 261 -1382 277 -1344 279 -250 277 -1324 309 -246 273 -234 261 -1380 277 -246 273 -1358 277 -246 273 -1328 309 -1340 277 -248 275 -236 261 -1380 275 -1344 279 -248 279 -1360 277 -244 273 -234 261 -1380 277 -246 275 -1354 277 -1344 277 -248 277 -1328 311 -246 273 -1324 307 -244 273 -1324 309 -244 273 -1320 309 -176 269 -118210 761 -168 267 -66 563 -132 99 -132 3543 -66 5345 -100 4355 -66 4617 -68 20503 -166 2379 -132 293 -98 4117 -66 1151 -98 3353 -66 3485 -66 2491 -66 6133 -66 233 -68 16307 -68 16959 -98 357 -66 5419 -134 799 -100 327 -100 791 -66 2481 -66 963 -100 3481 -98 1679 -134 2473 -100 227 -68 3087 -66 11527 -130 4305 -98 435 -66 563 -100 2887 -100 267 -66 1787 -66 9655 -66 4793 -100 2119 -66 359 -98 1313 -132 3393 -234 995 -66 2681 -98 99 -130 1379 -100 3757 -100 21695 -132 5135 -100 693 -98 4631 -100 2325 -68 4937 -66 10409 -98 897 -100 1287 -66 2565 -66 3753 -66 4055 -66 2023 -68 1961 -68 629 -66 431 -66 5039 -66 2155 -100 2673 -66 1163 -98 6539 -100 825 -66 1197 -100 3053 -66 13973 -68 15515 -100 1861 -66 1027 -66 797 -98 959 -98 787 -132 787 -64 3811 -132 1747 -66 6683 -66 1033 -68 24927 -66 1259 -100 1125 -68 663 -66 1687 -66 4357 -132 4567 -66 3969 -98 3317 -132 433 -134 6043 -66 3249 -100 431 -98 2367 -100 11265 -66 5085 -68 2355 -64 1815 -66 1395 -274 241 -1366 275 -244 275 -1362 275 -1338 277 -284 243 -1368 239 -278 275 -1362 275 -244 275 -1360 241 -278 273 -1356 275 -246 275 -1360 239 -280 275 -1360 +RAW_Data: 275 -244 275 -234 263 -1386 239 -280 273 -1356 275 -244 273 -1360 275 -244 277 -1364 275 -1336 277 -248 277 -1366 275 -244 273 -234 263 -1386 275 -1340 277 -248 279 -1364 275 -244 275 -234 263 -1384 273 -244 275 -1358 275 -244 275 -1364 275 -1342 275 -248 277 -236 265 -1384 275 -1340 277 -282 243 -1366 275 -246 273 -236 263 -1382 277 -244 275 -1358 275 -1342 277 -248 277 -1364 275 -246 275 -1360 239 -280 273 -1358 241 -278 275 -1356 275 -210 233 -10302 257 -2652 297 -232 297 -1354 277 -244 275 -1358 275 -1340 279 -248 279 -1360 275 -246 275 -1360 275 -246 273 -1360 275 -244 275 -1328 309 -242 273 -1324 309 -244 275 -1360 275 -246 273 -234 261 -1384 275 -246 273 -1358 275 -244 275 -1358 277 -248 273 -1358 275 -1340 279 -248 277 -1334 307 -242 273 -232 261 -1380 277 -1348 277 -250 277 -1364 275 -244 275 -234 261 -1380 277 -244 275 -1358 277 -246 277 -1360 277 -1342 275 -248 275 -236 263 -1380 277 -1344 277 -248 279 -1368 275 -244 275 -232 261 -1382 277 -244 275 -1356 275 -1344 277 -248 279 -1362 275 -246 275 -1360 275 -246 273 -1356 275 -246 273 -1356 275 -176 267 -10302 257 -2648 299 -234 297 -1352 277 -246 275 -1326 309 -1340 279 -248 277 -1330 309 -244 275 -1328 309 -244 273 -1324 309 -244 275 -1324 309 -246 273 -1324 307 -246 275 -1328 309 -244 273 -234 261 -1378 277 -248 275 -1328 309 -244 273 -1356 277 -248 275 -1326 309 -1344 277 -248 275 -1326 309 -246 273 -234 259 -1380 277 -1348 281 -248 279 -1328 307 -246 273 -234 259 -1382 277 -246 275 -1360 275 -248 275 -1324 309 -1340 279 -248 277 -238 261 -1382 277 -1344 277 -248 279 -1330 311 -244 273 -234 259 -1378 277 -248 275 -1326 309 -1340 279 -248 279 -1336 307 -246 271 -1324 309 -244 275 -1324 307 -246 273 -1326 309 -174 269 -10296 257 -2648 299 -234 297 -1352 277 -248 273 -1326 309 -1342 277 -248 277 -1328 309 -246 275 -1328 309 -244 273 -1326 309 -244 273 -1322 309 -244 273 -1328 307 -244 275 -1328 309 -246 273 -234 261 -1382 277 -246 275 -1326 309 -244 273 -1352 277 -248 275 -1330 309 -1340 277 -248 277 -1328 309 -244 275 -232 261 -1384 277 -1342 279 -250 279 -1328 309 -244 273 -234 263 -1380 277 -246 273 -1360 277 -246 275 -1326 309 -1340 277 -250 277 -236 263 -1382 277 -1342 277 -248 279 -1362 277 -246 273 -234 263 -1382 277 -244 275 -1356 277 -1340 279 -248 279 -1362 275 -246 275 -1328 307 -246 273 -1356 275 -246 273 -1356 275 -174 269 -10292 287 -2650 269 -236 301 -1354 275 -248 273 -1358 275 -1340 279 -248 277 -1332 307 -246 275 -1328 +RAW_Data: 309 -244 273 -1324 309 -244 273 -1356 275 -246 273 -1358 275 -244 277 -1330 309 -244 273 -234 261 -1382 277 -244 275 -1358 275 -246 273 -1356 277 -248 275 -1360 275 -1340 277 -248 277 -1360 275 -246 273 -236 261 -1382 279 -1344 279 -248 279 -1360 277 -244 273 -234 261 -1380 277 -246 275 -1360 277 -246 273 -1360 275 -1342 279 -248 275 -236 263 -1382 275 -1344 279 -248 279 -1362 277 -246 273 -234 263 -1380 277 -246 275 -1356 275 -1342 277 -248 281 -1336 307 -246 271 -1354 277 -246 275 -1328 307 -244 273 -1352 277 -176 269 -10300 257 -2650 299 -232 297 -1354 277 -246 275 -1356 277 -1342 277 -248 279 -1328 309 -244 275 -1360 275 -246 273 -1328 307 -246 273 -1356 277 -246 277 -1326 309 -244 277 -1360 277 -246 273 -234 263 -1384 277 -246 275 -1324 309 -246 275 -1358 277 -246 277 -1360 277 -1344 277 -248 277 -1326 309 -246 273 -236 261 -1382 277 -1348 279 -250 281 -1330 307 -246 273 -234 263 -1386 277 -244 275 -1356 277 -248 277 -1362 277 -1342 277 -250 277 -238 263 -1384 277 -1342 277 -250 281 -1332 309 -246 273 -234 263 -1380 277 -246 275 -1360 277 -1342 279 -248 281 -1334 307 -246 273 -1356 275 -248 275 -1328 309 -244 275 -1324 309 -176 269 -115034 163 -362 67 -894 529 -166 14663 -98 4135 -66 3681 -100 299 -68 9829 -66 3517 -64 21569 -66 3251 -66 2209 -64 23701 -66 3359 -68 1057 -66 723 -66 299 -134 765 -66 589 -98 1687 -134 2153 -66 3081 -68 10447 -66 11643 -66 2451 -66 2277 -66 2897 -66 755 -100 5539 -64 5117 -132 4867 -134 3931 -64 625 -66 1317 -98 11597 -66 2255 -66 1165 -66 1123 -66 6371 -100 699 -68 1811 -66 621 -68 2191 -64 1291 -134 3003 -66 2423 -64 1463 -66 663 -100 1127 -100 6169 -100 489 -100 6087 -100 2027 -66 1195 -66 13195 -66 557 -66 40423 -98 1919 -100 1061 -132 201 -66 2553 -132 12549 -66 1789 -100 921 -134 1067 -66 729 -66 10029 -66 3909 -100 265 -100 16017 -134 21177 -68 2461 -66 2215 -68 1197 -66 5911 -66 2645 -66 3419 -132 16275 -64 5091 -68 2123 -66 2677 -64 10305 -66 12381 -100 427 -166 25331 -66 2457 -66 11859 -248 279 -1368 275 -246 275 -1360 275 -1340 277 -246 279 -1364 239 -278 275 -1358 275 -244 275 -1362 239 -278 273 -1358 239 -280 271 -1360 241 -278 273 -1360 275 -244 275 -234 261 -1384 239 -280 273 -1356 275 -244 273 -1360 275 -244 275 -1358 275 -1344 277 -248 275 -1358 275 -244 273 -236 261 -1384 275 -1342 279 -246 279 -1360 275 -244 275 -234 263 -1384 239 -278 273 -1358 275 -244 275 -1362 275 -1342 275 -248 275 -238 263 -1382 275 -1344 275 -248 +RAW_Data: 277 -1364 275 -244 273 -234 263 -1380 275 -246 273 -1358 275 -1342 277 -246 279 -1366 275 -244 273 -1362 239 -278 239 -1386 275 -246 273 -1360 241 -208 269 -10290 257 -2686 265 -232 265 -1384 275 -246 275 -1358 275 -1344 277 -248 275 -1358 275 -246 275 -1360 277 -244 273 -1326 309 -244 271 -1354 275 -244 275 -1358 275 -246 273 -1358 275 -246 273 -234 263 -1378 275 -246 275 -1360 275 -244 273 -1356 275 -246 275 -1360 275 -1342 277 -246 277 -1360 275 -246 273 -232 261 -1382 277 -1342 279 -248 279 -1360 275 -244 275 -232 261 -1380 277 -244 275 -1356 277 -246 277 -1360 275 -1342 277 -246 275 -236 263 -1384 275 -1342 277 -248 277 -1362 275 -246 273 -234 261 -1378 277 -246 275 -1328 307 -1340 277 -246 279 -1366 275 -244 273 -1326 307 -244 273 -1324 309 -244 273 -1356 275 -174 267 -10304 255 -2648 297 -230 263 -1382 277 -244 275 -1330 307 -1338 277 -248 277 -1330 309 -244 273 -1356 275 -246 273 -1362 275 -244 273 -1356 275 -244 273 -1326 307 -244 273 -1360 273 -246 273 -236 261 -1380 275 -244 275 -1328 307 -244 273 -1358 275 -244 275 -1360 275 -1342 277 -246 277 -1364 275 -244 271 -232 261 -1384 277 -1340 279 -248 279 -1360 275 -246 273 -234 261 -1380 275 -244 275 -1360 277 -244 275 -1356 275 -1342 279 -246 277 -236 263 -1382 275 -1340 277 -248 279 -1366 275 -246 271 -234 261 -1382 277 -244 275 -1354 275 -1342 277 -248 277 -1364 273 -246 273 -1362 275 -244 271 -1360 275 -244 273 -1358 275 -174 267 -10272 289 -2646 265 -262 261 -1382 277 -244 275 -1356 275 -1342 277 -248 277 -1364 275 -244 275 -1360 275 -244 273 -1358 275 -244 273 -1358 275 -244 273 -1326 307 -244 275 -1358 275 -246 273 -234 261 -1382 275 -246 273 -1358 275 -244 273 -1358 275 -246 275 -1360 275 -1338 277 -248 277 -1362 277 -244 271 -234 261 -1380 277 -1344 279 -248 277 -1332 273 -278 271 -234 261 -1382 275 -244 275 -1356 277 -246 275 -1360 277 -1340 277 -246 277 -234 263 -1384 275 -1342 277 -248 277 -1366 275 -244 273 -234 261 -1380 275 -246 273 -1360 275 -1340 277 -246 279 -1334 307 -244 273 -1356 275 -246 273 -1360 275 -244 271 -1354 277 -174 269 -10300 257 -2648 297 -230 263 -1384 277 -244 273 -1356 277 -1342 277 -248 277 -1362 275 -244 275 -1330 307 -244 273 -1324 309 -244 273 -1324 307 -246 273 -1326 307 -244 273 -1358 275 -246 273 -234 261 -1380 277 -246 273 -1358 275 -244 275 -1354 277 -248 275 -1360 275 -1338 279 -246 277 -1360 275 -244 273 -234 261 -1378 279 -1344 279 -248 279 -1330 309 -244 271 -232 261 -1380 277 -246 273 -1360 +RAW_Data: 277 -244 275 -1360 275 -1340 277 -246 277 -236 261 -1380 275 -1346 277 -248 277 -1362 275 -246 273 -234 263 -1380 275 -244 275 -1358 275 -1340 277 -248 279 -1334 309 -244 273 -1324 307 -246 273 -1356 275 -244 273 -1356 275 -174 269 -10302 257 -2644 297 -232 263 -1384 277 -246 275 -1354 275 -1344 277 -248 275 -1360 275 -246 275 -1358 275 -246 273 -1326 307 -246 273 -1324 307 -244 273 -1328 307 -244 273 -1358 275 -244 273 -236 261 -1380 275 -246 273 -1358 275 -244 273 -1358 275 -246 273 -1360 275 -1344 275 -248 275 -1360 275 -244 273 -234 261 -1378 277 -1344 279 -248 277 -1362 275 -246 273 -234 261 -1378 275 -244 275 -1360 275 -246 275 -1358 275 -1344 277 -246 277 -234 263 -1380 275 -1338 279 -246 281 -1368 275 -244 271 -234 261 -1386 275 -244 271 -1358 275 -1342 277 -246 279 -1362 275 -244 275 -1326 273 -278 273 -1358 239 -278 273 -1358 275 -174 267 -127478 195 -964 2317 -66 763 -98 1455 -100 16109 -66 5683 -98 11469 -66 34413 -66 5443 -66 11613 -66 2737 -66 12191 -66 2951 -68 1851 -68 1895 -68 2643 +RAW_Data: 29262 361 -68 2635 -66 24113 -66 1131 -100 4157 -66 26253 -130 621 -18438 99 -298 231 -66 197 -496 753 -230 7503 -16526 65 -396 65 -296 99 -196 293 -64 429 -132 397 -66 329 -66 37701 -66 13475 -100 54967 -64 18209 -18340 97 -462 197 -98 587 -232 97 -100 259 -98 197 -262 297 -64 557 -100 599 -100 333 -234 42493 -13212 6449 -206 173 -214 217 -176 195 -218 181 -218 181 -182 217 -182 217 -176 187 -214 215 -180 217 -182 217 -182 217 -178 185 -424 1177 -388 387 -240 381 -214 181 -398 211 -380 419 -176 217 -394 203 -394 205 -380 189 -402 421 -168 219 -398 393 -190 191 -398 205 -406 185 -402 381 -212 215 -362 241 -378 421 -176 377 -218 197 -378 427 -210 393 -172 429 -172 397 -212 217 -362 389 -228 197 -372 417 -204 395 -210 181 -398 391 -192 201 -216888 761 -200 299 -166 695 -132 15435 -66 5611 -66 21049 -66 4947 -66 2355 -66 1921 -100 2223 -100 2107 -100 397 -98 3643 -66 5301 -98 14205 -66 37371 -246 175 -216 179 -216 177 -224 149 -246 159 -228 181 -212 201 -204 159 -244 151 -254 169 -214 181 -210 197 -182 181 -454 1141 -444 357 -228 361 -246 177 -396 209 -412 367 -188 187 -434 201 -394 185 -406 193 -402 377 -238 181 -386 381 -234 153 -424 205 -412 157 -412 383 -240 181 -398 203 -392 385 -236 371 -212 179 -400 383 -240 359 -210 375 -220 381 -246 175 -394 383 -240 181 -398 363 -222 379 -246 175 -394 383 -204 217 -182856 99 -66 99 -300 133 -402 65 -198 99 -328 65 -100 491 -164 593 -100 3547 -64 361 -66 789 -68 2521 -66 22883 -66 2659 -98 3309 -130 3789 -100 9689 -17178 99 -1388 65 -266 197 -100 131 -134 99 -232 627 -130 233 -66 1949 -100 14567 -198 165 -256 181 -208 159 -214 183 -220 163 -244 149 -246 159 -236 181 -254 141 -226 151 -246 157 -228 181 -212 201 -400 1163 -428 379 -230 355 -244 177 -396 207 -412 367 -222 157 -418 189 -410 207 -412 171 -430 357 -226 165 -404 413 -204 181 -428 173 -428 169 -426 353 -236 173 -414 173 -408 381 -244 337 -222 201 -408 397 -208 393 -204 395 -208 359 -246 177 -394 387 -200 205 -380 415 -202 395 -208 181 -432 357 -226 169 -195084 65 -300 763 -66 297 -364 593 -68 2883 -66 1357 -68 363 -98 3841 -66 3119 -66 5153 -66 4023 -268 143 -246 133 -290 141 -250 139 -254 141 -226 181 -248 137 -254 143 -252 139 -252 143 -230 181 -250 139 -254 145 -436 1135 -448 349 -240 347 -254 157 -434 167 -426 377 -226 157 -434 167 -426 155 -440 163 -434 375 -206 215 -380 381 -234 153 +RAW_Data: -424 205 -412 159 -412 381 -240 181 -398 203 -392 387 -236 369 -212 179 -400 383 -240 359 -244 339 -222 381 -246 175 -394 383 -240 181 -398 363 -222 381 -244 175 -392 383 -240 181 -184002 99 -360 63 -330 65 -132 129 -232 97 -198 295 -328 6031 -66 831 -132 3417 -66 2187 -64 2183 -100 6535 -66 1127 -66 2569 -66 2031 -66 2271 -66 2183 -66 3815 -66 3803 -66 493 -66 1909 -66 1627 -98 4805 -17512 67 -2164 131 -498 265 -430 163 -98 97 -64 99 -230 99 -100 229 -230 165 -196 63 -132 99 -66 927 -66 14955 -66 19621 -68 2627 -66 14305 -68 23247 -66 2891 -66 3941 -66 3021 -212 173 -242 181 -218 181 -214 181 -208 157 -250 141 -248 181 -218 179 -214 179 -210 159 -250 179 -214 181 -218 181 -404 1153 -404 389 -244 375 -192 181 -436 161 -414 383 -240 181 -398 205 -392 201 -394 205 -394 365 -246 177 -396 383 -204 217 -398 171 -426 167 -428 353 -242 173 -420 173 -408 373 -220 403 -208 175 -422 381 -194 399 -228 357 -246 355 -210 215 -400 387 -208 181 -398 391 -226 353 -246 177 -398 383 -204 217 -185098 163 -166 525 -98 293 -100 63 -66 229 -66 1183 -66 1507 -66 3089 -98 30187 -66 2847 -19112 133 -364 131 -394 97 -166 295 -66 229 -164 227 -66 263 -130 623 -98 2071 -66 493 -66 787 -98 691 -64 10249 -132 3879 -66 1949 -66 3453 -198 23157 -66 2845 -100 1193 -66 1587 -100 3797 -98 3187 -100 3319 -66 22119 -98 5513 -226 155 -244 153 -256 131 -248 151 -246 159 -262 121 -274 133 -272 127 -244 153 -254 167 -248 145 -244 133 -252 177 -398 1169 -418 381 -238 359 -242 141 -430 169 -426 357 -274 139 -422 171 -442 173 -428 167 -426 353 -236 171 -416 379 -226 149 -436 161 -438 173 -406 381 -234 153 -424 205 -380 389 -244 359 -206 215 -384 381 -246 335 -224 383 -246 355 -244 179 -404 385 -206 181 -432 359 -226 355 -246 175 -398 383 -240 181 -179760 97 -168 727 -66 97 -332 1389 -66 2793 -66 4955 -100 12453 -100 2425 -66 21965 -66 3809 -68 1683 -66 3095 -66 2153 -64 999 -208 173 -220 181 -214 191 -196 181 -212 183 -220 191 -212 181 -214 191 -198 181 -212 181 -222 191 -212 181 -214 191 -416 1167 -424 369 -220 373 -210 209 -390 207 -376 403 -190 187 -418 189 -408 209 -412 173 -428 357 -226 169 -404 399 -208 179 -412 209 -396 169 -428 355 -230 201 -378 205 -406 381 -244 339 -222 193 -400 413 -204 393 -208 347 -220 401 -210 175 -422 383 -202 217 -398 365 -222 377 -246 175 -390 385 -204 217 -179890 165 -1552 131 -164 65 +RAW_Data: -1448 361 -17056 131 -134 233 -1462 131 -166 953 -100 261 -164 5077 -272 137 -268 143 -252 141 -248 143 -246 159 -252 141 -244 143 -290 107 -276 145 -244 131 -250 179 -248 143 -252 141 -414 1165 -424 373 -236 359 -242 145 -434 169 -428 355 -230 169 -442 173 -434 157 -406 193 -402 379 -238 181 -422 335 -252 157 -434 167 -428 185 -406 381 -208 211 -390 207 -410 381 -200 373 -236 171 -414 383 -202 393 -210 379 -220 373 -208 211 -390 383 -204 217 -398 365 -220 379 -244 175 -394 381 -240 181 -161030 97 -166 167 -930 593 -2670 1091 -132 229 -98 461 -164 1649 -66 6311 -100 44723 -16832 67 -2656 131 -132 99 -132 263 -100 399 -68 893 -18950 99 -164 165 -198 525 -998 335 -66 565 -66 1057 -17880 97 -360 195 -262 131 -332 625 -98 197 -230 455 -98 9343 -16498 67 -368 131 -598 65 -1066 333 -300 789 -130 757 -66 87207 -16554 97 -3520 97 -786 591 -64 461 -98 21495 -66 24811 -18448 131 -296 491 -134 163 -760 1091 -230 893 -66 927 -68 4581 -68 32965 -64 45217 -17292 131 -1684 231 -132 327 -64 163 -330 263 -230 25751 diff --git a/lib/subghz/protocols/magellen.c b/lib/subghz/protocols/magellen.c new file mode 100644 index 0000000000..859f803519 --- /dev/null +++ b/lib/subghz/protocols/magellen.c @@ -0,0 +1,444 @@ +#include "magellen.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocolMagellen" + +static const SubGhzBlockConst subghz_protocol_magellen_const = { + .te_short = 200, + .te_long = 400, + .te_delta = 100, + .min_count_bit_for_found = 32, +}; + +struct SubGhzProtocolDecoderMagellen { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; + uint16_t header_count; +}; + +struct SubGhzProtocolEncoderMagellen { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + MagellenDecoderStepReset = 0, + MagellenDecoderStepCheckPreambula, + MagellenDecoderStepFoundPreambula, + MagellenDecoderStepSaveDuration, + MagellenDecoderStepCheckDuration, +} MagellenDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_magellen_decoder = { + .alloc = subghz_protocol_decoder_magellen_alloc, + .free = subghz_protocol_decoder_magellen_free, + + .feed = subghz_protocol_decoder_magellen_feed, + .reset = subghz_protocol_decoder_magellen_reset, + + .get_hash_data = subghz_protocol_decoder_magellen_get_hash_data, + .serialize = subghz_protocol_decoder_magellen_serialize, + .deserialize = subghz_protocol_decoder_magellen_deserialize, + .get_string = subghz_protocol_decoder_magellen_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_magellen_encoder = { + .alloc = subghz_protocol_encoder_magellen_alloc, + .free = subghz_protocol_encoder_magellen_free, + + .deserialize = subghz_protocol_encoder_magellen_deserialize, + .stop = subghz_protocol_encoder_magellen_stop, + .yield = subghz_protocol_encoder_magellen_yield, +}; + +const SubGhzProtocol subghz_protocol_magellen = { + .name = SUBGHZ_PROTOCOL_MAGELLEN_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_magellen_decoder, + .encoder = &subghz_protocol_magellen_encoder, +}; + +void* subghz_protocol_encoder_magellen_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderMagellen* instance = malloc(sizeof(SubGhzProtocolEncoderMagellen)); + + instance->base.protocol = &subghz_protocol_magellen; + 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_magellen_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderMagellen* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderMagellen instance + * @return true On success + */ +static bool subghz_protocol_encoder_magellen_get_upload(SubGhzProtocolEncoderMagellen* instance) { + furi_assert(instance); + + size_t index = 0; + + //Send header + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_magellen_const.te_short * 4); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_magellen_const.te_short); + for(uint8_t i = 0; i < 12; i++) { + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_magellen_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_magellen_const.te_short); + } + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_magellen_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_magellen_const.te_long); + + //Send start bit + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_magellen_const.te_long * 3); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_magellen_const.te_long); + + //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_magellen_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_magellen_const.te_long); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_magellen_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_magellen_const.te_short); + } + } + + //Send stop bit + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_magellen_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_magellen_const.te_long * 100); + + instance->encoder.size_upload = index; + return true; +} + +bool subghz_protocol_encoder_magellen_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderMagellen* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_magellen_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_encoder_magellen_get_upload(instance); + instance->encoder.is_running = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_magellen_stop(void* context) { + SubGhzProtocolEncoderMagellen* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_magellen_yield(void* context) { + SubGhzProtocolEncoderMagellen* 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_magellen_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderMagellen* instance = malloc(sizeof(SubGhzProtocolDecoderMagellen)); + instance->base.protocol = &subghz_protocol_magellen; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_magellen_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderMagellen* instance = context; + free(instance); +} + +void subghz_protocol_decoder_magellen_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderMagellen* instance = context; + instance->decoder.parser_step = MagellenDecoderStepReset; +} + +uint8_t subghz_protocol_magellen_crc8(uint8_t* data, size_t len) { + uint8_t crc = 0x00; + 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) ^ 0x31); + else + crc <<= 1; + } + } + return crc; +} + +static bool subghz_protocol_magellen_check_crc(SubGhzProtocolDecoderMagellen* instance) { + uint8_t data[3] = { + instance->decoder.decode_data >> 24, + instance->decoder.decode_data >> 16, + instance->decoder.decode_data >> 8}; + return (instance->decoder.decode_data & 0xFF) == + subghz_protocol_magellen_crc8(data, sizeof(data)); +} + +void subghz_protocol_decoder_magellen_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderMagellen* instance = context; + + switch(instance->decoder.parser_step) { + case MagellenDecoderStepReset: + if((level) && (DURATION_DIFF(duration, subghz_protocol_magellen_const.te_short) < + subghz_protocol_magellen_const.te_delta)) { + instance->decoder.parser_step = MagellenDecoderStepCheckPreambula; + instance->decoder.te_last = duration; + instance->header_count = 0; + } + break; + + case MagellenDecoderStepCheckPreambula: + if(level) { + instance->decoder.te_last = duration; + } else { + if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_magellen_const.te_short) < + subghz_protocol_magellen_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_magellen_const.te_short) < + subghz_protocol_magellen_const.te_delta)) { + // Found header + instance->header_count++; + } else if( + (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_magellen_const.te_short) < + subghz_protocol_magellen_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_magellen_const.te_long) < + subghz_protocol_magellen_const.te_delta * 2) && + (instance->header_count > 10)) { + instance->decoder.parser_step = MagellenDecoderStepFoundPreambula; + } else { + instance->decoder.parser_step = MagellenDecoderStepReset; + } + } + break; + + case MagellenDecoderStepFoundPreambula: + if(level) { + instance->decoder.te_last = duration; + } else { + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_magellen_const.te_short * 6) < + subghz_protocol_magellen_const.te_delta * 3) && + (DURATION_DIFF(duration, subghz_protocol_magellen_const.te_long) < + subghz_protocol_magellen_const.te_delta * 2)) { + instance->decoder.parser_step = MagellenDecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } else { + instance->decoder.parser_step = MagellenDecoderStepReset; + } + } + break; + + case MagellenDecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = MagellenDecoderStepCheckDuration; + } else { + instance->decoder.parser_step = MagellenDecoderStepReset; + } + break; + + case MagellenDecoderStepCheckDuration: + if(!level) { + if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_magellen_const.te_short) < + subghz_protocol_magellen_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_magellen_const.te_long) < + subghz_protocol_magellen_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = MagellenDecoderStepSaveDuration; + } else if( + (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_magellen_const.te_long) < + subghz_protocol_magellen_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_magellen_const.te_short) < + subghz_protocol_magellen_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = MagellenDecoderStepSaveDuration; + } else if(duration >= (subghz_protocol_magellen_const.te_long * 3)) { + //Found stop bit + if((instance->decoder.decode_count_bit == + subghz_protocol_magellen_const.min_count_bit_for_found) && + subghz_protocol_magellen_check_crc(instance)) { + 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 = MagellenDecoderStepReset; + } else { + instance->decoder.parser_step = MagellenDecoderStepReset; + } + } else { + instance->decoder.parser_step = MagellenDecoderStepReset; + } + break; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_magellen_check_remote_controller(SubGhzBlockGeneric* instance) { + /* +* package 32b data 24b CRC8 +* 0x037AE4828 => 001101111010111001001000 00101000 +* +* 0x037AE48 (flipped in reverse bit sequence) => 0x1275EC +* +* 0x1275EC => 0x12-event codes, 0x75EC-serial (dec 117236) +* +* event codes +* bit_0: 1-alarm, 0-close +* bit_1: 1-Tamper On (alarm), 0-Tamper Off (ok) +* bit_2: ? +* bit_3: 1-power on +* bit_4: model type - door alarm +* bit_5: model type - motion sensor +* bit_6: ? +* bit_7: ? +* +*/ + uint64_t data_rev = subghz_protocol_blocks_reverse_key(instance->data >> 8, 24); + instance->serial = data_rev & 0xFFFF; + instance->btn = (data_rev >> 16) & 0xFF; +} + +static void subghz_protocol_magellen_get_event_serialize(uint8_t event, string_t output) { + string_cat_printf( + output, + "%s%s%s%s%s%s%s%s", + (event & 0x1 ? " Alarm" : "Ok"), + ((event >> 1) & 0x1 ? ", Tamper On (Alarm)" : ""), + ((event >> 2) & 0x1 ? ", ?" : ""), + ((event >> 3) & 0x1 ? ", Power On" : ""), + ((event >> 4) & 0x1 ? ", MT:Door_Alarm" : ""), + ((event >> 5) & 0x1 ? ", MT:Motion_Sensor" : ""), + ((event >> 6) & 0x1 ? ", ?" : ""), + ((event >> 7) & 0x1 ? ", ?" : "")); +} + +uint8_t subghz_protocol_decoder_magellen_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderMagellen* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_magellen_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset) { + furi_assert(context); + SubGhzProtocolDecoderMagellen* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_magellen_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderMagellen* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_magellen_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void subghz_protocol_decoder_magellen_get_string(void* context, string_t output) { + furi_assert(context); + SubGhzProtocolDecoderMagellen* instance = context; + subghz_protocol_magellen_check_remote_controller(&instance->generic); + string_cat_printf( + output, + "%s %dbit\r\n" + "Key:0x%08lX\r\n" + "Sn:%03d%03d, Event:0x%02X\r\n" + "Stat:", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data & 0xFFFFFFFF), + (instance->generic.serial >> 8) & 0xFF, + instance->generic.serial & 0xFF, + instance->generic.btn); + + subghz_protocol_magellen_get_event_serialize(instance->generic.btn, output); +} diff --git a/lib/subghz/protocols/magellen.h b/lib/subghz/protocols/magellen.h new file mode 100644 index 0000000000..224f79011b --- /dev/null +++ b/lib/subghz/protocols/magellen.h @@ -0,0 +1,107 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_MAGELLEN_NAME "Magellen" + +typedef struct SubGhzProtocolDecoderMagellen SubGhzProtocolDecoderMagellen; +typedef struct SubGhzProtocolEncoderMagellen SubGhzProtocolEncoderMagellen; + +extern const SubGhzProtocolDecoder subghz_protocol_magellen_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_magellen_encoder; +extern const SubGhzProtocol subghz_protocol_magellen; + +/** + * Allocate SubGhzProtocolEncoderMagellen. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderMagellen* pointer to a SubGhzProtocolEncoderMagellen instance + */ +void* subghz_protocol_encoder_magellen_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderMagellen. + * @param context Pointer to a SubGhzProtocolEncoderMagellen instance + */ +void subghz_protocol_encoder_magellen_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderMagellen instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_magellen_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderMagellen instance + */ +void subghz_protocol_encoder_magellen_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderMagellen instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_magellen_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderMagellen. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderMagellen* pointer to a SubGhzProtocolDecoderMagellen instance + */ +void* subghz_protocol_decoder_magellen_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderMagellen. + * @param context Pointer to a SubGhzProtocolDecoderMagellen instance + */ +void subghz_protocol_decoder_magellen_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderMagellen. + * @param context Pointer to a SubGhzProtocolDecoderMagellen instance + */ +void subghz_protocol_decoder_magellen_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderMagellen instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_magellen_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderMagellen instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_magellen_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderMagellen. + * @param context Pointer to a SubGhzProtocolDecoderMagellen instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzPresetDefinition + * @return true On success + */ +bool subghz_protocol_decoder_magellen_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset); + +/** + * Deserialize data SubGhzProtocolDecoderMagellen. + * @param context Pointer to a SubGhzProtocolDecoderMagellen instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_magellen_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderMagellen instance + * @param output Resulting text + */ +void subghz_protocol_decoder_magellen_get_string(void* context, string_t output); diff --git a/lib/subghz/protocols/registry.c b/lib/subghz/protocols/registry.c index 19b03cebcf..b72278788c 100644 --- a/lib/subghz/protocols/registry.c +++ b/lib/subghz/protocols/registry.c @@ -11,7 +11,7 @@ const SubGhzProtocol* subghz_protocol_registry[] = { &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_honeywell_wdb, &subghz_protocol_magellen, }; diff --git a/lib/subghz/protocols/registry.h b/lib/subghz/protocols/registry.h index d756951329..36a560765a 100644 --- a/lib/subghz/protocols/registry.h +++ b/lib/subghz/protocols/registry.h @@ -33,6 +33,7 @@ #include "doitrand.h" #include "phoenix_v2.h" #include "honeywell_wdb.h" +#include "magellen.h" /** * Registration by name SubGhzProtocol. From 73c28437d6530bc90862ad60192b947e36360371 Mon Sep 17 00:00:00 2001 From: Daniel <71837281+darmiel@users.noreply.github.com> Date: Tue, 23 Aug 2022 09:13:41 +0200 Subject: [PATCH 17/78] fix[unirf]: display decoded after sending --- applications/unirfremix/unirfremix_app.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/applications/unirfremix/unirfremix_app.c b/applications/unirfremix/unirfremix_app.c index b3c010f92c..83aeaa2e84 100644 --- a/applications/unirfremix/unirfremix_app.c +++ b/applications/unirfremix/unirfremix_app.c @@ -690,9 +690,14 @@ static bool unirfremix_send_sub( flipper_format_file_close(fff_file); - subghz_protocol_decoder_base_deserialize(preset->decoder, fff_data); - subghz_protocol_decoder_base_get_string(preset->decoder, temp_str); - FURI_LOG_I(TAG, "Decoded: %s", string_get_cstr(temp_str)); + { + string_t decode_str; + string_init(decode_str); + subghz_protocol_decoder_base_deserialize(preset->decoder, fff_data); + subghz_protocol_decoder_base_get_string(preset->decoder, decode_str); + FURI_LOG_I(TAG, "Decoded: %s", string_get_cstr(decode_str)); + string_clear(decode_str); + } FURI_LOG_I(TAG, "Checking if protocol is dynamic"); const SubGhzProtocol* registry_protocol = From a7a9c38036633ee25de70903c6ceacabf4f3307c Mon Sep 17 00:00:00 2001 From: Max Andreev Date: Tue, 23 Aug 2022 14:29:26 +0300 Subject: [PATCH 18/78] Amap and PVS Studio reports in CI/CD (#1526) --- .github/CODEOWNERS | 4 - .github/actions/docker/action.yml | 11 -- .github/workflows/amap_analyse.yml | 120 ++++++++++++++++++++++ .github/workflows/build.yml | 4 + .github/workflows/check_submodules.yml | 1 + .github/workflows/lint_c.yml | 1 + .github/workflows/lint_python.yml | 1 + .github/workflows/pvs_studio.yml | 107 +++++++++++++++++++ .pvsoptions | 2 +- ReadMe.md | 24 ----- applications/subghz/subghz_setting.c | 18 ++-- assets/ReadMe.md | 6 -- docker-compose.yml | 12 --- docker/Dockerfile | 41 -------- docker/entrypoint.sh | 9 -- scripts/amap_mariadb_insert.py | 136 +++++++++++++++++++++++++ scripts/toolchain/fbtenv.cmd | 2 +- scripts/toolchain/fbtenv.sh | 8 +- 18 files changed, 384 insertions(+), 123 deletions(-) delete mode 100644 .github/actions/docker/action.yml create mode 100644 .github/workflows/amap_analyse.yml create mode 100644 .github/workflows/pvs_studio.yml delete mode 100644 docker-compose.yml delete mode 100644 docker/Dockerfile delete mode 100755 docker/entrypoint.sh create mode 100755 scripts/amap_mariadb_insert.py diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ea165de2f7..6dac0496ab 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -44,10 +44,6 @@ # Debug tools and plugins /debug/ @skotopes @DrZlo13 @hedger -# Docker -/docker/ @skotopes @DrZlo13 @hedger @drunkbatya -/docker-compose.yml @skotopes @DrZlo13 @hedger @drunkbatya - # Documentation /documentation/ @skotopes @DrZlo13 @hedger @drunkbatya diff --git a/.github/actions/docker/action.yml b/.github/actions/docker/action.yml deleted file mode 100644 index 3608f96e67..0000000000 --- a/.github/actions/docker/action.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: 'Run in docker' -inputs: - run: # id of input - description: 'A command to run' - required: true - default: '' -runs: - using: 'docker' - image: '../../../docker/Dockerfile' - args: - - ${{ inputs.run }} diff --git a/.github/workflows/amap_analyse.yml b/.github/workflows/amap_analyse.yml new file mode 100644 index 0000000000..3bfcba2cf5 --- /dev/null +++ b/.github/workflows/amap_analyse.yml @@ -0,0 +1,120 @@ +name: 'Analyze .map file with Amap' + +on: + push: + branches: + - dev + - "release*" + tags: + - '*' + pull_request: + +env: + TARGETS: f7 + +jobs: + amap_analyse: + runs-on: [self-hosted,FlipperZeroMacShell] + steps: + - name: 'Wait Build workflow' + uses: fountainhead/action-wait-for-check@v1.0.0 + id: wait-for-build + with: + token: ${{ secrets.GITHUB_TOKEN }} + checkName: 'main' + ref: ${{ github.event.pull_request.head.sha || github.sha }} + intervalSeconds: 20 + + - name: 'Check Build workflow status' + if: steps.wait-for-build.outputs.conclusion == 'failure' + run: | + exit 1 + + - name: 'Decontaminate previous build leftovers' + run: | + if [ -d .git ]; then + git submodule status \ + || git checkout `git rev-list --max-parents=0 HEAD | tail -n 1` + fi + + - name: 'Checkout code' + uses: actions/checkout@v2 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + + - name: 'Generate prefixes by commit' + id: names + run: | + REF="${{github.ref}}" + COMMIT_HASH="$(git rev-parse HEAD)" + SHA="$(git rev-parse --short HEAD)" + COMMIT_MSG="${{github.event.head_commit.message}}" + if [[ ${{ github.event_name }} == 'pull_request' ]]; then + REF="${{github.head_ref}}" + COMMIT_HASH="$(git log -1 --pretty=oneline | awk '{print $1}')" + SHA="$(cut -c -8 <<< "$COMMIT_HASH")" + COMMIT_MSG="$(git log -1 --pretty=format:"%s")" + PULL_ID="${{github.event.pull_request.number}}" + PULL_NAME="${{github.event.pull_request.title}}" + fi + BRANCH_NAME=${REF#refs/*/} + SUFFIX=${BRANCH_NAME//\//_}-$(date +'%d%m%Y')-${SHA} + if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then + SUFFIX=${BRANCH_NAME//\//_} + fi + echo "::set-output name=commit-hash::${COMMIT_HASH}" + echo "::set-output name=commit-msg::${COMMIT_MSG}" + echo "::set-output name=pull-id::${PULL_ID}" + echo "::set-output name=pull-name::${PULL_NAME}" + echo "::set-output name=branch-name::${BRANCH_NAME}" + echo "::set-output name=suffix::${SUFFIX}" + + - name: 'Make artifacts directory' + run: | + rm -rf artifacts + mkdir artifacts + + - name: 'Download build artifacts' + if: ${{ !github.event.pull_request.head.repo.fork }} + run: | + echo "${{ secrets.RSYNC_DEPLOY_KEY }}" > deploy_key; + chmod 600 ./deploy_key; + rsync -avzP \ + -e 'ssh -p ${{ secrets.RSYNC_DEPLOY_PORT }} -i ./deploy_key' \ + ${{ secrets.RSYNC_DEPLOY_USER }}@${{ secrets.RSYNC_DEPLOY_HOST }}:"${{ secrets.RSYNC_DEPLOY_BASE_PATH }}${{steps.names.outputs.branch-name}}/" artifacts/; + rm ./deploy_key; + + - name: 'Make .map file analyse' + run: | + cd artifacts/ + /Applications/amap/Contents/MacOS/amap -f flipper-z-f7-firmware-${{steps.names.outputs.suffix}}.elf.map + + - name: 'Upload report to DB' + run: | + FBT_TOOLCHAIN_PATH=/opt source scripts/toolchain/fbtenv.sh + get_size() + { + SECTION="$1"; + arm-none-eabi-size \ + -A artifacts/flipper-z-f7-firmware-${{steps.names.outputs.suffix}}.elf \ + | grep "^$SECTION" | awk '{print $2}' + } + export COMMIT_HASH="${{steps.names.outputs.commit-hash}}" + export COMMIT_MSG="${{steps.names.outputs.commit-msg}}" + export BRANCH_NAME="${{steps.names.outputs.branch-name}}" + export PULL_ID="${{steps.names.outputs.pull-id}}" + export PULL_NAME="${{steps.names.outputs.pull-name}}" + export BSS_SIZE="$(get_size ".bss")" + export TEXT_SIZE="$(get_size ".text")" + export RODATA_SIZE="$(get_size ".rodata")" + export DATA_SIZE="$(get_size ".data")" + export FREE_FLASH_SIZE="$(get_size ".free_flash")" + python3 -m pip install mariadb + python3 scripts/amap_mariadb_insert.py \ + ${{ secrets.AMAP_MARIADB_USER }} \ + ${{ secrets.AMAP_MARIADB_PASSWORD }} \ + ${{ secrets.AMAP_MARIADB_HOST }} \ + ${{ secrets.AMAP_MARIADB_PORT }} \ + ${{ secrets.AMAP_MARIADB_DATABASE }} \ + artifacts/flipper-z-f7-firmware-${{steps.names.outputs.suffix}}.elf.map.all diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a1ae875a8b..b677a293f6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -108,6 +108,10 @@ jobs: FBT_TOOLCHAIN_PATH=/opt ./fbt copro_dist tar czpf artifacts/flipper-z-any-core2_firmware-${{steps.names.outputs.suffix}}.tgz -C assets core2_firmware + - name: 'Copy .map file' + run: | + cp build/f7-firmware-D/firmware.elf.map artifacts/flipper-z-f7-firmware-${{steps.names.outputs.suffix}}.elf.map + - name: 'Upload artifacts to update server' if: ${{ !github.event.pull_request.head.repo.fork }} run: | diff --git a/.github/workflows/check_submodules.yml b/.github/workflows/check_submodules.yml index f9699be87a..e021c969a8 100644 --- a/.github/workflows/check_submodules.yml +++ b/.github/workflows/check_submodules.yml @@ -25,6 +25,7 @@ jobs: uses: actions/checkout@v2 with: fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} - name: 'Check protobuf branch' run: | diff --git a/.github/workflows/lint_c.yml b/.github/workflows/lint_c.yml index aaff396ec6..64d14b713b 100644 --- a/.github/workflows/lint_c.yml +++ b/.github/workflows/lint_c.yml @@ -28,6 +28,7 @@ jobs: uses: actions/checkout@v2 with: fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} - name: 'Check code formatting' id: syntax_check diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index c059f4348a..5051c56914 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -25,6 +25,7 @@ jobs: uses: actions/checkout@v2 with: fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} - name: 'Check code formatting' run: SET_GH_OUTPUT=1 FBT_TOOLCHAIN_PATH=/opt ./fbt lint_py diff --git a/.github/workflows/pvs_studio.yml b/.github/workflows/pvs_studio.yml new file mode 100644 index 0000000000..c238b1c6f9 --- /dev/null +++ b/.github/workflows/pvs_studio.yml @@ -0,0 +1,107 @@ +name: 'Static C/C++ analysis with PVS-Studio' + +on: + push: + branches: + - dev + - "release*" + tags: + - '*' + pull_request: + +env: + TARGETS: f7 + DEFAULT_TARGET: f7 + +jobs: + analyse_c_cpp: + runs-on: [self-hosted, FlipperZeroShell] + steps: + - name: 'Decontaminate previous build leftovers' + run: | + if [ -d .git ] + then + git submodule status \ + || git checkout `git rev-list --max-parents=0 HEAD | tail -n 1` + fi + + - name: 'Checkout code' + uses: actions/checkout@v2 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + + - name: 'Generate suffix and folder name' + id: names + run: | + REF=${{ github.ref }} + if [[ ${{ github.event_name }} == 'pull_request' ]]; then + REF=${{ github.head_ref }} + fi + BRANCH_OR_TAG=${REF#refs/*/} + SHA=$(git rev-parse --short HEAD) + + if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then + SUFFIX=${BRANCH_OR_TAG//\//_} + else + SUFFIX=${BRANCH_OR_TAG//\//_}-$(date +'%d%m%Y')-${SHA} + fi + + echo "WORKFLOW_BRANCH_OR_TAG=${BRANCH_OR_TAG}" >> $GITHUB_ENV + echo "DIST_SUFFIX=${SUFFIX}" >> $GITHUB_ENV + echo "::set-output name=artifacts-path::${BRANCH_OR_TAG}" + echo "::set-output name=suffix::${SUFFIX}" + echo "::set-output name=short-hash::${SHA}" + echo "::set-output name=default-target::${DEFAULT_TARGET}" + + - name: 'Make reports directory' + run: | + rm -rf reports/ + mkdir reports + + - name: 'Generate compile_comands.json' + run: | + FBT_TOOLCHAIN_PATH=/opt ./fbt COMPACT=1 version_json proto_ver icons firmware_cdb dolphin_internal dolphin_blocking + + - name: 'Static code analysis' + run: | + FBT_TOOLCHAIN_PATH=/opt source scripts/toolchain/fbtenv.sh + pvs-studio-analyzer credentials ${{ secrets.PVS_STUDIO_CREDENTIALS }} + pvs-studio-analyzer analyze \ + @.pvsoptions \ + -j$(grep -c processor /proc/cpuinfo) \ + -f build/f7-firmware-DC/compile_commands.json \ + -o PVS-Studio.log + + - name: 'Convert PVS-Studio output to html page' + run: plog-converter -a GA:1,2,3 -t fullhtml PVS-Studio.log -o reports/${{steps.names.outputs.default-target}}-${{steps.names.outputs.suffix}} + + - name: 'Upload artifacts to update server' + if: ${{ !github.event.pull_request.head.repo.fork }} + run: | + echo "${{ secrets.RSYNC_DEPLOY_KEY }}" > deploy_key; + chmod 600 ./deploy_key; + rsync -avrzP --mkpath \ + -e 'ssh -p ${{ secrets.RSYNC_DEPLOY_PORT }} -i ./deploy_key' \ + reports/ ${{ secrets.RSYNC_DEPLOY_USER }}@${{ secrets.RSYNC_DEPLOY_HOST }}:/home/data/firmware-pvs-studio-report/"${{steps.names.outputs.artifacts-path}}/"; + rm ./deploy_key; + + - name: 'Find Previous Comment' + if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request }} + uses: peter-evans/find-comment@v1 + id: fc + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: 'github-actions[bot]' + body-includes: 'PVS-Studio report for commit' + + - name: 'Create or update comment' + if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request}} + uses: peter-evans/create-or-update-comment@v1 + with: + comment-id: ${{ steps.fc.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + body: | + **PVS-Studio report for commit `${{steps.names.outputs.short-hash}}`:** + - [Report](https://update.flipperzero.one/builds/firmware-pvs-studio-report/${{steps.names.outputs.artifacts-path}}/${{steps.names.outputs.default-target}}-${{steps.names.outputs.suffix}}/index.html) + edit-mode: replace diff --git a/.pvsoptions b/.pvsoptions index 6715f87189..4c80ab6678 100644 --- a/.pvsoptions +++ b/.pvsoptions @@ -1 +1 @@ ---rules-config .pvsconfig -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/micro-ecc -e lib/microtar -e lib/mlib -e lib/qrcode -e lib/ST25RFAL002 -e lib/STM32CubeWB -e lib/u8g2 -e toolchain/ +--rules-config .pvsconfig -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/micro-ecc -e lib/microtar -e lib/mlib -e lib/qrcode -e lib/ST25RFAL002 -e lib/STM32CubeWB -e lib/u8g2 -e */arm-none-eabi/* diff --git a/ReadMe.md b/ReadMe.md index 36a887dc42..7a9777121a 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -61,29 +61,6 @@ One liner: `./fbt firmware_flash` 3. Run `dfu-util -D full.dfu -a 0` -# Build with Docker - -## Prerequisites - -1. Install [Docker Engine and Docker Compose](https://www.docker.com/get-started) -2. Prepare the container: - - ```sh - docker-compose up -d - ``` - -## Compile everything - -```sh -docker-compose exec dev ./fbt -``` - -Check `dist/` for build outputs. - -Use **`flipper-z-{target}-full-{suffix}.dfu`** to flash your device. - -If compilation fails, make sure all submodules are all initialized. Either clone with `--recursive` or use `git submodule update --init --recursive`. - # Build on Linux/macOS Check out `documentation/fbt.md` for details on building and flashing firmware. @@ -157,7 +134,6 @@ Connect your device via ST-Link and run: - `assets` - Assets used by applications and services - `furi` - Furi Core: os level primitives and helpers - `debug` - Debug tool: GDB-plugins, SVD-file and etc -- `docker` - Docker image sources (used for firmware build automation) - `documentation` - Documentation generation system configs and input files - `firmware` - Firmware source code - `lib` - Our and 3rd party libraries, drivers and etc... diff --git a/applications/subghz/subghz_setting.c b/applications/subghz/subghz_setting.c index 0a662f589b..b7c143cd5a 100644 --- a/applications/subghz/subghz_setting.c +++ b/applications/subghz/subghz_setting.c @@ -446,15 +446,15 @@ const char* subghz_setting_get_preset_name(SubGhzSetting* instance, size_t idx) int subghz_setting_get_inx_preset_by_name(SubGhzSetting* instance, const char* preset_name) { furi_assert(instance); size_t idx = 0; - for - M_EACH(item, instance->preset->data, SubGhzSettingCustomPresetItemArray_t) { - if(strcmp(string_get_cstr(item->custom_preset_name), preset_name) == 0) { - return idx; - } - idx++; - } - furi_crash("SubGhz: No name preset."); - return -1; + for + M_EACH(item, instance->preset->data, SubGhzSettingCustomPresetItemArray_t) { + if(strcmp(string_get_cstr(item->custom_preset_name), preset_name) == 0) { + return idx; + } + idx++; + } + furi_crash("SubGhz: No name preset."); + return -1; } bool subghz_setting_load_custom_preset( diff --git a/assets/ReadMe.md b/assets/ReadMe.md index 2cd99d56b6..2d493b4fec 100644 --- a/assets/ReadMe.md +++ b/assets/ReadMe.md @@ -9,12 +9,6 @@ ./fbt icons proto dolphin_internal dolphin_blocking dolphin_ext resources ``` -# Compiling with Docker-Compose - -```bash -docker-compose exec dev ./fbt icons proto dolphin_internal dolphin_blocking dolphin_ext resources -``` - # Asset naming rules ## Images and Animations diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 39aca411a1..0000000000 --- a/docker-compose.yml +++ /dev/null @@ -1,12 +0,0 @@ -version: '3' -services: - dev: - image: flipperdevices/flipperzero-toolchain - network_mode: host - privileged: true - tty: true - stdin_open: true - volumes: - - .:/project - - /dev/bus/usb:/dev/bus/usb - working_dir: '/project' diff --git a/docker/Dockerfile b/docker/Dockerfile deleted file mode 100644 index 64db408f3a..0000000000 --- a/docker/Dockerfile +++ /dev/null @@ -1,41 +0,0 @@ -FROM ubuntu:hirsute - -RUN apt-get update \ - && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \ - ca-certificates \ - build-essential \ - python3 \ - git \ - clang-format-12 \ - dfu-util \ - openocd \ - libncurses5 \ - python-setuptools \ - libpython2.7-dev \ - libxml2-dev \ - libxslt1-dev \ - zlib1g-dev \ - wget \ - python3-protobuf \ - protobuf-compiler \ - python3-pip \ - libpython3-dev \ - ccache \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* - -RUN wget --progress=dot:giga "https://developer.arm.com/-/media/Files/downloads/gnu-rm/10.3-2021.07/gcc-arm-none-eabi-10.3-2021.07-$(uname -m)-linux.tar.bz2" && \ - tar xjf gcc-arm-none-eabi-10.3-2021.07-$(uname -m)-linux.tar.bz2 && \ - rm gcc-arm-none-eabi-10.3-2021.07-$(uname -m)-linux.tar.bz2 && \ - cd gcc-arm-none-eabi-10.3-2021.07/bin/ && \ - rm -rf ../share && \ - for file in * ; do ln -s "${PWD}/${file}" "/usr/bin/${file}" ; done && \ - cd / && arm-none-eabi-gcc -v && arm-none-eabi-gdb -v - -RUN pip3 install heatshrink2==0.11.0 Pillow==9.1.1 - -RUN ln -s `which clang-format-12` /usr/local/bin/clang-format - -COPY entrypoint.sh / - -ENTRYPOINT ["/entrypoint.sh"] diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh deleted file mode 100755 index 4d553e0b42..0000000000 --- a/docker/entrypoint.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -if [ -z "$1" ]; then - bash -else - echo "Running $1" - set -ex - bash -c "$1" -fi diff --git a/scripts/amap_mariadb_insert.py b/scripts/amap_mariadb_insert.py new file mode 100755 index 0000000000..6ff1b3bf03 --- /dev/null +++ b/scripts/amap_mariadb_insert.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 + +from datetime import datetime +import argparse +import mariadb +import sys +import os + + +def parseArgs(): + parser = argparse.ArgumentParser() + parser.add_argument("db_user", help="MariaDB user") + parser.add_argument("db_pass", help="MariaDB password") + parser.add_argument("db_host", help="MariaDB hostname") + parser.add_argument("db_port", type=int, help="MariaDB port") + parser.add_argument("db_name", help="MariaDB database") + parser.add_argument("report_file", help="Report file(.map.all)") + args = parser.parse_args() + return args + + +def mariadbConnect(args): + try: + conn = mariadb.connect( + user=args.db_user, + password=args.db_pass, + host=args.db_host, + port=args.db_port, + database=args.db_name, + ) + except mariadb.Error as e: + print(f"Error connecting to MariaDB: {e}") + sys.exit(1) + return conn + + +def parseEnv(): + outArr = [] + outArr.append(datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + outArr.append(os.getenv("COMMIT_HASH", default=None)) + outArr.append(os.getenv("COMMIT_MSG", default=None)) + outArr.append(os.getenv("BRANCH_NAME", default=None)) + outArr.append(os.getenv("BSS_SIZE", default=None)) + outArr.append(os.getenv("TEXT_SIZE", default=None)) + outArr.append(os.getenv("RODATA_SIZE", default=None)) + outArr.append(os.getenv("DATA_SIZE", default=None)) + outArr.append(os.getenv("FREE_FLASH_SIZE", default=None)) + outArr.append(os.getenv("PULL_ID", default=None)) + outArr.append(os.getenv("PULL_NAME", default=None)) + return outArr + + +def createTables(cur, conn): + headerTable = "CREATE TABLE IF NOT EXISTS `header` ( \ + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, \ + `datetime` datetime NOT NULL, \ + `commit` varchar(40) NOT NULL, \ + `commit_msg` text NOT NULL, \ + `branch_name` text NOT NULL, \ + `bss_size` int(10) unsigned NOT NULL, \ + `text_size` int(10) unsigned NOT NULL, \ + `rodata_size` int(10) unsigned NOT NULL, \ + `data_size` int(10) unsigned NOT NULL, \ + `free_flash_size` int(10) unsigned NOT NULL, \ + `pullrequest_id` int(10) unsigned DEFAULT NULL, \ + `pullrequest_name` text DEFAULT NULL, \ + PRIMARY KEY (`id`), \ + KEY `header_id_index` (`id`) )" + dataTable = "CREATE TABLE IF NOT EXISTS `data` ( \ + `header_id` int(10) unsigned NOT NULL, \ + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, \ + `section` text NOT NULL, \ + `address` text NOT NULL, \ + `size` int(10) unsigned NOT NULL, \ + `name` text NOT NULL, \ + `lib` text NOT NULL, \ + `obj_name` text NOT NULL, \ + PRIMARY KEY (`id`), \ + KEY `data_id_index` (`id`), \ + KEY `data_header_id_index` (`header_id`), \ + CONSTRAINT `data_header_id_foreign` FOREIGN KEY (`header_id`) REFERENCES `header` (`id`) )" + cur.execute(headerTable) + cur.execute(dataTable) + conn.commit() + + +def insertHeader(data, cur, conn): + query = "INSERT INTO `header` ( \ + datetime, commit, commit_msg, branch_name, bss_size, text_size, \ + rodata_size, data_size, free_flash_size, pullrequest_id, pullrequest_name) \ + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + cur.execute(query, data) + conn.commit() + return cur.lastrowid + + +def parseFile(fileObj, headerID): + arr = [] + fileLines = fileObj.readlines() + for line in fileLines: + lineArr = [] + tempLineArr = line.split("\t") + lineArr.append(headerID) + lineArr.append(tempLineArr[0]) # section + lineArr.append(int(tempLineArr[2], 16)) # address hex + lineArr.append(int(tempLineArr[3])) # size + lineArr.append(tempLineArr[4]) # name + lineArr.append(tempLineArr[5]) # lib + lineArr.append(tempLineArr[6]) # obj_name + arr.append(tuple(lineArr)) + return arr + + +def insertData(data, cur, conn): + query = "INSERT INTO `data` ( \ + header_id, section, address, size, \ + name, lib, obj_name) \ + VALUES (?, ?, ?, ?, ? ,?, ?)" + cur.executemany(query, data) + conn.commit() + + +def main(): + args = parseArgs() + dbConn = mariadbConnect(args) + reportFile = open(args.report_file) + dbCurs = dbConn.cursor() + createTables(dbCurs, dbConn) + headerID = insertHeader(parseEnv(), dbCurs, dbConn) + insertData(parseFile(reportFile, headerID), dbCurs, dbConn) + reportFile.close() + dbCurs.close() + + +if __name__ == "__main__": + main() diff --git a/scripts/toolchain/fbtenv.cmd b/scripts/toolchain/fbtenv.cmd index aac2a33091..f955a4db3f 100644 --- a/scripts/toolchain/fbtenv.cmd +++ b/scripts/toolchain/fbtenv.cmd @@ -13,7 +13,7 @@ if not [%FBT_NOENV%] == [] ( exit /b 0 ) -set "FLIPPER_TOOLCHAIN_VERSION=8" +set "FLIPPER_TOOLCHAIN_VERSION=9" set "FBT_TOOLCHAIN_ROOT=%FBT_ROOT%\toolchain\i686-windows" diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index 654b1fe0d7..d9d3cbe89b 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -5,7 +5,7 @@ # public variables DEFAULT_SCRIPT_PATH="$(pwd -P)"; SCRIPT_PATH="${SCRIPT_PATH:-$DEFAULT_SCRIPT_PATH}"; -FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"8"}"; +FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"9"}"; FBT_TOOLCHAIN_PATH="${FBT_TOOLCHAIN_PATH:-$SCRIPT_PATH}"; fbtenv_check_sourced() @@ -13,12 +13,9 @@ fbtenv_check_sourced() case "${ZSH_EVAL_CONTEXT:-""}" in *:file:*) return 0;; esac - case ${0##*/} in dash|-dash|bash|-bash|ksh|-ksh|sh|-sh) + case ${0##*/} in dash|-dash|bash|-bash|ksh|-ksh|sh|-sh|*.sh|fbt) return 0;; esac - if [ "$(basename $0)" = "fbt" ]; then - return 0; - fi echo "Running this script manually is wrong, please source it"; echo "Example:"; printf "\tsource scripts/toolchain/fbtenv.sh\n"; @@ -202,6 +199,7 @@ fbtenv_main() fbtenv_check_script_path || return 1; fbtenv_get_kernel_type || return 1; fbtenv_check_download_toolchain || return 1; + PS1="[FBT]$PS1"; PATH="$TOOLCHAIN_ARCH_DIR/python/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/protobuf/bin:$PATH"; From ddd5d5a535ea29854b9ae1bbf4b80adb7c826746 Mon Sep 17 00:00:00 2001 From: Max Andreev Date: Tue, 23 Aug 2022 14:48:39 +0300 Subject: [PATCH 19/78] fix Amap reports outside pull-request (#1642) --- .github/workflows/amap_analyse.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/amap_analyse.yml b/.github/workflows/amap_analyse.yml index 3bfcba2cf5..dd903e2e83 100644 --- a/.github/workflows/amap_analyse.yml +++ b/.github/workflows/amap_analyse.yml @@ -103,13 +103,15 @@ jobs: export COMMIT_HASH="${{steps.names.outputs.commit-hash}}" export COMMIT_MSG="${{steps.names.outputs.commit-msg}}" export BRANCH_NAME="${{steps.names.outputs.branch-name}}" - export PULL_ID="${{steps.names.outputs.pull-id}}" - export PULL_NAME="${{steps.names.outputs.pull-name}}" export BSS_SIZE="$(get_size ".bss")" export TEXT_SIZE="$(get_size ".text")" export RODATA_SIZE="$(get_size ".rodata")" export DATA_SIZE="$(get_size ".data")" export FREE_FLASH_SIZE="$(get_size ".free_flash")" + if [[ ${{ github.event_name }} == 'pull_request' ]]; then + export PULL_ID="${{steps.names.outputs.pull-id}}" + export PULL_NAME="${{steps.names.outputs.pull-name}}" + fi python3 -m pip install mariadb python3 scripts/amap_mariadb_insert.py \ ${{ secrets.AMAP_MARIADB_USER }} \ From 545dabadb7cceaedd58d11c35ce32df7bece1a39 Mon Sep 17 00:00:00 2001 From: Daniel <71837281+darmiel@users.noreply.github.com> Date: Tue, 23 Aug 2022 14:48:08 +0200 Subject: [PATCH 20/78] refactor[unirf]: moved environment to struct --- applications/unirfremix/unirfremix_app.c | 73 +++++++++++++++--------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/applications/unirfremix/unirfremix_app.c b/applications/unirfremix/unirfremix_app.c index 83aeaa2e84..07cd65d830 100644 --- a/applications/unirfremix/unirfremix_app.c +++ b/applications/unirfremix/unirfremix_app.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #define UNIRFMAP_FOLDER "/ext/unirf" #define UNIRFMAP_EXTENSION ".txt" @@ -30,6 +32,7 @@ typedef struct { Gui* gui; SubGhzSetting* setting; + SubGhzEnvironment* environment; string_t up_file; string_t down_file; @@ -69,7 +72,6 @@ typedef struct { int file_blank; string_t signal; - } UniRFRemix; typedef struct { @@ -88,6 +90,11 @@ UniRFPreset* unirf_preset_alloc(void) { return preset; } +void unirf_preset_free(UniRFPreset* preset) { + string_clear(preset->name); + free(preset); +} + static char* char_to_str(char* str, int i) { char* converted = malloc(sizeof(char) * i + 1); memcpy(converted, str, i); @@ -601,17 +608,8 @@ static bool unirfremix_send_sub( return false; } - SubGhzEnvironment* environment = subghz_environment_alloc(); - subghz_environment_load_keystore(environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); - subghz_environment_load_keystore(environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); - subghz_environment_set_came_atomo_rainbow_table_file_name( - environment, EXT_PATH("subghz/assets/came_atomo")); - subghz_environment_set_nice_flor_s_rainbow_table_file_name( - environment, EXT_PATH("subghz/assets/nice_flor_s")); - - SubGhzReceiver* subghz_receiver = subghz_receiver_alloc_init(environment); - - UniRFPreset* preset = unirf_preset_alloc(); + SubGhzReceiver* subghz_receiver = subghz_receiver_alloc_init(app->environment); // no + UniRFPreset* preset = unirf_preset_alloc(); // no if(!unirf_key_load(preset, fff_file, fff_data, app->setting, subghz_receiver, path)) { FURI_LOG_E(TAG, "Could not load key"); return false; @@ -636,6 +634,9 @@ static bool unirfremix_send_sub( string_t temp_str; string_init(temp_str); + string_t temp_protocol_str; + string_init(temp_protocol_str); + bool res = false; do { if(!flipper_format_rewind(fff_file)) { @@ -643,7 +644,7 @@ static bool unirfremix_send_sub( break; } - if(!flipper_format_read_string(fff_file, "Protocol", temp_str)) { + if(!flipper_format_read_string(fff_file, "Protocol", temp_protocol_str)) { FURI_LOG_E(TAG, "Could not read Protocol"); break; } @@ -655,8 +656,8 @@ static bool unirfremix_send_sub( } SubGhzTransmitter* transmitter = - subghz_transmitter_alloc_init(environment, string_get_cstr(temp_str)); - FURI_LOG_I(TAG, "Got transmitter for %s", string_get_cstr(temp_str)); + subghz_transmitter_alloc_init(app->environment, string_get_cstr(temp_protocol_str)); + FURI_LOG_I(TAG, "Got transmitter for %s", string_get_cstr(temp_protocol_str)); if(transmitter) { subghz_transmitter_deserialize(transmitter, fff_data); @@ -686,22 +687,17 @@ static bool unirfremix_send_sub( furi_hal_subghz_stop_async_tx(); subghz_transmitter_stop(transmitter); - subghz_transmitter_free(transmitter); flipper_format_file_close(fff_file); - { - string_t decode_str; - string_init(decode_str); - subghz_protocol_decoder_base_deserialize(preset->decoder, fff_data); - subghz_protocol_decoder_base_get_string(preset->decoder, decode_str); - FURI_LOG_I(TAG, "Decoded: %s", string_get_cstr(decode_str)); - string_clear(decode_str); - } + subghz_protocol_decoder_base_deserialize(preset->decoder, fff_data); + subghz_protocol_decoder_base_get_string(preset->decoder, temp_str); + FURI_LOG_I(TAG, "Decoded: %s", string_get_cstr(temp_str)); FURI_LOG_I(TAG, "Checking if protocol is dynamic"); const SubGhzProtocol* registry_protocol = - subghz_protocol_registry_get_by_name(string_get_cstr(temp_str)); + subghz_protocol_registry_get_by_name(string_get_cstr(temp_protocol_str)); + FURI_LOG_I(TAG, "Protocol-TYPE %d", registry_protocol->type); if(registry_protocol && registry_protocol->type == SubGhzProtocolTypeDynamic) { FURI_LOG_I(TAG, " Protocol is dynamic. Updating Repeat"); unirf_save_protocol_to_file(fff_data, path); @@ -710,6 +706,8 @@ static bool unirfremix_send_sub( FURI_LOG_E(TAG, "Sending not allowed"); } + subghz_transmitter_free(transmitter); + FURI_LOG_I(TAG, "Cleaning up."); furi_hal_subghz_idle(); furi_hal_subghz_sleep(); @@ -719,10 +717,18 @@ static bool unirfremix_send_sub( res = true; } while(0); + unirf_preset_free(preset); + string_clear(temp_str); + string_clear(temp_protocol_str); + unirfremix_end_send(app); - subghz_environment_free(environment); + keeloq_reset_mfname(); + keeloq_reset_kl_type(); + star_line_reset_mfname(); + star_line_reset_kl_type(); + return res; } @@ -881,9 +887,20 @@ UniRFRemix* unirfremix_alloc() { app->gui = furi_record_open(RECORD_GUI); gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen); + // load subghz presets app->setting = subghz_setting_alloc(); subghz_setting_load(app->setting, EXT_PATH("subghz/assets/setting_user")); + // load mfcodes + app->environment = subghz_environment_alloc(); + subghz_environment_load_keystore(app->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); + subghz_environment_load_keystore( + app->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); + subghz_environment_set_came_atomo_rainbow_table_file_name( + app->environment, EXT_PATH("subghz/assets/came_atomo")); + subghz_environment_set_nice_flor_s_rainbow_table_file_name( + app->environment, EXT_PATH("subghz/assets/nice_flor_s")); + return app; } @@ -902,6 +919,7 @@ void unirfremix_free(UniRFRemix* app) { string_clear(app->ok_l); string_clear(app->file_path); + string_clear(app->signal); gui_remove_view_port(app->gui, app->view_port); furi_record_close(RECORD_GUI); @@ -911,6 +929,9 @@ void unirfremix_free(UniRFRemix* app) { furi_mutex_free(app->model_mutex); + subghz_setting_free(app->setting); + subghz_environment_free(app->environment); + free(app); } From f92127c0a7053e0a91dc6fb605bfd8ebefac937b Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Tue, 23 Aug 2022 06:19:17 -0700 Subject: [PATCH 21/78] Picopass load/info/delete (#1562) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * increase stack size * rfalPicoPassPollerWriteBlock * UI for loading picopass * Move picopass parsing and add delete, delete success Co-authored-by: あく --- applications/picopass/application.fam | 2 +- applications/picopass/picopass.c | 23 ++ applications/picopass/picopass_device.c | 227 +++++++++++++++++- applications/picopass/picopass_device.h | 21 ++ applications/picopass/picopass_i.h | 5 + applications/picopass/picopass_worker.c | 99 +------- applications/picopass/picopass_worker_i.h | 9 + .../picopass/scenes/picopass_scene_config.h | 4 + .../picopass/scenes/picopass_scene_delete.c | 58 +++++ .../scenes/picopass_scene_delete_success.c | 40 +++ .../scenes/picopass_scene_device_info.c | 82 +++++++ .../scenes/picopass_scene_file_select.c | 25 ++ .../scenes/picopass_scene_saved_menu.c | 24 ++ .../picopass/scenes/picopass_scene_start.c | 5 + lib/ST25RFAL002/include/rfal_picopass.h | 2 + lib/ST25RFAL002/source/rfal_picopass.c | 26 ++ 16 files changed, 559 insertions(+), 93 deletions(-) create mode 100644 applications/picopass/scenes/picopass_scene_delete.c create mode 100755 applications/picopass/scenes/picopass_scene_delete_success.c create mode 100644 applications/picopass/scenes/picopass_scene_device_info.c create mode 100644 applications/picopass/scenes/picopass_scene_file_select.c diff --git a/applications/picopass/application.fam b/applications/picopass/application.fam index 223094250d..ffc4b5182b 100644 --- a/applications/picopass/application.fam +++ b/applications/picopass/application.fam @@ -5,7 +5,7 @@ App( entry_point="picopass_app", cdefines=["APP_PICOPASS"], requires=["storage", "gui"], - stack_size=1 * 1024, + stack_size=4 * 1024, icon="A_Plugins_14", order=30, ) diff --git a/applications/picopass/picopass.c b/applications/picopass/picopass.c index 8c0db4e2a7..e9f48b6765 100644 --- a/applications/picopass/picopass.c +++ b/applications/picopass/picopass.c @@ -56,6 +56,11 @@ Picopass* picopass_alloc() { view_dispatcher_add_view( picopass->view_dispatcher, PicopassViewPopup, popup_get_view(picopass->popup)); + // Loading + picopass->loading = loading_alloc(); + view_dispatcher_add_view( + picopass->view_dispatcher, PicopassViewLoading, loading_get_view(picopass->loading)); + // Text Input picopass->text_input = text_input_alloc(); view_dispatcher_add_view( @@ -86,6 +91,10 @@ void picopass_free(Picopass* picopass) { view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewPopup); popup_free(picopass->popup); + // Loading + view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewLoading); + loading_free(picopass->loading); + // TextInput view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewTextInput); text_input_free(picopass->text_input); @@ -148,6 +157,20 @@ void picopass_blink_stop(Picopass* picopass) { notification_message(picopass->notifications, &picopass_sequence_blink_stop); } +void picopass_show_loading_popup(void* context, bool show) { + Picopass* picopass = context; + TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); + + if(show) { + // Raise timer priority so that animations can play + vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1); + view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewLoading); + } else { + // Restore default timer priority + vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY); + } +} + int32_t picopass_app(void* p) { UNUSED(p); Picopass* picopass = picopass_alloc(); diff --git a/applications/picopass/picopass_device.c b/applications/picopass/picopass_device.c index 9b422edd30..4cd6faaab7 100644 --- a/applications/picopass/picopass_device.c +++ b/applications/picopass/picopass_device.c @@ -8,6 +8,9 @@ static const char* picopass_file_header = "Flipper Picopass device"; static const uint32_t picopass_file_version = 1; +const uint8_t picopass_iclass_decryptionkey[] = + {0xb4, 0x21, 0x2c, 0xca, 0xb7, 0xed, 0x21, 0x0f, 0x7b, 0x93, 0xd4, 0x59, 0x39, 0xc7, 0xdd, 0x36}; + PicopassDevice* picopass_device_alloc() { PicopassDevice* picopass_dev = malloc(sizeof(PicopassDevice)); picopass_dev->dev_data.pacs.legacy = false; @@ -15,6 +18,7 @@ PicopassDevice* picopass_device_alloc() { picopass_dev->dev_data.pacs.pin_length = 0; picopass_dev->storage = furi_record_open(RECORD_STORAGE); picopass_dev->dialogs = furi_record_open(RECORD_DIALOGS); + string_init(picopass_dev->load_path); return picopass_dev; } @@ -111,7 +115,7 @@ static bool picopass_device_save_file( } while(0); if(!saved) { - dialog_message_show_storage_error(dev->dialogs, "Can not save\nkey file"); + dialog_message_show_storage_error(dev->dialogs, "Can not save\nfile"); } string_clear(temp_str); flipper_format_free(file); @@ -128,11 +132,83 @@ bool picopass_device_save(PicopassDevice* dev, const char* dev_name) { return false; } +static bool picopass_device_load_data(PicopassDevice* dev, string_t path, bool show_dialog) { + bool parsed = false; + FlipperFormat* file = flipper_format_file_alloc(dev->storage); + PicopassBlock* AA1 = dev->dev_data.AA1; + PicopassPacs* pacs = &dev->dev_data.pacs; + string_t temp_str; + string_init(temp_str); + bool deprecated_version = false; + + if(dev->loading_cb) { + dev->loading_cb(dev->loading_cb_ctx, true); + } + + do { + if(!flipper_format_file_open_existing(file, string_get_cstr(path))) break; + + // Read and verify file header + uint32_t version = 0; + if(!flipper_format_read_header(file, temp_str, &version)) break; + if(string_cmp_str(temp_str, picopass_file_header) || (version != picopass_file_version)) { + deprecated_version = true; + break; + } + + // Parse header blocks + bool block_read = true; + for(size_t i = 0; i < 6; i++) { + string_printf(temp_str, "Block %d", i); + if(!flipper_format_read_hex( + file, string_get_cstr(temp_str), AA1[i].data, PICOPASS_BLOCK_LEN)) { + block_read = false; + break; + } + } + + size_t app_limit = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0]; + for(size_t i = 6; i < app_limit; i++) { + string_printf(temp_str, "Block %d", i); + if(!flipper_format_read_hex( + file, string_get_cstr(temp_str), AA1[i].data, PICOPASS_BLOCK_LEN)) { + block_read = false; + break; + } + } + if(!block_read) break; + + if(picopass_device_parse_credential(AA1, pacs) != ERR_NONE) break; + if(picopass_device_parse_wiegand(pacs->credential, &pacs->record) != ERR_NONE) break; + + parsed = true; + } while(false); + + if(dev->loading_cb) { + dev->loading_cb(dev->loading_cb_ctx, false); + } + + if((!parsed) && (show_dialog)) { + if(deprecated_version) { + dialog_message_show_storage_error(dev->dialogs, "File format deprecated"); + } else { + dialog_message_show_storage_error(dev->dialogs, "Can not parse\nfile"); + } + } + + string_clear(temp_str); + flipper_format_free(file); + + return parsed; +} + void picopass_device_clear(PicopassDevice* dev) { furi_assert(dev); picopass_device_data_clear(&dev->dev_data); memset(&dev->dev_data, 0, sizeof(dev->dev_data)); + dev->format = PicopassDeviceSaveFormatHF; + string_reset(dev->load_path); } void picopass_device_free(PicopassDevice* picopass_dev) { @@ -144,6 +220,36 @@ void picopass_device_free(PicopassDevice* picopass_dev) { free(picopass_dev); } +bool picopass_file_select(PicopassDevice* dev) { + furi_assert(dev); + + // Input events and views are managed by file_browser + string_t picopass_app_folder; + string_init_set_str(picopass_app_folder, PICOPASS_APP_FOLDER); + bool res = dialog_file_browser_show( + dev->dialogs, + dev->load_path, + picopass_app_folder, + PICOPASS_APP_EXTENSION, + true, + &I_Nfc_10px, + true); + string_clear(picopass_app_folder); + if(res) { + string_t filename; + string_init(filename); + path_extract_filename(dev->load_path, filename, true); + strncpy(dev->dev_name, string_get_cstr(filename), PICOPASS_DEV_NAME_MAX_LEN); + res = picopass_device_load_data(dev, dev->load_path, true); + if(res) { + picopass_device_set_name(dev, dev->dev_name); + } + string_clear(filename); + } + + return res; +} + void picopass_device_data_clear(PicopassDeviceData* dev_data) { for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) { memset(dev_data->AA1[i].data, 0, sizeof(dev_data->AA1[i].data)); @@ -152,3 +258,122 @@ void picopass_device_data_clear(PicopassDeviceData* dev_data) { dev_data->pacs.se_enabled = false; dev_data->pacs.pin_length = 0; } + +bool picopass_device_delete(PicopassDevice* dev, bool use_load_path) { + furi_assert(dev); + + bool deleted = false; + string_t file_path; + string_init(file_path); + + do { + // Delete original file + if(use_load_path && !string_empty_p(dev->load_path)) { + string_set(file_path, dev->load_path); + } else { + string_printf( + file_path, "%s/%s%s", PICOPASS_APP_FOLDER, dev->dev_name, PICOPASS_APP_EXTENSION); + } + if(!storage_simply_remove(dev->storage, string_get_cstr(file_path))) break; + deleted = true; + } while(0); + + if(!deleted) { + dialog_message_show_storage_error(dev->dialogs, "Can not remove file"); + } + + string_clear(file_path); + return deleted; +} + +void picopass_device_set_loading_callback( + PicopassDevice* dev, + PicopassLoadingCallback callback, + void* context) { + furi_assert(dev); + + dev->loading_cb = callback; + dev->loading_cb_ctx = context; +} + +ReturnCode picopass_device_decrypt(uint8_t* enc_data, uint8_t* dec_data) { + uint8_t key[32] = {0}; + memcpy(key, picopass_iclass_decryptionkey, sizeof(picopass_iclass_decryptionkey)); + mbedtls_des3_context ctx; + mbedtls_des3_init(&ctx); + mbedtls_des3_set2key_dec(&ctx, key); + mbedtls_des3_crypt_ecb(&ctx, enc_data, dec_data); + mbedtls_des3_free(&ctx); + return ERR_NONE; +} + +ReturnCode picopass_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pacs) { + ReturnCode err; + + // Thank you proxmark! + pacs->legacy = (memcmp(AA1[5].data, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0); + pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0); + + pacs->biometrics = AA1[6].data[4]; + pacs->pin_length = AA1[6].data[6] & 0x0F; + pacs->encryption = AA1[6].data[7]; + + if(pacs->encryption == PicopassDeviceEncryption3DES) { + FURI_LOG_D(TAG, "3DES Encrypted"); + err = picopass_device_decrypt(AA1[7].data, pacs->credential); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "decrypt error %d", err); + return err; + } + + err = picopass_device_decrypt(AA1[8].data, pacs->pin0); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "decrypt error %d", err); + return err; + } + + err = picopass_device_decrypt(AA1[9].data, pacs->pin1); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "decrypt error %d", err); + return err; + } + } else if(pacs->encryption == PicopassDeviceEncryptionNone) { + FURI_LOG_D(TAG, "No Encryption"); + memcpy(pacs->credential, AA1[7].data, PICOPASS_BLOCK_LEN); + memcpy(pacs->pin0, AA1[8].data, PICOPASS_BLOCK_LEN); + memcpy(pacs->pin1, AA1[9].data, PICOPASS_BLOCK_LEN); + } else if(pacs->encryption == PicopassDeviceEncryptionDES) { + FURI_LOG_D(TAG, "DES Encrypted"); + } else { + FURI_LOG_D(TAG, "Unknown encryption"); + } + + return ERR_NONE; +} + +ReturnCode picopass_device_parse_wiegand(uint8_t* data, PicopassWiegandRecord* record) { + uint32_t* halves = (uint32_t*)data; + if(halves[0] == 0) { + uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[1])); + record->bitLength = 31 - leading0s; + } else { + uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[0])); + record->bitLength = 63 - leading0s; + } + FURI_LOG_D(TAG, "bitLength: %d", record->bitLength); + + if(record->bitLength == 26) { + uint8_t* v4 = data + 4; + uint32_t bot = v4[3] | (v4[2] << 8) | (v4[1] << 16) | (v4[0] << 24); + + record->CardNumber = (bot >> 1) & 0xFFFF; + record->FacilityCode = (bot >> 17) & 0xFF; + FURI_LOG_D(TAG, "FC:%u CN: %u\n", record->FacilityCode, record->CardNumber); + record->valid = true; + } else { + record->CardNumber = 0; + record->FacilityCode = 0; + record->valid = false; + } + return ERR_NONE; +} diff --git a/applications/picopass/picopass_device.h b/applications/picopass/picopass_device.h index 89e031ca7d..0415b8794c 100644 --- a/applications/picopass/picopass_device.h +++ b/applications/picopass/picopass_device.h @@ -7,6 +7,10 @@ #include +#include +#include +#include + #define PICOPASS_DEV_NAME_MAX_LEN 22 #define PICOPASS_READER_DATA_MAX_SIZE 64 #define PICOPASS_BLOCK_LEN 8 @@ -20,6 +24,8 @@ #define PICOPASS_APP_EXTENSION ".picopass" #define PICOPASS_APP_SHADOW_EXTENSION ".pas" +typedef void (*PicopassLoadingCallback)(void* context, bool state); + typedef enum { PicopassDeviceEncryptionUnknown = 0, PicopassDeviceEncryptionNone = 0x14, @@ -67,6 +73,9 @@ typedef struct { char dev_name[PICOPASS_DEV_NAME_MAX_LEN + 1]; string_t load_path; PicopassDeviceSaveFormat format; + PicopassLoadingCallback loading_cb; + void* loading_cb_ctx; + } PicopassDevice; PicopassDevice* picopass_device_alloc(); @@ -77,6 +86,18 @@ void picopass_device_set_name(PicopassDevice* dev, const char* name); bool picopass_device_save(PicopassDevice* dev, const char* dev_name); +bool picopass_file_select(PicopassDevice* dev); + void picopass_device_data_clear(PicopassDeviceData* dev_data); void picopass_device_clear(PicopassDevice* dev); + +bool picopass_device_delete(PicopassDevice* dev, bool use_load_path); + +void picopass_device_set_loading_callback( + PicopassDevice* dev, + PicopassLoadingCallback callback, + void* context); + +ReturnCode picopass_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pacs); +ReturnCode picopass_device_parse_wiegand(uint8_t* data, PicopassWiegandRecord* record); diff --git a/applications/picopass/picopass_i.h b/applications/picopass/picopass_i.h index dbf4f8be58..d295f53ac1 100644 --- a/applications/picopass/picopass_i.h +++ b/applications/picopass/picopass_i.h @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -55,6 +56,7 @@ struct Picopass { // Common Views Submenu* submenu; Popup* popup; + Loading* loading; TextInput* text_input; Widget* widget; }; @@ -62,6 +64,7 @@ struct Picopass { typedef enum { PicopassViewMenu, PicopassViewPopup, + PicopassViewLoading, PicopassViewTextInput, PicopassViewWidget, } PicopassView; @@ -75,3 +78,5 @@ void picopass_text_store_clear(Picopass* picopass); void picopass_blink_start(Picopass* picopass); void picopass_blink_stop(Picopass* picopass); + +void picopass_show_loading_popup(void* context, bool show); diff --git a/applications/picopass/picopass_worker.c b/applications/picopass/picopass_worker.c index 3079a98c4d..88df8d45b8 100644 --- a/applications/picopass/picopass_worker.c +++ b/applications/picopass/picopass_worker.c @@ -1,23 +1,9 @@ #include "picopass_worker_i.h" -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include #define TAG "PicopassWorker" const uint8_t picopass_iclass_key[] = {0xaf, 0xa7, 0x85, 0xa7, 0xda, 0xb3, 0x33, 0x78}; -const uint8_t picopass_iclass_decryptionkey[] = - {0xb4, 0x21, 0x2c, 0xca, 0xb7, 0xed, 0x21, 0x0f, 0x7b, 0x93, 0xd4, 0x59, 0x39, 0xc7, 0xdd, 0x36}; +const uint8_t picopass_factory_key[] = {0x76, 0x65, 0x54, 0x43, 0x32, 0x21, 0x10, 0x00}; static void picopass_worker_enable_field() { st25r3916TxRxOn(); @@ -31,44 +17,6 @@ static ReturnCode picopass_worker_disable_field(ReturnCode rc) { return rc; } -static ReturnCode picopass_worker_decrypt(uint8_t* enc_data, uint8_t* dec_data) { - uint8_t key[32] = {0}; - memcpy(key, picopass_iclass_decryptionkey, sizeof(picopass_iclass_decryptionkey)); - mbedtls_des3_context ctx; - mbedtls_des3_init(&ctx); - mbedtls_des3_set2key_dec(&ctx, key); - mbedtls_des3_crypt_ecb(&ctx, enc_data, dec_data); - mbedtls_des3_free(&ctx); - return ERR_NONE; -} - -static ReturnCode picopass_worker_parse_wiegand(uint8_t* data, PicopassWiegandRecord* record) { - uint32_t* halves = (uint32_t*)data; - if(halves[0] == 0) { - uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[1])); - record->bitLength = 31 - leading0s; - } else { - uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[0])); - record->bitLength = 63 - leading0s; - } - FURI_LOG_D(TAG, "bitLength: %d", record->bitLength); - - if(record->bitLength == 26) { - uint8_t* v4 = data + 4; - uint32_t bot = v4[3] | (v4[2] << 8) | (v4[1] << 16) | (v4[0] << 24); - - record->CardNumber = (bot >> 1) & 0xFFFF; - record->FacilityCode = (bot >> 17) & 0xFF; - FURI_LOG_D(TAG, "FC:%u CN: %u\n", record->FacilityCode, record->CardNumber); - record->valid = true; - } else { - record->CardNumber = 0; - record->FacilityCode = 0; - record->valid = false; - } - return ERR_NONE; -} - /***************************** Picopass Worker API *******************************/ PicopassWorker* picopass_worker_alloc() { @@ -272,46 +220,15 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) { FURI_LOG_E(TAG, "picopass_read_card error %d", err); } - // Thank you proxmark! - pacs->legacy = (memcmp(AA1[5].data, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0); - pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0); - - pacs->biometrics = AA1[6].data[4]; - pacs->pin_length = AA1[6].data[6] & 0x0F; - pacs->encryption = AA1[6].data[7]; - - if(pacs->encryption == PicopassDeviceEncryption3DES) { - FURI_LOG_D(TAG, "3DES Encrypted"); - err = picopass_worker_decrypt(AA1[7].data, pacs->credential); - if(err != ERR_NONE) { - FURI_LOG_E(TAG, "decrypt error %d", err); - break; - } - - err = picopass_worker_decrypt(AA1[8].data, pacs->pin0); - if(err != ERR_NONE) { - FURI_LOG_E(TAG, "decrypt error %d", err); - break; - } - - err = picopass_worker_decrypt(AA1[9].data, pacs->pin1); - if(err != ERR_NONE) { - FURI_LOG_E(TAG, "decrypt error %d", err); - break; - } - } else if(pacs->encryption == PicopassDeviceEncryptionNone) { - FURI_LOG_D(TAG, "No Encryption"); - memcpy(pacs->credential, AA1[7].data, PICOPASS_BLOCK_LEN); - memcpy(pacs->pin0, AA1[8].data, PICOPASS_BLOCK_LEN); - memcpy(pacs->pin1, AA1[9].data, PICOPASS_BLOCK_LEN); - } else if(pacs->encryption == PicopassDeviceEncryptionDES) { - FURI_LOG_D(TAG, "DES Encrypted"); - } else { - FURI_LOG_D(TAG, "Unknown encryption"); - break; + err = picopass_device_parse_credential(AA1, pacs); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "picopass_device_parse_credential error %d", err); } - picopass_worker_parse_wiegand(pacs->credential, &pacs->record); + err = picopass_device_parse_wiegand(pacs->credential, &pacs->record); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "picopass_device_parse_wiegand error %d", err); + } // Notify caller and exit if(picopass_worker->callback) { diff --git a/applications/picopass/picopass_worker_i.h b/applications/picopass/picopass_worker_i.h index 2610d5e7f0..789951900b 100644 --- a/applications/picopass/picopass_worker_i.h +++ b/applications/picopass/picopass_worker_i.h @@ -6,6 +6,15 @@ #include #include +#include + +#include +#include +#include +#include + +#include + struct PicopassWorker { FuriThread* thread; Storage* storage; diff --git a/applications/picopass/scenes/picopass_scene_config.h b/applications/picopass/scenes/picopass_scene_config.h index 0a3e73f297..87745378b6 100755 --- a/applications/picopass/scenes/picopass_scene_config.h +++ b/applications/picopass/scenes/picopass_scene_config.h @@ -5,3 +5,7 @@ ADD_SCENE(picopass, card_menu, CardMenu) ADD_SCENE(picopass, save_name, SaveName) ADD_SCENE(picopass, save_success, SaveSuccess) ADD_SCENE(picopass, saved_menu, SavedMenu) +ADD_SCENE(picopass, file_select, FileSelect) +ADD_SCENE(picopass, device_info, DeviceInfo) +ADD_SCENE(picopass, delete, Delete) +ADD_SCENE(picopass, delete_success, DeleteSuccess) diff --git a/applications/picopass/scenes/picopass_scene_delete.c b/applications/picopass/scenes/picopass_scene_delete.c new file mode 100644 index 0000000000..fb23cb5d4d --- /dev/null +++ b/applications/picopass/scenes/picopass_scene_delete.c @@ -0,0 +1,58 @@ +#include "../picopass_i.h" + +void picopass_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) { + Picopass* picopass = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(picopass->view_dispatcher, result); + } +} + +void picopass_scene_delete_on_enter(void* context) { + Picopass* picopass = context; + + // Setup Custom Widget view + char temp_str[64]; + snprintf(temp_str, sizeof(temp_str), "\e#Delete %s?\e#", picopass->dev->dev_name); + widget_add_text_box_element( + picopass->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, temp_str, false); + widget_add_button_element( + picopass->widget, + GuiButtonTypeLeft, + "Back", + picopass_scene_delete_widget_callback, + picopass); + widget_add_button_element( + picopass->widget, + GuiButtonTypeRight, + "Delete", + picopass_scene_delete_widget_callback, + picopass); + + view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget); +} + +bool picopass_scene_delete_on_event(void* context, SceneManagerEvent event) { + Picopass* picopass = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + return scene_manager_previous_scene(picopass->scene_manager); + } else if(event.event == GuiButtonTypeRight) { + if(picopass_device_delete(picopass->dev, true)) { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneDeleteSuccess); + } else { + scene_manager_search_and_switch_to_previous_scene( + picopass->scene_manager, PicopassSceneStart); + } + consumed = true; + } + } + return consumed; +} + +void picopass_scene_delete_on_exit(void* context) { + Picopass* picopass = context; + + widget_reset(picopass->widget); +} diff --git a/applications/picopass/scenes/picopass_scene_delete_success.c b/applications/picopass/scenes/picopass_scene_delete_success.c new file mode 100755 index 0000000000..f2a36a7fb1 --- /dev/null +++ b/applications/picopass/scenes/picopass_scene_delete_success.c @@ -0,0 +1,40 @@ +#include "../picopass_i.h" + +void picopass_scene_delete_success_popup_callback(void* context) { + Picopass* picopass = context; + view_dispatcher_send_custom_event(picopass->view_dispatcher, PicopassCustomEventViewExit); +} + +void picopass_scene_delete_success_on_enter(void* context) { + Picopass* picopass = context; + + // Setup view + Popup* popup = picopass->popup; + popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); + popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, picopass); + popup_set_callback(popup, picopass_scene_delete_success_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewPopup); +} + +bool picopass_scene_delete_success_on_event(void* context, SceneManagerEvent event) { + Picopass* picopass = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == PicopassCustomEventViewExit) { + consumed = scene_manager_search_and_switch_to_previous_scene( + picopass->scene_manager, PicopassSceneStart); + } + } + return consumed; +} + +void picopass_scene_delete_success_on_exit(void* context) { + Picopass* picopass = context; + + // Clear view + popup_reset(picopass->popup); +} diff --git a/applications/picopass/scenes/picopass_scene_device_info.c b/applications/picopass/scenes/picopass_scene_device_info.c new file mode 100644 index 0000000000..38891b6733 --- /dev/null +++ b/applications/picopass/scenes/picopass_scene_device_info.c @@ -0,0 +1,82 @@ +#include "../picopass_i.h" +#include + +void picopass_scene_device_info_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + Picopass* picopass = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(picopass->view_dispatcher, result); + } +} + +void picopass_scene_device_info_on_enter(void* context) { + Picopass* picopass = context; + + string_t credential_str; + string_t wiegand_str; + string_init(credential_str); + string_init(wiegand_str); + + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + + // Setup view + PicopassPacs* pacs = &picopass->dev->dev_data.pacs; + Widget* widget = picopass->widget; + + size_t bytesLength = 1 + pacs->record.bitLength / 8; + string_set_str(credential_str, ""); + for(uint8_t i = PICOPASS_BLOCK_LEN - bytesLength; i < PICOPASS_BLOCK_LEN; i++) { + string_cat_printf(credential_str, " %02X", pacs->credential[i]); + } + + if(pacs->record.valid) { + string_cat_printf( + wiegand_str, "FC: %u CN: %u", pacs->record.FacilityCode, pacs->record.CardNumber); + } else { + string_cat_printf(wiegand_str, "%d bits", pacs->record.bitLength); + } + + widget_add_string_element( + widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str)); + widget_add_string_element( + widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(credential_str)); + + string_clear(credential_str); + string_clear(wiegand_str); + + widget_add_button_element( + picopass->widget, + GuiButtonTypeLeft, + "Back", + picopass_scene_device_info_widget_callback, + picopass); + + view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget); +} + +bool picopass_scene_device_info_on_event(void* context, SceneManagerEvent event) { + Picopass* picopass = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(picopass->scene_manager); + } else if(event.event == PicopassCustomEventViewExit) { + view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget); + consumed = true; + } + return consumed; +} + +void picopass_scene_device_info_on_exit(void* context) { + Picopass* picopass = context; + + // Clear views + widget_reset(picopass->widget); +} diff --git a/applications/picopass/scenes/picopass_scene_file_select.c b/applications/picopass/scenes/picopass_scene_file_select.c new file mode 100644 index 0000000000..b3d4c3d73e --- /dev/null +++ b/applications/picopass/scenes/picopass_scene_file_select.c @@ -0,0 +1,25 @@ +#include "../picopass_i.h" +#include "picopass/picopass_device.h" + +void picopass_scene_file_select_on_enter(void* context) { + Picopass* picopass = context; + // Process file_select return + picopass_device_set_loading_callback(picopass->dev, picopass_show_loading_popup, picopass); + if(picopass_file_select(picopass->dev)) { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneSavedMenu); + } else { + scene_manager_search_and_switch_to_previous_scene( + picopass->scene_manager, PicopassSceneStart); + } + picopass_device_set_loading_callback(picopass->dev, NULL, picopass); +} + +bool picopass_scene_file_select_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void picopass_scene_file_select_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/picopass/scenes/picopass_scene_saved_menu.c b/applications/picopass/scenes/picopass_scene_saved_menu.c index 232cf26a97..8f0ce40bae 100644 --- a/applications/picopass/scenes/picopass_scene_saved_menu.c +++ b/applications/picopass/scenes/picopass_scene_saved_menu.c @@ -1,5 +1,11 @@ #include "../picopass_i.h" +enum SubmenuIndex { + SubmenuIndexDelete, + SubmenuIndexInfo, + SubmenuIndexWrite, +}; + void picopass_scene_saved_menu_submenu_callback(void* context, uint32_t index) { Picopass* picopass = context; @@ -8,6 +14,16 @@ void picopass_scene_saved_menu_submenu_callback(void* context, uint32_t index) { void picopass_scene_saved_menu_on_enter(void* context) { Picopass* picopass = context; + Submenu* submenu = picopass->submenu; + + submenu_add_item( + submenu, + "Delete", + SubmenuIndexDelete, + picopass_scene_saved_menu_submenu_callback, + picopass); + submenu_add_item( + submenu, "Info", SubmenuIndexInfo, picopass_scene_saved_menu_submenu_callback, picopass); submenu_set_selected_item( picopass->submenu, @@ -23,6 +39,14 @@ bool picopass_scene_saved_menu_on_event(void* context, SceneManagerEvent event) if(event.type == SceneManagerEventTypeCustom) { scene_manager_set_scene_state( picopass->scene_manager, PicopassSceneSavedMenu, event.event); + + if(event.event == SubmenuIndexDelete) { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneDelete); + consumed = true; + } else if(event.event == SubmenuIndexInfo) { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneDeviceInfo); + consumed = true; + } } return consumed; diff --git a/applications/picopass/scenes/picopass_scene_start.c b/applications/picopass/scenes/picopass_scene_start.c index 7f42fb1330..76c18a22a5 100644 --- a/applications/picopass/scenes/picopass_scene_start.c +++ b/applications/picopass/scenes/picopass_scene_start.c @@ -17,6 +17,8 @@ void picopass_scene_start_on_enter(void* context) { Submenu* submenu = picopass->submenu; submenu_add_item( submenu, "Read Card", SubmenuIndexRead, picopass_scene_start_submenu_callback, picopass); + submenu_add_item( + submenu, "Saved", SubmenuIndexSaved, picopass_scene_start_submenu_callback, picopass); submenu_set_selected_item( submenu, scene_manager_get_scene_state(picopass->scene_manager, PicopassSceneStart)); @@ -32,6 +34,9 @@ bool picopass_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.event == SubmenuIndexRead) { scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCard); consumed = true; + } else if(event.event == SubmenuIndexSaved) { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneFileSelect); + consumed = true; } scene_manager_set_scene_state(picopass->scene_manager, PicopassSceneStart, event.event); } diff --git a/lib/ST25RFAL002/include/rfal_picopass.h b/lib/ST25RFAL002/include/rfal_picopass.h index 5b8150251c..2baf96f375 100644 --- a/lib/ST25RFAL002/include/rfal_picopass.h +++ b/lib/ST25RFAL002/include/rfal_picopass.h @@ -26,6 +26,7 @@ enum { RFAL_PICOPASS_CMD_READCHECK = 0x88, RFAL_PICOPASS_CMD_CHECK = 0x05, RFAL_PICOPASS_CMD_READ = 0x0C, + RFAL_PICOPASS_CMD_WRITE = 0x0C, }; typedef struct { @@ -58,5 +59,6 @@ ReturnCode rfalPicoPassPollerSelect(uint8_t* csn, rfalPicoPassSelectRes* selRes) ReturnCode rfalPicoPassPollerReadCheck(rfalPicoPassReadCheckRes* rcRes); ReturnCode rfalPicoPassPollerCheck(uint8_t* mac, rfalPicoPassCheckRes* chkRes); ReturnCode rfalPicoPassPollerReadBlock(uint8_t blockNum, rfalPicoPassReadBlockRes* readRes); +ReturnCode rfalPicoPassPollerWriteBlock(uint8_t blockNum, uint8_t data[8], uint8_t mac[4]); #endif /* RFAL_PICOPASS_H */ diff --git a/lib/ST25RFAL002/source/rfal_picopass.c b/lib/ST25RFAL002/source/rfal_picopass.c index 55dbe6497b..d4422e4123 100644 --- a/lib/ST25RFAL002/source/rfal_picopass.c +++ b/lib/ST25RFAL002/source/rfal_picopass.c @@ -158,3 +158,29 @@ ReturnCode rfalPicoPassPollerReadBlock(uint8_t blockNum, rfalPicoPassReadBlockRe fwt); return ret; } + +ReturnCode rfalPicoPassPollerWriteBlock(uint8_t blockNum, uint8_t data[8], uint8_t mac[4]) { + ReturnCode ret; + + uint8_t txBuf[14] = {RFAL_PICOPASS_CMD_WRITE, blockNum, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + memcpy(txBuf + 2, data, RFAL_PICOPASS_MAX_BLOCK_LEN); + memcpy(txBuf + 10, mac, 4); + + uint16_t recvLen = 0; + uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS; + uint32_t fwt = rfalConvMsTo1fc(20); + rfalPicoPassReadBlockRes readRes; + + ret = rfalTransceiveBlockingTxRx( + txBuf, + sizeof(txBuf), + (uint8_t*)&readRes, + sizeof(rfalPicoPassReadBlockRes), + &recvLen, + flags, + fwt); + + // TODO: compare response + + return ret; +} From 9bfb641d3eddd30a8f8c5c216cb6e7c404aefe0a Mon Sep 17 00:00:00 2001 From: SG Date: Wed, 24 Aug 2022 01:57:39 +1000 Subject: [PATCH 22/78] [FL-2529][FL-1628] New LF-RFID subsystem (#1601) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Makefile: unit tests pack * RFID: pulse joiner and its unit test * Move pulse protocol helpers to appropriate place * Drop pulse_joiner tests * Generic protocol, protocols dictionary, unit test * Protocol dict unit test * iButton: protocols dictionary * Lib: varint * Lib: profiler * Unit test: varint * rfid: worker mockup * LFRFID: em4100 unit test * Storage: file_exist function * rfid: fsk osc * rfid: generic fsk demodulator * rfid: protocol em4100 * rfid: protocol h10301 * rfid: protocol io prox xsf * Unit test: rfid protocols * rfid: new hal * rfid: raw worker * Unit test: fix error output * rfid: worker * rfid: plain c cli * fw: migrate to scons * lfrfid: full io prox support * unit test: io prox protocol * SubGHZ: move bit defines to source * FSK oscillator: level duration compability * libs: bit manipulation library * lfrfid: ioprox protocol, use bit library and new level duration method of FSK ocillator * bit lib: unit tests * Bit lib: parity tests, remove every nth bit, copy bits * Lfrfid: awid protocol * bit lib: uint16 and uint32 getters, unit tests * lfrfid: FDX-B read, draft version * Minunit: better memeq assert * bit lib: reverse, print, print regions * Protocol dict: get protocol features, get protocol validate count * lfrfid worker: improved read * lfrfid raw worker: psk support * Cli: rfid plain C cli * protocol AWID: render * protocol em4100: render * protocol h10301: render * protocol indala26: support every indala 26 scramble * Protocol IO Prox: render * Protocol FDX-B: advanced read * lfrfid: remove unused test function * lfrfid: fix os primitives * bit lib: crc16 and unit tests * FDX-B: save data * lfrfid worker: increase stream size. Alloc raw worker only when needed. * lfrfid: indala26 emulation * lfrfid: prepare to write * lfrfid: fdx-b emulation * lfrfid: awid, ioprox write * lfrfid: write t55xx w\o validation * lfrfid: better t55xx block0 handling * lfrfid: use new t5577 functions in worker * lfrfid: improve protocol description * lfrfid: write and verify * lfrfid: delete cpp cli * lfrfid: improve worker usage * lfrfid-app: step to new worker * lfrfid: old indala (I40134) load fallback * lfrfid: indala26, recover wrong synced data * lfrfid: remove old worker * lfrfid app: dummy read screen * lfrfid app: less dummy read screen * lfrfid: generic 96-bit HID protocol (covers up to HID 37-bit) * rename * lfrfid: improve indala26 read * lfrfid: generic 192-bit HID protocol (covers all HID extended) * lfrfid: TODO about HID render * lfrfid: new protocol FDX-A * lfrfid-app: correct worker stop on exit * misc fixes * lfrfid: FDX-A and HID distinguishability has been fixed. * lfrfid: decode HID size header and render it (#1612) * lfrfid: rename HID96 and HID192 to HIDProx and HIDExt * lfrfid: extra actions scene * lfrfid: decode generic HID Proximity size lazily (#1618) * lib: stream of data buffers concept * lfrfid: raw file helper * lfrfid: changed raw worker api * lfrfid: packed varint pair * lfrfid: read stream speedup * lfrfid app: show read mode * Documentation * lfrfid app: raw read gui * lfrfid app: storage check for raw read * memleak fix * review fixes * lfrfid app: read blink color * lfrfid app: reset key name after read * review fixes * lfrfid app: fix copypasted text * review fixes * lfrfid: disable debug gpio * lfrfid: card detection events * lfrfid: change validation color from magenta to green * Update core_defines. * lfrfid: prefix fdx-b id by zeroes * lfrfid: parse up to 43-bit HID Proximity keys (#1640) * Fbt: downgrade toolchain and fix PS1 * lfrfid: fix unit tests * lfrfid app: remove printf * lfrfid: indala26, use bit 55 as data * lfrfid: indala26, better brief format * lfrfid: indala26, loading fallback * lfrfid: read timing tuning Co-authored-by: James Ide Co-authored-by: あく --- applications/archive/helpers/archive_apps.c | 18 +- .../archive/helpers/archive_favorites.c | 33 +- .../desktop/animations/animation_manager.c | 3 +- .../lfrfid/helpers/decoder_analyzer.cpp | 50 -- .../lfrfid/helpers/decoder_analyzer.h | 21 - .../lfrfid/helpers/decoder_emmarin.cpp | 72 -- applications/lfrfid/helpers/decoder_emmarin.h | 21 - .../lfrfid/helpers/decoder_gpio_out.cpp | 15 - .../lfrfid/helpers/decoder_gpio_out.h | 14 - applications/lfrfid/helpers/decoder_hid26.cpp | 98 --- applications/lfrfid/helpers/decoder_hid26.h | 24 - .../lfrfid/helpers/decoder_indala.cpp | 76 --- applications/lfrfid/helpers/decoder_indala.h | 25 - .../lfrfid/helpers/decoder_ioprox.cpp | 107 --- applications/lfrfid/helpers/decoder_ioprox.h | 26 - applications/lfrfid/helpers/emmarin.h | 15 - .../lfrfid/helpers/encoder_emmarin.cpp | 24 - applications/lfrfid/helpers/encoder_emmarin.h | 22 - applications/lfrfid/helpers/encoder_generic.h | 27 - .../lfrfid/helpers/encoder_hid_h10301.cpp | 46 -- .../lfrfid/helpers/encoder_hid_h10301.h | 26 - .../lfrfid/helpers/encoder_indala_40134.cpp | 36 - .../lfrfid/helpers/encoder_indala_40134.h | 23 - .../lfrfid/helpers/encoder_ioprox.cpp | 32 - applications/lfrfid/helpers/encoder_ioprox.h | 25 - applications/lfrfid/helpers/key_info.cpp | 76 --- applications/lfrfid/helpers/key_info.h | 17 - applications/lfrfid/helpers/osc_fsk.cpp | 20 - applications/lfrfid/helpers/osc_fsk.h | 30 - .../helpers/protocols/protocol_emmarin.cpp | 150 ----- .../helpers/protocols/protocol_emmarin.h | 22 - .../helpers/protocols/protocol_generic.h | 60 -- .../helpers/protocols/protocol_hid_h10301.cpp | 238 ------- .../helpers/protocols/protocol_hid_h10301.h | 22 - .../protocols/protocol_indala_40134.cpp | 237 ------- .../helpers/protocols/protocol_indala_40134.h | 22 - .../helpers/protocols/protocol_ioprox.cpp | 193 ------ .../helpers/protocols/protocol_ioprox.h | 26 - applications/lfrfid/helpers/pulse_joiner.cpp | 95 --- applications/lfrfid/helpers/pulse_joiner.h | 36 - applications/lfrfid/helpers/rfid_key.cpp | 65 -- applications/lfrfid/helpers/rfid_key.h | 27 - applications/lfrfid/helpers/rfid_reader.cpp | 175 ----- applications/lfrfid/helpers/rfid_reader.h | 59 -- .../lfrfid/helpers/rfid_timer_emulator.cpp | 56 -- .../lfrfid/helpers/rfid_timer_emulator.h | 31 - applications/lfrfid/helpers/rfid_worker.cpp | 136 ---- applications/lfrfid/helpers/rfid_worker.h | 48 -- applications/lfrfid/helpers/rfid_writer.cpp | 183 ----- applications/lfrfid/helpers/rfid_writer.h | 21 - .../lfrfid/helpers/state_sequencer.cpp | 50 -- applications/lfrfid/helpers/state_sequencer.h | 25 - applications/lfrfid/lfrfid_app.cpp | 108 ++- applications/lfrfid/lfrfid_app.h | 51 +- applications/lfrfid/lfrfid_cli.c | 575 ++++++++++++++++ applications/lfrfid/lfrfid_cli.cpp | 177 ----- .../scene/lfrfid_app_scene_delete_confirm.cpp | 47 +- .../scene/lfrfid_app_scene_delete_confirm.h | 1 - .../lfrfid/scene/lfrfid_app_scene_emulate.cpp | 23 +- .../lfrfid/scene/lfrfid_app_scene_emulate.h | 3 - .../scene/lfrfid_app_scene_extra_actions.cpp | 63 ++ .../scene/lfrfid_app_scene_extra_actions.h | 13 + .../scene/lfrfid_app_scene_raw_info.cpp | 77 +++ .../lfrfid/scene/lfrfid_app_scene_raw_info.h | 12 + .../scene/lfrfid_app_scene_raw_name.cpp | 46 ++ .../lfrfid/scene/lfrfid_app_scene_raw_name.h | 12 + .../scene/lfrfid_app_scene_raw_read.cpp | 107 +++ .../lfrfid/scene/lfrfid_app_scene_raw_read.h | 15 + .../scene/lfrfid_app_scene_raw_success.cpp | 45 ++ .../scene/lfrfid_app_scene_raw_success.h | 13 + .../lfrfid/scene/lfrfid_app_scene_read.cpp | 98 ++- .../scene/lfrfid_app_scene_read_menu.cpp | 6 +- .../scene/lfrfid_app_scene_read_success.cpp | 125 +--- .../scene/lfrfid_app_scene_read_success.h | 3 +- .../lfrfid/scene/lfrfid_app_scene_rpc.cpp | 10 +- .../scene/lfrfid_app_scene_save_data.cpp | 18 +- .../lfrfid/scene/lfrfid_app_scene_save_data.h | 21 - .../scene/lfrfid_app_scene_save_name.cpp | 18 +- .../scene/lfrfid_app_scene_save_type.cpp | 16 +- .../lfrfid/scene/lfrfid_app_scene_save_type.h | 4 +- .../scene/lfrfid_app_scene_saved_info.cpp | 87 +-- .../scene/lfrfid_app_scene_saved_info.h | 5 +- .../scene/lfrfid_app_scene_saved_key_menu.cpp | 6 +- .../lfrfid/scene/lfrfid_app_scene_start.cpp | 15 +- .../lfrfid/scene/lfrfid_app_scene_write.cpp | 95 +-- .../lfrfid/scene/lfrfid_app_scene_write.h | 4 - applications/storage/storage.h | 9 + applications/storage/storage_external_api.c | 12 + applications/unit_tests/lfrfid/bit_lib_test.c | 473 +++++++++++++ .../unit_tests/lfrfid/lfrfid_protocols.c | 464 +++++++++++++ applications/unit_tests/minunit.h | 174 +++-- .../protocol_dict/protocol_dict_test.c | 222 +++++++ applications/unit_tests/test_index.c | 6 + applications/unit_tests/varint/varint_test.c | 88 +++ applications/updater/util/update_task.c | 3 +- firmware.scons | 1 + firmware/targets/f7/furi_hal/furi_hal_rfid.c | 186 ++++++ .../targets/furi_hal_include/furi_hal_rfid.h | 18 + furi/core/core_defines.h | 2 + lib/SConscript | 1 + lib/flipper_format/flipper_format.h | 4 +- lib/lfrfid/SConscript | 19 + lib/lfrfid/lfrfid_dict_file.c | 182 +++++ lib/lfrfid/lfrfid_dict_file.h | 31 + lib/lfrfid/lfrfid_raw_file.c | 145 ++++ lib/lfrfid/lfrfid_raw_file.h | 95 +++ lib/lfrfid/lfrfid_raw_worker.c | 357 ++++++++++ lib/lfrfid/lfrfid_raw_worker.h | 68 ++ lib/lfrfid/lfrfid_worker.c | 169 +++++ lib/lfrfid/lfrfid_worker.h | 152 +++++ lib/lfrfid/lfrfid_worker_i.h | 64 ++ lib/lfrfid/lfrfid_worker_modes.c | 624 ++++++++++++++++++ lib/lfrfid/protocols/lfrfid_protocols.c | 22 + lib/lfrfid/protocols/lfrfid_protocols.h | 35 + lib/lfrfid/protocols/protocol_awid.c | 239 +++++++ lib/lfrfid/protocols/protocol_awid.h | 4 + lib/lfrfid/protocols/protocol_em4100.c | 292 ++++++++ lib/lfrfid/protocols/protocol_em4100.h | 4 + lib/lfrfid/protocols/protocol_fdx_a.c | 239 +++++++ lib/lfrfid/protocols/protocol_fdx_a.h | 4 + lib/lfrfid/protocols/protocol_fdx_b.c | 374 +++++++++++ lib/lfrfid/protocols/protocol_fdx_b.h | 4 + lib/lfrfid/protocols/protocol_h10301.c | 386 +++++++++++ lib/lfrfid/protocols/protocol_h10301.h | 4 + .../protocols/protocol_hid_ex_generic.c | 219 ++++++ .../protocols/protocol_hid_ex_generic.h | 4 + lib/lfrfid/protocols/protocol_hid_generic.c | 280 ++++++++ lib/lfrfid/protocols/protocol_hid_generic.h | 4 + lib/lfrfid/protocols/protocol_indala26.c | 353 ++++++++++ lib/lfrfid/protocols/protocol_indala26.h | 4 + lib/lfrfid/protocols/protocol_io_prox_xsf.c | 297 +++++++++ lib/lfrfid/protocols/protocol_io_prox_xsf.h | 4 + lib/lfrfid/tools/bit_lib.c | 291 ++++++++ lib/lfrfid/tools/bit_lib.h | 220 ++++++ lib/lfrfid/tools/fsk_demod.c | 93 +++ lib/lfrfid/tools/fsk_demod.h | 44 ++ lib/lfrfid/tools/fsk_ocs.c | 62 ++ lib/lfrfid/tools/fsk_osc.h | 60 ++ lib/lfrfid/tools/t5577.c | 94 +++ lib/lfrfid/tools/t5577.h | 56 ++ lib/lfrfid/tools/varint_pair.c | 77 +++ lib/lfrfid/tools/varint_pair.h | 79 +++ lib/one_wire/ibutton/encoder/encoder_cyfral.c | 126 ---- lib/one_wire/ibutton/encoder/encoder_cyfral.h | 54 -- .../ibutton/encoder/encoder_metakom.c | 93 --- .../ibutton/encoder/encoder_metakom.h | 54 -- lib/one_wire/ibutton/ibutton_key.h | 1 + lib/one_wire/ibutton/ibutton_worker.c | 24 +- lib/one_wire/ibutton/ibutton_worker_i.h | 27 +- lib/one_wire/ibutton/ibutton_worker_modes.c | 116 ++-- .../ibutton/protocols/ibutton_protocols.c | 8 + .../ibutton/protocols/ibutton_protocols.h | 11 + .../ibutton/protocols/protocol_cyfral.c | 344 ++++++++++ .../ibutton/protocols/protocol_cyfral.h | 4 + .../protocol_metakom.c | 201 ++++-- .../ibutton/protocols/protocol_metakom.h | 4 + .../ibutton/pulse_protocols/protocol_cyfral.c | 256 ------- .../ibutton/pulse_protocols/protocol_cyfral.h | 38 -- .../pulse_protocols/protocol_metakom.h | 38 -- lib/one_wire/pulse_protocols/pulse_decoder.c | 66 -- lib/one_wire/pulse_protocols/pulse_decoder.h | 70 -- lib/one_wire/pulse_protocols/pulse_protocol.c | 67 -- lib/one_wire/pulse_protocols/pulse_protocol.h | 122 ---- lib/subghz/protocols/keeloq_common.c | 4 + lib/subghz/protocols/keeloq_common.h | 3 - lib/toolbox/buffer_stream.c | 145 ++++ lib/toolbox/buffer_stream.h | 94 +++ lib/toolbox/profiler.c | 87 +++ lib/toolbox/profiler.h | 23 + lib/toolbox/protocols/protocol.h | 46 ++ lib/toolbox/protocols/protocol_dict.c | 226 +++++++ lib/toolbox/protocols/protocol_dict.h | 73 ++ lib/toolbox/pulse_joiner.c | 117 ++++ lib/toolbox/pulse_joiner.h | 46 ++ .../pulse_protocols/pulse_glue.c | 0 .../pulse_protocols/pulse_glue.h | 0 lib/toolbox/varint.c | 76 +++ lib/toolbox/varint.h | 35 + scripts/toolchain/fbtenv.sh | 4 +- 179 files changed, 10234 insertions(+), 4804 deletions(-) delete mode 100644 applications/lfrfid/helpers/decoder_analyzer.cpp delete mode 100644 applications/lfrfid/helpers/decoder_analyzer.h delete mode 100644 applications/lfrfid/helpers/decoder_emmarin.cpp delete mode 100644 applications/lfrfid/helpers/decoder_emmarin.h delete mode 100644 applications/lfrfid/helpers/decoder_gpio_out.cpp delete mode 100644 applications/lfrfid/helpers/decoder_gpio_out.h delete mode 100644 applications/lfrfid/helpers/decoder_hid26.cpp delete mode 100644 applications/lfrfid/helpers/decoder_hid26.h delete mode 100644 applications/lfrfid/helpers/decoder_indala.cpp delete mode 100644 applications/lfrfid/helpers/decoder_indala.h delete mode 100644 applications/lfrfid/helpers/decoder_ioprox.cpp delete mode 100644 applications/lfrfid/helpers/decoder_ioprox.h delete mode 100644 applications/lfrfid/helpers/emmarin.h delete mode 100644 applications/lfrfid/helpers/encoder_emmarin.cpp delete mode 100644 applications/lfrfid/helpers/encoder_emmarin.h delete mode 100644 applications/lfrfid/helpers/encoder_generic.h delete mode 100644 applications/lfrfid/helpers/encoder_hid_h10301.cpp delete mode 100644 applications/lfrfid/helpers/encoder_hid_h10301.h delete mode 100644 applications/lfrfid/helpers/encoder_indala_40134.cpp delete mode 100644 applications/lfrfid/helpers/encoder_indala_40134.h delete mode 100644 applications/lfrfid/helpers/encoder_ioprox.cpp delete mode 100644 applications/lfrfid/helpers/encoder_ioprox.h delete mode 100644 applications/lfrfid/helpers/key_info.cpp delete mode 100644 applications/lfrfid/helpers/key_info.h delete mode 100644 applications/lfrfid/helpers/osc_fsk.cpp delete mode 100644 applications/lfrfid/helpers/osc_fsk.h delete mode 100644 applications/lfrfid/helpers/protocols/protocol_emmarin.cpp delete mode 100644 applications/lfrfid/helpers/protocols/protocol_emmarin.h delete mode 100644 applications/lfrfid/helpers/protocols/protocol_generic.h delete mode 100644 applications/lfrfid/helpers/protocols/protocol_hid_h10301.cpp delete mode 100644 applications/lfrfid/helpers/protocols/protocol_hid_h10301.h delete mode 100644 applications/lfrfid/helpers/protocols/protocol_indala_40134.cpp delete mode 100644 applications/lfrfid/helpers/protocols/protocol_indala_40134.h delete mode 100644 applications/lfrfid/helpers/protocols/protocol_ioprox.cpp delete mode 100644 applications/lfrfid/helpers/protocols/protocol_ioprox.h delete mode 100644 applications/lfrfid/helpers/pulse_joiner.cpp delete mode 100644 applications/lfrfid/helpers/pulse_joiner.h delete mode 100644 applications/lfrfid/helpers/rfid_key.cpp delete mode 100644 applications/lfrfid/helpers/rfid_key.h delete mode 100644 applications/lfrfid/helpers/rfid_reader.cpp delete mode 100644 applications/lfrfid/helpers/rfid_reader.h delete mode 100644 applications/lfrfid/helpers/rfid_timer_emulator.cpp delete mode 100644 applications/lfrfid/helpers/rfid_timer_emulator.h delete mode 100644 applications/lfrfid/helpers/rfid_worker.cpp delete mode 100644 applications/lfrfid/helpers/rfid_worker.h delete mode 100644 applications/lfrfid/helpers/rfid_writer.cpp delete mode 100644 applications/lfrfid/helpers/rfid_writer.h delete mode 100644 applications/lfrfid/helpers/state_sequencer.cpp delete mode 100644 applications/lfrfid/helpers/state_sequencer.h create mode 100644 applications/lfrfid/lfrfid_cli.c delete mode 100644 applications/lfrfid/lfrfid_cli.cpp create mode 100644 applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp create mode 100644 applications/lfrfid/scene/lfrfid_app_scene_extra_actions.h create mode 100644 applications/lfrfid/scene/lfrfid_app_scene_raw_info.cpp create mode 100644 applications/lfrfid/scene/lfrfid_app_scene_raw_info.h create mode 100644 applications/lfrfid/scene/lfrfid_app_scene_raw_name.cpp create mode 100644 applications/lfrfid/scene/lfrfid_app_scene_raw_name.h create mode 100644 applications/lfrfid/scene/lfrfid_app_scene_raw_read.cpp create mode 100644 applications/lfrfid/scene/lfrfid_app_scene_raw_read.h create mode 100644 applications/lfrfid/scene/lfrfid_app_scene_raw_success.cpp create mode 100644 applications/lfrfid/scene/lfrfid_app_scene_raw_success.h create mode 100644 applications/unit_tests/lfrfid/bit_lib_test.c create mode 100644 applications/unit_tests/lfrfid/lfrfid_protocols.c create mode 100644 applications/unit_tests/protocol_dict/protocol_dict_test.c create mode 100644 applications/unit_tests/varint/varint_test.c create mode 100644 lib/lfrfid/SConscript create mode 100644 lib/lfrfid/lfrfid_dict_file.c create mode 100644 lib/lfrfid/lfrfid_dict_file.h create mode 100644 lib/lfrfid/lfrfid_raw_file.c create mode 100644 lib/lfrfid/lfrfid_raw_file.h create mode 100644 lib/lfrfid/lfrfid_raw_worker.c create mode 100644 lib/lfrfid/lfrfid_raw_worker.h create mode 100644 lib/lfrfid/lfrfid_worker.c create mode 100644 lib/lfrfid/lfrfid_worker.h create mode 100644 lib/lfrfid/lfrfid_worker_i.h create mode 100644 lib/lfrfid/lfrfid_worker_modes.c create mode 100644 lib/lfrfid/protocols/lfrfid_protocols.c create mode 100644 lib/lfrfid/protocols/lfrfid_protocols.h create mode 100644 lib/lfrfid/protocols/protocol_awid.c create mode 100644 lib/lfrfid/protocols/protocol_awid.h create mode 100644 lib/lfrfid/protocols/protocol_em4100.c create mode 100644 lib/lfrfid/protocols/protocol_em4100.h create mode 100644 lib/lfrfid/protocols/protocol_fdx_a.c create mode 100644 lib/lfrfid/protocols/protocol_fdx_a.h create mode 100644 lib/lfrfid/protocols/protocol_fdx_b.c create mode 100644 lib/lfrfid/protocols/protocol_fdx_b.h create mode 100644 lib/lfrfid/protocols/protocol_h10301.c create mode 100644 lib/lfrfid/protocols/protocol_h10301.h create mode 100644 lib/lfrfid/protocols/protocol_hid_ex_generic.c create mode 100644 lib/lfrfid/protocols/protocol_hid_ex_generic.h create mode 100644 lib/lfrfid/protocols/protocol_hid_generic.c create mode 100644 lib/lfrfid/protocols/protocol_hid_generic.h create mode 100644 lib/lfrfid/protocols/protocol_indala26.c create mode 100644 lib/lfrfid/protocols/protocol_indala26.h create mode 100644 lib/lfrfid/protocols/protocol_io_prox_xsf.c create mode 100644 lib/lfrfid/protocols/protocol_io_prox_xsf.h create mode 100644 lib/lfrfid/tools/bit_lib.c create mode 100644 lib/lfrfid/tools/bit_lib.h create mode 100644 lib/lfrfid/tools/fsk_demod.c create mode 100644 lib/lfrfid/tools/fsk_demod.h create mode 100644 lib/lfrfid/tools/fsk_ocs.c create mode 100644 lib/lfrfid/tools/fsk_osc.h create mode 100644 lib/lfrfid/tools/t5577.c create mode 100644 lib/lfrfid/tools/t5577.h create mode 100644 lib/lfrfid/tools/varint_pair.c create mode 100644 lib/lfrfid/tools/varint_pair.h delete mode 100644 lib/one_wire/ibutton/encoder/encoder_cyfral.c delete mode 100644 lib/one_wire/ibutton/encoder/encoder_cyfral.h delete mode 100644 lib/one_wire/ibutton/encoder/encoder_metakom.c delete mode 100644 lib/one_wire/ibutton/encoder/encoder_metakom.h create mode 100644 lib/one_wire/ibutton/protocols/ibutton_protocols.c create mode 100644 lib/one_wire/ibutton/protocols/ibutton_protocols.h create mode 100644 lib/one_wire/ibutton/protocols/protocol_cyfral.c create mode 100644 lib/one_wire/ibutton/protocols/protocol_cyfral.h rename lib/one_wire/ibutton/{pulse_protocols => protocols}/protocol_metakom.c (51%) create mode 100644 lib/one_wire/ibutton/protocols/protocol_metakom.h delete mode 100644 lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.c delete mode 100644 lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.h delete mode 100644 lib/one_wire/ibutton/pulse_protocols/protocol_metakom.h delete mode 100644 lib/one_wire/pulse_protocols/pulse_decoder.c delete mode 100644 lib/one_wire/pulse_protocols/pulse_decoder.h delete mode 100644 lib/one_wire/pulse_protocols/pulse_protocol.c delete mode 100644 lib/one_wire/pulse_protocols/pulse_protocol.h create mode 100644 lib/toolbox/buffer_stream.c create mode 100644 lib/toolbox/buffer_stream.h create mode 100644 lib/toolbox/profiler.c create mode 100644 lib/toolbox/profiler.h create mode 100644 lib/toolbox/protocols/protocol.h create mode 100644 lib/toolbox/protocols/protocol_dict.c create mode 100644 lib/toolbox/protocols/protocol_dict.h create mode 100644 lib/toolbox/pulse_joiner.c create mode 100644 lib/toolbox/pulse_joiner.h rename lib/{one_wire => toolbox}/pulse_protocols/pulse_glue.c (100%) rename lib/{one_wire => toolbox}/pulse_protocols/pulse_glue.h (100%) create mode 100644 lib/toolbox/varint.c create mode 100644 lib/toolbox/varint.h diff --git a/applications/archive/helpers/archive_apps.c b/applications/archive/helpers/archive_apps.c index 9a3f825f1c..72084f1134 100644 --- a/applications/archive/helpers/archive_apps.c +++ b/applications/archive/helpers/archive_apps.c @@ -29,23 +29,13 @@ bool archive_app_is_available(void* context, const char* path) { if(app == ArchiveAppTypeU2f) { bool file_exists = false; - Storage* fs_api = furi_record_open(RECORD_STORAGE); - File* file = storage_file_alloc(fs_api); - - file_exists = - storage_file_open(file, ANY_PATH("u2f/key.u2f"), FSAM_READ, FSOM_OPEN_EXISTING); - if(file_exists) { - storage_file_close(file); - file_exists = - storage_file_open(file, ANY_PATH("u2f/cnt.u2f"), FSAM_READ, FSOM_OPEN_EXISTING); - if(file_exists) { - storage_file_close(file); - } + Storage* storage = furi_record_open(RECORD_STORAGE); + + if(storage_file_exists(storage, ANY_PATH("u2f/key.u2f"))) { + file_exists = storage_file_exists(storage, ANY_PATH("u2f/cnt.u2f")); } - storage_file_free(file); furi_record_close(RECORD_STORAGE); - return file_exists; } else { return false; diff --git a/applications/archive/helpers/archive_favorites.c b/applications/archive/helpers/archive_favorites.c index 35199242e9..4d5b555f5a 100644 --- a/applications/archive/helpers/archive_favorites.c +++ b/applications/archive/helpers/archive_favorites.c @@ -82,9 +82,8 @@ uint16_t archive_favorites_count(void* context) { static bool archive_favourites_rescan() { string_t buffer; string_init(buffer); - Storage* fs_api = furi_record_open(RECORD_STORAGE); - File* file = storage_file_alloc(fs_api); - File* fav_item_file = storage_file_alloc(fs_api); + Storage* storage = furi_record_open(RECORD_STORAGE); + File* file = storage_file_alloc(storage); bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); if(result) { @@ -101,13 +100,8 @@ static bool archive_favourites_rescan() { archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer)); } } else { - bool file_exists = storage_file_open( - fav_item_file, string_get_cstr(buffer), FSAM_READ, FSOM_OPEN_EXISTING); - if(file_exists) { - storage_file_close(fav_item_file); + if(storage_file_exists(storage, string_get_cstr(buffer))) { archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer)); - } else { - storage_file_close(fav_item_file); } } } @@ -116,12 +110,11 @@ static bool archive_favourites_rescan() { string_clear(buffer); storage_file_close(file); - storage_common_remove(fs_api, ARCHIVE_FAV_PATH); - storage_common_rename(fs_api, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH); - storage_common_remove(fs_api, ARCHIVE_FAV_TEMP_PATH); + storage_common_remove(storage, ARCHIVE_FAV_PATH); + storage_common_rename(storage, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH); + storage_common_remove(storage, ARCHIVE_FAV_TEMP_PATH); storage_file_free(file); - storage_file_free(fav_item_file); furi_record_close(RECORD_STORAGE); return result; @@ -131,9 +124,8 @@ bool archive_favorites_read(void* context) { furi_assert(context); ArchiveBrowserView* browser = context; - Storage* fs_api = furi_record_open(RECORD_STORAGE); - File* file = storage_file_alloc(fs_api); - File* fav_item_file = storage_file_alloc(fs_api); + Storage* storage = furi_record_open(RECORD_STORAGE); + File* file = storage_file_alloc(storage); string_t buffer; FileInfo file_info; @@ -163,16 +155,12 @@ bool archive_favorites_read(void* context) { need_refresh = true; } } else { - bool file_exists = storage_file_open( - fav_item_file, string_get_cstr(buffer), FSAM_READ, FSOM_OPEN_EXISTING); - if(file_exists) { - storage_common_stat(fs_api, string_get_cstr(buffer), &file_info); - storage_file_close(fav_item_file); + if(storage_file_exists(storage, string_get_cstr(buffer))) { + storage_common_stat(storage, string_get_cstr(buffer), &file_info); archive_add_file_item( browser, (file_info.flags & FSF_DIRECTORY), string_get_cstr(buffer)); file_count++; } else { - storage_file_close(fav_item_file); need_refresh = true; } } @@ -183,7 +171,6 @@ bool archive_favorites_read(void* context) { storage_file_close(file); string_clear(buffer); storage_file_free(file); - storage_file_free(fav_item_file); furi_record_close(RECORD_STORAGE); archive_set_item_count(browser, file_count); diff --git a/applications/desktop/animations/animation_manager.c b/applications/desktop/animations/animation_manager.c index d755be9c04..1e2a521e12 100644 --- a/applications/desktop/animations/animation_manager.c +++ b/applications/desktop/animations/animation_manager.c @@ -220,8 +220,7 @@ static bool animation_manager_check_blocking(AnimationManager* animation_manager furi_assert(blocking_animation); animation_manager->sd_shown_sd_ok = true; } else if(!animation_manager->sd_shown_no_db) { - bool db_exists = storage_common_stat(storage, EXT_PATH("Manifest"), NULL) == FSE_OK; - if(!db_exists) { + if(!storage_file_exists(storage, EXT_PATH("Manifest"))) { blocking_animation = animation_storage_find_animation(NO_DB_ANIMATION_NAME); furi_assert(blocking_animation); animation_manager->sd_shown_no_db = true; diff --git a/applications/lfrfid/helpers/decoder_analyzer.cpp b/applications/lfrfid/helpers/decoder_analyzer.cpp deleted file mode 100644 index 8d344b8809..0000000000 --- a/applications/lfrfid/helpers/decoder_analyzer.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "decoder_analyzer.h" -#include -#include - -// FIXME: unused args? -bool DecoderAnalyzer::read(uint8_t* /* _data */, uint8_t /* _data_size */) { - bool result = false; - - if(ready) { - result = true; - - for(size_t i = 0; i < data_size; i++) { - printf("%lu ", data[i]); - if((i + 1) % 8 == 0) printf("\r\n"); - } - printf("\r\n--------\r\n"); - - ready = false; - } - - return result; -} - -void DecoderAnalyzer::process_front(bool polarity, uint32_t time) { - UNUSED(polarity); - if(ready) return; - - data[data_index] = time; - - if(data_index < data_size) { - data_index++; - } else { - data_index = 0; - ready = true; - } -} - -DecoderAnalyzer::DecoderAnalyzer() { - data = reinterpret_cast(calloc(data_size, sizeof(uint32_t))); - furi_check(data); - data_index = 0; - ready = false; -} - -DecoderAnalyzer::~DecoderAnalyzer() { - free(data); -} - -void DecoderAnalyzer::reset_state() { -} diff --git a/applications/lfrfid/helpers/decoder_analyzer.h b/applications/lfrfid/helpers/decoder_analyzer.h deleted file mode 100644 index eecea6edd9..0000000000 --- a/applications/lfrfid/helpers/decoder_analyzer.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include -#include - -class DecoderAnalyzer { -public: - bool read(uint8_t* data, uint8_t data_size); - void process_front(bool polarity, uint32_t time); - - DecoderAnalyzer(); - ~DecoderAnalyzer(); - -private: - void reset_state(); - - std::atomic ready; - - static const uint32_t data_size = 2048; - uint32_t data_index = 0; - uint32_t* data; -}; diff --git a/applications/lfrfid/helpers/decoder_emmarin.cpp b/applications/lfrfid/helpers/decoder_emmarin.cpp deleted file mode 100644 index daa8e238c2..0000000000 --- a/applications/lfrfid/helpers/decoder_emmarin.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "emmarin.h" -#include "decoder_emmarin.h" -#include -#include - -constexpr uint32_t clocks_in_us = 64; -constexpr uint32_t short_time = 255 * clocks_in_us; -constexpr uint32_t long_time = 510 * clocks_in_us; -constexpr uint32_t jitter_time = 100 * clocks_in_us; - -constexpr uint32_t short_time_low = short_time - jitter_time; -constexpr uint32_t short_time_high = short_time + jitter_time; -constexpr uint32_t long_time_low = long_time - jitter_time; -constexpr uint32_t long_time_high = long_time + jitter_time; - -void DecoderEMMarin::reset_state() { - ready = false; - read_data = 0; - manchester_advance( - manchester_saved_state, ManchesterEventReset, &manchester_saved_state, nullptr); -} - -bool DecoderEMMarin::read(uint8_t* data, uint8_t data_size) { - bool result = false; - - if(ready) { - result = true; - em_marin.decode( - reinterpret_cast(&read_data), sizeof(uint64_t), data, data_size); - ready = false; - } - - return result; -} - -void DecoderEMMarin::process_front(bool polarity, uint32_t time) { - if(ready) return; - if(time < short_time_low) return; - - ManchesterEvent event = ManchesterEventReset; - - if(time > short_time_low && time < short_time_high) { - if(polarity) { - event = ManchesterEventShortHigh; - } else { - event = ManchesterEventShortLow; - } - } else if(time > long_time_low && time < long_time_high) { - if(polarity) { - event = ManchesterEventLongHigh; - } else { - event = ManchesterEventLongLow; - } - } - - if(event != ManchesterEventReset) { - bool data; - bool data_ok = - manchester_advance(manchester_saved_state, event, &manchester_saved_state, &data); - - if(data_ok) { - read_data = (read_data << 1) | data; - - ready = em_marin.can_be_decoded( - reinterpret_cast(&read_data), sizeof(uint64_t)); - } - } -} - -DecoderEMMarin::DecoderEMMarin() { - reset_state(); -} diff --git a/applications/lfrfid/helpers/decoder_emmarin.h b/applications/lfrfid/helpers/decoder_emmarin.h deleted file mode 100644 index a3b48d71ce..0000000000 --- a/applications/lfrfid/helpers/decoder_emmarin.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include -#include -#include -#include "protocols/protocol_emmarin.h" -class DecoderEMMarin { -public: - bool read(uint8_t* data, uint8_t data_size); - void process_front(bool polarity, uint32_t time); - - DecoderEMMarin(); - -private: - void reset_state(); - - uint64_t read_data = 0; - std::atomic ready; - - ManchesterState manchester_saved_state; - ProtocolEMMarin em_marin; -}; diff --git a/applications/lfrfid/helpers/decoder_gpio_out.cpp b/applications/lfrfid/helpers/decoder_gpio_out.cpp deleted file mode 100644 index dfb4342672..0000000000 --- a/applications/lfrfid/helpers/decoder_gpio_out.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "decoder_gpio_out.h" -#include -#include - -void DecoderGpioOut::process_front(bool polarity, uint32_t /* time */) { - furi_hal_gpio_write(&gpio_ext_pa7, polarity); -} - -DecoderGpioOut::DecoderGpioOut() { - furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeOutputPushPull); -} - -DecoderGpioOut::~DecoderGpioOut() { - furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeAnalog); -} diff --git a/applications/lfrfid/helpers/decoder_gpio_out.h b/applications/lfrfid/helpers/decoder_gpio_out.h deleted file mode 100644 index 087720dfde..0000000000 --- a/applications/lfrfid/helpers/decoder_gpio_out.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include -#include - -class DecoderGpioOut { -public: - void process_front(bool polarity, uint32_t time); - - DecoderGpioOut(); - ~DecoderGpioOut(); - -private: - void reset_state(); -}; diff --git a/applications/lfrfid/helpers/decoder_hid26.cpp b/applications/lfrfid/helpers/decoder_hid26.cpp deleted file mode 100644 index e530b50892..0000000000 --- a/applications/lfrfid/helpers/decoder_hid26.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "decoder_hid26.h" -#include - -constexpr uint32_t clocks_in_us = 64; - -constexpr uint32_t jitter_time_us = 20; -constexpr uint32_t min_time_us = 64; -constexpr uint32_t max_time_us = 80; - -constexpr uint32_t min_time = (min_time_us - jitter_time_us) * clocks_in_us; -constexpr uint32_t mid_time = ((max_time_us - min_time_us) / 2 + min_time_us) * clocks_in_us; -constexpr uint32_t max_time = (max_time_us + jitter_time_us) * clocks_in_us; - -bool DecoderHID26::read(uint8_t* data, uint8_t data_size) { - bool result = false; - furi_assert(data_size >= 3); - - if(ready) { - result = true; - hid.decode( - reinterpret_cast(&stored_data), sizeof(uint32_t) * 3, data, data_size); - ready = false; - } - - return result; -} - -void DecoderHID26::process_front(bool polarity, uint32_t time) { - if(ready) return; - - if(polarity == true) { - last_pulse_time = time; - } else { - last_pulse_time += time; - - if(last_pulse_time > min_time && last_pulse_time < max_time) { - bool pulse; - - if(last_pulse_time < mid_time) { - // 6 pulses - pulse = false; - } else { - // 5 pulses - pulse = true; - } - - if(last_pulse == pulse) { - pulse_count++; - - if(pulse) { - if(pulse_count > 4) { - pulse_count = 0; - store_data(1); - } - } else { - if(pulse_count > 5) { - pulse_count = 0; - store_data(0); - } - } - } else { - if(last_pulse) { - if(pulse_count > 2) { - store_data(1); - } - } else { - if(pulse_count > 3) { - store_data(0); - } - } - - pulse_count = 0; - last_pulse = pulse; - } - } - } -} - -DecoderHID26::DecoderHID26() { - reset_state(); -} - -void DecoderHID26::store_data(bool data) { - stored_data[0] = (stored_data[0] << 1) | ((stored_data[1] >> 31) & 1); - stored_data[1] = (stored_data[1] << 1) | ((stored_data[2] >> 31) & 1); - stored_data[2] = (stored_data[2] << 1) | data; - - if(hid.can_be_decoded(reinterpret_cast(&stored_data), sizeof(uint32_t) * 3)) { - ready = true; - } -} - -void DecoderHID26::reset_state() { - last_pulse = false; - pulse_count = 0; - ready = false; - last_pulse_time = 0; -} diff --git a/applications/lfrfid/helpers/decoder_hid26.h b/applications/lfrfid/helpers/decoder_hid26.h deleted file mode 100644 index c73ff88c40..0000000000 --- a/applications/lfrfid/helpers/decoder_hid26.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include -#include -#include "protocols/protocol_hid_h10301.h" - -class DecoderHID26 { -public: - bool read(uint8_t* data, uint8_t data_size); - void process_front(bool polarity, uint32_t time); - DecoderHID26(); - -private: - uint32_t last_pulse_time = 0; - bool last_pulse; - uint8_t pulse_count; - - uint32_t stored_data[3] = {0, 0, 0}; - void store_data(bool data); - - std::atomic ready; - - void reset_state(); - ProtocolHID10301 hid; -}; diff --git a/applications/lfrfid/helpers/decoder_indala.cpp b/applications/lfrfid/helpers/decoder_indala.cpp deleted file mode 100644 index 100dde73bd..0000000000 --- a/applications/lfrfid/helpers/decoder_indala.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "decoder_indala.h" -#include - -constexpr uint32_t clocks_in_us = 64; -constexpr uint32_t us_per_bit = 255; - -bool DecoderIndala::read(uint8_t* data, uint8_t data_size) { - bool result = false; - - if(ready) { - result = true; - if(cursed_data_valid) { - indala.decode( - reinterpret_cast(&cursed_raw_data), - sizeof(uint64_t), - data, - data_size); - } else { - indala.decode( - reinterpret_cast(&raw_data), sizeof(uint64_t), data, data_size); - } - reset_state(); - } - - return result; -} - -void DecoderIndala::process_front(bool polarity, uint32_t time) { - if(ready) return; - - process_internal(polarity, time, &raw_data); - if(ready) return; - - if(polarity) { - time = time + 110; - } else { - time = time - 110; - } - - process_internal(!polarity, time, &cursed_raw_data); - if(ready) { - cursed_data_valid = true; - } -} - -void DecoderIndala::process_internal(bool polarity, uint32_t time, uint64_t* data) { - time /= clocks_in_us; - time += (us_per_bit / 2); - - uint32_t bit_count = (time / us_per_bit); - - if(bit_count < 64) { - for(uint32_t i = 0; i < bit_count; i++) { - *data = (*data << 1) | polarity; - - if((*data >> 32) == 0xa0000000ULL) { - if(indala.can_be_decoded( - reinterpret_cast(data), sizeof(uint64_t))) { - ready = true; - break; - } - } - } - } -} - -DecoderIndala::DecoderIndala() { - reset_state(); -} - -void DecoderIndala::reset_state() { - raw_data = 0; - cursed_raw_data = 0; - ready = false; - cursed_data_valid = false; -} diff --git a/applications/lfrfid/helpers/decoder_indala.h b/applications/lfrfid/helpers/decoder_indala.h deleted file mode 100644 index 5fbde7b6bd..0000000000 --- a/applications/lfrfid/helpers/decoder_indala.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include -#include -#include -#include "protocols/protocol_indala_40134.h" - -class DecoderIndala { -public: - bool read(uint8_t* data, uint8_t data_size); - void process_front(bool polarity, uint32_t time); - - void process_internal(bool polarity, uint32_t time, uint64_t* data); - - DecoderIndala(); - -private: - void reset_state(); - - uint64_t raw_data; - uint64_t cursed_raw_data; - - std::atomic ready; - std::atomic cursed_data_valid; - ProtocolIndala40134 indala; -}; diff --git a/applications/lfrfid/helpers/decoder_ioprox.cpp b/applications/lfrfid/helpers/decoder_ioprox.cpp deleted file mode 100644 index 7b44d3ceae..0000000000 --- a/applications/lfrfid/helpers/decoder_ioprox.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "decoder_ioprox.h" -#include -#include -#include - -constexpr uint32_t clocks_in_us = 64; - -constexpr uint32_t jitter_time_us = 20; -constexpr uint32_t min_time_us = 64; -constexpr uint32_t max_time_us = 80; -constexpr uint32_t baud_time_us = 500; - -constexpr uint32_t min_time = (min_time_us - jitter_time_us) * clocks_in_us; -constexpr uint32_t mid_time = ((max_time_us - min_time_us) / 2 + min_time_us) * clocks_in_us; -constexpr uint32_t max_time = (max_time_us + jitter_time_us) * clocks_in_us; -constexpr uint32_t baud_time = baud_time_us * clocks_in_us; - -bool DecoderIoProx::read(uint8_t* data, uint8_t data_size) { - bool result = false; - furi_assert(data_size >= 4); - - if(ready) { - result = true; - ioprox.decode(raw_data, sizeof(raw_data), data, data_size); - ready = false; - } - - return result; -} - -void DecoderIoProx::process_front(bool is_rising_edge, uint32_t time) { - if(ready) { - return; - } - - // Always track the time that's gone by. - current_period_duration += time; - demodulation_sample_duration += time; - - // If a baud time has elapsed, we're at a sample point. - if(demodulation_sample_duration >= baud_time) { - // Start a new baud period... - demodulation_sample_duration = 0; - demodulated_value_invalid = false; - - // ... and if we didn't have any baud errors, capture a sample. - if(!demodulated_value_invalid) { - store_data(current_demodulated_value); - } - } - - // - // FSK demodulator. - // - - // If this isn't a rising edge, this isn't a pulse of interest. - // We're done. - if(!is_rising_edge) { - return; - } - - bool is_valid_low = (current_period_duration > min_time) && - (current_period_duration <= mid_time); - bool is_valid_high = (current_period_duration > mid_time) && - (current_period_duration < max_time); - - // If this is between the minimum and our threshold, this is a logical 0. - if(is_valid_low) { - current_demodulated_value = false; - } - // Otherwise, if between our threshold and the max time, it's a logical 1. - else if(is_valid_high) { - current_demodulated_value = true; - } - // Otherwise, invalidate this sample. - else { - demodulated_value_invalid = true; - } - - // We're starting a new period; track that. - current_period_duration = 0; -} - -DecoderIoProx::DecoderIoProx() { - reset_state(); -} - -void DecoderIoProx::store_data(bool data) { - for(int i = 0; i < 7; ++i) { - raw_data[i] = (raw_data[i] << 1) | ((raw_data[i + 1] >> 7) & 1); - } - raw_data[7] = (raw_data[7] << 1) | data; - - if(ioprox.can_be_decoded(raw_data, sizeof(raw_data))) { - ready = true; - } -} - -void DecoderIoProx::reset_state() { - current_demodulated_value = false; - demodulated_value_invalid = false; - - current_period_duration = 0; - demodulation_sample_duration = 0; - - ready = false; -} diff --git a/applications/lfrfid/helpers/decoder_ioprox.h b/applications/lfrfid/helpers/decoder_ioprox.h deleted file mode 100644 index aff4a47786..0000000000 --- a/applications/lfrfid/helpers/decoder_ioprox.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include -#include -#include "protocols/protocol_ioprox.h" - -class DecoderIoProx { -public: - bool read(uint8_t* data, uint8_t data_size); - void process_front(bool polarity, uint32_t time); - DecoderIoProx(); - -private: - uint32_t current_period_duration = 0; - uint32_t demodulation_sample_duration = 0; - - bool current_demodulated_value = false; - bool demodulated_value_invalid = false; - - uint8_t raw_data[8] = {0}; - void store_data(bool data); - - std::atomic ready; - - void reset_state(); - ProtocolIoProx ioprox; -}; diff --git a/applications/lfrfid/helpers/emmarin.h b/applications/lfrfid/helpers/emmarin.h deleted file mode 100644 index ff8273bf76..0000000000 --- a/applications/lfrfid/helpers/emmarin.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include - -#define EM_HEADER_POS 55 -#define EM_HEADER_MASK (0x1FFLLU << EM_HEADER_POS) - -#define EM_FIRST_ROW_POS 50 -#define EM_ROW_COUNT 10 - -#define EM_COLUMN_POS 4 -#define EM_STOP_POS 0 -#define EM_STOP_MASK (0x1LLU << EM_STOP_POS) - -#define EM_HEADER_AND_STOP_MASK (EM_HEADER_MASK | EM_STOP_MASK) -#define EM_HEADER_AND_STOP_DATA (EM_HEADER_MASK) diff --git a/applications/lfrfid/helpers/encoder_emmarin.cpp b/applications/lfrfid/helpers/encoder_emmarin.cpp deleted file mode 100644 index c329ab4004..0000000000 --- a/applications/lfrfid/helpers/encoder_emmarin.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "encoder_emmarin.h" -#include "protocols/protocol_emmarin.h" -#include - -void EncoderEM::init(const uint8_t* data, const uint8_t data_size) { - ProtocolEMMarin em_marin; - em_marin.encode(data, data_size, reinterpret_cast(&card_data), sizeof(uint64_t)); - - card_data_index = 0; -} - -// data transmitted as manchester encoding -// 0 - high2low -// 1 - low2high -void EncoderEM::get_next(bool* polarity, uint16_t* period, uint16_t* pulse) { - *period = clocks_per_bit; - *pulse = clocks_per_bit / 2; - *polarity = (card_data >> (63 - card_data_index)) & 1; - - card_data_index++; - if(card_data_index >= 64) { - card_data_index = 0; - } -} diff --git a/applications/lfrfid/helpers/encoder_emmarin.h b/applications/lfrfid/helpers/encoder_emmarin.h deleted file mode 100644 index 560daec1b5..0000000000 --- a/applications/lfrfid/helpers/encoder_emmarin.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "encoder_generic.h" - -class EncoderEM : public EncoderGeneric { -public: - /** - * @brief init data to emulate - * - * @param data 1 byte FC, next 4 byte SN - * @param data_size must be 5 - */ - void init(const uint8_t* data, const uint8_t data_size) final; - - void get_next(bool* polarity, uint16_t* period, uint16_t* pulse) final; - -private: - // clock pulses per bit - static const uint8_t clocks_per_bit = 64; - - uint64_t card_data; - uint8_t card_data_index; -}; diff --git a/applications/lfrfid/helpers/encoder_generic.h b/applications/lfrfid/helpers/encoder_generic.h deleted file mode 100644 index dc6ae85039..0000000000 --- a/applications/lfrfid/helpers/encoder_generic.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include -#include - -class EncoderGeneric { -public: - /** - * @brief init encoder - * - * @param data data array - * @param data_size data array size - */ - virtual void init(const uint8_t* data, const uint8_t data_size) = 0; - - /** - * @brief Get the next timer pulse - * - * @param polarity pulse polarity true = high2low, false = low2high - * @param period overall period time in timer clicks - * @param pulse pulse time in timer clicks - */ - virtual void get_next(bool* polarity, uint16_t* period, uint16_t* pulse) = 0; - - virtual ~EncoderGeneric(){}; - -private: -}; diff --git a/applications/lfrfid/helpers/encoder_hid_h10301.cpp b/applications/lfrfid/helpers/encoder_hid_h10301.cpp deleted file mode 100644 index 09f637fee1..0000000000 --- a/applications/lfrfid/helpers/encoder_hid_h10301.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "encoder_hid_h10301.h" -#include "protocols/protocol_hid_h10301.h" -#include - -void EncoderHID_H10301::init(const uint8_t* data, const uint8_t data_size) { - ProtocolHID10301 hid; - hid.encode(data, data_size, reinterpret_cast(&card_data), sizeof(card_data) * 3); - - card_data_index = 0; -} - -void EncoderHID_H10301::write_bit(bool bit, uint8_t position) { - write_raw_bit(bit, position + 0); - write_raw_bit(!bit, position + 1); -} - -void EncoderHID_H10301::write_raw_bit(bool bit, uint8_t position) { - if(bit) { - card_data[position / 32] |= 1UL << (31 - (position % 32)); - } else { - card_data[position / 32] &= ~(1UL << (31 - (position % 32))); - } -} - -void EncoderHID_H10301::get_next(bool* polarity, uint16_t* period, uint16_t* pulse) { - uint8_t bit = (card_data[card_data_index / 32] >> (31 - (card_data_index % 32))) & 1; - - bool advance = fsk->next(bit, period); - if(advance) { - card_data_index++; - if(card_data_index >= (32 * card_data_max)) { - card_data_index = 0; - } - } - - *polarity = true; - *pulse = *period / 2; -} - -EncoderHID_H10301::EncoderHID_H10301() { - fsk = new OscFSK(8, 10, 50); -} - -EncoderHID_H10301::~EncoderHID_H10301() { - delete fsk; -} diff --git a/applications/lfrfid/helpers/encoder_hid_h10301.h b/applications/lfrfid/helpers/encoder_hid_h10301.h deleted file mode 100644 index 8cc5aa5cbf..0000000000 --- a/applications/lfrfid/helpers/encoder_hid_h10301.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include "encoder_generic.h" -#include "osc_fsk.h" - -class EncoderHID_H10301 : public EncoderGeneric { -public: - /** - * @brief init data to emulate - * - * @param data 1 byte FC, next 2 byte SN - * @param data_size must be 3 - */ - void init(const uint8_t* data, const uint8_t data_size) final; - void get_next(bool* polarity, uint16_t* period, uint16_t* pulse) final; - EncoderHID_H10301(); - ~EncoderHID_H10301(); - -private: - static const uint8_t card_data_max = 3; - uint32_t card_data[card_data_max]; - uint8_t card_data_index; - void write_bit(bool bit, uint8_t position); - void write_raw_bit(bool bit, uint8_t position); - - OscFSK* fsk; -}; diff --git a/applications/lfrfid/helpers/encoder_indala_40134.cpp b/applications/lfrfid/helpers/encoder_indala_40134.cpp deleted file mode 100644 index 764237d1fe..0000000000 --- a/applications/lfrfid/helpers/encoder_indala_40134.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "encoder_indala_40134.h" -#include "protocols/protocol_indala_40134.h" -#include - -void EncoderIndala_40134::init(const uint8_t* data, const uint8_t data_size) { - ProtocolIndala40134 indala; - indala.encode(data, data_size, reinterpret_cast(&card_data), sizeof(card_data)); - - last_bit = card_data & 1; - card_data_index = 0; - current_polarity = true; -} - -void EncoderIndala_40134::get_next(bool* polarity, uint16_t* period, uint16_t* pulse) { - *period = 2; - *pulse = 1; - *polarity = current_polarity; - - bit_clock_index++; - if(bit_clock_index >= clock_per_bit) { - bit_clock_index = 0; - - bool current_bit = (card_data >> (63 - card_data_index)) & 1; - - if(current_bit != last_bit) { - current_polarity = !current_polarity; - } - - last_bit = current_bit; - - card_data_index++; - if(card_data_index >= 64) { - card_data_index = 0; - } - } -} diff --git a/applications/lfrfid/helpers/encoder_indala_40134.h b/applications/lfrfid/helpers/encoder_indala_40134.h deleted file mode 100644 index eda29457f3..0000000000 --- a/applications/lfrfid/helpers/encoder_indala_40134.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include "encoder_generic.h" - -class EncoderIndala_40134 : public EncoderGeneric { -public: - /** - * @brief init data to emulate - * - * @param data indala raw data - * @param data_size must be 5 - */ - void init(const uint8_t* data, const uint8_t data_size) final; - - void get_next(bool* polarity, uint16_t* period, uint16_t* pulse) final; - -private: - uint64_t card_data; - uint8_t card_data_index; - uint8_t bit_clock_index; - bool last_bit; - bool current_polarity; - static const uint8_t clock_per_bit = 16; -}; diff --git a/applications/lfrfid/helpers/encoder_ioprox.cpp b/applications/lfrfid/helpers/encoder_ioprox.cpp deleted file mode 100644 index 4177991863..0000000000 --- a/applications/lfrfid/helpers/encoder_ioprox.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "encoder_ioprox.h" -#include "protocols/protocol_ioprox.h" -#include - -void EncoderIoProx::init(const uint8_t* data, const uint8_t data_size) { - ProtocolIoProx ioprox; - ioprox.encode(data, data_size, card_data, sizeof(card_data)); - card_data_index = 0; -} - -void EncoderIoProx::get_next(bool* polarity, uint16_t* period, uint16_t* pulse) { - uint8_t bit = (card_data[card_data_index / 8] >> (7 - (card_data_index % 8))) & 1; - - bool advance = fsk->next(bit, period); - if(advance) { - card_data_index++; - if(card_data_index >= (8 * card_data_max)) { - card_data_index = 0; - } - } - - *polarity = true; - *pulse = *period / 2; -} - -EncoderIoProx::EncoderIoProx() { - fsk = new OscFSK(8, 10, 64); -} - -EncoderIoProx::~EncoderIoProx() { - delete fsk; -} diff --git a/applications/lfrfid/helpers/encoder_ioprox.h b/applications/lfrfid/helpers/encoder_ioprox.h deleted file mode 100644 index 568b406711..0000000000 --- a/applications/lfrfid/helpers/encoder_ioprox.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include "encoder_generic.h" -#include "osc_fsk.h" - -class EncoderIoProx : public EncoderGeneric { -public: - /** - * @brief init data to emulate - * - * @param data 1 byte FC, 1 byte Version, 2 bytes code - * @param data_size must be 4 - */ - void init(const uint8_t* data, const uint8_t data_size) final; - void get_next(bool* polarity, uint16_t* period, uint16_t* pulse) final; - EncoderIoProx(); - ~EncoderIoProx(); - -private: - static const uint8_t card_data_max = 8; - - uint8_t card_data[card_data_max]; - uint8_t card_data_index; - - OscFSK* fsk; -}; diff --git a/applications/lfrfid/helpers/key_info.cpp b/applications/lfrfid/helpers/key_info.cpp deleted file mode 100644 index 4803cd6dc2..0000000000 --- a/applications/lfrfid/helpers/key_info.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "key_info.h" -#include - -const char* lfrfid_key_get_type_string(LfrfidKeyType type) { - switch(type) { - case LfrfidKeyType::KeyEM4100: - return "EM4100"; - break; - case LfrfidKeyType::KeyH10301: - return "H10301"; - break; - case LfrfidKeyType::KeyI40134: - return "I40134"; - break; - case LfrfidKeyType::KeyIoProxXSF: - return "IoProxXSF"; - break; - } - - return "Unknown"; -} - -const char* lfrfid_key_get_manufacturer_string(LfrfidKeyType type) { - switch(type) { - case LfrfidKeyType::KeyEM4100: - return "EM-Marin"; - break; - case LfrfidKeyType::KeyH10301: - return "HID"; - break; - case LfrfidKeyType::KeyI40134: - return "Indala"; - break; - case LfrfidKeyType::KeyIoProxXSF: - return "Kantech"; - } - - return "Unknown"; -} - -bool lfrfid_key_get_string_type(const char* string, LfrfidKeyType* type) { - bool result = true; - - if(strcmp("EM4100", string) == 0) { - *type = LfrfidKeyType::KeyEM4100; - } else if(strcmp("H10301", string) == 0) { - *type = LfrfidKeyType::KeyH10301; - } else if(strcmp("I40134", string) == 0) { - *type = LfrfidKeyType::KeyI40134; - } else if(strcmp("IoProxXSF", string) == 0) { - *type = LfrfidKeyType::KeyIoProxXSF; - } else { - result = false; - } - - return result; -} - -uint8_t lfrfid_key_get_type_data_count(LfrfidKeyType type) { - switch(type) { - case LfrfidKeyType::KeyEM4100: - return 5; - break; - case LfrfidKeyType::KeyH10301: - return 3; - break; - case LfrfidKeyType::KeyI40134: - return 3; - break; - case LfrfidKeyType::KeyIoProxXSF: - return 4; - break; - } - - return 0; -} diff --git a/applications/lfrfid/helpers/key_info.h b/applications/lfrfid/helpers/key_info.h deleted file mode 100644 index 75a0a94063..0000000000 --- a/applications/lfrfid/helpers/key_info.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include - -static const uint8_t LFRFID_KEY_SIZE = 8; -static const uint8_t LFRFID_KEY_NAME_SIZE = 22; - -enum class LfrfidKeyType : uint8_t { - KeyEM4100, - KeyH10301, - KeyI40134, - KeyIoProxXSF, -}; - -const char* lfrfid_key_get_type_string(LfrfidKeyType type); -const char* lfrfid_key_get_manufacturer_string(LfrfidKeyType type); -bool lfrfid_key_get_string_type(const char* string, LfrfidKeyType* type); -uint8_t lfrfid_key_get_type_data_count(LfrfidKeyType type); diff --git a/applications/lfrfid/helpers/osc_fsk.cpp b/applications/lfrfid/helpers/osc_fsk.cpp deleted file mode 100644 index 5f3b5367b7..0000000000 --- a/applications/lfrfid/helpers/osc_fsk.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "osc_fsk.h" - -OscFSK::OscFSK(uint16_t _freq_low, uint16_t _freq_hi, uint16_t _osc_phase_max) - : freq{_freq_low, _freq_hi} - , osc_phase_max(_osc_phase_max) { - osc_phase_current = 0; -} - -bool OscFSK::next(bool bit, uint16_t* period) { - bool advance = false; - *period = freq[bit]; - osc_phase_current += *period; - - if(osc_phase_current > osc_phase_max) { - advance = true; - osc_phase_current -= osc_phase_max; - } - - return advance; -} diff --git a/applications/lfrfid/helpers/osc_fsk.h b/applications/lfrfid/helpers/osc_fsk.h deleted file mode 100644 index eaaaa10ad0..0000000000 --- a/applications/lfrfid/helpers/osc_fsk.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once -#include - -/** - * This code tries to fit the periods into a given number of cycles (phases) by taking cycles from the next cycle of periods. - */ -class OscFSK { -public: - /** - * Get next period - * @param bit bit value - * @param period return period - * @return bool whether to advance to the next bit - */ - bool next(bool bit, uint16_t* period); - - /** - * FSK ocillator constructor - * - * @param freq_low bit 0 freq - * @param freq_hi bit 1 freq - * @param osc_phase_max max oscillator phase - */ - OscFSK(uint16_t freq_low, uint16_t freq_hi, uint16_t osc_phase_max); - -private: - const uint16_t freq[2]; - const uint16_t osc_phase_max; - int32_t osc_phase_current; -}; diff --git a/applications/lfrfid/helpers/protocols/protocol_emmarin.cpp b/applications/lfrfid/helpers/protocols/protocol_emmarin.cpp deleted file mode 100644 index 4ac180e300..0000000000 --- a/applications/lfrfid/helpers/protocols/protocol_emmarin.cpp +++ /dev/null @@ -1,150 +0,0 @@ -#include "protocol_emmarin.h" -#include - -#define EM_HEADER_POS 55 -#define EM_HEADER_MASK (0x1FFLLU << EM_HEADER_POS) - -#define EM_FIRST_ROW_POS 50 - -#define EM_ROW_COUNT 10 -#define EM_COLUMN_COUNT 4 -#define EM_BITS_PER_ROW_COUNT (EM_COLUMN_COUNT + 1) - -#define EM_COLUMN_POS 4 -#define EM_STOP_POS 0 -#define EM_STOP_MASK (0x1LLU << EM_STOP_POS) - -#define EM_HEADER_AND_STOP_MASK (EM_HEADER_MASK | EM_STOP_MASK) -#define EM_HEADER_AND_STOP_DATA (EM_HEADER_MASK) - -typedef uint64_t EMMarinCardData; - -void write_nibble(bool low_nibble, uint8_t data, EMMarinCardData* card_data) { - uint8_t parity_sum = 0; - uint8_t start = 0; - if(!low_nibble) start = 4; - - for(int8_t i = (start + 3); i >= start; i--) { - parity_sum += (data >> i) & 1; - *card_data = (*card_data << 1) | ((data >> i) & 1); - } - - *card_data = (*card_data << 1) | ((parity_sum % 2) & 1); -} - -uint8_t ProtocolEMMarin::get_encoded_data_size() { - return sizeof(EMMarinCardData); -} - -uint8_t ProtocolEMMarin::get_decoded_data_size() { - return 5; -} - -void ProtocolEMMarin::encode( - const uint8_t* decoded_data, - const uint8_t decoded_data_size, - uint8_t* encoded_data, - const uint8_t encoded_data_size) { - furi_check(decoded_data_size >= get_decoded_data_size()); - furi_check(encoded_data_size >= get_encoded_data_size()); - - EMMarinCardData card_data; - - // header - card_data = 0b111111111; - - // data - for(uint8_t i = 0; i < get_decoded_data_size(); i++) { - write_nibble(false, decoded_data[i], &card_data); - write_nibble(true, decoded_data[i], &card_data); - } - - // column parity and stop bit - uint8_t parity_sum; - - for(uint8_t c = 0; c < EM_COLUMN_COUNT; c++) { - parity_sum = 0; - for(uint8_t i = 1; i <= EM_ROW_COUNT; i++) { - uint8_t parity_bit = (card_data >> (i * EM_BITS_PER_ROW_COUNT - 1)) & 1; - parity_sum += parity_bit; - } - card_data = (card_data << 1) | ((parity_sum % 2) & 1); - } - - // stop bit - card_data = (card_data << 1) | 0; - - memcpy(encoded_data, &card_data, get_encoded_data_size()); -} - -void ProtocolEMMarin::decode( - const uint8_t* encoded_data, - const uint8_t encoded_data_size, - uint8_t* decoded_data, - const uint8_t decoded_data_size) { - furi_check(decoded_data_size >= get_decoded_data_size()); - furi_check(encoded_data_size >= get_encoded_data_size()); - - uint8_t decoded_data_index = 0; - EMMarinCardData card_data = *(reinterpret_cast(encoded_data)); - - // clean result - memset(decoded_data, 0, decoded_data_size); - - // header - for(uint8_t i = 0; i < 9; i++) { - card_data = card_data << 1; - } - - // nibbles - uint8_t value = 0; - for(uint8_t r = 0; r < EM_ROW_COUNT; r++) { - uint8_t nibble = 0; - for(uint8_t i = 0; i < 5; i++) { - if(i < 4) nibble = (nibble << 1) | (card_data & (1LLU << 63) ? 1 : 0); - card_data = card_data << 1; - } - value = (value << 4) | nibble; - if(r % 2) { - decoded_data[decoded_data_index] |= value; - decoded_data_index++; - value = 0; - } - } -} - -bool ProtocolEMMarin::can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) { - furi_check(encoded_data_size >= get_encoded_data_size()); - const EMMarinCardData* card_data = reinterpret_cast(encoded_data); - - // check header and stop bit - if((*card_data & EM_HEADER_AND_STOP_MASK) != EM_HEADER_AND_STOP_DATA) return false; - - // check row parity - for(uint8_t i = 0; i < EM_ROW_COUNT; i++) { - uint8_t parity_sum = 0; - - for(uint8_t j = 0; j < EM_BITS_PER_ROW_COUNT; j++) { - parity_sum += (*card_data >> (EM_FIRST_ROW_POS - i * EM_BITS_PER_ROW_COUNT + j)) & 1; - } - - if((parity_sum % 2)) { - return false; - } - } - - // check columns parity - for(uint8_t i = 0; i < EM_COLUMN_COUNT; i++) { - uint8_t parity_sum = 0; - - for(uint8_t j = 0; j < EM_ROW_COUNT + 1; j++) { - parity_sum += (*card_data >> (EM_COLUMN_POS - i + j * EM_BITS_PER_ROW_COUNT)) & 1; - } - - if((parity_sum % 2)) { - return false; - } - } - - return true; -} diff --git a/applications/lfrfid/helpers/protocols/protocol_emmarin.h b/applications/lfrfid/helpers/protocols/protocol_emmarin.h deleted file mode 100644 index 7a866f9097..0000000000 --- a/applications/lfrfid/helpers/protocols/protocol_emmarin.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "protocol_generic.h" - -class ProtocolEMMarin : public ProtocolGeneric { -public: - uint8_t get_encoded_data_size() final; - uint8_t get_decoded_data_size() final; - - void encode( - const uint8_t* decoded_data, - const uint8_t decoded_data_size, - uint8_t* encoded_data, - const uint8_t encoded_data_size) final; - - void decode( - const uint8_t* encoded_data, - const uint8_t encoded_data_size, - uint8_t* decoded_data, - const uint8_t decoded_data_size) final; - - bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) final; -}; diff --git a/applications/lfrfid/helpers/protocols/protocol_generic.h b/applications/lfrfid/helpers/protocols/protocol_generic.h deleted file mode 100644 index d593f70899..0000000000 --- a/applications/lfrfid/helpers/protocols/protocol_generic.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once -#include "stdint.h" -#include "stdbool.h" - -class ProtocolGeneric { -public: - /** - * @brief Get the encoded data size - * - * @return uint8_t size of encoded data in bytes - */ - virtual uint8_t get_encoded_data_size() = 0; - - /** - * @brief Get the decoded data size - * - * @return uint8_t size of decoded data in bytes - */ - virtual uint8_t get_decoded_data_size() = 0; - - /** - * @brief encode decoded data - * - * @param decoded_data - * @param decoded_data_size - * @param encoded_data - * @param encoded_data_size - */ - virtual void encode( - const uint8_t* decoded_data, - const uint8_t decoded_data_size, - uint8_t* encoded_data, - const uint8_t encoded_data_size) = 0; - - /** - * @brief decode encoded data - * - * @param encoded_data - * @param encoded_data_size - * @param decoded_data - * @param decoded_data_size - */ - virtual void decode( - const uint8_t* encoded_data, - const uint8_t encoded_data_size, - uint8_t* decoded_data, - const uint8_t decoded_data_size) = 0; - - /** - * @brief fast check that data can be correctly decoded - * - * @param encoded_data - * @param encoded_data_size - * @return true - can be correctly decoded - * @return false - cannot be correctly decoded - */ - virtual bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) = 0; - - virtual ~ProtocolGeneric(){}; -}; diff --git a/applications/lfrfid/helpers/protocols/protocol_hid_h10301.cpp b/applications/lfrfid/helpers/protocols/protocol_hid_h10301.cpp deleted file mode 100644 index b718388388..0000000000 --- a/applications/lfrfid/helpers/protocols/protocol_hid_h10301.cpp +++ /dev/null @@ -1,238 +0,0 @@ -#include "protocol_hid_h10301.h" -#include - -typedef uint32_t HID10301CardData; -constexpr uint8_t HID10301Count = 3; -constexpr uint8_t HID10301BitSize = sizeof(HID10301CardData) * 8; - -static void write_raw_bit(bool bit, uint8_t position, HID10301CardData* card_data) { - if(bit) { - card_data[position / HID10301BitSize] |= - 1UL << (HID10301BitSize - (position % HID10301BitSize) - 1); - } else { - card_data[position / (sizeof(HID10301CardData) * 8)] &= - ~(1UL << (HID10301BitSize - (position % HID10301BitSize) - 1)); - } -} - -static void write_bit(bool bit, uint8_t position, HID10301CardData* card_data) { - write_raw_bit(bit, position + 0, card_data); - write_raw_bit(!bit, position + 1, card_data); -} - -uint8_t ProtocolHID10301::get_encoded_data_size() { - return sizeof(HID10301CardData) * HID10301Count; -} - -uint8_t ProtocolHID10301::get_decoded_data_size() { - return 3; -} - -void ProtocolHID10301::encode( - const uint8_t* decoded_data, - const uint8_t decoded_data_size, - uint8_t* encoded_data, - const uint8_t encoded_data_size) { - furi_check(decoded_data_size >= get_decoded_data_size()); - furi_check(encoded_data_size >= get_encoded_data_size()); - - HID10301CardData card_data[HID10301Count] = {0, 0, 0}; - - uint32_t fc_cn = (decoded_data[0] << 16) | (decoded_data[1] << 8) | decoded_data[2]; - - // even parity sum calculation (high 12 bits of data) - uint8_t even_parity_sum = 0; - for(int8_t i = 12; i < 24; i++) { - if(((fc_cn >> i) & 1) == 1) { - even_parity_sum++; - } - } - - // odd parity sum calculation (low 12 bits of data) - uint8_t odd_parity_sum = 1; - for(int8_t i = 0; i < 12; i++) { - if(((fc_cn >> i) & 1) == 1) { - odd_parity_sum++; - } - } - - // 0x1D preamble - write_raw_bit(0, 0, card_data); - write_raw_bit(0, 1, card_data); - write_raw_bit(0, 2, card_data); - write_raw_bit(1, 3, card_data); - write_raw_bit(1, 4, card_data); - write_raw_bit(1, 5, card_data); - write_raw_bit(0, 6, card_data); - write_raw_bit(1, 7, card_data); - - // company / OEM code 1 - write_bit(0, 8, card_data); - write_bit(0, 10, card_data); - write_bit(0, 12, card_data); - write_bit(0, 14, card_data); - write_bit(0, 16, card_data); - write_bit(0, 18, card_data); - write_bit(1, 20, card_data); - - // card format / length 1 - write_bit(0, 22, card_data); - write_bit(0, 24, card_data); - write_bit(0, 26, card_data); - write_bit(0, 28, card_data); - write_bit(0, 30, card_data); - write_bit(0, 32, card_data); - write_bit(0, 34, card_data); - write_bit(0, 36, card_data); - write_bit(0, 38, card_data); - write_bit(0, 40, card_data); - write_bit(1, 42, card_data); - - // even parity bit - write_bit((even_parity_sum % 2), 44, card_data); - - // data - for(uint8_t i = 0; i < 24; i++) { - write_bit((fc_cn >> (23 - i)) & 1, 46 + (i * 2), card_data); - } - - // odd parity bit - write_bit((odd_parity_sum % 2), 94, card_data); - - memcpy(encoded_data, &card_data, get_encoded_data_size()); -} - -void ProtocolHID10301::decode( - const uint8_t* encoded_data, - const uint8_t encoded_data_size, - uint8_t* decoded_data, - const uint8_t decoded_data_size) { - furi_check(decoded_data_size >= get_decoded_data_size()); - furi_check(encoded_data_size >= get_encoded_data_size()); - - const HID10301CardData* card_data = reinterpret_cast(encoded_data); - - // data decoding - uint32_t result = 0; - - // decode from word 1 - // coded with 01 = 0, 10 = 1 transitions - for(int8_t i = 9; i >= 0; i--) { - switch((*(card_data + 1) >> (2 * i)) & 0b11) { - case 0b01: - result = (result << 1) | 0; - break; - case 0b10: - result = (result << 1) | 1; - break; - default: - break; - } - } - - // decode from word 2 - // coded with 01 = 0, 10 = 1 transitions - for(int8_t i = 15; i >= 0; i--) { - switch((*(card_data + 2) >> (2 * i)) & 0b11) { - case 0b01: - result = (result << 1) | 0; - break; - case 0b10: - result = (result << 1) | 1; - break; - default: - break; - } - } - - uint8_t data[3] = {(uint8_t)(result >> 17), (uint8_t)(result >> 9), (uint8_t)(result >> 1)}; - - memcpy(decoded_data, &data, get_decoded_data_size()); -} - -bool ProtocolHID10301::can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) { - furi_check(encoded_data_size >= get_encoded_data_size()); - - const HID10301CardData* card_data = reinterpret_cast(encoded_data); - - // packet preamble - // raw data - if(*(encoded_data + 3) != 0x1D) { - return false; - } - - // encoded company/oem - // coded with 01 = 0, 10 = 1 transitions - // stored in word 0 - if((*card_data >> 10 & 0x3FFF) != 0x1556) { - return false; - } - - // encoded format/length - // coded with 01 = 0, 10 = 1 transitions - // stored in word 0 and word 1 - if((((*card_data & 0x3FF) << 12) | ((*(card_data + 1) >> 20) & 0xFFF)) != 0x155556) { - return false; - } - - // data decoding - uint32_t result = 0; - - // decode from word 1 - // coded with 01 = 0, 10 = 1 transitions - for(int8_t i = 9; i >= 0; i--) { - switch((*(card_data + 1) >> (2 * i)) & 0b11) { - case 0b01: - result = (result << 1) | 0; - break; - case 0b10: - result = (result << 1) | 1; - break; - default: - return false; - break; - } - } - - // decode from word 2 - // coded with 01 = 0, 10 = 1 transitions - for(int8_t i = 15; i >= 0; i--) { - switch((*(card_data + 2) >> (2 * i)) & 0b11) { - case 0b01: - result = (result << 1) | 0; - break; - case 0b10: - result = (result << 1) | 1; - break; - default: - return false; - break; - } - } - - // trailing parity (odd) test - uint8_t parity_sum = 0; - for(int8_t i = 0; i < 13; i++) { - if(((result >> i) & 1) == 1) { - parity_sum++; - } - } - - if((parity_sum % 2) != 1) { - return false; - } - - // leading parity (even) test - parity_sum = 0; - for(int8_t i = 13; i < 26; i++) { - if(((result >> i) & 1) == 1) { - parity_sum++; - } - } - - if((parity_sum % 2) == 1) { - return false; - } - - return true; -} diff --git a/applications/lfrfid/helpers/protocols/protocol_hid_h10301.h b/applications/lfrfid/helpers/protocols/protocol_hid_h10301.h deleted file mode 100644 index fbd6e0b2bf..0000000000 --- a/applications/lfrfid/helpers/protocols/protocol_hid_h10301.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "protocol_generic.h" - -class ProtocolHID10301 : public ProtocolGeneric { -public: - uint8_t get_encoded_data_size() final; - uint8_t get_decoded_data_size() final; - - void encode( - const uint8_t* decoded_data, - const uint8_t decoded_data_size, - uint8_t* encoded_data, - const uint8_t encoded_data_size) final; - - void decode( - const uint8_t* encoded_data, - const uint8_t encoded_data_size, - uint8_t* decoded_data, - const uint8_t decoded_data_size) final; - - bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) final; -}; diff --git a/applications/lfrfid/helpers/protocols/protocol_indala_40134.cpp b/applications/lfrfid/helpers/protocols/protocol_indala_40134.cpp deleted file mode 100644 index 482339def3..0000000000 --- a/applications/lfrfid/helpers/protocols/protocol_indala_40134.cpp +++ /dev/null @@ -1,237 +0,0 @@ -#include "protocol_indala_40134.h" -#include - -typedef uint64_t Indala40134CardData; - -static void set_bit(bool bit, uint8_t position, Indala40134CardData* card_data) { - position = (sizeof(Indala40134CardData) * 8) - 1 - position; - if(bit) { - *card_data |= 1ull << position; - } else { - *card_data &= ~(1ull << position); - } -} - -static bool get_bit(uint8_t position, const Indala40134CardData* card_data) { - position = (sizeof(Indala40134CardData) * 8) - 1 - position; - return (*card_data >> position) & 1; -} - -uint8_t ProtocolIndala40134::get_encoded_data_size() { - return sizeof(Indala40134CardData); -} - -uint8_t ProtocolIndala40134::get_decoded_data_size() { - return 3; -} - -void ProtocolIndala40134::encode( - const uint8_t* decoded_data, - const uint8_t decoded_data_size, - uint8_t* encoded_data, - const uint8_t encoded_data_size) { - furi_check(decoded_data_size >= get_decoded_data_size()); - furi_check(encoded_data_size >= get_encoded_data_size()); - - uint32_t fc_and_card = (decoded_data[0] << 16) | (decoded_data[1] << 8) | decoded_data[2]; - Indala40134CardData card_data = 0; - - // preamble - set_bit(1, 0, &card_data); - set_bit(1, 2, &card_data); - set_bit(1, 32, &card_data); - - // factory code - set_bit(((fc_and_card >> 23) & 1), 57, &card_data); - set_bit(((fc_and_card >> 22) & 1), 49, &card_data); - set_bit(((fc_and_card >> 21) & 1), 44, &card_data); - set_bit(((fc_and_card >> 20) & 1), 47, &card_data); - set_bit(((fc_and_card >> 19) & 1), 48, &card_data); - set_bit(((fc_and_card >> 18) & 1), 53, &card_data); - set_bit(((fc_and_card >> 17) & 1), 39, &card_data); - set_bit(((fc_and_card >> 16) & 1), 58, &card_data); - - // card number - set_bit(((fc_and_card >> 15) & 1), 42, &card_data); - set_bit(((fc_and_card >> 14) & 1), 45, &card_data); - set_bit(((fc_and_card >> 13) & 1), 43, &card_data); - set_bit(((fc_and_card >> 12) & 1), 40, &card_data); - set_bit(((fc_and_card >> 11) & 1), 52, &card_data); - set_bit(((fc_and_card >> 10) & 1), 36, &card_data); - set_bit(((fc_and_card >> 9) & 1), 35, &card_data); - set_bit(((fc_and_card >> 8) & 1), 51, &card_data); - set_bit(((fc_and_card >> 7) & 1), 46, &card_data); - set_bit(((fc_and_card >> 6) & 1), 33, &card_data); - set_bit(((fc_and_card >> 5) & 1), 37, &card_data); - set_bit(((fc_and_card >> 4) & 1), 54, &card_data); - set_bit(((fc_and_card >> 3) & 1), 56, &card_data); - set_bit(((fc_and_card >> 2) & 1), 59, &card_data); - set_bit(((fc_and_card >> 1) & 1), 50, &card_data); - set_bit(((fc_and_card >> 0) & 1), 41, &card_data); - - // checksum - uint8_t checksum = 0; - checksum += ((fc_and_card >> 14) & 1); - checksum += ((fc_and_card >> 12) & 1); - checksum += ((fc_and_card >> 9) & 1); - checksum += ((fc_and_card >> 8) & 1); - checksum += ((fc_and_card >> 6) & 1); - checksum += ((fc_and_card >> 5) & 1); - checksum += ((fc_and_card >> 2) & 1); - checksum += ((fc_and_card >> 0) & 1); - - // wiegand parity bits - // even parity sum calculation (high 12 bits of data) - uint8_t even_parity_sum = 0; - for(int8_t i = 12; i < 24; i++) { - if(((fc_and_card >> i) & 1) == 1) { - even_parity_sum++; - } - } - - // odd parity sum calculation (low 12 bits of data) - uint8_t odd_parity_sum = 1; - for(int8_t i = 0; i < 12; i++) { - if(((fc_and_card >> i) & 1) == 1) { - odd_parity_sum++; - } - } - - // even parity bit - set_bit((even_parity_sum % 2), 34, &card_data); - - // odd parity bit - set_bit((odd_parity_sum % 2), 38, &card_data); - - // checksum - if((checksum & 1) == 1) { - set_bit(0, 62, &card_data); - set_bit(1, 63, &card_data); - } else { - set_bit(1, 62, &card_data); - set_bit(0, 63, &card_data); - } - - memcpy(encoded_data, &card_data, get_encoded_data_size()); -} - -// factory code -static uint8_t get_fc(const Indala40134CardData* card_data) { - uint8_t fc = 0; - - fc = fc << 1 | get_bit(57, card_data); - fc = fc << 1 | get_bit(49, card_data); - fc = fc << 1 | get_bit(44, card_data); - fc = fc << 1 | get_bit(47, card_data); - fc = fc << 1 | get_bit(48, card_data); - fc = fc << 1 | get_bit(53, card_data); - fc = fc << 1 | get_bit(39, card_data); - fc = fc << 1 | get_bit(58, card_data); - - return fc; -} - -// card number -static uint16_t get_cn(const Indala40134CardData* card_data) { - uint16_t cn = 0; - - cn = cn << 1 | get_bit(42, card_data); - cn = cn << 1 | get_bit(45, card_data); - cn = cn << 1 | get_bit(43, card_data); - cn = cn << 1 | get_bit(40, card_data); - cn = cn << 1 | get_bit(52, card_data); - cn = cn << 1 | get_bit(36, card_data); - cn = cn << 1 | get_bit(35, card_data); - cn = cn << 1 | get_bit(51, card_data); - cn = cn << 1 | get_bit(46, card_data); - cn = cn << 1 | get_bit(33, card_data); - cn = cn << 1 | get_bit(37, card_data); - cn = cn << 1 | get_bit(54, card_data); - cn = cn << 1 | get_bit(56, card_data); - cn = cn << 1 | get_bit(59, card_data); - cn = cn << 1 | get_bit(50, card_data); - cn = cn << 1 | get_bit(41, card_data); - - return cn; -} - -void ProtocolIndala40134::decode( - const uint8_t* encoded_data, - const uint8_t encoded_data_size, - uint8_t* decoded_data, - const uint8_t decoded_data_size) { - furi_check(decoded_data_size >= get_decoded_data_size()); - furi_check(encoded_data_size >= get_encoded_data_size()); - - const Indala40134CardData* card_data = - reinterpret_cast(encoded_data); - - uint8_t fc = get_fc(card_data); - uint16_t card = get_cn(card_data); - - decoded_data[0] = fc; - decoded_data[1] = card >> 8; - decoded_data[2] = card; -} - -bool ProtocolIndala40134::can_be_decoded( - const uint8_t* encoded_data, - const uint8_t encoded_data_size) { - furi_check(encoded_data_size >= get_encoded_data_size()); - bool can_be_decoded = false; - - const Indala40134CardData* card_data = - reinterpret_cast(encoded_data); - - do { - // preambula - if((*card_data >> 32) != 0xa0000000UL) break; - - // data - const uint32_t fc_and_card = get_fc(card_data) << 16 | get_cn(card_data); - - // checksum - const uint8_t checksum = get_bit(62, card_data) << 1 | get_bit(63, card_data); - uint8_t checksum_sum = 0; - checksum_sum += ((fc_and_card >> 14) & 1); - checksum_sum += ((fc_and_card >> 12) & 1); - checksum_sum += ((fc_and_card >> 9) & 1); - checksum_sum += ((fc_and_card >> 8) & 1); - checksum_sum += ((fc_and_card >> 6) & 1); - checksum_sum += ((fc_and_card >> 5) & 1); - checksum_sum += ((fc_and_card >> 2) & 1); - checksum_sum += ((fc_and_card >> 0) & 1); - checksum_sum = checksum_sum & 0b1; - - if(checksum_sum == 1 && checksum == 0b01) { - } else if(checksum_sum == 0 && checksum == 0b10) { - } else { - break; - } - - // wiegand parity bits - // even parity sum calculation (high 12 bits of data) - const bool even_parity = get_bit(34, card_data); - uint8_t even_parity_sum = 0; - for(int8_t i = 12; i < 24; i++) { - if(((fc_and_card >> i) & 1) == 1) { - even_parity_sum++; - } - } - if(even_parity_sum % 2 != even_parity) break; - - // odd parity sum calculation (low 12 bits of data) - const bool odd_parity = get_bit(38, card_data); - uint8_t odd_parity_sum = 1; - for(int8_t i = 0; i < 12; i++) { - if(((fc_and_card >> i) & 1) == 1) { - odd_parity_sum++; - } - } - if(odd_parity_sum % 2 != odd_parity) break; - - can_be_decoded = true; - } while(false); - - return can_be_decoded; -} diff --git a/applications/lfrfid/helpers/protocols/protocol_indala_40134.h b/applications/lfrfid/helpers/protocols/protocol_indala_40134.h deleted file mode 100644 index d378bb2cee..0000000000 --- a/applications/lfrfid/helpers/protocols/protocol_indala_40134.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "protocol_generic.h" - -class ProtocolIndala40134 : public ProtocolGeneric { -public: - uint8_t get_encoded_data_size() final; - uint8_t get_decoded_data_size() final; - - void encode( - const uint8_t* decoded_data, - const uint8_t decoded_data_size, - uint8_t* encoded_data, - const uint8_t encoded_data_size) final; - - void decode( - const uint8_t* encoded_data, - const uint8_t encoded_data_size, - uint8_t* decoded_data, - const uint8_t decoded_data_size) final; - - bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) final; -}; diff --git a/applications/lfrfid/helpers/protocols/protocol_ioprox.cpp b/applications/lfrfid/helpers/protocols/protocol_ioprox.cpp deleted file mode 100644 index b3b6a0e598..0000000000 --- a/applications/lfrfid/helpers/protocols/protocol_ioprox.cpp +++ /dev/null @@ -1,193 +0,0 @@ -#include "protocol_ioprox.h" -#include -#include - -/** - * Writes a bit into the output buffer. - */ -static void write_bit(bool bit, uint8_t position, uint8_t* data) { - if(bit) { - data[position / 8] |= 1UL << (7 - (position % 8)); - } else { - data[position / 8] &= ~(1UL << (7 - (position % 8))); - } -} - -/** - * Writes up to eight contiguous bits into the output buffer. - */ -static void write_bits(uint8_t byte, uint8_t position, uint8_t* data, uint8_t length) { - furi_check(length <= 8); - furi_check(length > 0); - - for(uint8_t i = 0; i < length; ++i) { - uint8_t shift = 7 - i; - write_bit((byte >> shift) & 1, position + i, data); - } -} - -uint8_t ProtocolIoProx::get_encoded_data_size() { - return 8; -} - -uint8_t ProtocolIoProx::get_decoded_data_size() { - return 4; -} - -void ProtocolIoProx::encode( - const uint8_t* decoded_data, - const uint8_t decoded_data_size, - uint8_t* encoded_data, - const uint8_t encoded_data_size) { - furi_check(decoded_data_size >= get_decoded_data_size()); - furi_check(encoded_data_size >= get_encoded_data_size()); - - // Packet to transmit: - // - // 0 10 20 30 40 50 60 - // v v v v v v v - // 01234567 8 90123456 7 89012345 6 78901234 5 67890123 4 56789012 3 45678901 23 - // ----------------------------------------------------------------------------- - // 00000000 0 11110000 1 facility 1 version_ 1 code-one 1 code-two 1 checksum 11 - - // Preamble. - write_bits(0b00000000, 0, encoded_data, 8); - write_bit(0, 8, encoded_data); - - write_bits(0b11110000, 9, encoded_data, 8); - write_bit(1, 17, encoded_data); - - // Facility code. - write_bits(decoded_data[0], 18, encoded_data, 8); - write_bit(1, 26, encoded_data); - - // Version - write_bits(decoded_data[1], 27, encoded_data, 8); - write_bit(1, 35, encoded_data); - - // Code one - write_bits(decoded_data[2], 36, encoded_data, 8); - write_bit(1, 44, encoded_data); - - // Code two - write_bits(decoded_data[3], 45, encoded_data, 8); - write_bit(1, 53, encoded_data); - - // Checksum - write_bits(compute_checksum(encoded_data, 8), 54, encoded_data, 8); - write_bit(1, 62, encoded_data); - write_bit(1, 63, encoded_data); -} - -void ProtocolIoProx::decode( - const uint8_t* encoded_data, - const uint8_t encoded_data_size, - uint8_t* decoded_data, - const uint8_t decoded_data_size) { - furi_check(decoded_data_size >= get_decoded_data_size()); - furi_check(encoded_data_size >= get_encoded_data_size()); - - // Packet structure: - // (Note: the second word seems fixed; but this may not be a guarantee; - // it currently has no meaning.) - // - //0 1 2 3 4 5 6 7 - //v v v v v v v v - //01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF - //----------------------------------------------------------------------- - //00000000 01111000 01FFFFFF FF1VVVVV VVV1CCCC CCCC1CCC CCCCC1XX XXXXXX11 - // - // F = facility code - // V = version - // C = code - // X = checksum - - // Facility code - decoded_data[0] = (encoded_data[2] << 2) | (encoded_data[3] >> 6); - - // Version code. - decoded_data[1] = (encoded_data[3] << 3) | (encoded_data[4] >> 5); - - // Code bytes. - decoded_data[2] = (encoded_data[4] << 4) | (encoded_data[5] >> 4); - decoded_data[3] = (encoded_data[5] << 5) | (encoded_data[6] >> 3); -} - -bool ProtocolIoProx::can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) { - furi_check(encoded_data_size >= get_encoded_data_size()); - - // Packet framing - // - //0 1 2 3 4 5 6 7 - //v v v v v v v v - //01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF - //----------------------------------------------------------------------- - //00000000 01______ _1______ __1_____ ___1____ ____1___ _____1XX XXXXXX11 - // - // _ = variable data - // 0 = preamble 0 - // 1 = framing 1 - // X = checksum - - // Validate the packet preamble is there... - if(encoded_data[0] != 0b00000000) { - return false; - } - if((encoded_data[1] >> 6) != 0b01) { - return false; - } - - // ... check for known ones... - if((encoded_data[2] & 0b01000000) == 0) { - return false; - } - if((encoded_data[3] & 0b00100000) == 0) { - return false; - } - if((encoded_data[4] & 0b00010000) == 0) { - return false; - } - if((encoded_data[5] & 0b00001000) == 0) { - return false; - } - if((encoded_data[6] & 0b00000100) == 0) { - return false; - } - if((encoded_data[7] & 0b00000011) == 0) { - return false; - } - - // ... and validate our checksums. - uint8_t checksum = compute_checksum(encoded_data, 8); - uint8_t checkval = (encoded_data[6] << 6) | (encoded_data[7] >> 2); - - if(checksum != checkval) { - return false; - } - - return true; -} - -uint8_t ProtocolIoProx::compute_checksum(const uint8_t* data, const uint8_t data_size) { - furi_check(data_size == get_encoded_data_size()); - - // Packet structure: - // - //0 1 2 3 4 5 6 7 - //v v v v v v v v - //01234567 8 9ABCDEF0 1 23456789 A BCDEF012 3 456789AB C DEF01234 5 6789ABCD EF - //00000000 0 VVVVVVVV 1 WWWWWWWW 1 XXXXXXXX 1 YYYYYYYY 1 ZZZZZZZZ 1 CHECKSUM 11 - // - // algorithm as observed by the proxmark3 folks - // CHECKSUM == 0xFF - (V + W + X + Y + Z) - - uint8_t checksum = 0; - - checksum += (data[1] << 1) | (data[2] >> 7); // VVVVVVVVV - checksum += (data[2] << 2) | (data[3] >> 6); // WWWWWWWWW - checksum += (data[3] << 3) | (data[4] >> 5); // XXXXXXXXX - checksum += (data[4] << 4) | (data[5] >> 4); // YYYYYYYYY - checksum += (data[5] << 5) | (data[6] >> 3); // ZZZZZZZZZ - - return 0xFF - checksum; -} diff --git a/applications/lfrfid/helpers/protocols/protocol_ioprox.h b/applications/lfrfid/helpers/protocols/protocol_ioprox.h deleted file mode 100644 index 2fff53b171..0000000000 --- a/applications/lfrfid/helpers/protocols/protocol_ioprox.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include "protocol_generic.h" - -class ProtocolIoProx : public ProtocolGeneric { -public: - uint8_t get_encoded_data_size() final; - uint8_t get_decoded_data_size() final; - - void encode( - const uint8_t* decoded_data, - const uint8_t decoded_data_size, - uint8_t* encoded_data, - const uint8_t encoded_data_size) final; - - void decode( - const uint8_t* encoded_data, - const uint8_t encoded_data_size, - uint8_t* decoded_data, - const uint8_t decoded_data_size) final; - - bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) final; - -private: - /** Computes the IoProx checksum of the provided (decoded) data. */ - uint8_t compute_checksum(const uint8_t* data, const uint8_t data_size); -}; diff --git a/applications/lfrfid/helpers/pulse_joiner.cpp b/applications/lfrfid/helpers/pulse_joiner.cpp deleted file mode 100644 index c72019b143..0000000000 --- a/applications/lfrfid/helpers/pulse_joiner.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "pulse_joiner.h" -#include - -bool PulseJoiner::push_pulse(bool polarity, uint16_t period, uint16_t pulse) { - bool result = false; - furi_check((pulse_index + 1) < pulse_max); - - if(polarity == false && pulse_index == 0) { - // first negative pulse is ommited - - } else { - pulses[pulse_index].polarity = polarity; - pulses[pulse_index].time = pulse; - pulse_index++; - } - - if(period > pulse) { - pulses[pulse_index].polarity = !polarity; - pulses[pulse_index].time = period - pulse; - pulse_index++; - } - - if(pulse_index >= 4) { - // we know that first pulse is always high - // so we wait 2 edges, hi2low and next low2hi - - uint8_t edges_count = 0; - bool last_polarity = pulses[0].polarity; - - for(uint8_t i = 1; i < pulse_index; i++) { - if(pulses[i].polarity != last_polarity) { - edges_count++; - last_polarity = pulses[i].polarity; - } - } - - if(edges_count >= 2) { - result = true; - } - } - - return result; -} - -void PulseJoiner::pop_pulse(uint16_t* period, uint16_t* pulse) { - furi_check(pulse_index <= (pulse_max + 1)); - - uint16_t tmp_period = 0; - uint16_t tmp_pulse = 0; - uint8_t edges_count = 0; - bool last_polarity = pulses[0].polarity; - uint8_t next_fist_pulse = 0; - - for(uint8_t i = 0; i < pulse_max; i++) { - // count edges - if(pulses[i].polarity != last_polarity) { - edges_count++; - last_polarity = pulses[i].polarity; - } - - // wait for 2 edges - if(edges_count == 2) { - next_fist_pulse = i; - break; - } - - // sum pulse time - if(pulses[i].polarity) { - tmp_period += pulses[i].time; - tmp_pulse += pulses[i].time; - } else { - tmp_period += pulses[i].time; - } - pulse_index--; - } - - *period = tmp_period; - *pulse = tmp_pulse; - - // remove counted periods and shift data - for(uint8_t i = 0; i < pulse_max; i++) { - if((next_fist_pulse + i) < pulse_max) { - pulses[i].polarity = pulses[next_fist_pulse + i].polarity; - pulses[i].time = pulses[next_fist_pulse + i].time; - } else { - break; - } - } -} - -PulseJoiner::PulseJoiner() { - for(uint8_t i = 0; i < pulse_max; i++) { - pulses[i] = {false, 0}; - } -} diff --git a/applications/lfrfid/helpers/pulse_joiner.h b/applications/lfrfid/helpers/pulse_joiner.h deleted file mode 100644 index 1639d83716..0000000000 --- a/applications/lfrfid/helpers/pulse_joiner.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include "stdint.h" - -class PulseJoiner { -public: - /** - * @brief Push timer pulse. First negative pulse is ommited. - * - * @param polarity pulse polarity: true = high2low, false = low2high - * @param period overall period time in timer clicks - * @param pulse pulse time in timer clicks - * - * @return true - next pulse can and must be popped immediatly - */ - bool push_pulse(bool polarity, uint16_t period, uint16_t pulse); - - /** - * @brief Get the next timer pulse. Call only if push_pulse returns true. - * - * @param period overall period time in timer clicks - * @param pulse pulse time in timer clicks - */ - void pop_pulse(uint16_t* period, uint16_t* pulse); - - PulseJoiner(); - -private: - struct Pulse { - bool polarity; - uint16_t time; - }; - - uint8_t pulse_index = 0; - static const uint8_t pulse_max = 6; - Pulse pulses[pulse_max]; -}; diff --git a/applications/lfrfid/helpers/rfid_key.cpp b/applications/lfrfid/helpers/rfid_key.cpp deleted file mode 100644 index 2d99d40f26..0000000000 --- a/applications/lfrfid/helpers/rfid_key.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "rfid_key.h" -#include -#include - -RfidKey::RfidKey() { - clear(); -} - -RfidKey::~RfidKey() { -} - -void RfidKey::set_type(LfrfidKeyType _type) { - type = _type; -} - -void RfidKey::set_data(const uint8_t* _data, const uint8_t _data_size) { - furi_assert(_data_size <= data.size()); - for(uint8_t i = 0; i < _data_size; i++) { - data[i] = _data[i]; - } -} - -void RfidKey::set_name(const char* _name) { - strlcpy(name, _name, get_name_length()); -} - -LfrfidKeyType RfidKey::get_type() { - return type; -} - -const uint8_t* RfidKey::get_data() { - return &data[0]; -} - -const char* RfidKey::get_type_text() { - return lfrfid_key_get_type_string(type); -} - -uint8_t RfidKey::get_type_data_count() const { - return lfrfid_key_get_type_data_count(type); -} - -char* RfidKey::get_name() { - return name; -} - -uint8_t RfidKey::get_name_length() { - return LFRFID_KEY_NAME_SIZE; -} - -void RfidKey::clear() { - set_name(""); - set_type(LfrfidKeyType::KeyEM4100); - data.fill(0); -} - -RfidKey& RfidKey::operator=(const RfidKey& rhs) { - if(this == &rhs) return *this; - - set_type(rhs.type); - set_name(rhs.name); - set_data(&rhs.data[0], get_type_data_count()); - - return *this; -} diff --git a/applications/lfrfid/helpers/rfid_key.h b/applications/lfrfid/helpers/rfid_key.h deleted file mode 100644 index 29b87cf9c0..0000000000 --- a/applications/lfrfid/helpers/rfid_key.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include "key_info.h" -#include - -class RfidKey { -public: - RfidKey(); - ~RfidKey(); - - void set_type(LfrfidKeyType type); - void set_data(const uint8_t* data, const uint8_t data_size); - void set_name(const char* name); - - LfrfidKeyType get_type(); - const uint8_t* get_data(); - const char* get_type_text(); - uint8_t get_type_data_count() const; - char* get_name(); - uint8_t get_name_length(); - void clear(); - RfidKey& operator=(const RfidKey& rhs); - -private: - std::array data; - LfrfidKeyType type; - char name[LFRFID_KEY_NAME_SIZE + 1]; -}; diff --git a/applications/lfrfid/helpers/rfid_reader.cpp b/applications/lfrfid/helpers/rfid_reader.cpp deleted file mode 100644 index 029b1cb4bd..0000000000 --- a/applications/lfrfid/helpers/rfid_reader.cpp +++ /dev/null @@ -1,175 +0,0 @@ -#include "rfid_reader.h" -#include -#include -#include - -/** - * @brief private violation assistant for RfidReader - */ -struct RfidReaderAccessor { - static void decode(RfidReader& rfid_reader, bool polarity) { - rfid_reader.decode(polarity); - } -}; - -void RfidReader::decode(bool polarity) { - uint32_t current_dwt_value = DWT->CYCCNT; - uint32_t period = current_dwt_value - last_dwt_value; - last_dwt_value = current_dwt_value; - -#ifdef RFID_GPIO_DEBUG - decoder_gpio_out.process_front(polarity, period); -#endif - - switch(type) { - case Type::Normal: - decoder_em.process_front(polarity, period); - decoder_hid26.process_front(polarity, period); - decoder_ioprox.process_front(polarity, period); - break; - case Type::Indala: - decoder_em.process_front(polarity, period); - decoder_hid26.process_front(polarity, period); - decoder_ioprox.process_front(polarity, period); - decoder_indala.process_front(polarity, period); - break; - } - - detect_ticks++; -} - -bool RfidReader::switch_timer_elapsed() { - const uint32_t seconds_to_switch = furi_kernel_get_tick_frequency() * 2.0f; - return (furi_get_tick() - switch_os_tick_last) > seconds_to_switch; -} - -void RfidReader::switch_timer_reset() { - switch_os_tick_last = furi_get_tick(); -} - -void RfidReader::switch_mode() { - switch(type) { - case Type::Normal: - type = Type::Indala; - furi_hal_rfid_change_read_config(62500.0f, 0.25f); - break; - case Type::Indala: - type = Type::Normal; - furi_hal_rfid_change_read_config(125000.0f, 0.5f); - break; - } - - switch_timer_reset(); -} - -static void comparator_trigger_callback(bool level, void* comp_ctx) { - RfidReader* _this = static_cast(comp_ctx); - - RfidReaderAccessor::decode(*_this, !level); -} - -RfidReader::RfidReader() { -} - -void RfidReader::start() { - type = Type::Normal; - - furi_hal_rfid_pins_read(); - furi_hal_rfid_tim_read(125000, 0.5); - furi_hal_rfid_tim_read_start(); - start_comparator(); - - switch_timer_reset(); - last_read_count = 0; -} - -void RfidReader::start_forced(RfidReader::Type _type) { - start(); - if(_type == Type::Indala) { - switch_mode(); - } -} - -void RfidReader::stop() { - furi_hal_rfid_pins_reset(); - furi_hal_rfid_tim_read_stop(); - furi_hal_rfid_tim_reset(); - stop_comparator(); -} - -bool RfidReader::read(LfrfidKeyType* _type, uint8_t* data, uint8_t data_size, bool switch_enable) { - bool result = false; - bool something_read = false; - - // reading - if(decoder_em.read(data, data_size)) { - *_type = LfrfidKeyType::KeyEM4100; - something_read = true; - } - - if(decoder_hid26.read(data, data_size)) { - *_type = LfrfidKeyType::KeyH10301; - something_read = true; - } - - if(decoder_ioprox.read(data, data_size)) { - *_type = LfrfidKeyType::KeyIoProxXSF; - something_read = true; - } - - if(decoder_indala.read(data, data_size)) { - *_type = LfrfidKeyType::KeyI40134; - something_read = true; - } - - // validation - if(something_read) { - switch_timer_reset(); - - if(last_read_type == *_type && memcmp(last_read_data, data, data_size) == 0) { - last_read_count = last_read_count + 1; - - if(last_read_count > 2) { - result = true; - } - } else { - last_read_type = *_type; - memcpy(last_read_data, data, data_size); - last_read_count = 0; - } - } - - // mode switching - if(switch_enable && switch_timer_elapsed()) { - switch_mode(); - last_read_count = 0; - } - - return result; -} - -bool RfidReader::detect() { - bool detected = false; - if(detect_ticks > 10) { - detected = true; - } - detect_ticks = 0; - - return detected; -} - -bool RfidReader::any_read() { - return last_read_count > 0; -} - -void RfidReader::start_comparator(void) { - furi_hal_rfid_comp_set_callback(comparator_trigger_callback, this); - last_dwt_value = DWT->CYCCNT; - - furi_hal_rfid_comp_start(); -} - -void RfidReader::stop_comparator(void) { - furi_hal_rfid_comp_stop(); - furi_hal_rfid_comp_set_callback(NULL, NULL); -} diff --git a/applications/lfrfid/helpers/rfid_reader.h b/applications/lfrfid/helpers/rfid_reader.h deleted file mode 100644 index 903bbecf93..0000000000 --- a/applications/lfrfid/helpers/rfid_reader.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once -//#include "decoder_analyzer.h" -#include "decoder_gpio_out.h" -#include "decoder_emmarin.h" -#include "decoder_hid26.h" -#include "decoder_indala.h" -#include "decoder_ioprox.h" -#include "key_info.h" - -//#define RFID_GPIO_DEBUG 1 - -class RfidReader { -public: - enum class Type : uint8_t { - Normal, - Indala, - }; - - RfidReader(); - void start(); - void start_forced(RfidReader::Type type); - void stop(); - bool read(LfrfidKeyType* type, uint8_t* data, uint8_t data_size, bool switch_enable = true); - - bool detect(); - bool any_read(); - -private: - friend struct RfidReaderAccessor; - - //DecoderAnalyzer decoder_analyzer; -#ifdef RFID_GPIO_DEBUG - DecoderGpioOut decoder_gpio_out; -#endif - DecoderEMMarin decoder_em; - DecoderHID26 decoder_hid26; - DecoderIndala decoder_indala; - DecoderIoProx decoder_ioprox; - - uint32_t last_dwt_value; - - void start_comparator(void); - void stop_comparator(void); - - void decode(bool polarity); - - uint32_t detect_ticks; - - uint32_t switch_os_tick_last; - bool switch_timer_elapsed(); - void switch_timer_reset(); - void switch_mode(); - - LfrfidKeyType last_read_type; - uint8_t last_read_data[LFRFID_KEY_SIZE]; - uint8_t last_read_count; - - Type type = Type::Normal; -}; diff --git a/applications/lfrfid/helpers/rfid_timer_emulator.cpp b/applications/lfrfid/helpers/rfid_timer_emulator.cpp deleted file mode 100644 index f5337c31dd..0000000000 --- a/applications/lfrfid/helpers/rfid_timer_emulator.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "rfid_timer_emulator.h" - -RfidTimerEmulator::RfidTimerEmulator() { -} - -RfidTimerEmulator::~RfidTimerEmulator() { - std::map::iterator it; - - for(it = encoders.begin(); it != encoders.end(); ++it) { - delete it->second; - } - - encoders.clear(); -} - -void RfidTimerEmulator::start(LfrfidKeyType type, const uint8_t* data, uint8_t data_size) { - if(encoders.count(type)) { - current_encoder = encoders.find(type)->second; - - if(data_size >= lfrfid_key_get_type_data_count(type)) { - current_encoder->init(data, data_size); - - furi_hal_rfid_tim_emulate(125000); - furi_hal_rfid_pins_emulate(); - - furi_hal_rfid_tim_emulate_start(RfidTimerEmulator::timer_update_callback, this); - } - } else { - // not found - } -} - -void RfidTimerEmulator::stop() { - furi_hal_rfid_tim_emulate_stop(); - furi_hal_rfid_tim_reset(); - furi_hal_rfid_pins_reset(); -} - -void RfidTimerEmulator::timer_update_callback(void* ctx) { - RfidTimerEmulator* _this = static_cast(ctx); - - bool result; - bool polarity; - uint16_t period; - uint16_t pulse; - - do { - _this->current_encoder->get_next(&polarity, &period, &pulse); - result = _this->pulse_joiner.push_pulse(polarity, period, pulse); - } while(result == false); - - _this->pulse_joiner.pop_pulse(&period, &pulse); - - furi_hal_rfid_set_emulate_period(period - 1); - furi_hal_rfid_set_emulate_pulse(pulse); -} diff --git a/applications/lfrfid/helpers/rfid_timer_emulator.h b/applications/lfrfid/helpers/rfid_timer_emulator.h deleted file mode 100644 index 2129a1c7f8..0000000000 --- a/applications/lfrfid/helpers/rfid_timer_emulator.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include -#include "key_info.h" -#include "encoder_generic.h" -#include "encoder_emmarin.h" -#include "encoder_hid_h10301.h" -#include "encoder_indala_40134.h" -#include "encoder_ioprox.h" -#include "pulse_joiner.h" -#include - -class RfidTimerEmulator { -public: - RfidTimerEmulator(); - ~RfidTimerEmulator(); - void start(LfrfidKeyType type, const uint8_t* data, uint8_t data_size); - void stop(); - -private: - EncoderGeneric* current_encoder = nullptr; - - std::map encoders = { - {LfrfidKeyType::KeyEM4100, new EncoderEM()}, - {LfrfidKeyType::KeyH10301, new EncoderHID_H10301()}, - {LfrfidKeyType::KeyI40134, new EncoderIndala_40134()}, - {LfrfidKeyType::KeyIoProxXSF, new EncoderIoProx()}, - }; - - PulseJoiner pulse_joiner; - static void timer_update_callback(void* ctx); -}; diff --git a/applications/lfrfid/helpers/rfid_worker.cpp b/applications/lfrfid/helpers/rfid_worker.cpp deleted file mode 100644 index af15a340fb..0000000000 --- a/applications/lfrfid/helpers/rfid_worker.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "rfid_worker.h" - -RfidWorker::RfidWorker() { -} - -RfidWorker::~RfidWorker() { -} - -void RfidWorker::start_read() { - reader.start(); -} - -bool RfidWorker::read() { - static const uint8_t data_size = LFRFID_KEY_SIZE; - uint8_t data[data_size] = {0}; - LfrfidKeyType type; - - bool result = reader.read(&type, data, data_size); - - if(result) { - key.set_type(type); - key.set_data(data, data_size); - }; - - return result; -} - -bool RfidWorker::detect() { - return reader.detect(); -} - -bool RfidWorker::any_read() { - return reader.any_read(); -} - -void RfidWorker::stop_read() { - reader.stop(); -} - -void RfidWorker::start_write() { - write_result = WriteResult::Nothing; - write_sequence = new TickSequencer(); - validate_counts = 0; - - write_sequence->do_every_tick(1, std::bind(&RfidWorker::sq_write, this)); - write_sequence->do_after_tick(2, std::bind(&RfidWorker::sq_write_start_validate, this)); - write_sequence->do_every_tick(30, std::bind(&RfidWorker::sq_write_validate, this)); - write_sequence->do_every_tick(1, std::bind(&RfidWorker::sq_write_stop_validate, this)); -} - -RfidWorker::WriteResult RfidWorker::write() { - write_sequence->tick(); - return write_result; -} - -void RfidWorker::stop_write() { - delete write_sequence; - reader.stop(); -} - -void RfidWorker::start_emulate() { - emulator.start(key.get_type(), key.get_data(), key.get_type_data_count()); -} - -void RfidWorker::stop_emulate() { - emulator.stop(); -} - -void RfidWorker::sq_write() { - for(size_t i = 0; i < 5; i++) { - switch(key.get_type()) { - case LfrfidKeyType::KeyEM4100: - writer.start(); - writer.write_em(key.get_data()); - writer.stop(); - break; - case LfrfidKeyType::KeyH10301: - writer.start(); - writer.write_hid(key.get_data()); - writer.stop(); - break; - case LfrfidKeyType::KeyI40134: - writer.start(); - writer.write_indala(key.get_data()); - writer.stop(); - break; - case LfrfidKeyType::KeyIoProxXSF: - writer.start(); - writer.write_ioprox(key.get_data()); - writer.stop(); - break; - } - } -} - -void RfidWorker::sq_write_start_validate() { - switch(key.get_type()) { - case LfrfidKeyType::KeyEM4100: - case LfrfidKeyType::KeyH10301: - case LfrfidKeyType::KeyIoProxXSF: - reader.start_forced(RfidReader::Type::Normal); - break; - case LfrfidKeyType::KeyI40134: - reader.start_forced(RfidReader::Type::Indala); - break; - } -} - -void RfidWorker::sq_write_validate() { - static const uint8_t data_size = LFRFID_KEY_SIZE; - uint8_t data[data_size] = {0}; - LfrfidKeyType type; - - bool result = reader.read(&type, data, data_size); - - if(result && (write_result != WriteResult::Ok)) { - if(validate_counts > (5 * 60)) { - write_result = WriteResult::NotWritable; - } - - if(type == key.get_type()) { - if(memcmp(data, key.get_data(), key.get_type_data_count()) == 0) { - write_result = WriteResult::Ok; - validate_counts = 0; - } else { - validate_counts++; - } - } else { - validate_counts++; - } - }; -} - -void RfidWorker::sq_write_stop_validate() { - reader.stop(); -} diff --git a/applications/lfrfid/helpers/rfid_worker.h b/applications/lfrfid/helpers/rfid_worker.h deleted file mode 100644 index 2c49ad14e0..0000000000 --- a/applications/lfrfid/helpers/rfid_worker.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once -#include "key_info.h" -#include "rfid_reader.h" -#include "rfid_writer.h" -#include "rfid_timer_emulator.h" -#include "rfid_key.h" -#include "state_sequencer.h" - -class RfidWorker { -public: - RfidWorker(); - ~RfidWorker(); - - void start_read(); - bool read(); - bool detect(); - bool any_read(); - void stop_read(); - - enum class WriteResult : uint8_t { - Ok, - NotWritable, - Nothing, - }; - - void start_write(); - WriteResult write(); - void stop_write(); - - void start_emulate(); - void stop_emulate(); - - RfidKey key; - -private: - RfidWriter writer; - RfidReader reader; - RfidTimerEmulator emulator; - - WriteResult write_result; - TickSequencer* write_sequence; - - void sq_write(); - void sq_write_start_validate(); - void sq_write_validate(); - uint16_t validate_counts; - void sq_write_stop_validate(); -}; diff --git a/applications/lfrfid/helpers/rfid_writer.cpp b/applications/lfrfid/helpers/rfid_writer.cpp deleted file mode 100644 index 31838fde0b..0000000000 --- a/applications/lfrfid/helpers/rfid_writer.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include "rfid_writer.h" -#include "protocols/protocol_ioprox.h" -#include -#include "protocols/protocol_emmarin.h" -#include "protocols/protocol_hid_h10301.h" -#include "protocols/protocol_indala_40134.h" - -/** - * @brief all timings are specified in field clocks (field clock = 125 kHz, 8 us) - * - */ -class T55xxTiming { -public: - constexpr static const uint16_t wait_time = 400; - constexpr static const uint8_t start_gap = 30; - constexpr static const uint8_t write_gap = 18; - constexpr static const uint8_t data_0 = 24; - constexpr static const uint8_t data_1 = 56; - constexpr static const uint16_t program = 700; -}; - -class T55xxCmd { -public: - constexpr static const uint8_t opcode_page_0 = 0b10; - constexpr static const uint8_t opcode_page_1 = 0b11; - constexpr static const uint8_t opcode_reset = 0b00; -}; - -RfidWriter::RfidWriter() { -} - -RfidWriter::~RfidWriter() { -} - -void RfidWriter::start() { - furi_hal_rfid_tim_read(125000, 0.5); - furi_hal_rfid_pins_read(); - furi_hal_rfid_tim_read_start(); - - // do not ground the antenna - furi_hal_rfid_pin_pull_release(); -} - -void RfidWriter::stop() { - furi_hal_rfid_tim_read_stop(); - furi_hal_rfid_tim_reset(); - furi_hal_rfid_pins_reset(); -} - -void RfidWriter::write_gap(uint32_t gap_time) { - furi_hal_rfid_tim_read_stop(); - furi_delay_us(gap_time * 8); - furi_hal_rfid_tim_read_start(); -} - -void RfidWriter::write_bit(bool value) { - if(value) { - furi_delay_us(T55xxTiming::data_1 * 8); - } else { - furi_delay_us(T55xxTiming::data_0 * 8); - } - write_gap(T55xxTiming::write_gap); -} - -void RfidWriter::write_byte(uint8_t value) { - for(uint8_t i = 0; i < 8; i++) { - write_bit((value >> i) & 1); - } -} - -void RfidWriter::write_block(uint8_t page, uint8_t block, bool lock_bit, uint32_t data) { - furi_delay_us(T55xxTiming::wait_time * 8); - - // start gap - write_gap(T55xxTiming::start_gap); - - // opcode - switch(page) { - case 0: - write_bit(1); - write_bit(0); - break; - case 1: - write_bit(1); - write_bit(1); - break; - default: - furi_check(false); - break; - } - - // lock bit - write_bit(lock_bit); - - // data - for(uint8_t i = 0; i < 32; i++) { - write_bit((data >> (31 - i)) & 1); - } - - // block address - write_bit((block >> 2) & 1); - write_bit((block >> 1) & 1); - write_bit((block >> 0) & 1); - - furi_delay_us(T55xxTiming::program * 8); - - furi_delay_us(T55xxTiming::wait_time * 8); - write_reset(); -} - -void RfidWriter::write_reset() { - write_gap(T55xxTiming::start_gap); - write_bit(1); - write_bit(0); -} - -void RfidWriter::write_em(const uint8_t em_data[5]) { - ProtocolEMMarin em_card; - uint64_t em_encoded_data; - em_card.encode(em_data, 5, reinterpret_cast(&em_encoded_data), sizeof(uint64_t)); - const uint32_t em_config_block_data = 0b00000000000101001000000001000000; - - FURI_CRITICAL_ENTER(); - write_block(0, 0, false, em_config_block_data); - write_block(0, 1, false, em_encoded_data); - write_block(0, 2, false, em_encoded_data >> 32); - write_reset(); - FURI_CRITICAL_EXIT(); -} - -void RfidWriter::write_hid(const uint8_t hid_data[3]) { - ProtocolHID10301 hid_card; - uint32_t card_data[3]; - hid_card.encode(hid_data, 3, reinterpret_cast(&card_data), sizeof(card_data) * 3); - - const uint32_t hid_config_block_data = 0b00000000000100000111000001100000; - - FURI_CRITICAL_ENTER(); - write_block(0, 0, false, hid_config_block_data); - write_block(0, 1, false, card_data[0]); - write_block(0, 2, false, card_data[1]); - write_block(0, 3, false, card_data[2]); - write_reset(); - FURI_CRITICAL_EXIT(); -} - -/** Endian fixup. Translates an ioprox block into a t5577 block */ -static uint32_t ioprox_encode_block(const uint8_t block_data[4]) { - uint8_t raw_card_data[] = {block_data[3], block_data[2], block_data[1], block_data[0]}; - return *reinterpret_cast(&raw_card_data); -} - -void RfidWriter::write_ioprox(const uint8_t ioprox_data[4]) { - ProtocolIoProx ioprox_card; - - uint8_t encoded_data[8]; - ioprox_card.encode(ioprox_data, 4, encoded_data, sizeof(encoded_data)); - - const uint32_t ioprox_config_block_data = 0b00000000000101000111000001000000; - - FURI_CRITICAL_ENTER(); - write_block(0, 0, false, ioprox_config_block_data); - write_block(0, 1, false, ioprox_encode_block(&encoded_data[0])); - write_block(0, 2, false, ioprox_encode_block(&encoded_data[4])); - write_reset(); - FURI_CRITICAL_EXIT(); -} - -void RfidWriter::write_indala(const uint8_t indala_data[3]) { - ProtocolIndala40134 indala_card; - uint32_t card_data[2]; - indala_card.encode( - indala_data, 3, reinterpret_cast(&card_data), sizeof(card_data) * 2); - - const uint32_t indala_config_block_data = 0b00000000000010000001000001000000; - - FURI_CRITICAL_ENTER(); - write_block(0, 0, false, indala_config_block_data); - write_block(0, 1, false, card_data[0]); - write_block(0, 2, false, card_data[1]); - write_reset(); - FURI_CRITICAL_EXIT(); -} diff --git a/applications/lfrfid/helpers/rfid_writer.h b/applications/lfrfid/helpers/rfid_writer.h deleted file mode 100644 index 98d2bf9555..0000000000 --- a/applications/lfrfid/helpers/rfid_writer.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include "stdint.h" - -class RfidWriter { -public: - RfidWriter(); - ~RfidWriter(); - void start(); - void stop(); - void write_em(const uint8_t em_data[5]); - void write_hid(const uint8_t hid_data[3]); - void write_ioprox(const uint8_t ioprox_data[4]); - void write_indala(const uint8_t indala_data[3]); - -private: - void write_gap(uint32_t gap_time); - void write_bit(bool value); - void write_byte(uint8_t value); - void write_block(uint8_t page, uint8_t block, bool lock_bit, uint32_t data); - void write_reset(); -}; diff --git a/applications/lfrfid/helpers/state_sequencer.cpp b/applications/lfrfid/helpers/state_sequencer.cpp deleted file mode 100644 index e6718df5cd..0000000000 --- a/applications/lfrfid/helpers/state_sequencer.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "state_sequencer.h" -#include "stdio.h" - -TickSequencer::TickSequencer() { -} - -TickSequencer::~TickSequencer() { -} - -void TickSequencer::tick() { - if(tick_count == list_it->first) { - tick_count = 0; - - list_it++; - if(list_it == list.end()) { - list_it = list.begin(); - } - } - - list_it->second(); - tick_count++; -} - -void TickSequencer::reset() { - list_it = list.begin(); - tick_count = 0; -} - -void TickSequencer::clear() { - list.clear(); - reset(); -} - -void TickSequencer::do_every_tick(uint32_t tick_count, std::function fn) { - list.push_back(std::make_pair(tick_count, fn)); - reset(); -} - -void TickSequencer::do_after_tick(uint32_t tick_count, std::function fn) { - if(tick_count > 1) { - list.push_back( - std::make_pair(tick_count - 1, std::bind(&TickSequencer::do_nothing, this))); - } - list.push_back(std::make_pair(1, fn)); - - reset(); -} - -void TickSequencer::do_nothing() { -} diff --git a/applications/lfrfid/helpers/state_sequencer.h b/applications/lfrfid/helpers/state_sequencer.h deleted file mode 100644 index 12512ab517..0000000000 --- a/applications/lfrfid/helpers/state_sequencer.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include "stdint.h" -#include -#include - -class TickSequencer { -public: - TickSequencer(); - ~TickSequencer(); - - void tick(); - void reset(); - void clear(); - - void do_every_tick(uint32_t tick_count, std::function fn); - void do_after_tick(uint32_t tick_count, std::function fn); - -private: - std::list > > list; - std::list > >::iterator list_it; - - uint32_t tick_count; - - void do_nothing(); -}; diff --git a/applications/lfrfid/lfrfid_app.cpp b/applications/lfrfid/lfrfid_app.cpp index f1a575de54..9373ca8c71 100644 --- a/applications/lfrfid/lfrfid_app.cpp +++ b/applications/lfrfid/lfrfid_app.cpp @@ -21,6 +21,11 @@ #include "scene/lfrfid_app_scene_delete_confirm.h" #include "scene/lfrfid_app_scene_delete_success.h" #include "scene/lfrfid_app_scene_rpc.h" +#include "scene/lfrfid_app_scene_extra_actions.h" +#include "scene/lfrfid_app_scene_raw_info.h" +#include "scene/lfrfid_app_scene_raw_name.h" +#include "scene/lfrfid_app_scene_raw_read.h" +#include "scene/lfrfid_app_scene_raw_success.h" #include #include @@ -28,24 +33,44 @@ #include const char* LfRfidApp::app_folder = ANY_PATH("lfrfid"); +const char* LfRfidApp::app_sd_folder = EXT_PATH("lfrfid"); const char* LfRfidApp::app_extension = ".rfid"; const char* LfRfidApp::app_filetype = "Flipper RFID key"; LfRfidApp::LfRfidApp() : scene_controller{this} - , notification{"notification"} - , storage{"storage"} - , dialogs{"dialogs"} + , notification{RECORD_NOTIFICATION} + , storage{RECORD_STORAGE} + , dialogs{RECORD_DIALOGS} , text_store(40) { + string_init(file_name); + string_init(raw_file_name); string_init_set_str(file_path, app_folder); + + dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); + + size_t size = protocol_dict_get_max_data_size(dict); + new_key_data = (uint8_t*)malloc(size); + old_key_data = (uint8_t*)malloc(size); + + lfworker = lfrfid_worker_alloc(dict); } LfRfidApp::~LfRfidApp() { + string_clear(raw_file_name); + string_clear(file_name); string_clear(file_path); + protocol_dict_free(dict); + + lfrfid_worker_free(lfworker); + if(rpc_ctx) { rpc_system_app_set_callback(rpc_ctx, NULL, NULL); rpc_system_app_send_exited(rpc_ctx); } + + free(new_key_data); + free(old_key_data); } static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) { @@ -88,7 +113,7 @@ void LfRfidApp::run(void* _args) { scene_controller.process(100, SceneType::Rpc); } else { string_set_str(file_path, args); - load_key_data(file_path, &worker.key, true); + load_key_data(file_path, true); view_controller.attach_to_gui(ViewDispatcherTypeFullscreen); scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate()); scene_controller.process(100, SceneType::Emulate); @@ -114,11 +139,16 @@ void LfRfidApp::run(void* _args) { scene_controller.add_scene(SceneType::SavedInfo, new LfRfidAppSceneSavedInfo()); scene_controller.add_scene(SceneType::DeleteConfirm, new LfRfidAppSceneDeleteConfirm()); scene_controller.add_scene(SceneType::DeleteSuccess, new LfRfidAppSceneDeleteSuccess()); + scene_controller.add_scene(SceneType::ExtraActions, new LfRfidAppSceneExtraActions()); + scene_controller.add_scene(SceneType::RawInfo, new LfRfidAppSceneRawInfo()); + scene_controller.add_scene(SceneType::RawName, new LfRfidAppSceneRawName()); + scene_controller.add_scene(SceneType::RawRead, new LfRfidAppSceneRawRead()); + scene_controller.add_scene(SceneType::RawSuccess, new LfRfidAppSceneRawSuccess()); scene_controller.process(100); } } -bool LfRfidApp::save_key(RfidKey* key) { +bool LfRfidApp::save_key() { bool result = false; make_app_folder(); @@ -128,9 +158,9 @@ bool LfRfidApp::save_key(RfidKey* key) { string_left(file_path, filename_start); } - string_cat_printf(file_path, "/%s%s", key->get_name(), app_extension); + string_cat_printf(file_path, "/%s%s", string_get_cstr(file_name), app_extension); - result = save_key_data(file_path, key); + result = save_key_data(file_path); return result; } @@ -143,56 +173,27 @@ bool LfRfidApp::load_key_from_file_select(bool need_restore) { dialogs, file_path, file_path, app_extension, true, &I_125_10px, true); if(result) { - result = load_key_data(file_path, &worker.key, true); + result = load_key_data(file_path, true); } return result; } -bool LfRfidApp::delete_key(RfidKey* key) { - UNUSED(key); +bool LfRfidApp::delete_key() { return storage_simply_remove(storage, string_get_cstr(file_path)); } -bool LfRfidApp::load_key_data(string_t path, RfidKey* key, bool show_dialog) { - FlipperFormat* file = flipper_format_file_alloc(storage); +bool LfRfidApp::load_key_data(string_t path, bool show_dialog) { bool result = false; - string_t str_result; - string_init(str_result); do { - if(!flipper_format_file_open_existing(file, string_get_cstr(path))) break; - - // header - uint32_t version; - if(!flipper_format_read_header(file, str_result, &version)) break; - if(string_cmp_str(str_result, app_filetype) != 0) break; - if(version != 1) break; - - // key type - LfrfidKeyType type; - RfidKey loaded_key; - - if(!flipper_format_read_string(file, "Key type", str_result)) break; - if(!lfrfid_key_get_string_type(string_get_cstr(str_result), &type)) break; - loaded_key.set_type(type); + protocol_id = lfrfid_dict_file_load(dict, string_get_cstr(path)); + if(protocol_id == PROTOCOL_NO) break; - // key data - uint8_t key_data[loaded_key.get_type_data_count()] = {}; - if(!flipper_format_read_hex(file, "Data", key_data, loaded_key.get_type_data_count())) - break; - loaded_key.set_data(key_data, loaded_key.get_type_data_count()); - - path_extract_filename(path, str_result, true); - loaded_key.set_name(string_get_cstr(str_result)); - - *key = loaded_key; + path_extract_filename(path, file_name, true); result = true; } while(0); - flipper_format_free(file); - string_clear(str_result); - if((!result) && (show_dialog)) { dialog_message_show_storage_error(dialogs, "Cannot load\nkey file"); } @@ -200,27 +201,8 @@ bool LfRfidApp::load_key_data(string_t path, RfidKey* key, bool show_dialog) { return result; } -bool LfRfidApp::save_key_data(string_t path, RfidKey* key) { - FlipperFormat* file = flipper_format_file_alloc(storage); - bool result = false; - - do { - if(!flipper_format_file_open_always(file, string_get_cstr(path))) break; - if(!flipper_format_write_header_cstr(file, app_filetype, 1)) break; - if(!flipper_format_write_comment_cstr(file, "Key type can be EM4100, H10301 or I40134")) - break; - if(!flipper_format_write_string_cstr( - file, "Key type", lfrfid_key_get_type_string(key->get_type()))) - break; - if(!flipper_format_write_comment_cstr( - file, "Data size for EM4100 is 5, for H10301 is 3, for I40134 is 3")) - break; - if(!flipper_format_write_hex(file, "Data", key->get_data(), key->get_type_data_count())) - break; - result = true; - } while(0); - - flipper_format_free(file); +bool LfRfidApp::save_key_data(string_t path) { + bool result = lfrfid_dict_file_save(dict, protocol_id, string_get_cstr(path)); if(!result) { dialog_message_show_storage_error(dialogs, "Cannot save\nkey file"); diff --git a/applications/lfrfid/lfrfid_app.h b/applications/lfrfid/lfrfid_app.h index db022c9aae..153218dbdf 100644 --- a/applications/lfrfid/lfrfid_app.h +++ b/applications/lfrfid/lfrfid_app.h @@ -20,9 +20,15 @@ #include #include -#include "helpers/rfid_worker.h" #include "rpc/rpc_app.h" +#include +#include +#include +#include + +#define LFRFID_KEY_NAME_SIZE 22 + class LfRfidApp { public: enum class EventType : uint8_t { @@ -32,7 +38,19 @@ class LfRfidApp { Stay, Retry, Exit, - EmulateStart, + ReadEventSenseStart, + ReadEventSenseEnd, + ReadEventSenseCardStart, + ReadEventSenseCardEnd, + ReadEventStartASK, + ReadEventStartPSK, + ReadEventDone, + ReadEventOverrun, + ReadEventError, + WriteEventOK, + WriteEventProtocolCannotBeWritten, + WriteEventFobCannotBeWritten, + WriteEventTooLongToWrite, RpcLoadFile, RpcSessionClose, }; @@ -57,12 +75,17 @@ class LfRfidApp { DeleteConfirm, DeleteSuccess, Rpc, + ExtraActions, + RawInfo, + RawName, + RawRead, + RawSuccess, }; class Event { public: union { - int32_t menu_index; + int32_t signed_int; } payload; EventType type; @@ -79,8 +102,6 @@ class LfRfidApp { RecordController storage; RecordController dialogs; - RfidWorker worker; - TextStore text_store; string_t file_path; @@ -90,15 +111,27 @@ class LfRfidApp { void run(void* args); static const char* app_folder; + static const char* app_sd_folder; static const char* app_extension; static const char* app_filetype; - bool save_key(RfidKey* key); + bool save_key(); bool load_key_from_file_select(bool need_restore); - bool delete_key(RfidKey* key); + bool delete_key(); - bool load_key_data(string_t path, RfidKey* key, bool show_dialog); - bool save_key_data(string_t path, RfidKey* key); + bool load_key_data(string_t path, bool show_dialog); + bool save_key_data(string_t path); void make_app_folder(); + + ProtocolDict* dict; + LFRFIDWorker* lfworker; + string_t file_name; + ProtocolId protocol_id; + LFRFIDWorkerReadType read_type; + + uint8_t* old_key_data; + uint8_t* new_key_data; + + string_t raw_file_name; }; diff --git a/applications/lfrfid/lfrfid_cli.c b/applications/lfrfid/lfrfid_cli.c new file mode 100644 index 0000000000..9a6930a671 --- /dev/null +++ b/applications/lfrfid/lfrfid_cli.c @@ -0,0 +1,575 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +static void lfrfid_cli(Cli* cli, string_t args, void* context); + +// app cli function +void lfrfid_on_system_start() { + Cli* cli = furi_record_open(RECORD_CLI); + cli_add_command(cli, "rfid", CliCommandFlagDefault, lfrfid_cli, NULL); + furi_record_close(RECORD_CLI); +} + +static void lfrfid_cli_print_usage() { + printf("Usage:\r\n"); + printf("rfid read \r\n"); + printf("rfid \r\n"); + printf("rfid raw_read \r\n"); + printf("rfid raw_emulate \r\n"); +}; + +typedef struct { + ProtocolId protocol; + FuriEventFlag* event; +} LFRFIDCliReadContext; + +static void lfrfid_cli_read_callback(LFRFIDWorkerReadResult result, ProtocolId proto, void* ctx) { + furi_assert(ctx); + LFRFIDCliReadContext* context = ctx; + if(result == LFRFIDWorkerReadDone) { + context->protocol = proto; + FURI_SW_MEMBARRIER(); + } + furi_event_flag_set(context->event, 1 << result); +} + +static void lfrfid_cli_read(Cli* cli, string_t args) { + string_t type_string; + string_init(type_string); + LFRFIDWorkerReadType type = LFRFIDWorkerReadTypeAuto; + + if(args_read_string_and_trim(args, type_string)) { + if(string_cmp_str(type_string, "normal") == 0 || string_cmp_str(type_string, "ask") == 0) { + // ask + type = LFRFIDWorkerReadTypeASKOnly; + } else if( + string_cmp_str(type_string, "indala") == 0 || + string_cmp_str(type_string, "psk") == 0) { + // psk + type = LFRFIDWorkerReadTypePSKOnly; + } else { + lfrfid_cli_print_usage(); + string_clear(type_string); + return; + } + } + string_clear(type_string); + + ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); + LFRFIDWorker* worker = lfrfid_worker_alloc(dict); + LFRFIDCliReadContext context; + context.protocol = PROTOCOL_NO; + context.event = furi_event_flag_alloc(); + + lfrfid_worker_start_thread(worker); + + printf("Reading RFID...\r\nPress Ctrl+C to abort\r\n"); + + const uint32_t available_flags = (1 << LFRFIDWorkerReadDone); + + lfrfid_worker_read_start(worker, type, lfrfid_cli_read_callback, &context); + + while(true) { + uint32_t flags = + furi_event_flag_wait(context.event, available_flags, FuriFlagWaitAny, 100); + + if(flags != FuriFlagErrorTimeout) { + if(FURI_BIT(flags, LFRFIDWorkerReadDone)) { + break; + } + } + + if(cli_cmd_interrupt_received(cli)) break; + } + + lfrfid_worker_stop(worker); + lfrfid_worker_stop_thread(worker); + lfrfid_worker_free(worker); + + if(context.protocol != PROTOCOL_NO) { + printf("%s ", protocol_dict_get_name(dict, context.protocol)); + + size_t size = protocol_dict_get_data_size(dict, context.protocol); + uint8_t* data = malloc(size); + protocol_dict_get_data(dict, context.protocol, data, size); + for(size_t i = 0; i < size; i++) { + printf("%02X", data[i]); + } + printf("\r\n"); + free(data); + + string_t info; + string_init(info); + protocol_dict_render_data(dict, info, context.protocol); + if(string_size(info) > 0) { + printf("%s\r\n", string_get_cstr(info)); + } + string_clear(info); + } + + printf("Reading stopped\r\n"); + protocol_dict_free(dict); + + furi_event_flag_free(context.event); +} + +static bool lfrfid_cli_parse_args(string_t args, ProtocolDict* dict, ProtocolId* protocol) { + bool result = false; + string_t protocol_name, data_text; + string_init(protocol_name); + string_init(data_text); + size_t data_size = protocol_dict_get_max_data_size(dict); + uint8_t* data = malloc(data_size); + + do { + // load args + if(!args_read_string_and_trim(args, protocol_name) || + !args_read_string_and_trim(args, data_text)) { + lfrfid_cli_print_usage(); + break; + } + + // check protocol arg + *protocol = protocol_dict_get_protocol_by_name(dict, string_get_cstr(protocol_name)); + if(*protocol == PROTOCOL_NO) { + printf( + "Unknown protocol: %s\r\n" + "Available protocols:\r\n", + string_get_cstr(protocol_name)); + + for(ProtocolId i = 0; i < LFRFIDProtocolMax; i++) { + printf( + "\t%s, %d bytes long\r\n", + protocol_dict_get_name(dict, i), + protocol_dict_get_data_size(dict, i)); + } + break; + } + + data_size = protocol_dict_get_data_size(dict, *protocol); + + // check data arg + if(!args_read_hex_bytes(data_text, data, data_size)) { + printf( + "%s data needs to be %d bytes long\r\n", + protocol_dict_get_name(dict, *protocol), + data_size); + break; + } + + // load data to protocol + protocol_dict_set_data(dict, *protocol, data, data_size); + + result = true; + } while(false); + + free(data); + string_clear(protocol_name); + string_clear(data_text); + return result; +} + +static void lfrfid_cli_write_callback(LFRFIDWorkerWriteResult result, void* ctx) { + furi_assert(ctx); + FuriEventFlag* events = ctx; + furi_event_flag_set(events, 1 << result); +} + +static void lfrfid_cli_write(Cli* cli, string_t args) { + ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); + ProtocolId protocol; + + if(!lfrfid_cli_parse_args(args, dict, &protocol)) { + protocol_dict_free(dict); + return; + } + + LFRFIDWorker* worker = lfrfid_worker_alloc(dict); + FuriEventFlag* event = furi_event_flag_alloc(); + + lfrfid_worker_start_thread(worker); + lfrfid_worker_write_start(worker, protocol, lfrfid_cli_write_callback, event); + + printf("Writing RFID...\r\nPress Ctrl+C to abort\r\n"); + const uint32_t available_flags = (1 << LFRFIDWorkerWriteOK) | + (1 << LFRFIDWorkerWriteProtocolCannotBeWritten) | + (1 << LFRFIDWorkerWriteFobCannotBeWritten); + + while(!cli_cmd_interrupt_received(cli)) { + uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100); + if(flags != FuriFlagErrorTimeout) { + if(FURI_BIT(flags, LFRFIDWorkerWriteOK)) { + printf("Written!\r\n"); + break; + } + + if(FURI_BIT(flags, LFRFIDWorkerWriteProtocolCannotBeWritten)) { + printf("This protocol cannot be written.\r\n"); + break; + } + + if(FURI_BIT(flags, LFRFIDWorkerWriteFobCannotBeWritten)) { + printf("Seems this fob cannot be written.\r\n"); + } + } + } + printf("Writing stopped\r\n"); + + lfrfid_worker_stop(worker); + lfrfid_worker_stop_thread(worker); + lfrfid_worker_free(worker); + protocol_dict_free(dict); + furi_event_flag_free(event); +} + +static void lfrfid_cli_emulate(Cli* cli, string_t args) { + ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); + ProtocolId protocol; + + if(!lfrfid_cli_parse_args(args, dict, &protocol)) { + protocol_dict_free(dict); + return; + } + + LFRFIDWorker* worker = lfrfid_worker_alloc(dict); + + lfrfid_worker_start_thread(worker); + lfrfid_worker_emulate_start(worker, protocol); + + printf("Emulating RFID...\r\nPress Ctrl+C to abort\r\n"); + while(!cli_cmd_interrupt_received(cli)) { + furi_delay_ms(100); + } + printf("Emulation stopped\r\n"); + + lfrfid_worker_stop(worker); + lfrfid_worker_stop_thread(worker); + lfrfid_worker_free(worker); + protocol_dict_free(dict); +} + +static void lfrfid_cli_raw_analyze(Cli* cli, string_t args) { + UNUSED(cli); + string_t filepath, info_string; + string_init(filepath); + string_init(info_string); + Storage* storage = furi_record_open(RECORD_STORAGE); + LFRFIDRawFile* file = lfrfid_raw_file_alloc(storage); + + do { + float frequency = 0; + float duty_cycle = 0; + + if(!args_read_probably_quoted_string_and_trim(args, filepath)) { + lfrfid_cli_print_usage(); + break; + } + + if(!lfrfid_raw_file_open_read(file, string_get_cstr(filepath))) { + printf("Failed to open file\r\n"); + break; + } + + if(!lfrfid_raw_file_read_header(file, &frequency, &duty_cycle)) { + printf("Invalid header\r\n"); + break; + } + + bool file_end = false; + uint32_t total_warns = 0; + uint32_t total_duration = 0; + uint32_t total_pulse = 0; + ProtocolId total_protocol = PROTOCOL_NO; + + ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); + protocol_dict_decoders_start(dict); + + while(!file_end) { + uint32_t pulse = 0; + uint32_t duration = 0; + if(lfrfid_raw_file_read_pair(file, &duration, &pulse, &file_end)) { + bool warn = false; + + if(pulse > duration || pulse <= 0 || duration <= 0) { + total_warns += 1; + warn = true; + } + + string_printf(info_string, "[%ld %ld]", pulse, duration); + printf("%-16s", string_get_cstr(info_string)); + string_printf(info_string, "[%ld %ld]", pulse, duration - pulse); + printf("%-16s", string_get_cstr(info_string)); + + if(warn) { + printf(" <<----"); + } + + if(total_protocol == PROTOCOL_NO) { + total_protocol = protocol_dict_decoders_feed(dict, true, pulse); + if(total_protocol == PROTOCOL_NO) { + total_protocol = + protocol_dict_decoders_feed(dict, false, duration - pulse); + } + + if(total_protocol != PROTOCOL_NO) { + printf(" ", protocol_dict_get_name(dict, total_protocol)); + } + } + + printf("\r\n"); + + total_pulse += pulse; + total_duration += duration; + + if(total_protocol != PROTOCOL_NO) { + break; + } + } else { + printf("Failed to read pair\r\n"); + break; + } + } + + printf(" Frequency: %f\r\n", (double)frequency); + printf(" Duty Cycle: %f\r\n", (double)duty_cycle); + printf(" Warns: %ld\r\n", total_warns); + printf(" Pulse sum: %ld\r\n", total_pulse); + printf("Duration sum: %ld\r\n", total_duration); + printf(" Average: %f\r\n", (double)((float)total_pulse / (float)total_duration)); + printf(" Protocol: "); + + if(total_protocol != PROTOCOL_NO) { + size_t data_size = protocol_dict_get_data_size(dict, total_protocol); + uint8_t* data = malloc(data_size); + protocol_dict_get_data(dict, total_protocol, data, data_size); + + printf("%s [", protocol_dict_get_name(dict, total_protocol)); + for(size_t i = 0; i < data_size; i++) { + printf("%02X", data[i]); + if(i < data_size - 1) { + printf(" "); + } + } + printf("]\r\n"); + + protocol_dict_render_data(dict, info_string, total_protocol); + printf("%s\r\n", string_get_cstr(info_string)); + + free(data); + } else { + printf("not found\r\n"); + } + + protocol_dict_free(dict); + } while(false); + + string_clear(filepath); + string_clear(info_string); + lfrfid_raw_file_free(file); + furi_record_close(RECORD_STORAGE); +} + +static void lfrfid_cli_raw_read_callback(LFRFIDWorkerReadRawResult result, void* context) { + furi_assert(context); + FuriEventFlag* event = context; + furi_event_flag_set(event, 1 << result); +} + +static void lfrfid_cli_raw_read(Cli* cli, string_t args) { + UNUSED(cli); + + string_t filepath, type_string; + string_init(filepath); + string_init(type_string); + LFRFIDWorkerReadType type = LFRFIDWorkerReadTypeAuto; + + do { + if(args_read_string_and_trim(args, type_string)) { + if(string_cmp_str(type_string, "normal") == 0 || + string_cmp_str(type_string, "ask") == 0) { + // ask + type = LFRFIDWorkerReadTypeASKOnly; + } else if( + string_cmp_str(type_string, "indala") == 0 || + string_cmp_str(type_string, "psk") == 0) { + // psk + type = LFRFIDWorkerReadTypePSKOnly; + } else { + lfrfid_cli_print_usage(); + break; + } + } + + if(!args_read_probably_quoted_string_and_trim(args, filepath)) { + lfrfid_cli_print_usage(); + break; + } + + ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); + LFRFIDWorker* worker = lfrfid_worker_alloc(dict); + FuriEventFlag* event = furi_event_flag_alloc(); + + lfrfid_worker_start_thread(worker); + + bool overrun = false; + + const uint32_t available_flags = (1 << LFRFIDWorkerReadRawFileError) | + (1 << LFRFIDWorkerReadRawOverrun); + + lfrfid_worker_read_raw_start( + worker, string_get_cstr(filepath), type, lfrfid_cli_raw_read_callback, event); + while(true) { + uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100); + + if(flags != FuriFlagErrorTimeout) { + if(FURI_BIT(flags, LFRFIDWorkerReadRawFileError)) { + printf("File is not RFID raw file\r\n"); + break; + } + + if(FURI_BIT(flags, LFRFIDWorkerReadRawOverrun)) { + if(!overrun) { + printf("Overrun\r\n"); + overrun = true; + } + } + } + + if(cli_cmd_interrupt_received(cli)) break; + } + + if(overrun) { + printf("An overrun occurred during read\r\n"); + } + + lfrfid_worker_stop(worker); + + lfrfid_worker_stop_thread(worker); + lfrfid_worker_free(worker); + protocol_dict_free(dict); + + furi_event_flag_free(event); + + } while(false); + + string_clear(filepath); + string_clear(type_string); +} + +static void lfrfid_cli_raw_emulate_callback(LFRFIDWorkerEmulateRawResult result, void* context) { + furi_assert(context); + FuriEventFlag* event = context; + furi_event_flag_set(event, 1 << result); +} + +static void lfrfid_cli_raw_emulate(Cli* cli, string_t args) { + UNUSED(cli); + + string_t filepath; + string_init(filepath); + Storage* storage = furi_record_open(RECORD_STORAGE); + + do { + if(!args_read_probably_quoted_string_and_trim(args, filepath)) { + lfrfid_cli_print_usage(); + break; + } + + if(!storage_file_exists(storage, string_get_cstr(filepath))) { + printf("File not found: \"%s\"\r\n", string_get_cstr(filepath)); + break; + } + + ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); + LFRFIDWorker* worker = lfrfid_worker_alloc(dict); + FuriEventFlag* event = furi_event_flag_alloc(); + + lfrfid_worker_start_thread(worker); + + bool overrun = false; + + const uint32_t available_flags = (1 << LFRFIDWorkerEmulateRawFileError) | + (1 << LFRFIDWorkerEmulateRawOverrun); + + lfrfid_worker_emulate_raw_start( + worker, string_get_cstr(filepath), lfrfid_cli_raw_emulate_callback, event); + while(true) { + uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100); + + if(flags != FuriFlagErrorTimeout) { + if(FURI_BIT(flags, LFRFIDWorkerEmulateRawFileError)) { + printf("File is not RFID raw file\r\n"); + break; + } + + if(FURI_BIT(flags, LFRFIDWorkerEmulateRawOverrun)) { + if(!overrun) { + printf("Overrun\r\n"); + overrun = true; + } + } + } + + if(cli_cmd_interrupt_received(cli)) break; + } + + if(overrun) { + printf("An overrun occurred during emulation\r\n"); + } + + lfrfid_worker_stop(worker); + + lfrfid_worker_stop_thread(worker); + lfrfid_worker_free(worker); + protocol_dict_free(dict); + + furi_event_flag_free(event); + + } while(false); + + furi_record_close(RECORD_STORAGE); + string_clear(filepath); +} + +static void lfrfid_cli(Cli* cli, string_t args, void* context) { + UNUSED(context); + string_t cmd; + string_init(cmd); + + if(!args_read_string_and_trim(args, cmd)) { + string_clear(cmd); + lfrfid_cli_print_usage(); + return; + } + + if(string_cmp_str(cmd, "read") == 0) { + lfrfid_cli_read(cli, args); + } else if(string_cmp_str(cmd, "write") == 0) { + lfrfid_cli_write(cli, args); + } else if(string_cmp_str(cmd, "emulate") == 0) { + lfrfid_cli_emulate(cli, args); + } else if(string_cmp_str(cmd, "raw_read") == 0) { + lfrfid_cli_raw_read(cli, args); + } else if(string_cmp_str(cmd, "raw_emulate") == 0) { + lfrfid_cli_raw_emulate(cli, args); + } else if(string_cmp_str(cmd, "raw_analyze") == 0) { + lfrfid_cli_raw_analyze(cli, args); + } else { + lfrfid_cli_print_usage(); + } + + string_clear(cmd); +} \ No newline at end of file diff --git a/applications/lfrfid/lfrfid_cli.cpp b/applications/lfrfid/lfrfid_cli.cpp deleted file mode 100644 index 732197e953..0000000000 --- a/applications/lfrfid/lfrfid_cli.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include -#include -#include -#include -#include - -#include "helpers/rfid_reader.h" -#include "helpers/rfid_timer_emulator.h" - -static void lfrfid_cli(Cli* cli, string_t args, void* context); - -// app cli function -extern "C" void lfrfid_on_system_start() { -#ifdef SRV_CLI - Cli* cli = static_cast(furi_record_open("cli")); - cli_add_command(cli, "rfid", CliCommandFlagDefault, lfrfid_cli, NULL); - furi_record_close("cli"); -#else - UNUSED(lfrfid_cli); -#endif -} - -void lfrfid_cli_print_usage() { - printf("Usage:\r\n"); - printf("rfid read \r\n"); - printf("rfid \r\n"); - printf("\t choose from:\r\n"); - printf("\tEM4100, EM-Marin (5 bytes key_data)\r\n"); - printf("\tH10301, HID26 (3 bytes key_data)\r\n"); - printf("\tI40134, Indala (3 bytes key_data)\r\n"); - printf("\tIoProxXSF, IoProx (4 bytes key_data)\r\n"); - printf("\t are hex-formatted\r\n"); -}; - -static bool lfrfid_cli_get_key_type(string_t data, LfrfidKeyType* type) { - bool result = false; - - if(string_cmp_str(data, "EM4100") == 0 || string_cmp_str(data, "EM-Marin") == 0) { - result = true; - *type = LfrfidKeyType::KeyEM4100; - } else if(string_cmp_str(data, "H10301") == 0 || string_cmp_str(data, "HID26") == 0) { - result = true; - *type = LfrfidKeyType::KeyH10301; - } else if(string_cmp_str(data, "I40134") == 0 || string_cmp_str(data, "Indala") == 0) { - result = true; - *type = LfrfidKeyType::KeyI40134; - } else if(string_cmp_str(data, "IoProxXSF") == 0 || string_cmp_str(data, "IoProx") == 0) { - result = true; - *type = LfrfidKeyType::KeyIoProxXSF; - } - - return result; -} - -static void lfrfid_cli_read(Cli* cli, string_t args) { - RfidReader reader; - string_t type_string; - string_init(type_string); - bool simple_mode = true; - LfrfidKeyType type; - RfidReader::Type reader_type = RfidReader::Type::Normal; - static const uint8_t data_size = LFRFID_KEY_SIZE; - uint8_t data[data_size] = {0}; - - if(args_read_string_and_trim(args, type_string)) { - simple_mode = false; - - if(string_cmp_str(type_string, "normal") == 0) { - reader_type = RfidReader::Type::Normal; - } else if(string_cmp_str(type_string, "indala") == 0) { - reader_type = RfidReader::Type::Indala; - } else { - lfrfid_cli_print_usage(); - string_clear(type_string); - return; - } - } - - if(simple_mode) { - reader.start(); - } else { - reader.start_forced(reader_type); - } - - printf("Reading RFID...\r\nPress Ctrl+C to abort\r\n"); - while(!cli_cmd_interrupt_received(cli)) { - if(reader.read(&type, data, data_size, simple_mode)) { - printf("%s", lfrfid_key_get_type_string(type)); - printf(" "); - - for(uint8_t i = 0; i < lfrfid_key_get_type_data_count(type); i++) { - printf("%02X", data[i]); - } - printf("\r\n"); - break; - } - furi_delay_ms(100); - } - - printf("Reading stopped\r\n"); - reader.stop(); - - string_clear(type_string); -} - -static void lfrfid_cli_write(Cli* cli, string_t args) { - UNUSED(cli); - UNUSED(args); - // TODO implement rfid write - printf("Not Implemented :(\r\n"); -} - -static void lfrfid_cli_emulate(Cli* cli, string_t args) { - string_t data; - string_init(data); - RfidTimerEmulator emulator; - - static const uint8_t data_size = LFRFID_KEY_SIZE; - uint8_t key_data[data_size] = {0}; - uint8_t key_data_size = 0; - LfrfidKeyType type; - - if(!args_read_string_and_trim(args, data)) { - lfrfid_cli_print_usage(); - string_clear(data); - return; - } - - if(!lfrfid_cli_get_key_type(data, &type)) { - lfrfid_cli_print_usage(); - string_clear(data); - return; - } - - key_data_size = lfrfid_key_get_type_data_count(type); - - if(!args_read_hex_bytes(args, key_data, key_data_size)) { - lfrfid_cli_print_usage(); - string_clear(data); - return; - } - - emulator.start(type, key_data, key_data_size); - - printf("Emulating RFID...\r\nPress Ctrl+C to abort\r\n"); - while(!cli_cmd_interrupt_received(cli)) { - furi_delay_ms(100); - } - printf("Emulation stopped\r\n"); - emulator.stop(); - - string_clear(data); -} - -static void lfrfid_cli(Cli* cli, string_t args, void* context) { - UNUSED(context); - string_t cmd; - string_init(cmd); - - if(!args_read_string_and_trim(args, cmd)) { - string_clear(cmd); - lfrfid_cli_print_usage(); - return; - } - - if(string_cmp_str(cmd, "read") == 0) { - lfrfid_cli_read(cli, args); - } else if(string_cmp_str(cmd, "write") == 0) { - lfrfid_cli_write(cli, args); - } else if(string_cmp_str(cmd, "emulate") == 0) { - lfrfid_cli_emulate(cli, args); - } else { - lfrfid_cli_print_usage(); - } - - string_clear(cmd); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp b/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp index 236ca8c29f..58ff4dcdfc 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp @@ -5,7 +5,6 @@ void LfRfidAppSceneDeleteConfirm::on_enter(LfRfidApp* app, bool /* need_restore */) { string_init(string_data); - string_init(string_decrypted); string_init(string_header); auto container = app->view_controller.get(); @@ -21,49 +20,26 @@ void LfRfidAppSceneDeleteConfirm::on_enter(LfRfidApp* app, bool /* need_restore auto line_1 = container->add(); auto line_2 = container->add(); auto line_3 = container->add(); - auto line_4 = container->add(); - RfidKey& key = app->worker.key; - const uint8_t* data = key.get_data(); - - for(uint8_t i = 0; i < key.get_type_data_count(); i++) { + size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); + uint8_t* data = (uint8_t*)malloc(size); + protocol_dict_get_data(app->dict, app->protocol_id, data, size); + for(uint8_t i = 0; i < MIN(size, (size_t)8); i++) { if(i != 0) { string_cat_printf(string_data, " "); } + string_cat_printf(string_data, "%02X", data[i]); } + free(data); - string_printf(string_header, "Delete %s?", key.get_name()); + string_printf(string_header, "Delete %s?", string_get_cstr(app->file_name)); line_1->set_text( - string_get_cstr(string_header), 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary); + string_get_cstr(string_header), 64, 0, 128 - 2, AlignCenter, AlignTop, FontPrimary); line_2->set_text( - string_get_cstr(string_data), 64, 29, 0, AlignCenter, AlignBottom, FontSecondary); - - switch(key.get_type()) { - case LfrfidKeyType::KeyEM4100: - string_printf( - string_decrypted, "%03u,%05u", data[2], (uint16_t)((data[3] << 8) | (data[4]))); - - break; - case LfrfidKeyType::KeyH10301: - case LfrfidKeyType::KeyI40134: - string_printf( - string_decrypted, "FC: %u ID: %u", data[0], (uint16_t)((data[1] << 8) | (data[2]))); - break; - case LfrfidKeyType::KeyIoProxXSF: - string_printf( - string_decrypted, - "FC: %u VC: %u ID: %u", - data[0], - data[1], - (uint16_t)((data[2] << 8) | (data[3]))); - break; - } + string_get_cstr(string_data), 64, 19, 0, AlignCenter, AlignTop, FontSecondary); line_3->set_text( - string_get_cstr(string_decrypted), 64, 39, 0, AlignCenter, AlignBottom, FontSecondary); - - line_4->set_text( - lfrfid_key_get_type_string(key.get_type()), + protocol_dict_get_name(app->dict, app->protocol_id), 64, 49, 0, @@ -78,7 +54,7 @@ bool LfRfidAppSceneDeleteConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* eve bool consumed = false; if(event->type == LfRfidApp::EventType::Next) { - app->delete_key(&app->worker.key); + app->delete_key(); app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::DeleteSuccess); consumed = true; } else if(event->type == LfRfidApp::EventType::Stay) { @@ -94,7 +70,6 @@ bool LfRfidAppSceneDeleteConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* eve void LfRfidAppSceneDeleteConfirm::on_exit(LfRfidApp* app) { app->view_controller.get()->clean(); string_clear(string_data); - string_clear(string_decrypted); string_clear(string_header); } diff --git a/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.h b/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.h index e30764f023..f9daed5432 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.h +++ b/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.h @@ -13,5 +13,4 @@ class LfRfidAppSceneDeleteConfirm : public GenericScene { string_t string_header; string_t string_data; - string_t string_decrypted; }; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_emulate.cpp b/applications/lfrfid/scene/lfrfid_app_scene_emulate.cpp index cad4f17c7e..02cb011d13 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_emulate.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_emulate.cpp @@ -3,28 +3,21 @@ #include void LfRfidAppSceneEmulate::on_enter(LfRfidApp* app, bool /* need_restore */) { - string_init(data_string); - DOLPHIN_DEED(DolphinDeedRfidEmulate); - const uint8_t* data = app->worker.key.get_data(); - - for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) { - string_cat_printf(data_string, "%02X", data[i]); - } - auto popup = app->view_controller.get(); popup->set_header("Emulating", 89, 30, AlignCenter, AlignTop); - if(strlen(app->worker.key.get_name())) { - popup->set_text(app->worker.key.get_name(), 89, 43, AlignCenter, AlignTop); + if(string_size(app->file_name)) { + popup->set_text(string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); } else { - popup->set_text(string_get_cstr(data_string), 89, 43, AlignCenter, AlignTop); + popup->set_text( + protocol_dict_get_name(app->dict, app->protocol_id), 89, 43, AlignCenter, AlignTop); } popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61); app->view_controller.switch_to(); - app->worker.start_emulate(); - + lfrfid_worker_start_thread(app->lfworker); + lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id); notification_message(app->notification, &sequence_blink_start_magenta); } @@ -37,7 +30,7 @@ bool LfRfidAppSceneEmulate::on_event(LfRfidApp* app, LfRfidApp::Event* event) { void LfRfidAppSceneEmulate::on_exit(LfRfidApp* app) { app->view_controller.get()->clean(); - app->worker.stop_emulate(); - string_clear(data_string); + lfrfid_worker_stop(app->lfworker); + lfrfid_worker_stop_thread(app->lfworker); notification_message(app->notification, &sequence_blink_stop); } diff --git a/applications/lfrfid/scene/lfrfid_app_scene_emulate.h b/applications/lfrfid/scene/lfrfid_app_scene_emulate.h index 937e49af9b..13d2b857dc 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_emulate.h +++ b/applications/lfrfid/scene/lfrfid_app_scene_emulate.h @@ -6,7 +6,4 @@ class LfRfidAppSceneEmulate : public GenericScene { void on_enter(LfRfidApp* app, bool need_restore) final; bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; void on_exit(LfRfidApp* app) final; - -private: - string_t data_string; }; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp b/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp new file mode 100644 index 0000000000..ea4f03dbb4 --- /dev/null +++ b/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp @@ -0,0 +1,63 @@ +#include "lfrfid_app_scene_extra_actions.h" + +typedef enum { + SubmenuASK, + SubmenuPSK, + SubmenuRAW, +} SubmenuIndex; + +void LfRfidAppSceneExtraActions::on_enter(LfRfidApp* app, bool need_restore) { + auto submenu = app->view_controller.get(); + + submenu->add_item("Read ASK (Animal, Ordinary Card)", SubmenuASK, submenu_callback, app); + submenu->add_item("Read PSK (Indala)", SubmenuPSK, submenu_callback, app); + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + submenu->add_item("Read RAW RFID data", SubmenuRAW, submenu_callback, app); + } + + if(need_restore) { + submenu->set_selected_item(submenu_item_selected); + } + + app->view_controller.switch_to(); +} + +bool LfRfidAppSceneExtraActions::on_event(LfRfidApp* app, LfRfidApp::Event* event) { + bool consumed = false; + + if(event->type == LfRfidApp::EventType::MenuSelected) { + submenu_item_selected = event->payload.signed_int; + switch(event->payload.signed_int) { + case SubmenuASK: + app->read_type = LFRFIDWorkerReadTypeASKOnly; + app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read); + break; + case SubmenuPSK: + app->read_type = LFRFIDWorkerReadTypePSKOnly; + app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read); + break; + case SubmenuRAW: + app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::RawName); + break; + } + + consumed = true; + } + + return consumed; +} + +void LfRfidAppSceneExtraActions::on_exit(LfRfidApp* app) { + app->view_controller.get()->clean(); +} + +void LfRfidAppSceneExtraActions::submenu_callback(void* context, uint32_t index) { + LfRfidApp* app = static_cast(context); + LfRfidApp::Event event; + + event.type = LfRfidApp::EventType::MenuSelected; + event.payload.signed_int = index; + + app->view_controller.send_event(&event); +} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.h b/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.h new file mode 100644 index 0000000000..dcd746146c --- /dev/null +++ b/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.h @@ -0,0 +1,13 @@ +#pragma once +#include "../lfrfid_app.h" + +class LfRfidAppSceneExtraActions : public GenericScene { +public: + void on_enter(LfRfidApp* app, bool need_restore) final; + bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; + void on_exit(LfRfidApp* app) final; + +private: + static void submenu_callback(void* context, uint32_t index); + uint32_t submenu_item_selected = 0; +}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_raw_info.cpp b/applications/lfrfid/scene/lfrfid_app_scene_raw_info.cpp new file mode 100644 index 0000000000..ce3634b2ac --- /dev/null +++ b/applications/lfrfid/scene/lfrfid_app_scene_raw_info.cpp @@ -0,0 +1,77 @@ +#include "lfrfid_app_scene_raw_info.h" +#include "../view/elements/button_element.h" +#include "../view/elements/icon_element.h" +#include "../view/elements/string_element.h" + +static void ok_callback(void* context) { + LfRfidApp* app = static_cast(context); + LfRfidApp::Event event; + event.type = LfRfidApp::EventType::Next; + app->view_controller.send_event(&event); +} + +static void back_callback(void* context) { + LfRfidApp* app = static_cast(context); + LfRfidApp::Event event; + event.type = LfRfidApp::EventType::Back; + app->view_controller.send_event(&event); +} + +void LfRfidAppSceneRawInfo::on_enter(LfRfidApp* app, bool /* need_restore */) { + string_init(string_info); + + auto container = app->view_controller.get(); + + bool sd_exist = storage_sd_status(app->storage) == FSE_OK; + if(!sd_exist) { + auto icon = container->add(); + icon->set_icon(0, 0, &I_SDQuestion_35x43); + auto line = container->add(); + line->set_text( + "No SD card found.\nThis function will not\nwork without\nSD card.", + 81, + 4, + 0, + AlignCenter, + AlignTop, + FontSecondary); + + auto button = container->add(); + button->set_type(ButtonElement::Type::Left, "Back"); + button->set_callback(app, back_callback); + } else { + string_printf( + string_info, + "RAW RFID data reader\r\n" + "1) Put the Flipper on your card\r\n" + "2) Press OK\r\n" + "3) Wait until data is read"); + + auto line = container->add(); + line->set_text(string_get_cstr(string_info), 0, 1, 0, AlignLeft, AlignTop, FontSecondary); + + auto button = container->add(); + button->set_type(ButtonElement::Type::Center, "OK"); + button->set_callback(app, ok_callback); + } + + app->view_controller.switch_to(); +} + +bool LfRfidAppSceneRawInfo::on_event(LfRfidApp* app, LfRfidApp::Event* event) { + bool consumed = false; + if(event->type == LfRfidApp::EventType::Next) { + app->scene_controller.switch_to_scene({LfRfidApp::SceneType::RawRead}); + consumed = true; + } else if(event->type == LfRfidApp::EventType::Back) { + app->scene_controller.search_and_switch_to_previous_scene( + {LfRfidApp::SceneType::ExtraActions}); + consumed = true; + } + return consumed; +} + +void LfRfidAppSceneRawInfo::on_exit(LfRfidApp* app) { + app->view_controller.get()->clean(); + string_clear(string_info); +} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_raw_info.h b/applications/lfrfid/scene/lfrfid_app_scene_raw_info.h new file mode 100644 index 0000000000..eecca14368 --- /dev/null +++ b/applications/lfrfid/scene/lfrfid_app_scene_raw_info.h @@ -0,0 +1,12 @@ +#pragma once +#include "../lfrfid_app.h" + +class LfRfidAppSceneRawInfo : public GenericScene { +public: + void on_enter(LfRfidApp* app, bool need_restore) final; + bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; + void on_exit(LfRfidApp* app) final; + +private: + string_t string_info; +}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_raw_name.cpp b/applications/lfrfid/scene/lfrfid_app_scene_raw_name.cpp new file mode 100644 index 0000000000..0ad346198e --- /dev/null +++ b/applications/lfrfid/scene/lfrfid_app_scene_raw_name.cpp @@ -0,0 +1,46 @@ + +#include "lfrfid_app_scene_raw_name.h" +#include "m-string.h" +#include +#include + +void LfRfidAppSceneRawName::on_enter(LfRfidApp* app, bool /* need_restore */) { + const char* key_name = string_get_cstr(app->raw_file_name); + + bool key_name_empty = (string_size(app->raw_file_name) == 0); + if(key_name_empty) { + app->text_store.set("RfidRecord"); + } else { + app->text_store.set("%s", key_name); + } + + auto text_input = app->view_controller.get(); + text_input->set_header_text("Name the raw file"); + + text_input->set_result_callback( + save_callback, app, app->text_store.text, LFRFID_KEY_NAME_SIZE, key_name_empty); + + app->view_controller.switch_to(); +} + +bool LfRfidAppSceneRawName::on_event(LfRfidApp* app, LfRfidApp::Event* event) { + bool consumed = false; + + if(event->type == LfRfidApp::EventType::Next) { + string_set_str(app->raw_file_name, app->text_store.text); + app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::RawInfo); + } + + return consumed; +} + +void LfRfidAppSceneRawName::on_exit(LfRfidApp* app) { + app->view_controller.get()->clean(); +} + +void LfRfidAppSceneRawName::save_callback(void* context) { + LfRfidApp* app = static_cast(context); + LfRfidApp::Event event; + event.type = LfRfidApp::EventType::Next; + app->view_controller.send_event(&event); +} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_raw_name.h b/applications/lfrfid/scene/lfrfid_app_scene_raw_name.h new file mode 100644 index 0000000000..225d135e5e --- /dev/null +++ b/applications/lfrfid/scene/lfrfid_app_scene_raw_name.h @@ -0,0 +1,12 @@ +#pragma once +#include "../lfrfid_app.h" + +class LfRfidAppSceneRawName : public GenericScene { +public: + void on_enter(LfRfidApp* app, bool need_restore) final; + bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; + void on_exit(LfRfidApp* app) final; + +private: + static void save_callback(void* context); +}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_raw_read.cpp b/applications/lfrfid/scene/lfrfid_app_scene_raw_read.cpp new file mode 100644 index 0000000000..0d04e6bc75 --- /dev/null +++ b/applications/lfrfid/scene/lfrfid_app_scene_raw_read.cpp @@ -0,0 +1,107 @@ +#include "lfrfid_app_scene_raw_read.h" +#include + +#define RAW_READ_TIME 5000 + +static void lfrfid_read_callback(LFRFIDWorkerReadRawResult result, void* ctx) { + LfRfidApp* app = static_cast(ctx); + LfRfidApp::Event event; + + switch(result) { + case LFRFIDWorkerReadRawFileError: + event.type = LfRfidApp::EventType::ReadEventError; + break; + case LFRFIDWorkerReadRawOverrun: + event.type = LfRfidApp::EventType::ReadEventOverrun; + break; + } + + app->view_controller.send_event(&event); +} + +static void timer_callback(void* ctx) { + LfRfidApp* app = static_cast(ctx); + LfRfidApp::Event event; + event.type = LfRfidApp::EventType::ReadEventDone; + app->view_controller.send_event(&event); +} + +void LfRfidAppSceneRawRead::on_enter(LfRfidApp* app, bool /* need_restore */) { + string_init(string_file_name); + auto popup = app->view_controller.get(); + popup->set_icon(0, 3, &I_RFIDDolphinReceive_97x61); + app->view_controller.switch_to(); + lfrfid_worker_start_thread(app->lfworker); + app->make_app_folder(); + + timer = furi_timer_alloc(timer_callback, FuriTimerTypeOnce, app); + furi_timer_start(timer, RAW_READ_TIME); + string_printf( + string_file_name, "%s/%s.ask.raw", app->app_sd_folder, string_get_cstr(app->raw_file_name)); + popup->set_header("Reading\nRAW RFID\nASK", 89, 30, AlignCenter, AlignTop); + lfrfid_worker_read_raw_start( + app->lfworker, + string_get_cstr(string_file_name), + LFRFIDWorkerReadTypeASKOnly, + lfrfid_read_callback, + app); + + notification_message(app->notification, &sequence_blink_start_cyan); + + is_psk = false; + error = false; +} + +bool LfRfidAppSceneRawRead::on_event(LfRfidApp* app, LfRfidApp::Event* event) { + UNUSED(app); + bool consumed = true; + auto popup = app->view_controller.get(); + + switch(event->type) { + case LfRfidApp::EventType::ReadEventError: + error = true; + popup->set_header("Reading\nRAW RFID\nFile error", 89, 30, AlignCenter, AlignTop); + notification_message(app->notification, &sequence_blink_start_red); + furi_timer_stop(timer); + break; + case LfRfidApp::EventType::ReadEventDone: + if(!error) { + if(is_psk) { + notification_message(app->notification, &sequence_success); + app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::RawSuccess); + } else { + popup->set_header("Reading\nRAW RFID\nPSK", 89, 30, AlignCenter, AlignTop); + notification_message(app->notification, &sequence_blink_start_yellow); + lfrfid_worker_stop(app->lfworker); + string_printf( + string_file_name, + "%s/%s.psk.raw", + app->app_sd_folder, + string_get_cstr(app->raw_file_name)); + lfrfid_worker_read_raw_start( + app->lfworker, + string_get_cstr(string_file_name), + LFRFIDWorkerReadTypePSKOnly, + lfrfid_read_callback, + app); + furi_timer_start(timer, RAW_READ_TIME); + is_psk = true; + } + } + break; + default: + consumed = false; + break; + } + + return consumed; +} + +void LfRfidAppSceneRawRead::on_exit(LfRfidApp* app) { + notification_message(app->notification, &sequence_blink_stop); + app->view_controller.get()->clean(); + lfrfid_worker_stop(app->lfworker); + lfrfid_worker_stop_thread(app->lfworker); + furi_timer_free(timer); + string_clear(string_file_name); +} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_raw_read.h b/applications/lfrfid/scene/lfrfid_app_scene_raw_read.h new file mode 100644 index 0000000000..09ef746390 --- /dev/null +++ b/applications/lfrfid/scene/lfrfid_app_scene_raw_read.h @@ -0,0 +1,15 @@ +#pragma once +#include "../lfrfid_app.h" + +class LfRfidAppSceneRawRead : public GenericScene { +public: + void on_enter(LfRfidApp* app, bool need_restore) final; + bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; + void on_exit(LfRfidApp* app) final; + +private: + string_t string_file_name; + FuriTimer* timer; + bool is_psk; + bool error; +}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_raw_success.cpp b/applications/lfrfid/scene/lfrfid_app_scene_raw_success.cpp new file mode 100644 index 0000000000..227ab580a8 --- /dev/null +++ b/applications/lfrfid/scene/lfrfid_app_scene_raw_success.cpp @@ -0,0 +1,45 @@ +#include "lfrfid_app_scene_raw_success.h" +#include "../view/elements/button_element.h" +#include "../view/elements/icon_element.h" +#include "../view/elements/string_element.h" + +void LfRfidAppSceneRawSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) { + string_init(string_info); + + string_printf(string_info, "RAW RFID read success!\r\n"); + string_cat_printf(string_info, "Now you can analyze files\r\n"); + string_cat_printf(string_info, "Or send them to developers"); + + auto container = app->view_controller.get(); + + auto line = container->add(); + line->set_text(string_get_cstr(string_info), 0, 1, 0, AlignLeft, AlignTop, FontSecondary); + + auto button = container->add(); + button->set_type(ButtonElement::Type::Center, "OK"); + button->set_callback(app, LfRfidAppSceneRawSuccess::ok_callback); + + app->view_controller.switch_to(); +} + +bool LfRfidAppSceneRawSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) { + bool consumed = false; + if(event->type == LfRfidApp::EventType::Next) { + app->scene_controller.search_and_switch_to_previous_scene( + {LfRfidApp::SceneType::ExtraActions}); + consumed = true; + } + return consumed; +} + +void LfRfidAppSceneRawSuccess::on_exit(LfRfidApp* app) { + app->view_controller.get()->clean(); + string_clear(string_info); +} + +void LfRfidAppSceneRawSuccess::ok_callback(void* context) { + LfRfidApp* app = static_cast(context); + LfRfidApp::Event event; + event.type = LfRfidApp::EventType::Next; + app->view_controller.send_event(&event); +} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_raw_success.h b/applications/lfrfid/scene/lfrfid_app_scene_raw_success.h new file mode 100644 index 0000000000..0a0b0116b5 --- /dev/null +++ b/applications/lfrfid/scene/lfrfid_app_scene_raw_success.h @@ -0,0 +1,13 @@ +#pragma once +#include "../lfrfid_app.h" + +class LfRfidAppSceneRawSuccess : public GenericScene { +public: + void on_enter(LfRfidApp* app, bool need_restore) final; + bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; + void on_exit(LfRfidApp* app) final; + +private: + string_t string_info; + static void ok_callback(void* context); +}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_read.cpp b/applications/lfrfid/scene/lfrfid_app_scene_read.cpp index 67279a163e..120eb1a072 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_read.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_read.cpp @@ -1,40 +1,100 @@ #include "lfrfid_app_scene_read.h" #include +static void lfrfid_read_callback(LFRFIDWorkerReadResult result, ProtocolId protocol, void* ctx) { + LfRfidApp* app = static_cast(ctx); + LfRfidApp::Event event; + + switch(result) { + case LFRFIDWorkerReadSenseStart: + event.type = LfRfidApp::EventType::ReadEventSenseStart; + break; + case LFRFIDWorkerReadSenseEnd: + event.type = LfRfidApp::EventType::ReadEventSenseEnd; + break; + case LFRFIDWorkerReadSenseCardStart: + event.type = LfRfidApp::EventType::ReadEventSenseCardStart; + break; + case LFRFIDWorkerReadSenseCardEnd: + event.type = LfRfidApp::EventType::ReadEventSenseCardEnd; + break; + case LFRFIDWorkerReadDone: + event.type = LfRfidApp::EventType::ReadEventDone; + break; + case LFRFIDWorkerReadStartASK: + event.type = LfRfidApp::EventType::ReadEventStartASK; + break; + case LFRFIDWorkerReadStartPSK: + event.type = LfRfidApp::EventType::ReadEventStartPSK; + break; + } + + event.payload.signed_int = protocol; + + app->view_controller.send_event(&event); +} + void LfRfidAppSceneRead::on_enter(LfRfidApp* app, bool /* need_restore */) { auto popup = app->view_controller.get(); DOLPHIN_DEED(DolphinDeedRfidRead); - popup->set_header("Reading\nLF RFID", 89, 34, AlignCenter, AlignTop); + if(app->read_type == LFRFIDWorkerReadTypePSKOnly) { + popup->set_header("Reading\nLF RFID\nPSK", 89, 30, AlignCenter, AlignTop); + } else { + popup->set_header("Reading\nLF RFID\nASK", 89, 30, AlignCenter, AlignTop); + } + popup->set_icon(0, 3, &I_RFIDDolphinReceive_97x61); app->view_controller.switch_to(); - app->worker.start_read(); + lfrfid_worker_start_thread(app->lfworker); + lfrfid_worker_read_start(app->lfworker, app->read_type, lfrfid_read_callback, app); + + notification_message(app->notification, &sequence_blink_start_cyan); } bool LfRfidAppSceneRead::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Tick) { - if(app->worker.read()) { - DOLPHIN_DEED(DolphinDeedRfidReadSuccess); - notification_message(app->notification, &sequence_success); - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadSuccess); - } else { - if(app->worker.any_read()) { - notification_message(app->notification, &sequence_blink_yellow_10); - } else if(app->worker.detect()) { - notification_message(app->notification, &sequence_blink_yellow_10); - } else { - notification_message(app->notification, &sequence_blink_cyan_10); - } - } + bool consumed = true; + auto popup = app->view_controller.get(); + + switch(event->type) { + case LfRfidApp::EventType::ReadEventSenseStart: + notification_message(app->notification, &sequence_blink_stop); + notification_message(app->notification, &sequence_blink_start_yellow); + break; + case LfRfidApp::EventType::ReadEventSenseCardStart: + notification_message(app->notification, &sequence_blink_stop); + notification_message(app->notification, &sequence_blink_start_green); + break; + case LfRfidApp::EventType::ReadEventSenseEnd: + case LfRfidApp::EventType::ReadEventSenseCardEnd: + notification_message(app->notification, &sequence_blink_stop); + notification_message(app->notification, &sequence_blink_start_cyan); + break; + case LfRfidApp::EventType::ReadEventDone: + app->protocol_id = event->payload.signed_int; + DOLPHIN_DEED(DolphinDeedRfidReadSuccess); + notification_message(app->notification, &sequence_success); + string_reset(app->file_name); + app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadSuccess); + break; + case LfRfidApp::EventType::ReadEventStartPSK: + popup->set_header("Reading\nLF RFID\nPSK", 89, 30, AlignCenter, AlignTop); + break; + case LfRfidApp::EventType::ReadEventStartASK: + popup->set_header("Reading\nLF RFID\nASK", 89, 30, AlignCenter, AlignTop); + break; + default: + consumed = false; + break; } return consumed; } void LfRfidAppSceneRead::on_exit(LfRfidApp* app) { + notification_message(app->notification, &sequence_blink_stop); app->view_controller.get()->clean(); - app->worker.stop_read(); + lfrfid_worker_stop(app->lfworker); + lfrfid_worker_stop_thread(app->lfworker); } diff --git a/applications/lfrfid/scene/lfrfid_app_scene_read_menu.cpp b/applications/lfrfid/scene/lfrfid_app_scene_read_menu.cpp index 76c9123065..aa3b3f1fba 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_read_menu.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_read_menu.cpp @@ -24,8 +24,8 @@ bool LfRfidAppSceneReadKeyMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event bool consumed = false; if(event->type == LfRfidApp::EventType::MenuSelected) { - submenu_item_selected = event->payload.menu_index; - switch(event->payload.menu_index) { + submenu_item_selected = event->payload.signed_int; + switch(event->payload.signed_int) { case SubmenuWrite: app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Write); break; @@ -54,7 +54,7 @@ void LfRfidAppSceneReadKeyMenu::submenu_callback(void* context, uint32_t index) LfRfidApp::Event event; event.type = LfRfidApp::EventType::MenuSelected; - event.payload.menu_index = index; + event.payload.signed_int = index; app->view_controller.send_event(&event); } diff --git a/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp b/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp index 010cac2cfa..277b43a3e5 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp @@ -4,10 +4,37 @@ #include "../view/elements/string_element.h" void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) { - string_init(string[0]); - string_init(string[1]); - string_init(string[2]); - string_init(string[3]); + string_init(string_info); + string_init(string_header); + + string_init_printf( + string_header, + "%s[%s]", + protocol_dict_get_name(app->dict, app->protocol_id), + protocol_dict_get_manufacturer(app->dict, app->protocol_id)); + + size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); + uint8_t* data = (uint8_t*)malloc(size); + protocol_dict_get_data(app->dict, app->protocol_id, data, size); + for(uint8_t i = 0; i < size; i++) { + if(i != 0) { + string_cat_printf(string_info, " "); + } + + if(i >= 9) { + string_cat_printf(string_info, "..."); + break; + } else { + string_cat_printf(string_info, "%02X", data[i]); + } + } + free(data); + + string_t render_data; + string_init(render_data); + protocol_dict_render_brief_data(app->dict, render_data, app->protocol_id); + string_cat_printf(string_info, "\r\n%s", string_get_cstr(render_data)); + string_clear(render_data); auto container = app->view_controller.get(); @@ -19,90 +46,11 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool /* need_restore */ button->set_type(ButtonElement::Type::Right, "More"); button->set_callback(app, LfRfidAppSceneReadSuccess::more_callback); - auto icon = container->add(); - icon->set_icon(3, 12, &I_RFIDBigChip_37x36); - auto header = container->add(); - header->set_text(app->worker.key.get_type_text(), 89, 3, 0, AlignCenter); - - auto line_1_text = container->add(); - auto line_2l_text = container->add(); - auto line_2r_text = container->add(); - auto line_3_text = container->add(); - - auto line_1_value = container->add(); - auto line_2l_value = container->add(); - auto line_2r_value = container->add(); - auto line_3_value = container->add(); - - const uint8_t* data = app->worker.key.get_data(); - - switch(app->worker.key.get_type()) { - case LfrfidKeyType::KeyEM4100: - line_1_text->set_text("HEX:", 65, 23, 0, AlignRight, AlignBottom, FontSecondary); - line_2l_text->set_text("Mod:", 65, 35, 0, AlignRight, AlignBottom, FontSecondary); - line_3_text->set_text("ID:", 65, 47, 0, AlignRight, AlignBottom, FontSecondary); + header->set_text(string_get_cstr(string_header), 0, 2, 0, AlignLeft, AlignTop, FontPrimary); - for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) { - string_cat_printf(string[0], "%02X", data[i]); - } - - string_printf(string[1], "Manchester"); - string_printf(string[2], "%03u,%05u", data[2], (uint16_t)((data[3] << 8) | (data[4]))); - - line_1_value->set_text( - string_get_cstr(string[0]), 68, 23, 0, AlignLeft, AlignBottom, FontSecondary); - line_2l_value->set_text( - string_get_cstr(string[1]), 68, 35, 0, AlignLeft, AlignBottom, FontSecondary); - line_3_value->set_text( - string_get_cstr(string[2]), 68, 47, 0, AlignLeft, AlignBottom, FontSecondary); - break; - case LfrfidKeyType::KeyH10301: - case LfrfidKeyType::KeyI40134: - line_1_text->set_text("HEX:", 65, 23, 0, AlignRight, AlignBottom, FontSecondary); - line_2l_text->set_text("FC:", 65, 35, 0, AlignRight, AlignBottom, FontSecondary); - line_3_text->set_text("Card:", 65, 47, 0, AlignRight, AlignBottom, FontSecondary); - - for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) { - string_cat_printf(string[0], "%02X", data[i]); - } - - string_printf(string[1], "%u", data[0]); - string_printf(string[2], "%u", (uint16_t)((data[1] << 8) | (data[2]))); - - line_1_value->set_text( - string_get_cstr(string[0]), 68, 23, 0, AlignLeft, AlignBottom, FontSecondary); - line_2l_value->set_text( - string_get_cstr(string[1]), 68, 35, 0, AlignLeft, AlignBottom, FontSecondary); - line_3_value->set_text( - string_get_cstr(string[2]), 68, 47, 0, AlignLeft, AlignBottom, FontSecondary); - break; - - case LfrfidKeyType::KeyIoProxXSF: - line_1_text->set_text("HEX:", 65, 23, 0, AlignRight, AlignBottom, FontSecondary); - line_2l_text->set_text("FC:", 65, 35, 0, AlignRight, AlignBottom, FontSecondary); - line_2r_text->set_text("VС:", 95, 35, 0, AlignRight, AlignBottom, FontSecondary); - line_3_text->set_text("Card:", 65, 47, 0, AlignRight, AlignBottom, FontSecondary); - - for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) { - string_cat_printf(string[0], "%02X", data[i]); - } - - string_printf(string[1], "%u", data[0]); - string_printf(string[2], "%u", (uint16_t)((data[2] << 8) | (data[3]))); - string_printf(string[3], "%u", data[1]); - - line_1_value->set_text( - string_get_cstr(string[0]), 68, 23, 0, AlignLeft, AlignBottom, FontSecondary); - line_2l_value->set_text( - string_get_cstr(string[1]), 68, 35, 0, AlignLeft, AlignBottom, FontSecondary); - line_2r_value->set_text( - string_get_cstr(string[3]), 98, 35, 0, AlignLeft, AlignBottom, FontSecondary); - line_3_value->set_text( - string_get_cstr(string[2]), 68, 47, 0, AlignLeft, AlignBottom, FontSecondary); - - break; - } + auto text = container->add(); + text->set_text(string_get_cstr(string_info), 0, 16, 0, AlignLeft, AlignTop, FontSecondary); app->view_controller.switch_to(); @@ -129,9 +77,8 @@ bool LfRfidAppSceneReadSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event void LfRfidAppSceneReadSuccess::on_exit(LfRfidApp* app) { notification_message_block(app->notification, &sequence_reset_green); app->view_controller.get()->clean(); - string_clear(string[0]); - string_clear(string[1]); - string_clear(string[2]); + string_clear(string_info); + string_clear(string_header); } void LfRfidAppSceneReadSuccess::back_callback(void* context) { diff --git a/applications/lfrfid/scene/lfrfid_app_scene_read_success.h b/applications/lfrfid/scene/lfrfid_app_scene_read_success.h index ac0e3c1b5c..6d90f63109 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_read_success.h +++ b/applications/lfrfid/scene/lfrfid_app_scene_read_success.h @@ -11,5 +11,6 @@ class LfRfidAppSceneReadSuccess : public GenericScene { static void back_callback(void* context); static void more_callback(void* context); - string_t string[3]; + string_t string_header; + string_t string_info; }; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp b/applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp index 54a57c9a2e..c2e5ec2a61 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp @@ -37,12 +37,13 @@ bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) { bool result = false; if(arg && !emulating) { string_set_str(app->file_path, arg); - if(app->load_key_data(app->file_path, &(app->worker.key), false)) { - app->worker.start_emulate(); + if(app->load_key_data(app->file_path, false)) { + lfrfid_worker_start_thread(app->lfworker); + lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id); emulating = true; auto popup = app->view_controller.get(); - app->text_store.set("emulating\n%s", app->worker.key.get_name()); + app->text_store.set("emulating\n%s", string_get_cstr(app->file_name)); popup->set_text(app->text_store.text, 89, 44, AlignCenter, AlignTop); notification_message(app->notification, &sequence_blink_start_magenta); @@ -57,7 +58,8 @@ bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) { void LfRfidAppSceneRpc::on_exit(LfRfidApp* app) { if(emulating) { - app->worker.stop_emulate(); + lfrfid_worker_stop(app->lfworker); + lfrfid_worker_stop_thread(app->lfworker); notification_message(app->notification, &sequence_blink_stop); } app->view_controller.get()->clean(); diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_data.cpp b/applications/lfrfid/scene/lfrfid_app_scene_save_data.cpp index 3a13e6838e..c506cd7299 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_data.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_save_data.cpp @@ -3,31 +3,29 @@ void LfRfidAppSceneSaveData::on_enter(LfRfidApp* app, bool need_restore) { auto byte_input = app->view_controller.get(); - RfidKey& key = app->worker.key; - - if(need_restore) printf("restored\r\n"); + size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); if(need_restore) { - key.set_data(old_key_data, key.get_type_data_count()); + protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size); } else { - memcpy(old_key_data, key.get_data(), key.get_type_data_count()); + protocol_dict_get_data(app->dict, app->protocol_id, app->old_key_data, size); } - memcpy(new_key_data, key.get_data(), key.get_type_data_count()); + protocol_dict_get_data(app->dict, app->protocol_id, app->new_key_data, size); + byte_input->set_header_text("Enter the data in hex"); - byte_input->set_result_callback( - save_callback, NULL, app, new_key_data, app->worker.key.get_type_data_count()); + byte_input->set_result_callback(save_callback, NULL, app, app->new_key_data, size); app->view_controller.switch_to(); } bool LfRfidAppSceneSaveData::on_event(LfRfidApp* app, LfRfidApp::Event* event) { bool consumed = false; - RfidKey& key = app->worker.key; if(event->type == LfRfidApp::EventType::Next) { - key.set_data(new_key_data, key.get_type_data_count()); + size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); + protocol_dict_set_data(app->dict, app->protocol_id, app->new_key_data, size); DOLPHIN_DEED(DolphinDeedRfidAdd); app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveName); } diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_data.h b/applications/lfrfid/scene/lfrfid_app_scene_save_data.h index 6458ae649e..d03cae1251 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_data.h +++ b/applications/lfrfid/scene/lfrfid_app_scene_save_data.h @@ -9,25 +9,4 @@ class LfRfidAppSceneSaveData : public GenericScene { private: static void save_callback(void* context); - uint8_t old_key_data[LFRFID_KEY_SIZE] = { - 0xAA, - 0xAA, - 0xAA, - 0xAA, - 0xAA, - 0xAA, - 0xAA, - 0xAA, - }; - - uint8_t new_key_data[LFRFID_KEY_SIZE] = { - 0xBB, - 0xBB, - 0xBB, - 0xBB, - 0xBB, - 0xBB, - 0xBB, - 0xBB, - }; }; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp b/applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp index d7ba2c9edb..ed58b6453e 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp @@ -4,9 +4,9 @@ #include void LfRfidAppSceneSaveName::on_enter(LfRfidApp* app, bool /* need_restore */) { - const char* key_name = app->worker.key.get_name(); + const char* key_name = string_get_cstr(app->file_name); - bool key_name_empty = !strcmp(key_name, ""); + bool key_name_empty = (string_size(app->file_name) == 0); if(key_name_empty) { string_set_str(app->file_path, app->app_folder); set_random_name(app->text_store.text, app->text_store.text_size); @@ -18,11 +18,7 @@ void LfRfidAppSceneSaveName::on_enter(LfRfidApp* app, bool /* need_restore */) { text_input->set_header_text("Name the card"); text_input->set_result_callback( - save_callback, - app, - app->text_store.text, - app->worker.key.get_name_length(), - key_name_empty); + save_callback, app, app->text_store.text, LFRFID_KEY_NAME_SIZE, key_name_empty); string_t folder_path; string_init(folder_path); @@ -42,13 +38,13 @@ bool LfRfidAppSceneSaveName::on_event(LfRfidApp* app, LfRfidApp::Event* event) { bool consumed = false; if(event->type == LfRfidApp::EventType::Next) { - if(strlen(app->worker.key.get_name())) { - app->delete_key(&app->worker.key); + if(string_size(app->file_name) > 0) { + app->delete_key(); } - app->worker.key.set_name(app->text_store.text); + string_set_str(app->file_name, app->text_store.text); - if(app->save_key(&app->worker.key)) { + if(app->save_key()) { app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveSuccess); } else { app->scene_controller.search_and_switch_to_previous_scene( diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp b/applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp index 334bb1a03d..b017e7b057 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp @@ -3,12 +3,12 @@ void LfRfidAppSceneSaveType::on_enter(LfRfidApp* app, bool need_restore) { auto submenu = app->view_controller.get(); - for(uint8_t i = 0; i <= keys_count; i++) { + for(uint8_t i = 0; i < keys_count; i++) { string_init_printf( submenu_name[i], "%s %s", - lfrfid_key_get_manufacturer_string(static_cast(i)), - lfrfid_key_get_type_string(static_cast(i))); + protocol_dict_get_manufacturer(app->dict, i), + protocol_dict_get_name(app->dict, i)); submenu->add_item(string_get_cstr(submenu_name[i]), i, submenu_callback, app); } @@ -19,15 +19,15 @@ void LfRfidAppSceneSaveType::on_enter(LfRfidApp* app, bool need_restore) { app->view_controller.switch_to(); // clear key name - app->worker.key.set_name(""); + string_reset(app->file_name); } bool LfRfidAppSceneSaveType::on_event(LfRfidApp* app, LfRfidApp::Event* event) { bool consumed = false; if(event->type == LfRfidApp::EventType::MenuSelected) { - submenu_item_selected = event->payload.menu_index; - app->worker.key.set_type(static_cast(event->payload.menu_index)); + submenu_item_selected = event->payload.signed_int; + app->protocol_id = event->payload.signed_int; app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveData); consumed = true; } @@ -37,7 +37,7 @@ bool LfRfidAppSceneSaveType::on_event(LfRfidApp* app, LfRfidApp::Event* event) { void LfRfidAppSceneSaveType::on_exit(LfRfidApp* app) { app->view_controller.get()->clean(); - for(uint8_t i = 0; i <= keys_count; i++) { + for(uint8_t i = 0; i < keys_count; i++) { string_clear(submenu_name[i]); } } @@ -47,7 +47,7 @@ void LfRfidAppSceneSaveType::submenu_callback(void* context, uint32_t index) { LfRfidApp::Event event; event.type = LfRfidApp::EventType::MenuSelected; - event.payload.menu_index = index; + event.payload.signed_int = index; app->view_controller.send_event(&event); } diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_type.h b/applications/lfrfid/scene/lfrfid_app_scene_save_type.h index 847c0dabbf..e4c1be3e64 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_type.h +++ b/applications/lfrfid/scene/lfrfid_app_scene_save_type.h @@ -10,6 +10,6 @@ class LfRfidAppSceneSaveType : public GenericScene { private: static void submenu_callback(void* context, uint32_t index); uint32_t submenu_item_selected = 0; - static const uint8_t keys_count = static_cast(LfrfidKeyType::KeyIoProxXSF); - string_t submenu_name[keys_count + 1]; + static const uint8_t keys_count = static_cast(LFRFIDProtocol::LFRFIDProtocolMax); + string_t submenu_name[keys_count]; }; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_saved_info.cpp b/applications/lfrfid/scene/lfrfid_app_scene_saved_info.cpp index dd4a3d4ebf..614dd505c2 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_saved_info.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_saved_info.cpp @@ -4,65 +4,36 @@ #include "../view/elements/string_element.h" void LfRfidAppSceneSavedInfo::on_enter(LfRfidApp* app, bool /* need_restore */) { - string_init(string_data); - string_init(string_decrypted); - - auto container = app->view_controller.get(); - - auto button = container->add(); - button->set_type(ButtonElement::Type::Left, "Back"); - button->set_callback(app, LfRfidAppSceneSavedInfo::back_callback); - - auto line_1 = container->add(); - auto line_2 = container->add(); - auto line_3 = container->add(); - auto line_4 = container->add(); - - RfidKey& key = app->worker.key; - const uint8_t* data = key.get_data(); - - for(uint8_t i = 0; i < key.get_type_data_count(); i++) { + string_init(string_info); + + string_printf( + string_info, + "%s [%s]\r\n", + string_get_cstr(app->file_name), + protocol_dict_get_name(app->dict, app->protocol_id)); + + size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); + uint8_t* data = (uint8_t*)malloc(size); + protocol_dict_get_data(app->dict, app->protocol_id, data, size); + for(uint8_t i = 0; i < size; i++) { if(i != 0) { - string_cat_printf(string_data, " "); + string_cat_printf(string_info, " "); } - string_cat_printf(string_data, "%02X", data[i]); - } - line_1->set_text(key.get_name(), 64, 17, 128 - 2, AlignCenter, AlignBottom, FontSecondary); - line_2->set_text( - string_get_cstr(string_data), 64, 29, 0, AlignCenter, AlignBottom, FontPrimary); + string_cat_printf(string_info, "%02X", data[i]); + } + free(data); - switch(key.get_type()) { - case LfrfidKeyType::KeyEM4100: - string_printf( - string_decrypted, "%03u,%05u", data[2], (uint16_t)((data[3] << 8) | (data[4]))); + string_t render_data; + string_init(render_data); + protocol_dict_render_data(app->dict, render_data, app->protocol_id); + string_cat_printf(string_info, "\r\n%s", string_get_cstr(render_data)); + string_clear(render_data); - break; - case LfrfidKeyType::KeyH10301: - case LfrfidKeyType::KeyI40134: - string_printf( - string_decrypted, "FC: %u ID: %u", data[0], (uint16_t)((data[1] << 8) | (data[2]))); - break; - case LfrfidKeyType::KeyIoProxXSF: - string_printf( - string_decrypted, - "FC: %u VC: %u ID: %u", - data[0], - data[1], - (uint16_t)((data[2] << 8) | (data[3]))); - break; - } - line_3->set_text( - string_get_cstr(string_decrypted), 64, 39, 0, AlignCenter, AlignBottom, FontSecondary); + auto container = app->view_controller.get(); - line_4->set_text( - lfrfid_key_get_type_string(key.get_type()), - 64, - 49, - 0, - AlignCenter, - AlignBottom, - FontSecondary); + auto line_1 = container->add(); + line_1->set_text(string_get_cstr(string_info), 0, 1, 0, AlignLeft, AlignTop, FontSecondary); app->view_controller.switch_to(); } @@ -73,13 +44,5 @@ bool LfRfidAppSceneSavedInfo::on_event(LfRfidApp* /* app */, LfRfidApp::Event* / void LfRfidAppSceneSavedInfo::on_exit(LfRfidApp* app) { app->view_controller.get()->clean(); - string_clear(string_data); - string_clear(string_decrypted); -} - -void LfRfidAppSceneSavedInfo::back_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Back; - app->view_controller.send_event(&event); + string_clear(string_info); } diff --git a/applications/lfrfid/scene/lfrfid_app_scene_saved_info.h b/applications/lfrfid/scene/lfrfid_app_scene_saved_info.h index 5aa33e8ad7..b0b588bcb1 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_saved_info.h +++ b/applications/lfrfid/scene/lfrfid_app_scene_saved_info.h @@ -8,8 +8,5 @@ class LfRfidAppSceneSavedInfo : public GenericScene { void on_exit(LfRfidApp* app) final; private: - static void back_callback(void* context); - - string_t string_data; - string_t string_decrypted; + string_t string_info; }; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_saved_key_menu.cpp b/applications/lfrfid/scene/lfrfid_app_scene_saved_key_menu.cpp index e6677fe8da..e7a38d8ad1 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_saved_key_menu.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_saved_key_menu.cpp @@ -28,8 +28,8 @@ bool LfRfidAppSceneSavedKeyMenu::on_event(LfRfidApp* app, LfRfidApp::Event* even bool consumed = false; if(event->type == LfRfidApp::EventType::MenuSelected) { - submenu_item_selected = event->payload.menu_index; - switch(event->payload.menu_index) { + submenu_item_selected = event->payload.signed_int; + switch(event->payload.signed_int) { case SubmenuEmulate: app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Emulate); break; @@ -61,7 +61,7 @@ void LfRfidAppSceneSavedKeyMenu::submenu_callback(void* context, uint32_t index) LfRfidApp::Event event; event.type = LfRfidApp::EventType::MenuSelected; - event.payload.menu_index = index; + event.payload.signed_int = index; app->view_controller.send_event(&event); } diff --git a/applications/lfrfid/scene/lfrfid_app_scene_start.cpp b/applications/lfrfid/scene/lfrfid_app_scene_start.cpp index f5afad5c98..5005c9afb5 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_start.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_start.cpp @@ -4,6 +4,7 @@ typedef enum { SubmenuRead, SubmenuSaved, SubmenuAddManually, + SubmenuExtraActions, } SubmenuIndex; void LfRfidAppSceneStart::on_enter(LfRfidApp* app, bool need_restore) { @@ -12,6 +13,7 @@ void LfRfidAppSceneStart::on_enter(LfRfidApp* app, bool need_restore) { submenu->add_item("Read", SubmenuRead, submenu_callback, app); submenu->add_item("Saved", SubmenuSaved, submenu_callback, app); submenu->add_item("Add Manually", SubmenuAddManually, submenu_callback, app); + submenu->add_item("Extra Actions", SubmenuExtraActions, submenu_callback, app); if(need_restore) { submenu->set_selected_item(submenu_item_selected); @@ -20,15 +22,17 @@ void LfRfidAppSceneStart::on_enter(LfRfidApp* app, bool need_restore) { app->view_controller.switch_to(); // clear key - app->worker.key.clear(); + string_reset(app->file_name); + app->protocol_id = PROTOCOL_NO; + app->read_type = LFRFIDWorkerReadTypeAuto; } bool LfRfidAppSceneStart::on_event(LfRfidApp* app, LfRfidApp::Event* event) { bool consumed = false; if(event->type == LfRfidApp::EventType::MenuSelected) { - submenu_item_selected = event->payload.menu_index; - switch(event->payload.menu_index) { + submenu_item_selected = event->payload.signed_int; + switch(event->payload.signed_int) { case SubmenuRead: app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read); break; @@ -38,6 +42,9 @@ bool LfRfidAppSceneStart::on_event(LfRfidApp* app, LfRfidApp::Event* event) { case SubmenuAddManually: app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveType); break; + case SubmenuExtraActions: + app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ExtraActions); + break; } consumed = true; } @@ -54,7 +61,7 @@ void LfRfidAppSceneStart::submenu_callback(void* context, uint32_t index) { LfRfidApp::Event event; event.type = LfRfidApp::EventType::MenuSelected; - event.payload.menu_index = index; + event.payload.signed_int = index; app->view_controller.send_event(&event); } diff --git a/applications/lfrfid/scene/lfrfid_app_scene_write.cpp b/applications/lfrfid/scene/lfrfid_app_scene_write.cpp index 274ba31582..8e04d8e8de 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_write.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_write.cpp @@ -1,66 +1,79 @@ #include "lfrfid_app_scene_write.h" -void LfRfidAppSceneWrite::on_enter(LfRfidApp* app, bool /* need_restore */) { - card_not_supported = false; - string_init(data_string); - - const uint8_t* data = app->worker.key.get_data(); +static void lfrfid_write_callback(LFRFIDWorkerWriteResult result, void* ctx) { + LfRfidApp* app = static_cast(ctx); + LfRfidApp::Event event; - for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) { - string_cat_printf(data_string, "%02X", data[i]); + switch(result) { + case LFRFIDWorkerWriteOK: + event.type = LfRfidApp::EventType::WriteEventOK; + break; + case LFRFIDWorkerWriteProtocolCannotBeWritten: + event.type = LfRfidApp::EventType::WriteEventProtocolCannotBeWritten; + break; + case LFRFIDWorkerWriteFobCannotBeWritten: + event.type = LfRfidApp::EventType::WriteEventFobCannotBeWritten; + break; + case LFRFIDWorkerWriteTooLongToWrite: + event.type = LfRfidApp::EventType::WriteEventTooLongToWrite; + break; } + app->view_controller.send_event(&event); +} + +void LfRfidAppSceneWrite::on_enter(LfRfidApp* app, bool /* need_restore */) { auto popup = app->view_controller.get(); popup->set_header("Writing", 89, 30, AlignCenter, AlignTop); - if(strlen(app->worker.key.get_name())) { - popup->set_text(app->worker.key.get_name(), 89, 43, AlignCenter, AlignTop); + if(string_size(app->file_name)) { + popup->set_text(string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); } else { - popup->set_text(string_get_cstr(data_string), 89, 43, AlignCenter, AlignTop); + popup->set_text( + protocol_dict_get_name(app->dict, app->protocol_id), 89, 43, AlignCenter, AlignTop); } popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61); app->view_controller.switch_to(); - app->worker.start_write(); + lfrfid_worker_start_thread(app->lfworker); + lfrfid_worker_write_start( + app->lfworker, (LFRFIDProtocol)app->protocol_id, lfrfid_write_callback, app); + notification_message(app->notification, &sequence_blink_start_magenta); } bool LfRfidAppSceneWrite::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Tick) { - RfidWorker::WriteResult result = app->worker.write(); + bool consumed = true; + auto popup = app->view_controller.get(); - switch(result) { - case RfidWorker::WriteResult::Nothing: - notification_message(app->notification, &sequence_blink_magenta_10); - break; - case RfidWorker::WriteResult::Ok: - notification_message(app->notification, &sequence_success); - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::WriteSuccess); - break; - case RfidWorker::WriteResult::NotWritable: - if(!card_not_supported) { - auto popup = app->view_controller.get(); - popup->set_icon(72, 17, &I_DolphinCommon_56x48); - popup->set_header("Still trying to write...", 64, 3, AlignCenter, AlignTop); - popup->set_text( - "Make sure this\ncard is writable\nand not\nprotected.", - 3, - 17, - AlignLeft, - AlignTop); - card_not_supported = true; - } - notification_message(app->notification, &sequence_blink_yellow_10); - break; - } + switch(event->type) { + case LfRfidApp::EventType::WriteEventOK: + notification_message(app->notification, &sequence_success); + app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::WriteSuccess); + break; + case LfRfidApp::EventType::WriteEventProtocolCannotBeWritten: + popup->set_icon(72, 17, &I_DolphinCommon_56x48); + popup->set_header("Error", 64, 3, AlignCenter, AlignTop); + popup->set_text("This protocol\ncannot be written", 3, 17, AlignLeft, AlignTop); + notification_message(app->notification, &sequence_blink_start_red); + break; + case LfRfidApp::EventType::WriteEventFobCannotBeWritten: + case LfRfidApp::EventType::WriteEventTooLongToWrite: + popup->set_icon(72, 17, &I_DolphinCommon_56x48); + popup->set_header("Still trying to write...", 64, 3, AlignCenter, AlignTop); + popup->set_text( + "Make sure this\ncard is writable\nand not\nprotected.", 3, 17, AlignLeft, AlignTop); + notification_message(app->notification, &sequence_blink_start_yellow); + break; + default: + consumed = false; } return consumed; } void LfRfidAppSceneWrite::on_exit(LfRfidApp* app) { + notification_message(app->notification, &sequence_blink_stop); app->view_controller.get()->clean(); - app->worker.stop_write(); - string_clear(data_string); + lfrfid_worker_stop(app->lfworker); + lfrfid_worker_stop_thread(app->lfworker); } diff --git a/applications/lfrfid/scene/lfrfid_app_scene_write.h b/applications/lfrfid/scene/lfrfid_app_scene_write.h index 3abadebab5..7564eff9dd 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_write.h +++ b/applications/lfrfid/scene/lfrfid_app_scene_write.h @@ -6,8 +6,4 @@ class LfRfidAppSceneWrite : public GenericScene { void on_enter(LfRfidApp* app, bool need_restore) final; bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; void on_exit(LfRfidApp* app) final; - -private: - string_t data_string; - bool card_not_supported; }; diff --git a/applications/storage/storage.h b/applications/storage/storage.h index 55a951d128..1a7c934950 100644 --- a/applications/storage/storage.h +++ b/applications/storage/storage.h @@ -136,6 +136,15 @@ bool storage_file_sync(File* file); */ bool storage_file_eof(File* file); +/** + * @brief Check that file exists + * + * @param storage + * @param path + * @return true if file exists + */ +bool storage_file_exists(Storage* storage, const char* path); + /******************* Dir Functions *******************/ /** Opens a directory to get objects from it diff --git a/applications/storage/storage_external_api.c b/applications/storage/storage_external_api.c index b32080dfcc..80cafb2828 100644 --- a/applications/storage/storage_external_api.c +++ b/applications/storage/storage_external_api.c @@ -240,6 +240,18 @@ bool storage_file_eof(File* file) { return S_RETURN_BOOL; } +bool storage_file_exists(Storage* storage, const char* path) { + bool exist = false; + FileInfo fileinfo; + FS_Error error = storage_common_stat(storage, path, &fileinfo); + + if(error == FSE_OK && !(fileinfo.flags & FSF_DIRECTORY)) { + exist = true; + } + + return exist; +} + /****************** DIR ******************/ static bool storage_dir_open_internal(File* file, const char* path) { diff --git a/applications/unit_tests/lfrfid/bit_lib_test.c b/applications/unit_tests/lfrfid/bit_lib_test.c new file mode 100644 index 0000000000..7266157033 --- /dev/null +++ b/applications/unit_tests/lfrfid/bit_lib_test.c @@ -0,0 +1,473 @@ +#include +#include "../minunit.h" +#include + +MU_TEST(test_bit_lib_increment_index) { + uint32_t index = 0; + + // test increment + for(uint32_t i = 0; i < 31; ++i) { + bit_lib_increment_index(index, 32); + mu_assert_int_eq(i + 1, index); + } + + // test wrap around + for(uint32_t i = 0; i < 512; ++i) { + bit_lib_increment_index(index, 32); + mu_assert_int_less_than(32, index); + } +} + +MU_TEST(test_bit_lib_is_set) { + uint32_t value = 0x0000FFFF; + + for(uint32_t i = 0; i < 16; ++i) { + mu_check(bit_lib_bit_is_set(value, i)); + mu_check(!bit_lib_bit_is_not_set(value, i)); + } + + for(uint32_t i = 16; i < 32; ++i) { + mu_check(!bit_lib_bit_is_set(value, i)); + mu_check(bit_lib_bit_is_not_set(value, i)); + } +} + +MU_TEST(test_bit_lib_push) { +#define TEST_BIT_LIB_PUSH_DATA_SIZE 4 + uint8_t data[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0}; + uint8_t expected_data_1[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0x00, 0x00, 0x0F, 0xFF}; + uint8_t expected_data_2[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0x00, 0xFF, 0xF0, 0x00}; + uint8_t expected_data_3[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0xFF, 0x00, 0x00, 0xFF}; + uint8_t expected_data_4[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0xFF, 0xFF, 0xFF, 0xFF}; + uint8_t expected_data_5[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0x00, 0x00, 0x00, 0x00}; + uint8_t expected_data_6[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0xCC, 0xCC, 0xCC, 0xCC}; + + for(uint32_t i = 0; i < 12; ++i) { + bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, true); + } + mu_assert_mem_eq(expected_data_1, data, TEST_BIT_LIB_PUSH_DATA_SIZE); + + for(uint32_t i = 0; i < 12; ++i) { + bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, false); + } + mu_assert_mem_eq(expected_data_2, data, TEST_BIT_LIB_PUSH_DATA_SIZE); + + for(uint32_t i = 0; i < 4; ++i) { + bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, false); + } + for(uint32_t i = 0; i < 8; ++i) { + bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, true); + } + mu_assert_mem_eq(expected_data_3, data, TEST_BIT_LIB_PUSH_DATA_SIZE); + + for(uint32_t i = 0; i < TEST_BIT_LIB_PUSH_DATA_SIZE * 8; ++i) { + bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, true); + } + mu_assert_mem_eq(expected_data_4, data, TEST_BIT_LIB_PUSH_DATA_SIZE); + + for(uint32_t i = 0; i < TEST_BIT_LIB_PUSH_DATA_SIZE * 8; ++i) { + bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, false); + } + mu_assert_mem_eq(expected_data_5, data, TEST_BIT_LIB_PUSH_DATA_SIZE); + + for(uint32_t i = 0; i < TEST_BIT_LIB_PUSH_DATA_SIZE * 2; ++i) { + bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, true); + bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, true); + bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, false); + bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, false); + } + mu_assert_mem_eq(expected_data_6, data, TEST_BIT_LIB_PUSH_DATA_SIZE); +} + +MU_TEST(test_bit_lib_set_bit) { + uint8_t value[2] = {0x00, 0xFF}; + bit_lib_set_bit(value, 15, false); + mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0xFE}), 2); + bit_lib_set_bit(value, 14, false); + mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0xFC}), 2); + bit_lib_set_bit(value, 13, false); + mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0xF8}), 2); + bit_lib_set_bit(value, 12, false); + mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0xF0}), 2); + bit_lib_set_bit(value, 11, false); + mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0xE0}), 2); + bit_lib_set_bit(value, 10, false); + mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0xC0}), 2); + bit_lib_set_bit(value, 9, false); + mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0x80}), 2); + bit_lib_set_bit(value, 8, false); + mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0x00}), 2); + + bit_lib_set_bit(value, 7, true); + mu_assert_mem_eq(value, ((uint8_t[]){0x01, 0x00}), 2); + bit_lib_set_bit(value, 6, true); + mu_assert_mem_eq(value, ((uint8_t[]){0x03, 0x00}), 2); + bit_lib_set_bit(value, 5, true); + mu_assert_mem_eq(value, ((uint8_t[]){0x07, 0x00}), 2); + bit_lib_set_bit(value, 4, true); + mu_assert_mem_eq(value, ((uint8_t[]){0x0F, 0x00}), 2); + bit_lib_set_bit(value, 3, true); + mu_assert_mem_eq(value, ((uint8_t[]){0x1F, 0x00}), 2); + bit_lib_set_bit(value, 2, true); + mu_assert_mem_eq(value, ((uint8_t[]){0x3F, 0x00}), 2); + bit_lib_set_bit(value, 1, true); + mu_assert_mem_eq(value, ((uint8_t[]){0x7F, 0x00}), 2); + bit_lib_set_bit(value, 0, true); + mu_assert_mem_eq(value, ((uint8_t[]){0xFF, 0x00}), 2); +} + +MU_TEST(test_bit_lib_set_bits) { + uint8_t value[2] = {0b00000000, 0b11111111}; + // set 4 bits to 0b0100 from 12 index + bit_lib_set_bits(value, 12, 0b0100, 4); + // [0100] + mu_assert_mem_eq(value, ((uint8_t[]){0b00000000, 0b11110100}), 2); + + // set 2 bits to 0b11 from 11 index + bit_lib_set_bits(value, 11, 0b11, 2); + // [11] + mu_assert_mem_eq(value, ((uint8_t[]){0b00000000, 0b11111100}), 2); + + // set 3 bits to 0b111 from 0 index + bit_lib_set_bits(value, 0, 0b111, 3); + // [111] + mu_assert_mem_eq(value, ((uint8_t[]){0b11100000, 0b11111100}), 2); + + // set 8 bits to 0b11111000 from 3 index + bit_lib_set_bits(value, 3, 0b11111000, 8); + // [11111 000] + mu_assert_mem_eq(value, ((uint8_t[]){0b11111111, 0b00011100}), 2); +} + +MU_TEST(test_bit_lib_get_bit) { + uint8_t value[2] = {0b00000000, 0b11111111}; + for(uint32_t i = 0; i < 8; ++i) { + mu_check(bit_lib_get_bit(value, i) == false); + } + for(uint32_t i = 8; i < 16; ++i) { + mu_check(bit_lib_get_bit(value, i) == true); + } +} + +MU_TEST(test_bit_lib_get_bits) { + uint8_t value[2] = {0b00000000, 0b11111111}; + mu_assert_int_eq(0b00000000, bit_lib_get_bits(value, 0, 8)); + mu_assert_int_eq(0b00000001, bit_lib_get_bits(value, 1, 8)); + mu_assert_int_eq(0b00000011, bit_lib_get_bits(value, 2, 8)); + mu_assert_int_eq(0b00000111, bit_lib_get_bits(value, 3, 8)); + mu_assert_int_eq(0b00001111, bit_lib_get_bits(value, 4, 8)); + mu_assert_int_eq(0b00011111, bit_lib_get_bits(value, 5, 8)); + mu_assert_int_eq(0b00111111, bit_lib_get_bits(value, 6, 8)); + mu_assert_int_eq(0b01111111, bit_lib_get_bits(value, 7, 8)); + mu_assert_int_eq(0b11111111, bit_lib_get_bits(value, 8, 8)); +} + +MU_TEST(test_bit_lib_get_bits_16) { + uint8_t value[2] = {0b00001001, 0b10110001}; + mu_assert_int_eq(0b0, bit_lib_get_bits_16(value, 0, 1)); + mu_assert_int_eq(0b00, bit_lib_get_bits_16(value, 0, 2)); + mu_assert_int_eq(0b000, bit_lib_get_bits_16(value, 0, 3)); + mu_assert_int_eq(0b0000, bit_lib_get_bits_16(value, 0, 4)); + mu_assert_int_eq(0b00001, bit_lib_get_bits_16(value, 0, 5)); + mu_assert_int_eq(0b000010, bit_lib_get_bits_16(value, 0, 6)); + mu_assert_int_eq(0b0000100, bit_lib_get_bits_16(value, 0, 7)); + mu_assert_int_eq(0b00001001, bit_lib_get_bits_16(value, 0, 8)); + mu_assert_int_eq(0b000010011, bit_lib_get_bits_16(value, 0, 9)); + mu_assert_int_eq(0b0000100110, bit_lib_get_bits_16(value, 0, 10)); + mu_assert_int_eq(0b00001001101, bit_lib_get_bits_16(value, 0, 11)); + mu_assert_int_eq(0b000010011011, bit_lib_get_bits_16(value, 0, 12)); + mu_assert_int_eq(0b0000100110110, bit_lib_get_bits_16(value, 0, 13)); + mu_assert_int_eq(0b00001001101100, bit_lib_get_bits_16(value, 0, 14)); + mu_assert_int_eq(0b000010011011000, bit_lib_get_bits_16(value, 0, 15)); + mu_assert_int_eq(0b0000100110110001, bit_lib_get_bits_16(value, 0, 16)); +} + +MU_TEST(test_bit_lib_get_bits_32) { + uint8_t value[4] = {0b00001001, 0b10110001, 0b10001100, 0b01100010}; + mu_assert_int_eq(0b0, bit_lib_get_bits_32(value, 0, 1)); + mu_assert_int_eq(0b00, bit_lib_get_bits_32(value, 0, 2)); + mu_assert_int_eq(0b000, bit_lib_get_bits_32(value, 0, 3)); + mu_assert_int_eq(0b0000, bit_lib_get_bits_32(value, 0, 4)); + mu_assert_int_eq(0b00001, bit_lib_get_bits_32(value, 0, 5)); + mu_assert_int_eq(0b000010, bit_lib_get_bits_32(value, 0, 6)); + mu_assert_int_eq(0b0000100, bit_lib_get_bits_32(value, 0, 7)); + mu_assert_int_eq(0b00001001, bit_lib_get_bits_32(value, 0, 8)); + mu_assert_int_eq(0b000010011, bit_lib_get_bits_32(value, 0, 9)); + mu_assert_int_eq(0b0000100110, bit_lib_get_bits_32(value, 0, 10)); + mu_assert_int_eq(0b00001001101, bit_lib_get_bits_32(value, 0, 11)); + mu_assert_int_eq(0b000010011011, bit_lib_get_bits_32(value, 0, 12)); + mu_assert_int_eq(0b0000100110110, bit_lib_get_bits_32(value, 0, 13)); + mu_assert_int_eq(0b00001001101100, bit_lib_get_bits_32(value, 0, 14)); + mu_assert_int_eq(0b000010011011000, bit_lib_get_bits_32(value, 0, 15)); + mu_assert_int_eq(0b0000100110110001, bit_lib_get_bits_32(value, 0, 16)); + mu_assert_int_eq(0b00001001101100011, bit_lib_get_bits_32(value, 0, 17)); + mu_assert_int_eq(0b000010011011000110, bit_lib_get_bits_32(value, 0, 18)); + mu_assert_int_eq(0b0000100110110001100, bit_lib_get_bits_32(value, 0, 19)); + mu_assert_int_eq(0b00001001101100011000, bit_lib_get_bits_32(value, 0, 20)); + mu_assert_int_eq(0b000010011011000110001, bit_lib_get_bits_32(value, 0, 21)); + mu_assert_int_eq(0b0000100110110001100011, bit_lib_get_bits_32(value, 0, 22)); + mu_assert_int_eq(0b00001001101100011000110, bit_lib_get_bits_32(value, 0, 23)); + mu_assert_int_eq(0b000010011011000110001100, bit_lib_get_bits_32(value, 0, 24)); + mu_assert_int_eq(0b0000100110110001100011000, bit_lib_get_bits_32(value, 0, 25)); + mu_assert_int_eq(0b00001001101100011000110001, bit_lib_get_bits_32(value, 0, 26)); + mu_assert_int_eq(0b000010011011000110001100011, bit_lib_get_bits_32(value, 0, 27)); + mu_assert_int_eq(0b0000100110110001100011000110, bit_lib_get_bits_32(value, 0, 28)); + mu_assert_int_eq(0b00001001101100011000110001100, bit_lib_get_bits_32(value, 0, 29)); + mu_assert_int_eq(0b000010011011000110001100011000, bit_lib_get_bits_32(value, 0, 30)); + mu_assert_int_eq(0b0000100110110001100011000110001, bit_lib_get_bits_32(value, 0, 31)); + mu_assert_int_eq(0b00001001101100011000110001100010, bit_lib_get_bits_32(value, 0, 32)); +} + +MU_TEST(test_bit_lib_test_parity_u32) { + // test even parity + mu_assert_int_eq(bit_lib_test_parity_32(0b00000000, BitLibParityEven), 0); + mu_assert_int_eq(bit_lib_test_parity_32(0b00000001, BitLibParityEven), 1); + mu_assert_int_eq(bit_lib_test_parity_32(0b00000010, BitLibParityEven), 1); + mu_assert_int_eq(bit_lib_test_parity_32(0b00000011, BitLibParityEven), 0); + mu_assert_int_eq(bit_lib_test_parity_32(0b00000100, BitLibParityEven), 1); + mu_assert_int_eq(bit_lib_test_parity_32(0b00000101, BitLibParityEven), 0); + mu_assert_int_eq(bit_lib_test_parity_32(0b00000110, BitLibParityEven), 0); + mu_assert_int_eq(bit_lib_test_parity_32(0b00000111, BitLibParityEven), 1); + mu_assert_int_eq(bit_lib_test_parity_32(0b00001000, BitLibParityEven), 1); + mu_assert_int_eq(bit_lib_test_parity_32(0b00001001, BitLibParityEven), 0); + mu_assert_int_eq(bit_lib_test_parity_32(0b00001010, BitLibParityEven), 0); + mu_assert_int_eq(bit_lib_test_parity_32(0b00001011, BitLibParityEven), 1); + mu_assert_int_eq(bit_lib_test_parity_32(0b00001100, BitLibParityEven), 0); + mu_assert_int_eq(bit_lib_test_parity_32(0b00001101, BitLibParityEven), 1); + mu_assert_int_eq(bit_lib_test_parity_32(0b00001110, BitLibParityEven), 1); + mu_assert_int_eq(bit_lib_test_parity_32(0b00001111, BitLibParityEven), 0); + mu_assert_int_eq(bit_lib_test_parity_32(0b00010000, BitLibParityEven), 1); + + // test odd parity + mu_assert_int_eq(bit_lib_test_parity_32(0b00000000, BitLibParityOdd), 1); + mu_assert_int_eq(bit_lib_test_parity_32(0b00000001, BitLibParityOdd), 0); + mu_assert_int_eq(bit_lib_test_parity_32(0b00000010, BitLibParityOdd), 0); + mu_assert_int_eq(bit_lib_test_parity_32(0b00000011, BitLibParityOdd), 1); + mu_assert_int_eq(bit_lib_test_parity_32(0b00000100, BitLibParityOdd), 0); + mu_assert_int_eq(bit_lib_test_parity_32(0b00000101, BitLibParityOdd), 1); + mu_assert_int_eq(bit_lib_test_parity_32(0b00000110, BitLibParityOdd), 1); + mu_assert_int_eq(bit_lib_test_parity_32(0b00000111, BitLibParityOdd), 0); + mu_assert_int_eq(bit_lib_test_parity_32(0b00001000, BitLibParityOdd), 0); + mu_assert_int_eq(bit_lib_test_parity_32(0b00001001, BitLibParityOdd), 1); + mu_assert_int_eq(bit_lib_test_parity_32(0b00001010, BitLibParityOdd), 1); + mu_assert_int_eq(bit_lib_test_parity_32(0b00001011, BitLibParityOdd), 0); + mu_assert_int_eq(bit_lib_test_parity_32(0b00001100, BitLibParityOdd), 1); + mu_assert_int_eq(bit_lib_test_parity_32(0b00001101, BitLibParityOdd), 0); + mu_assert_int_eq(bit_lib_test_parity_32(0b00001110, BitLibParityOdd), 0); + mu_assert_int_eq(bit_lib_test_parity_32(0b00001111, BitLibParityOdd), 1); + mu_assert_int_eq(bit_lib_test_parity_32(0b00010000, BitLibParityOdd), 0); +} + +MU_TEST(test_bit_lib_test_parity) { + // next data contains valid parity for 1-3 nibble and invalid for 4 nibble + uint8_t data_always_0_parity[2] = {0b11101110, 0b11101111}; + uint8_t data_always_1_parity[2] = {0b00010001, 0b00010000}; + uint8_t data_always_odd_parity[2] = {0b00000011, 0b11110111}; + uint8_t data_always_even_parity[2] = {0b00010111, 0b10110011}; + + // test alawys 0 parity + mu_check(bit_lib_test_parity(data_always_0_parity, 0, 12, BitLibParityAlways0, 4)); + mu_check(bit_lib_test_parity(data_always_0_parity, 4, 8, BitLibParityAlways0, 4)); + mu_check(bit_lib_test_parity(data_always_0_parity, 8, 4, BitLibParityAlways0, 4)); + mu_check(bit_lib_test_parity(data_always_1_parity, 12, 4, BitLibParityAlways0, 4)); + + mu_check(!bit_lib_test_parity(data_always_0_parity, 0, 16, BitLibParityAlways0, 4)); + mu_check(!bit_lib_test_parity(data_always_0_parity, 4, 12, BitLibParityAlways0, 4)); + mu_check(!bit_lib_test_parity(data_always_0_parity, 8, 8, BitLibParityAlways0, 4)); + mu_check(!bit_lib_test_parity(data_always_0_parity, 12, 4, BitLibParityAlways0, 4)); + + // test alawys 1 parity + mu_check(bit_lib_test_parity(data_always_1_parity, 0, 12, BitLibParityAlways1, 4)); + mu_check(bit_lib_test_parity(data_always_1_parity, 4, 8, BitLibParityAlways1, 4)); + mu_check(bit_lib_test_parity(data_always_1_parity, 8, 4, BitLibParityAlways1, 4)); + mu_check(bit_lib_test_parity(data_always_0_parity, 12, 4, BitLibParityAlways1, 4)); + + mu_check(!bit_lib_test_parity(data_always_1_parity, 0, 16, BitLibParityAlways1, 4)); + mu_check(!bit_lib_test_parity(data_always_1_parity, 4, 12, BitLibParityAlways1, 4)); + mu_check(!bit_lib_test_parity(data_always_1_parity, 8, 8, BitLibParityAlways1, 4)); + mu_check(!bit_lib_test_parity(data_always_1_parity, 12, 4, BitLibParityAlways1, 4)); + + // test odd parity + mu_check(bit_lib_test_parity(data_always_odd_parity, 0, 12, BitLibParityOdd, 4)); + mu_check(bit_lib_test_parity(data_always_odd_parity, 4, 8, BitLibParityOdd, 4)); + mu_check(bit_lib_test_parity(data_always_odd_parity, 8, 4, BitLibParityOdd, 4)); + mu_check(bit_lib_test_parity(data_always_even_parity, 12, 4, BitLibParityOdd, 4)); + + mu_check(!bit_lib_test_parity(data_always_odd_parity, 0, 16, BitLibParityOdd, 4)); + mu_check(!bit_lib_test_parity(data_always_odd_parity, 4, 12, BitLibParityOdd, 4)); + mu_check(!bit_lib_test_parity(data_always_odd_parity, 8, 8, BitLibParityOdd, 4)); + mu_check(!bit_lib_test_parity(data_always_odd_parity, 12, 4, BitLibParityOdd, 4)); + + // test even parity + mu_check(bit_lib_test_parity(data_always_even_parity, 0, 12, BitLibParityEven, 4)); + mu_check(bit_lib_test_parity(data_always_even_parity, 4, 8, BitLibParityEven, 4)); + mu_check(bit_lib_test_parity(data_always_even_parity, 8, 4, BitLibParityEven, 4)); + mu_check(bit_lib_test_parity(data_always_odd_parity, 12, 4, BitLibParityEven, 4)); + + mu_check(!bit_lib_test_parity(data_always_even_parity, 0, 16, BitLibParityEven, 4)); + mu_check(!bit_lib_test_parity(data_always_even_parity, 4, 12, BitLibParityEven, 4)); + mu_check(!bit_lib_test_parity(data_always_even_parity, 8, 8, BitLibParityEven, 4)); + mu_check(!bit_lib_test_parity(data_always_even_parity, 12, 4, BitLibParityEven, 4)); +} + +MU_TEST(test_bit_lib_remove_bit_every_nth) { + // TODO: more tests + uint8_t data_i[1] = {0b00001111}; + uint8_t data_o[1] = {0b00011111}; + size_t length; + + length = bit_lib_remove_bit_every_nth(data_i, 0, 8, 3); + mu_assert_int_eq(6, length); + mu_assert_mem_eq(data_o, data_i, 1); +} + +MU_TEST(test_bit_lib_reverse_bits) { + uint8_t data_1_i[2] = {0b11001010, 0b00011111}; + uint8_t data_1_o[2] = {0b11111000, 0b01010011}; + + // reverse bits [0..15] + bit_lib_reverse_bits(data_1_i, 0, 16); + mu_assert_mem_eq(data_1_o, data_1_i, 2); + + uint8_t data_2_i[2] = {0b11001010, 0b00011111}; + uint8_t data_2_o[2] = {0b11001000, 0b01011111}; + + // reverse bits [4..11] + bit_lib_reverse_bits(data_2_i, 4, 8); + mu_assert_mem_eq(data_2_o, data_2_i, 2); +} + +MU_TEST(test_bit_lib_copy_bits) { + uint8_t data_1_i[2] = {0b11001010, 0b00011111}; + uint8_t data_1_o[2] = {0}; + + // data_1_o[0..15] = data_1_i[0..15] + bit_lib_copy_bits(data_1_o, 0, 16, data_1_i, 0); + mu_assert_mem_eq(data_1_i, data_1_o, 2); + + memset(data_1_o, 0, 2); + // data_1_o[4..11] = data_1_i[0..7] + bit_lib_copy_bits(data_1_o, 4, 8, data_1_i, 0); + mu_assert_mem_eq(((uint8_t[]){0b00001100, 0b10100000}), data_1_o, 2); +} + +MU_TEST(test_bit_lib_get_bit_count) { + mu_assert_int_eq(0, bit_lib_get_bit_count(0)); + mu_assert_int_eq(1, bit_lib_get_bit_count(0b1)); + mu_assert_int_eq(1, bit_lib_get_bit_count(0b10)); + mu_assert_int_eq(2, bit_lib_get_bit_count(0b11)); + mu_assert_int_eq(4, bit_lib_get_bit_count(0b11000011)); + mu_assert_int_eq(6, bit_lib_get_bit_count(0b11000011000011)); + mu_assert_int_eq(8, bit_lib_get_bit_count(0b11111111)); + mu_assert_int_eq(16, bit_lib_get_bit_count(0b11111110000000000000000111111111)); + mu_assert_int_eq(32, bit_lib_get_bit_count(0b11111111111111111111111111111111)); +} + +MU_TEST(test_bit_lib_reverse_16_fast) { + mu_assert_int_eq(0b0000000000000000, bit_lib_reverse_16_fast(0b0000000000000000)); + mu_assert_int_eq(0b1000000000000000, bit_lib_reverse_16_fast(0b0000000000000001)); + mu_assert_int_eq(0b1100000000000000, bit_lib_reverse_16_fast(0b0000000000000011)); + mu_assert_int_eq(0b0000100000001001, bit_lib_reverse_16_fast(0b1001000000010000)); +} + +MU_TEST(test_bit_lib_crc16) { + uint8_t data[9] = {'1', '2', '3', '4', '5', '6', '7', '8', '9'}; + uint8_t data_size = 9; + + // Algorithm + // Check Poly Init RefIn RefOut XorOut + // CRC-16/CCITT-FALSE + // 0x29B1 0x1021 0xFFFF false false 0x0000 + mu_assert_int_eq(0x29B1, bit_lib_crc16(data, data_size, 0x1021, 0xFFFF, false, false, 0x0000)); + // CRC-16/ARC + // 0xBB3D 0x8005 0x0000 true true 0x0000 + mu_assert_int_eq(0xBB3D, bit_lib_crc16(data, data_size, 0x8005, 0x0000, true, true, 0x0000)); + // CRC-16/AUG-CCITT + // 0xE5CC 0x1021 0x1D0F false false 0x0000 + mu_assert_int_eq(0xE5CC, bit_lib_crc16(data, data_size, 0x1021, 0x1D0F, false, false, 0x0000)); + // CRC-16/BUYPASS + // 0xFEE8 0x8005 0x0000 false false 0x0000 + mu_assert_int_eq(0xFEE8, bit_lib_crc16(data, data_size, 0x8005, 0x0000, false, false, 0x0000)); + // CRC-16/CDMA2000 + // 0x4C06 0xC867 0xFFFF false false 0x0000 + mu_assert_int_eq(0x4C06, bit_lib_crc16(data, data_size, 0xC867, 0xFFFF, false, false, 0x0000)); + // CRC-16/DDS-110 + // 0x9ECF 0x8005 0x800D false false 0x0000 + mu_assert_int_eq(0x9ECF, bit_lib_crc16(data, data_size, 0x8005, 0x800D, false, false, 0x0000)); + // CRC-16/DECT-R + // 0x007E 0x0589 0x0000 false false 0x0001 + mu_assert_int_eq(0x007E, bit_lib_crc16(data, data_size, 0x0589, 0x0000, false, false, 0x0001)); + // CRC-16/DECT-X + // 0x007F 0x0589 0x0000 false false 0x0000 + mu_assert_int_eq(0x007F, bit_lib_crc16(data, data_size, 0x0589, 0x0000, false, false, 0x0000)); + // CRC-16/DNP + // 0xEA82 0x3D65 0x0000 true true 0xFFFF + mu_assert_int_eq(0xEA82, bit_lib_crc16(data, data_size, 0x3D65, 0x0000, true, true, 0xFFFF)); + // CRC-16/EN-13757 + // 0xC2B7 0x3D65 0x0000 false false 0xFFFF + mu_assert_int_eq(0xC2B7, bit_lib_crc16(data, data_size, 0x3D65, 0x0000, false, false, 0xFFFF)); + // CRC-16/GENIBUS + // 0xD64E 0x1021 0xFFFF false false 0xFFFF + mu_assert_int_eq(0xD64E, bit_lib_crc16(data, data_size, 0x1021, 0xFFFF, false, false, 0xFFFF)); + // CRC-16/MAXIM + // 0x44C2 0x8005 0x0000 true true 0xFFFF + mu_assert_int_eq(0x44C2, bit_lib_crc16(data, data_size, 0x8005, 0x0000, true, true, 0xFFFF)); + // CRC-16/MCRF4XX + // 0x6F91 0x1021 0xFFFF true true 0x0000 + mu_assert_int_eq(0x6F91, bit_lib_crc16(data, data_size, 0x1021, 0xFFFF, true, true, 0x0000)); + // CRC-16/RIELLO + // 0x63D0 0x1021 0xB2AA true true 0x0000 + mu_assert_int_eq(0x63D0, bit_lib_crc16(data, data_size, 0x1021, 0xB2AA, true, true, 0x0000)); + // CRC-16/T10-DIF + // 0xD0DB 0x8BB7 0x0000 false false 0x0000 + mu_assert_int_eq(0xD0DB, bit_lib_crc16(data, data_size, 0x8BB7, 0x0000, false, false, 0x0000)); + // CRC-16/TELEDISK + // 0x0FB3 0xA097 0x0000 false false 0x0000 + mu_assert_int_eq(0x0FB3, bit_lib_crc16(data, data_size, 0xA097, 0x0000, false, false, 0x0000)); + // CRC-16/TMS37157 + // 0x26B1 0x1021 0x89EC true true 0x0000 + mu_assert_int_eq(0x26B1, bit_lib_crc16(data, data_size, 0x1021, 0x89EC, true, true, 0x0000)); + // CRC-16/USB + // 0xB4C8 0x8005 0xFFFF true true 0xFFFF + mu_assert_int_eq(0xB4C8, bit_lib_crc16(data, data_size, 0x8005, 0xFFFF, true, true, 0xFFFF)); + // CRC-A + // 0xBF05 0x1021 0xC6C6 true true 0x0000 + mu_assert_int_eq(0xBF05, bit_lib_crc16(data, data_size, 0x1021, 0xC6C6, true, true, 0x0000)); + // CRC-16/KERMIT + // 0x2189 0x1021 0x0000 true true 0x0000 + mu_assert_int_eq(0x2189, bit_lib_crc16(data, data_size, 0x1021, 0x0000, true, true, 0x0000)); + // CRC-16/MODBUS + // 0x4B37 0x8005 0xFFFF true true 0x0000 + mu_assert_int_eq(0x4B37, bit_lib_crc16(data, data_size, 0x8005, 0xFFFF, true, true, 0x0000)); + // CRC-16/X-25 + // 0x906E 0x1021 0xFFFF true true 0xFFFF + mu_assert_int_eq(0x906E, bit_lib_crc16(data, data_size, 0x1021, 0xFFFF, true, true, 0xFFFF)); + // CRC-16/XMODEM + // 0x31C3 0x1021 0x0000 false false 0x0000 + mu_assert_int_eq(0x31C3, bit_lib_crc16(data, data_size, 0x1021, 0x0000, false, false, 0x0000)); +} + +MU_TEST_SUITE(test_bit_lib) { + MU_RUN_TEST(test_bit_lib_increment_index); + MU_RUN_TEST(test_bit_lib_is_set); + MU_RUN_TEST(test_bit_lib_push); + MU_RUN_TEST(test_bit_lib_set_bit); + MU_RUN_TEST(test_bit_lib_set_bits); + MU_RUN_TEST(test_bit_lib_get_bit); + MU_RUN_TEST(test_bit_lib_get_bits); + MU_RUN_TEST(test_bit_lib_get_bits_16); + MU_RUN_TEST(test_bit_lib_get_bits_32); + MU_RUN_TEST(test_bit_lib_test_parity_u32); + MU_RUN_TEST(test_bit_lib_test_parity); + MU_RUN_TEST(test_bit_lib_remove_bit_every_nth); + MU_RUN_TEST(test_bit_lib_copy_bits); + MU_RUN_TEST(test_bit_lib_reverse_bits); + MU_RUN_TEST(test_bit_lib_get_bit_count); + MU_RUN_TEST(test_bit_lib_reverse_16_fast); + MU_RUN_TEST(test_bit_lib_crc16); +} + +int run_minunit_test_bit_lib() { + MU_RUN_SUITE(test_bit_lib); + return MU_EXIT_CODE; +} \ No newline at end of file diff --git a/applications/unit_tests/lfrfid/lfrfid_protocols.c b/applications/unit_tests/lfrfid/lfrfid_protocols.c new file mode 100644 index 0000000000..4401cbb4d3 --- /dev/null +++ b/applications/unit_tests/lfrfid/lfrfid_protocols.c @@ -0,0 +1,464 @@ +#include +#include "../minunit.h" +#include +#include +#include + +#define LF_RFID_READ_TIMING_MULTIPLIER 8 + +#define EM_TEST_DATA \ + { 0x58, 0x00, 0x85, 0x64, 0x02 } +#define EM_TEST_DATA_SIZE 5 +#define EM_TEST_EMULATION_TIMINGS_COUNT (64 * 2) + +const int8_t em_test_timings[EM_TEST_EMULATION_TIMINGS_COUNT] = { + 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, -32, + 32, 32, -32, -32, 32, 32, -32, -32, 32, 32, -32, -32, 32, -32, 32, -32, 32, 32, -32, + -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, + 32, 32, -32, -32, 32, -32, 32, -32, 32, 32, -32, -32, 32, 32, -32, -32, 32, 32, -32, + -32, 32, -32, 32, 32, -32, 32, -32, -32, 32, -32, 32, -32, 32, 32, -32, -32, 32, -32, + 32, 32, -32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, 32, -32, + -32, 32, 32, -32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, +}; + +#define HID10301_TEST_DATA \ + { 0x8D, 0x48, 0xA8 } +#define HID10301_TEST_DATA_SIZE 3 +#define HID10301_TEST_EMULATION_TIMINGS_COUNT (541 * 2) + +const int8_t hid10301_test_timings[HID10301_TEST_EMULATION_TIMINGS_COUNT] = { + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, + 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, + 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, + 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, + 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, + 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, + 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, + 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, + 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, + 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, + 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, +}; + +#define IOPROX_XSF_TEST_DATA \ + { 0x65, 0x01, 0x05, 0x39 } +#define IOPROX_XSF_TEST_DATA_SIZE 4 +#define IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT (468 * 2) + +const int8_t ioprox_xsf_test_timings[IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT] = { + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, + 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, + 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, + 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, + 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, + 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, +}; + +#define INDALA26_EMULATION_TIMINGS_COUNT (1024 * 2) +#define INDALA26_TEST_DATA \ + { 0x3B, 0x73, 0x64, 0xA8 } +#define INDALA26_TEST_DATA_SIZE 4 + +const int8_t indala26_test_timings[INDALA26_EMULATION_TIMINGS_COUNT] = { + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, + 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 1, +}; + +MU_TEST(test_lfrfid_protocol_em_read_simple) { + ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); + mu_assert_int_eq(EM_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolEM4100)); + mu_assert_string_eq("EM4100", protocol_dict_get_name(dict, LFRFIDProtocolEM4100)); + mu_assert_string_eq("EM-Micro", protocol_dict_get_manufacturer(dict, LFRFIDProtocolEM4100)); + + const uint8_t data[EM_TEST_DATA_SIZE] = EM_TEST_DATA; + + protocol_dict_decoders_start(dict); + + ProtocolId protocol = PROTOCOL_NO; + PulseGlue* pulse_glue = pulse_glue_alloc(); + + for(size_t i = 0; i < EM_TEST_EMULATION_TIMINGS_COUNT * 10; i++) { + bool pulse_pop = pulse_glue_push( + pulse_glue, + em_test_timings[i % EM_TEST_EMULATION_TIMINGS_COUNT] >= 0, + abs(em_test_timings[i % EM_TEST_EMULATION_TIMINGS_COUNT]) * + LF_RFID_READ_TIMING_MULTIPLIER); + + if(pulse_pop) { + uint32_t length, period; + pulse_glue_pop(pulse_glue, &length, &period); + + protocol = protocol_dict_decoders_feed(dict, true, period); + if(protocol != PROTOCOL_NO) break; + + protocol = protocol_dict_decoders_feed(dict, false, length - period); + if(protocol != PROTOCOL_NO) break; + } + } + + pulse_glue_free(pulse_glue); + + mu_assert_int_eq(LFRFIDProtocolEM4100, protocol); + uint8_t received_data[EM_TEST_DATA_SIZE] = {0}; + protocol_dict_get_data(dict, protocol, received_data, EM_TEST_DATA_SIZE); + + mu_assert_mem_eq(data, received_data, EM_TEST_DATA_SIZE); + + protocol_dict_free(dict); +} + +MU_TEST(test_lfrfid_protocol_em_emulate_simple) { + ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); + mu_assert_int_eq(EM_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolEM4100)); + mu_assert_string_eq("EM4100", protocol_dict_get_name(dict, LFRFIDProtocolEM4100)); + mu_assert_string_eq("EM-Micro", protocol_dict_get_manufacturer(dict, LFRFIDProtocolEM4100)); + + const uint8_t data[EM_TEST_DATA_SIZE] = EM_TEST_DATA; + + protocol_dict_set_data(dict, LFRFIDProtocolEM4100, data, EM_TEST_DATA_SIZE); + mu_check(protocol_dict_encoder_start(dict, LFRFIDProtocolEM4100)); + + for(size_t i = 0; i < EM_TEST_EMULATION_TIMINGS_COUNT; i++) { + LevelDuration level_duration = protocol_dict_encoder_yield(dict, LFRFIDProtocolEM4100); + + if(level_duration_get_level(level_duration)) { + mu_assert_int_eq(em_test_timings[i], level_duration_get_duration(level_duration)); + } else { + mu_assert_int_eq(em_test_timings[i], -level_duration_get_duration(level_duration)); + } + } + + protocol_dict_free(dict); +} + +MU_TEST(test_lfrfid_protocol_h10301_read_simple) { + ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); + mu_assert_int_eq( + HID10301_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolH10301)); + mu_assert_string_eq("H10301", protocol_dict_get_name(dict, LFRFIDProtocolH10301)); + mu_assert_string_eq("HID", protocol_dict_get_manufacturer(dict, LFRFIDProtocolH10301)); + + const uint8_t data[HID10301_TEST_DATA_SIZE] = HID10301_TEST_DATA; + + protocol_dict_decoders_start(dict); + + ProtocolId protocol = PROTOCOL_NO; + PulseGlue* pulse_glue = pulse_glue_alloc(); + + for(size_t i = 0; i < HID10301_TEST_EMULATION_TIMINGS_COUNT * 10; i++) { + bool pulse_pop = pulse_glue_push( + pulse_glue, + hid10301_test_timings[i % HID10301_TEST_EMULATION_TIMINGS_COUNT] >= 0, + abs(hid10301_test_timings[i % HID10301_TEST_EMULATION_TIMINGS_COUNT]) * + LF_RFID_READ_TIMING_MULTIPLIER); + + if(pulse_pop) { + uint32_t length, period; + pulse_glue_pop(pulse_glue, &length, &period); + + protocol = protocol_dict_decoders_feed(dict, true, period); + if(protocol != PROTOCOL_NO) break; + + protocol = protocol_dict_decoders_feed(dict, false, length - period); + if(protocol != PROTOCOL_NO) break; + } + } + + pulse_glue_free(pulse_glue); + + mu_assert_int_eq(LFRFIDProtocolH10301, protocol); + uint8_t received_data[HID10301_TEST_DATA_SIZE] = {0}; + protocol_dict_get_data(dict, protocol, received_data, HID10301_TEST_DATA_SIZE); + + mu_assert_mem_eq(data, received_data, HID10301_TEST_DATA_SIZE); + + protocol_dict_free(dict); +} + +MU_TEST(test_lfrfid_protocol_h10301_emulate_simple) { + ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); + mu_assert_int_eq( + HID10301_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolH10301)); + mu_assert_string_eq("H10301", protocol_dict_get_name(dict, LFRFIDProtocolH10301)); + mu_assert_string_eq("HID", protocol_dict_get_manufacturer(dict, LFRFIDProtocolH10301)); + + const uint8_t data[HID10301_TEST_DATA_SIZE] = HID10301_TEST_DATA; + + protocol_dict_set_data(dict, LFRFIDProtocolH10301, data, HID10301_TEST_DATA_SIZE); + mu_check(protocol_dict_encoder_start(dict, LFRFIDProtocolH10301)); + + for(size_t i = 0; i < HID10301_TEST_EMULATION_TIMINGS_COUNT; i++) { + LevelDuration level_duration = protocol_dict_encoder_yield(dict, LFRFIDProtocolH10301); + + if(level_duration_get_level(level_duration)) { + mu_assert_int_eq( + hid10301_test_timings[i], level_duration_get_duration(level_duration)); + } else { + mu_assert_int_eq( + hid10301_test_timings[i], -level_duration_get_duration(level_duration)); + } + } + + protocol_dict_free(dict); +} + +MU_TEST(test_lfrfid_protocol_ioprox_xsf_read_simple) { + ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); + mu_assert_int_eq( + IOPROX_XSF_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolIOProxXSF)); + mu_assert_string_eq("IoProxXSF", protocol_dict_get_name(dict, LFRFIDProtocolIOProxXSF)); + mu_assert_string_eq("Kantech", protocol_dict_get_manufacturer(dict, LFRFIDProtocolIOProxXSF)); + + const uint8_t data[IOPROX_XSF_TEST_DATA_SIZE] = IOPROX_XSF_TEST_DATA; + + protocol_dict_decoders_start(dict); + + ProtocolId protocol = PROTOCOL_NO; + PulseGlue* pulse_glue = pulse_glue_alloc(); + + for(size_t i = 0; i < IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT * 10; i++) { + bool pulse_pop = pulse_glue_push( + pulse_glue, + ioprox_xsf_test_timings[i % IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT] >= 0, + abs(ioprox_xsf_test_timings[i % IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT]) * + LF_RFID_READ_TIMING_MULTIPLIER); + + if(pulse_pop) { + uint32_t length, period; + pulse_glue_pop(pulse_glue, &length, &period); + + protocol = protocol_dict_decoders_feed(dict, true, period); + if(protocol != PROTOCOL_NO) break; + + protocol = protocol_dict_decoders_feed(dict, false, length - period); + if(protocol != PROTOCOL_NO) break; + } + } + + pulse_glue_free(pulse_glue); + + mu_assert_int_eq(LFRFIDProtocolIOProxXSF, protocol); + uint8_t received_data[IOPROX_XSF_TEST_DATA_SIZE] = {0}; + protocol_dict_get_data(dict, protocol, received_data, IOPROX_XSF_TEST_DATA_SIZE); + + mu_assert_mem_eq(data, received_data, IOPROX_XSF_TEST_DATA_SIZE); + + protocol_dict_free(dict); +} + +MU_TEST(test_lfrfid_protocol_ioprox_xsf_emulate_simple) { + ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); + mu_assert_int_eq( + IOPROX_XSF_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolIOProxXSF)); + mu_assert_string_eq("IoProxXSF", protocol_dict_get_name(dict, LFRFIDProtocolIOProxXSF)); + mu_assert_string_eq("Kantech", protocol_dict_get_manufacturer(dict, LFRFIDProtocolIOProxXSF)); + + const uint8_t data[IOPROX_XSF_TEST_DATA_SIZE] = IOPROX_XSF_TEST_DATA; + + protocol_dict_set_data(dict, LFRFIDProtocolIOProxXSF, data, IOPROX_XSF_TEST_DATA_SIZE); + mu_check(protocol_dict_encoder_start(dict, LFRFIDProtocolIOProxXSF)); + + for(size_t i = 0; i < IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT; i++) { + LevelDuration level_duration = protocol_dict_encoder_yield(dict, LFRFIDProtocolIOProxXSF); + + if(level_duration_get_level(level_duration)) { + mu_assert_int_eq( + ioprox_xsf_test_timings[i], level_duration_get_duration(level_duration)); + } else { + mu_assert_int_eq( + ioprox_xsf_test_timings[i], -level_duration_get_duration(level_duration)); + } + } + + protocol_dict_free(dict); +} + +MU_TEST(test_lfrfid_protocol_inadala26_emulate_simple) { + ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); + mu_assert_int_eq( + INDALA26_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolIndala26)); + mu_assert_string_eq("Indala26", protocol_dict_get_name(dict, LFRFIDProtocolIndala26)); + mu_assert_string_eq("Motorola", protocol_dict_get_manufacturer(dict, LFRFIDProtocolIndala26)); + + const uint8_t data[INDALA26_TEST_DATA_SIZE] = INDALA26_TEST_DATA; + + protocol_dict_set_data(dict, LFRFIDProtocolIndala26, data, INDALA26_TEST_DATA_SIZE); + mu_check(protocol_dict_encoder_start(dict, LFRFIDProtocolIndala26)); + + for(size_t i = 0; i < INDALA26_EMULATION_TIMINGS_COUNT; i++) { + LevelDuration level_duration = protocol_dict_encoder_yield(dict, LFRFIDProtocolIndala26); + + if(level_duration_get_level(level_duration)) { + mu_assert_int_eq( + indala26_test_timings[i], level_duration_get_duration(level_duration)); + } else { + mu_assert_int_eq( + indala26_test_timings[i], -level_duration_get_duration(level_duration)); + } + } + + protocol_dict_free(dict); +} + +MU_TEST_SUITE(test_lfrfid_protocols_suite) { + MU_RUN_TEST(test_lfrfid_protocol_em_read_simple); + MU_RUN_TEST(test_lfrfid_protocol_em_emulate_simple); + + MU_RUN_TEST(test_lfrfid_protocol_h10301_read_simple); + MU_RUN_TEST(test_lfrfid_protocol_h10301_emulate_simple); + + MU_RUN_TEST(test_lfrfid_protocol_ioprox_xsf_read_simple); + MU_RUN_TEST(test_lfrfid_protocol_ioprox_xsf_emulate_simple); + + MU_RUN_TEST(test_lfrfid_protocol_inadala26_emulate_simple); +} + +int run_minunit_test_lfrfid_protocols() { + MU_RUN_SUITE(test_lfrfid_protocols_suite); + return MU_EXIT_CODE; +} \ No newline at end of file diff --git a/applications/unit_tests/minunit.h b/applications/unit_tests/minunit.h index d1efd13e61..17eb7b3f13 100644 --- a/applications/unit_tests/minunit.h +++ b/applications/unit_tests/minunit.h @@ -151,46 +151,46 @@ void minunit_print_fail(const char* error); #define MU_EXIT_CODE minunit_fail /* Assertions */ -#define mu_check(test) \ - MU__SAFE_BLOCK( \ - minunit_assert++; if(!(test)) { \ - snprintf( \ - minunit_last_message, \ - MINUNIT_MESSAGE_LEN, \ - "%s failed:\n\t%s:%d: %s", \ - __func__, \ - __FILE__, \ - __LINE__, \ - #test); \ - minunit_status = 1; \ - return; \ +#define mu_check(test) \ + MU__SAFE_BLOCK( \ + minunit_assert++; if(!(test)) { \ + snprintf( \ + minunit_last_message, \ + MINUNIT_MESSAGE_LEN, \ + "%s failed:\r\n\t%s:%d: %s", \ + __func__, \ + __FILE__, \ + __LINE__, \ + #test); \ + minunit_status = 1; \ + return; \ } else { minunit_print_progress(); }) -#define mu_fail(message) \ - MU__SAFE_BLOCK(minunit_assert++; snprintf( \ - minunit_last_message, \ - MINUNIT_MESSAGE_LEN, \ - "%s failed:\n\t%s:%d: %s", \ - __func__, \ - __FILE__, \ - __LINE__, \ - message); \ - minunit_status = 1; \ +#define mu_fail(message) \ + MU__SAFE_BLOCK(minunit_assert++; snprintf( \ + minunit_last_message, \ + MINUNIT_MESSAGE_LEN, \ + "%s failed:\r\n\t%s:%d: %s", \ + __func__, \ + __FILE__, \ + __LINE__, \ + message); \ + minunit_status = 1; \ return;) -#define mu_assert(test, message) \ - MU__SAFE_BLOCK( \ - minunit_assert++; if(!(test)) { \ - snprintf( \ - minunit_last_message, \ - MINUNIT_MESSAGE_LEN, \ - "%s failed:\n\t%s:%d: %s", \ - __func__, \ - __FILE__, \ - __LINE__, \ - message); \ - minunit_status = 1; \ - return; \ +#define mu_assert(test, message) \ + MU__SAFE_BLOCK( \ + minunit_assert++; if(!(test)) { \ + snprintf( \ + minunit_last_message, \ + MINUNIT_MESSAGE_LEN, \ + "%s failed:\r\n\t%s:%d: %s", \ + __func__, \ + __FILE__, \ + __LINE__, \ + message); \ + minunit_status = 1; \ + return; \ } else { minunit_print_progress(); }) #define mu_assert_int_eq(expected, result) \ @@ -201,7 +201,7 @@ void minunit_print_fail(const char* error); snprintf( \ minunit_last_message, \ MINUNIT_MESSAGE_LEN, \ - "%s failed:\n\t%s:%d: %d expected but was %d", \ + "%s failed:\r\n\t%s:%d: %d expected but was %d", \ __func__, \ __FILE__, \ __LINE__, \ @@ -219,7 +219,7 @@ void minunit_print_fail(const char* error); snprintf( \ minunit_last_message, \ MINUNIT_MESSAGE_LEN, \ - "%s failed:\n\t%s:%d: expected different results but both were %d", \ + "%s failed:\r\n\t%s:%d: expected different results but both were %d", \ __func__, \ __FILE__, \ __LINE__, \ @@ -236,7 +236,7 @@ void minunit_print_fail(const char* error); snprintf( \ minunit_last_message, \ MINUNIT_MESSAGE_LEN, \ - "%s failed:\n\t%s:%d: %d <= %d", \ + "%s failed:\r\n\t%s:%d: %d <= %d", \ __func__, \ __FILE__, \ __LINE__, \ @@ -254,7 +254,7 @@ void minunit_print_fail(const char* error); snprintf( \ minunit_last_message, \ MINUNIT_MESSAGE_LEN, \ - "%s failed:\n\t%s:%d: %d >= %d", \ + "%s failed:\r\n\t%s:%d: %d >= %d", \ __func__, \ __FILE__, \ __LINE__, \ @@ -274,7 +274,7 @@ void minunit_print_fail(const char* error); snprintf( \ minunit_last_message, \ MINUNIT_MESSAGE_LEN, \ - "%s failed:\n\t%s:%d: %d was not between (inclusive) %d and %d", \ + "%s failed:\r\n\t%s:%d: %d was not between (inclusive) %d and %d", \ __func__, \ __FILE__, \ __LINE__, \ @@ -302,7 +302,7 @@ void minunit_print_fail(const char* error); snprintf( \ minunit_last_message, \ MINUNIT_MESSAGE_LEN, \ - "%s failed:\n\t%s:%d: expected to be one of %s but was %d", \ + "%s failed:\r\n\t%s:%d: expected to be one of %s but was %d", \ __func__, \ __FILE__, \ __LINE__, \ @@ -321,7 +321,7 @@ void minunit_print_fail(const char* error); snprintf( \ minunit_last_message, \ MINUNIT_MESSAGE_LEN, \ - "%s failed:\n\t%s:%d: %.*g expected but was %.*g", \ + "%s failed:\r\n\t%s:%d: %.*g expected but was %.*g", \ __func__, \ __FILE__, \ __LINE__, \ @@ -341,7 +341,7 @@ void minunit_print_fail(const char* error); snprintf( \ minunit_last_message, \ MINUNIT_MESSAGE_LEN, \ - "%s failed:\n\t%s:%d: %f <= %f", \ + "%s failed:\r\n\t%s:%d: %f <= %f", \ __func__, \ __FILE__, \ __LINE__, \ @@ -359,7 +359,7 @@ void minunit_print_fail(const char* error); snprintf( \ minunit_last_message, \ MINUNIT_MESSAGE_LEN, \ - "%s failed:\n\t%s:%d: %f >= %f", \ + "%s failed:\r\n\t%s:%d: %f >= %f", \ __func__, \ __FILE__, \ __LINE__, \ @@ -379,7 +379,7 @@ void minunit_print_fail(const char* error); snprintf( \ minunit_last_message, \ MINUNIT_MESSAGE_LEN, \ - "%s failed:\n\t%s:%d: %f was not between (inclusive) %f and %f", \ + "%s failed:\r\n\t%s:%d: %f was not between (inclusive) %f and %f", \ __func__, \ __FILE__, \ __LINE__, \ @@ -400,7 +400,7 @@ void minunit_print_fail(const char* error); snprintf( \ minunit_last_message, \ MINUNIT_MESSAGE_LEN, \ - "%s failed:\n\t%s:%d: '%s' expected but was '%s'", \ + "%s failed:\r\n\t%s:%d: '%s' expected but was '%s'", \ __func__, \ __FILE__, \ __LINE__, \ @@ -410,13 +410,41 @@ void minunit_print_fail(const char* error); return; \ } else { minunit_print_progress(); }) +#define mu_assert_mem_eq(expected, result, size) \ + MU__SAFE_BLOCK( \ + const void* minunit_tmp_e = expected; const void* minunit_tmp_r = result; \ + minunit_assert++; \ + if(memcmp(minunit_tmp_e, minunit_tmp_r, size)) { \ + snprintf( \ + minunit_last_message, \ + MINUNIT_MESSAGE_LEN, \ + "%s failed:\r\n\t%s:%d: mem not equal\r\n\tEXP RES", \ + __func__, \ + __FILE__, \ + __LINE__); \ + for(size_t __index = 0; __index < size; __index++) { \ + if(strlen(minunit_last_message) > MINUNIT_MESSAGE_LEN - 20) break; \ + uint8_t __e = ((uint8_t*)minunit_tmp_e)[__index]; \ + uint8_t __r = ((uint8_t*)minunit_tmp_r)[__index]; \ + snprintf( \ + minunit_last_message + strlen(minunit_last_message), \ + MINUNIT_MESSAGE_LEN - strlen(minunit_last_message), \ + "\r\n\t%02X %s %02X", \ + __e, \ + ((__e == __r) ? ".." : "!="), \ + __r); \ + } \ + minunit_status = 1; \ + return; \ + } else { minunit_print_progress(); }) + #define mu_assert_null(result) \ MU__SAFE_BLOCK( \ minunit_assert++; if(result == NULL) { minunit_print_progress(); } else { \ snprintf( \ minunit_last_message, \ MINUNIT_MESSAGE_LEN, \ - "%s failed:\n\t%s:%d: Expected result was not NULL", \ + "%s failed:\r\n\t%s:%d: Expected result was not NULL", \ __func__, \ __FILE__, \ __LINE__); \ @@ -430,7 +458,7 @@ void minunit_print_fail(const char* error); snprintf( \ minunit_last_message, \ MINUNIT_MESSAGE_LEN, \ - "%s failed:\n\t%s:%d: Expected result was not NULL", \ + "%s failed:\r\n\t%s:%d: Expected result was not NULL", \ __func__, \ __FILE__, \ __LINE__); \ @@ -438,32 +466,32 @@ void minunit_print_fail(const char* error); return; \ }) -#define mu_assert_pointers_eq(pointer1, pointer2) \ - MU__SAFE_BLOCK( \ - minunit_assert++; if(pointer1 == pointer2) { minunit_print_progress(); } else { \ - snprintf( \ - minunit_last_message, \ - MINUNIT_MESSAGE_LEN, \ - "%s failed:\n\t%s:%d: Expected the pointers to point to the same memory location", \ - __func__, \ - __FILE__, \ - __LINE__); \ - minunit_status = 1; \ - return; \ +#define mu_assert_pointers_eq(pointer1, pointer2) \ + MU__SAFE_BLOCK( \ + minunit_assert++; if(pointer1 == pointer2) { minunit_print_progress(); } else { \ + snprintf( \ + minunit_last_message, \ + MINUNIT_MESSAGE_LEN, \ + "%s failed:\r\n\t%s:%d: Expected the pointers to point to the same memory location", \ + __func__, \ + __FILE__, \ + __LINE__); \ + minunit_status = 1; \ + return; \ }) -#define mu_assert_pointers_not_eq(pointer1, pointer2) \ - MU__SAFE_BLOCK( \ - minunit_assert++; if(pointer1 != pointer2) { minunit_print_progress(); } else { \ - snprintf( \ - minunit_last_message, \ - MINUNIT_MESSAGE_LEN, \ - "%s failed:\n\t%s:%d: Expected the pointers to point to the same memory location", \ - __func__, \ - __FILE__, \ - __LINE__); \ - minunit_status = 1; \ - return; \ +#define mu_assert_pointers_not_eq(pointer1, pointer2) \ + MU__SAFE_BLOCK( \ + minunit_assert++; if(pointer1 != pointer2) { minunit_print_progress(); } else { \ + snprintf( \ + minunit_last_message, \ + MINUNIT_MESSAGE_LEN, \ + "%s failed:\r\n\t%s:%d: Expected the pointers to point to the same memory location", \ + __func__, \ + __FILE__, \ + __LINE__); \ + minunit_status = 1; \ + return; \ }) /* diff --git a/applications/unit_tests/protocol_dict/protocol_dict_test.c b/applications/unit_tests/protocol_dict/protocol_dict_test.c new file mode 100644 index 0000000000..73e77ec900 --- /dev/null +++ b/applications/unit_tests/protocol_dict/protocol_dict_test.c @@ -0,0 +1,222 @@ +#include +#include "../minunit.h" +#include + +typedef enum { + TestDictProtocol0, + TestDictProtocol1, + + TestDictProtocolMax, +} TestDictProtocols; + +/*********************** PROTOCOL 0 START ***********************/ + +typedef struct { + uint32_t data; + size_t encoder_counter; +} Protocol0Data; + +static const uint32_t protocol_0_decoder_result = 0xDEADBEEF; + +static void* protocol_0_alloc() { + void* data = malloc(sizeof(Protocol0Data)); + return data; +} + +static void protocol_0_free(Protocol0Data* data) { + free(data); +} + +static uint8_t* protocol_0_get_data(Protocol0Data* data) { + return (uint8_t*)&data->data; +} + +static void protocol_0_decoder_start(Protocol0Data* data) { + data->data = 0; +} + +static bool protocol_0_decoder_feed(Protocol0Data* data, bool level, uint32_t duration) { + if(level && duration == 666) { + data->data = protocol_0_decoder_result; + return true; + } else { + return false; + } +} + +static bool protocol_0_encoder_start(Protocol0Data* data) { + data->encoder_counter = 0; + return true; +} + +static LevelDuration protocol_0_encoder_yield(Protocol0Data* data) { + data->encoder_counter++; + return level_duration_make(data->encoder_counter % 2, data->data); +} + +/*********************** PROTOCOL 1 START ***********************/ + +typedef struct { + uint64_t data; + size_t encoder_counter; +} Protocol1Data; + +static const uint64_t protocol_1_decoder_result = 0x1234567890ABCDEF; + +static void* protocol_1_alloc() { + void* data = malloc(sizeof(Protocol1Data)); + return data; +} + +static void protocol_1_free(Protocol1Data* data) { + free(data); +} + +static uint8_t* protocol_1_get_data(Protocol1Data* data) { + return (uint8_t*)&data->data; +} + +static void protocol_1_decoder_start(Protocol1Data* data) { + data->data = 0; +} + +static bool protocol_1_decoder_feed(Protocol1Data* data, bool level, uint32_t duration) { + if(level && duration == 543) { + data->data = 0x1234567890ABCDEF; + return true; + } else { + return false; + } +} + +static bool protocol_1_encoder_start(Protocol1Data* data) { + data->encoder_counter = 0; + return true; +} + +static LevelDuration protocol_1_encoder_yield(Protocol1Data* data) { + data->encoder_counter++; + return level_duration_make(!(data->encoder_counter % 2), 100); +} + +/*********************** PROTOCOLS DESCRIPTION ***********************/ +static const ProtocolBase protocol_0 = { + .name = "Protocol 0", + .manufacturer = "Manufacturer 0", + .data_size = 4, + .alloc = (ProtocolAlloc)protocol_0_alloc, + .free = (ProtocolFree)protocol_0_free, + .get_data = (ProtocolGetData)protocol_0_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_0_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_0_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_0_encoder_start, + .yield = (ProtocolEncoderYield)protocol_0_encoder_yield, + }, +}; + +static const ProtocolBase protocol_1 = { + .name = "Protocol 1", + .manufacturer = "Manufacturer 1", + .data_size = 8, + .alloc = (ProtocolAlloc)protocol_1_alloc, + .free = (ProtocolFree)protocol_1_free, + .get_data = (ProtocolGetData)protocol_1_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_1_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_1_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_1_encoder_start, + .yield = (ProtocolEncoderYield)protocol_1_encoder_yield, + }, +}; + +static const ProtocolBase* test_protocols_base[] = { + [TestDictProtocol0] = &protocol_0, + [TestDictProtocol1] = &protocol_1, +}; + +MU_TEST(test_protocol_dict) { + ProtocolDict* dict = protocol_dict_alloc(test_protocols_base, TestDictProtocolMax); + size_t max_data_size = protocol_dict_get_max_data_size(dict); + mu_assert_int_eq(8, max_data_size); + uint8_t* data = malloc(max_data_size); + + protocol_dict_decoders_start(dict); + ProtocolId protocol_id = PROTOCOL_NO; + + for(size_t i = 0; i < 100; i++) { + protocol_id = protocol_dict_decoders_feed(dict, i % 2, 100); + mu_assert_int_eq(PROTOCOL_NO, protocol_id); + } + + // trigger protocol 1 + protocol_id = protocol_dict_decoders_feed(dict, true, 543); + mu_assert_int_eq(TestDictProtocol1, protocol_id); + + mu_assert_string_eq("Protocol 1", protocol_dict_get_name(dict, protocol_id)); + mu_assert_string_eq("Manufacturer 1", protocol_dict_get_manufacturer(dict, protocol_id)); + + size_t data_size = protocol_dict_get_data_size(dict, protocol_id); + mu_assert_int_eq(8, data_size); + + protocol_dict_get_data(dict, protocol_id, data, data_size); + mu_assert_mem_eq(&protocol_1_decoder_result, data, data_size); + + // trigger protocol 0 + protocol_id = protocol_dict_decoders_feed(dict, true, 666); + mu_assert_int_eq(TestDictProtocol0, protocol_id); + + mu_assert_string_eq("Protocol 0", protocol_dict_get_name(dict, protocol_id)); + mu_assert_string_eq("Manufacturer 0", protocol_dict_get_manufacturer(dict, protocol_id)); + + data_size = protocol_dict_get_data_size(dict, protocol_id); + mu_assert_int_eq(4, data_size); + + protocol_dict_get_data(dict, protocol_id, data, data_size); + mu_assert_mem_eq(&protocol_0_decoder_result, data, data_size); + + protocol_dict_decoders_start(dict); + + protocol_id = TestDictProtocol0; + + const uint8_t protocol_0_test_data[4] = {100, 0, 0, 0}; + protocol_dict_set_data(dict, protocol_id, protocol_0_test_data, 4); + + mu_check(protocol_dict_encoder_start(dict, protocol_id)); + + LevelDuration level; + level = protocol_dict_encoder_yield(dict, protocol_id); + mu_assert_int_eq(true, level_duration_get_level(level)); + mu_assert_int_eq(100, level_duration_get_duration(level)); + level = protocol_dict_encoder_yield(dict, protocol_id); + mu_assert_int_eq(false, level_duration_get_level(level)); + mu_assert_int_eq(100, level_duration_get_duration(level)); + level = protocol_dict_encoder_yield(dict, protocol_id); + mu_assert_int_eq(true, level_duration_get_level(level)); + mu_assert_int_eq(100, level_duration_get_duration(level)); + + mu_check(protocol_dict_encoder_start(dict, protocol_id)); + level = protocol_dict_encoder_yield(dict, protocol_id); + mu_assert_int_eq(true, level_duration_get_level(level)); + mu_assert_int_eq(100, level_duration_get_duration(level)); + + protocol_dict_free(dict); + free(data); +} + +MU_TEST_SUITE(test_protocol_dict_suite) { + MU_RUN_TEST(test_protocol_dict); +} + +int run_minunit_test_protocol_dict() { + MU_RUN_SUITE(test_protocol_dict_suite); + return MU_EXIT_CODE; +} \ No newline at end of file diff --git a/applications/unit_tests/test_index.c b/applications/unit_tests/test_index.c index e528224651..81d891b2ba 100644 --- a/applications/unit_tests/test_index.c +++ b/applications/unit_tests/test_index.c @@ -19,7 +19,10 @@ int run_minunit_test_stream(); int run_minunit_test_storage(); int run_minunit_test_subghz(); int run_minunit_test_dirwalk(); +int run_minunit_test_protocol_dict(); +int run_minunit_test_lfrfid_protocols(); int run_minunit_test_nfc(); +int run_minunit_test_bit_lib(); typedef int (*UnitTestEntry)(); @@ -39,6 +42,9 @@ const UnitTest unit_tests[] = { {.name = "subghz", .entry = run_minunit_test_subghz}, {.name = "infrared", .entry = run_minunit_test_infrared}, {.name = "nfc", .entry = run_minunit_test_nfc}, + {.name = "protocol_dict", .entry = run_minunit_test_protocol_dict}, + {.name = "lfrfid", .entry = run_minunit_test_lfrfid_protocols}, + {.name = "bit_lib", .entry = run_minunit_test_bit_lib}, }; void minunit_print_progress() { diff --git a/applications/unit_tests/varint/varint_test.c b/applications/unit_tests/varint/varint_test.c new file mode 100644 index 0000000000..8faab13688 --- /dev/null +++ b/applications/unit_tests/varint/varint_test.c @@ -0,0 +1,88 @@ +#include +#include +#include "../minunit.h" +#include +#include + +MU_TEST(test_varint_basic_u) { + mu_assert_int_eq(1, varint_uint32_length(0)); + mu_assert_int_eq(5, varint_uint32_length(UINT32_MAX)); + + uint8_t data[8] = {}; + uint32_t out_value; + + mu_assert_int_eq(1, varint_uint32_pack(0, data)); + mu_assert_int_eq(1, varint_uint32_unpack(&out_value, data, 8)); + mu_assert_int_eq(0, out_value); + + mu_assert_int_eq(5, varint_uint32_pack(UINT32_MAX, data)); + mu_assert_int_eq(5, varint_uint32_unpack(&out_value, data, 8)); + mu_assert_int_eq(UINT32_MAX, out_value); +} + +MU_TEST(test_varint_basic_i) { + mu_assert_int_eq(5, varint_int32_length(INT32_MIN / 2)); + mu_assert_int_eq(1, varint_int32_length(0)); + mu_assert_int_eq(5, varint_int32_length(INT32_MAX / 2)); + + mu_assert_int_eq(2, varint_int32_length(127)); + mu_assert_int_eq(2, varint_int32_length(-127)); + + uint8_t data[8] = {}; + int32_t out_value; + mu_assert_int_eq(1, varint_int32_pack(0, data)); + mu_assert_int_eq(1, varint_int32_unpack(&out_value, data, 8)); + mu_assert_int_eq(0, out_value); + + mu_assert_int_eq(2, varint_int32_pack(127, data)); + mu_assert_int_eq(2, varint_int32_unpack(&out_value, data, 8)); + mu_assert_int_eq(127, out_value); + + mu_assert_int_eq(2, varint_int32_pack(-127, data)); + mu_assert_int_eq(2, varint_int32_unpack(&out_value, data, 8)); + mu_assert_int_eq(-127, out_value); + + mu_assert_int_eq(5, varint_int32_pack(INT32_MAX, data)); + mu_assert_int_eq(5, varint_int32_unpack(&out_value, data, 8)); + mu_assert_int_eq(INT32_MAX, out_value); + + mu_assert_int_eq(5, varint_int32_pack(INT32_MIN / 2 + 1, data)); + mu_assert_int_eq(5, varint_int32_unpack(&out_value, data, 8)); + mu_assert_int_eq(INT32_MIN / 2 + 1, out_value); +} + +MU_TEST(test_varint_rand_u) { + uint8_t data[8] = {}; + uint32_t out_value; + + for(size_t i = 0; i < 200000; i++) { + uint32_t rand_value = rand(); + mu_assert_int_eq( + varint_uint32_pack(rand_value, data), varint_uint32_unpack(&out_value, data, 8)); + mu_assert_int_eq(rand_value, out_value); + } +} + +MU_TEST(test_varint_rand_i) { + uint8_t data[8] = {}; + int32_t out_value; + + for(size_t i = 0; i < 200000; i++) { + int32_t rand_value = rand() + (INT32_MIN / 2 + 1); + mu_assert_int_eq( + varint_int32_pack(rand_value, data), varint_int32_unpack(&out_value, data, 8)); + mu_assert_int_eq(rand_value, out_value); + } +} + +MU_TEST_SUITE(test_varint_suite) { + MU_RUN_TEST(test_varint_basic_u); + MU_RUN_TEST(test_varint_basic_i); + MU_RUN_TEST(test_varint_rand_u); + MU_RUN_TEST(test_varint_rand_i); +} + +int run_minunit_test_varint() { + MU_RUN_SUITE(test_varint_suite); + return MU_EXIT_CODE; +} \ No newline at end of file diff --git a/applications/updater/util/update_task.c b/applications/updater/util/update_task.c index 6864076d68..b047731977 100644 --- a/applications/updater/util/update_task.c +++ b/applications/updater/util/update_task.c @@ -170,8 +170,7 @@ static bool update_task_check_file_exists(UpdateTask* update_task, string_t file string_t tmp_path; string_init_set(tmp_path, update_task->update_path); path_append(tmp_path, string_get_cstr(filename)); - bool exists = - (storage_common_stat(update_task->storage, string_get_cstr(tmp_path), NULL) == FSE_OK); + bool exists = storage_file_exists(update_task->storage, string_get_cstr(tmp_path)); string_clear(tmp_path); return exists; } diff --git a/firmware.scons b/firmware.scons index 745543070c..f47e9ff265 100644 --- a/firmware.scons +++ b/firmware.scons @@ -200,6 +200,7 @@ fwelf = fwenv["FW_ELF"] = fwenv.Program( "misc", "mbedtls", "loclass", + "lfrfid", # 2nd round "flipperformat", "toolbox", diff --git a/firmware/targets/f7/furi_hal/furi_hal_rfid.c b/firmware/targets/f7/furi_hal/furi_hal_rfid.c index 507c53bfe1..0ade85e0af 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rfid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_rfid.c @@ -6,6 +6,7 @@ #include #include +#include #define FURI_HAL_RFID_READ_TIMER TIM1 #define FURI_HAL_RFID_READ_TIMER_CHANNEL LL_TIM_CHANNEL_CH1N @@ -16,8 +17,14 @@ #define FURI_HAL_RFID_EMULATE_TIMER_IRQ FuriHalInterruptIdTIM2 #define FURI_HAL_RFID_EMULATE_TIMER_CHANNEL LL_TIM_CHANNEL_CH3 +#define RFID_CAPTURE_TIM TIM2 +#define RFID_CAPTURE_IND_CH LL_TIM_CHANNEL_CH3 +#define RFID_CAPTURE_DIR_CH LL_TIM_CHANNEL_CH4 + typedef struct { FuriHalRfidEmulateCallback callback; + FuriHalRfidDMACallback dma_callback; + FuriHalRfidReadCaptureCallback read_capture_callback; void* context; } FuriHalRfid; @@ -212,6 +219,185 @@ void furi_hal_rfid_tim_emulate_stop() { furi_hal_interrupt_set_isr(FURI_HAL_RFID_EMULATE_TIMER_IRQ, NULL, NULL); } +static void furi_hal_capture_dma_isr(void* context) { + UNUSED(context); + + // Channel 3, positive level + if(LL_TIM_IsActiveFlag_CC3(RFID_CAPTURE_TIM)) { + LL_TIM_ClearFlag_CC3(RFID_CAPTURE_TIM); + furi_hal_rfid->read_capture_callback( + true, LL_TIM_IC_GetCaptureCH3(RFID_CAPTURE_TIM), furi_hal_rfid->context); + } + + // Channel 4, overall level + if(LL_TIM_IsActiveFlag_CC4(RFID_CAPTURE_TIM)) { + LL_TIM_ClearFlag_CC4(RFID_CAPTURE_TIM); + LL_TIM_SetCounter(RFID_CAPTURE_TIM, 0); + furi_hal_rfid->read_capture_callback( + false, LL_TIM_IC_GetCaptureCH4(RFID_CAPTURE_TIM), furi_hal_rfid->context); + } +} + +void furi_hal_rfid_tim_read_capture_start(FuriHalRfidReadCaptureCallback callback, void* context) { + FURI_CRITICAL_ENTER(); + LL_TIM_DeInit(RFID_CAPTURE_TIM); + FURI_CRITICAL_EXIT(); + + furi_assert(furi_hal_rfid); + + furi_hal_rfid->read_capture_callback = callback; + furi_hal_rfid->context = context; + + // Timer: base + LL_TIM_InitTypeDef TIM_InitStruct = {0}; + TIM_InitStruct.Prescaler = 64 - 1; + TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; + TIM_InitStruct.Autoreload = UINT32_MAX; + TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; + LL_TIM_Init(RFID_CAPTURE_TIM, &TIM_InitStruct); + + // Timer: advanced + LL_TIM_SetClockSource(RFID_CAPTURE_TIM, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_DisableARRPreload(RFID_CAPTURE_TIM); + LL_TIM_SetTriggerInput(RFID_CAPTURE_TIM, LL_TIM_TS_TI2FP2); + LL_TIM_SetSlaveMode(RFID_CAPTURE_TIM, LL_TIM_SLAVEMODE_DISABLED); + LL_TIM_SetTriggerOutput(RFID_CAPTURE_TIM, LL_TIM_TRGO_RESET); + LL_TIM_EnableMasterSlaveMode(RFID_CAPTURE_TIM); + LL_TIM_DisableDMAReq_TRIG(RFID_CAPTURE_TIM); + LL_TIM_DisableIT_TRIG(RFID_CAPTURE_TIM); + LL_TIM_SetRemap(RFID_CAPTURE_TIM, LL_TIM_TIM2_TI4_RMP_COMP1); + + // Timer: channel 3 indirect + LL_TIM_IC_SetActiveInput(RFID_CAPTURE_TIM, RFID_CAPTURE_IND_CH, LL_TIM_ACTIVEINPUT_INDIRECTTI); + LL_TIM_IC_SetPrescaler(RFID_CAPTURE_TIM, RFID_CAPTURE_IND_CH, LL_TIM_ICPSC_DIV1); + LL_TIM_IC_SetPolarity(RFID_CAPTURE_TIM, RFID_CAPTURE_IND_CH, LL_TIM_IC_POLARITY_FALLING); + LL_TIM_IC_SetFilter(RFID_CAPTURE_TIM, RFID_CAPTURE_IND_CH, LL_TIM_IC_FILTER_FDIV1); + + // Timer: channel 4 direct + LL_TIM_IC_SetActiveInput(RFID_CAPTURE_TIM, RFID_CAPTURE_DIR_CH, LL_TIM_ACTIVEINPUT_DIRECTTI); + LL_TIM_IC_SetPrescaler(RFID_CAPTURE_TIM, RFID_CAPTURE_DIR_CH, LL_TIM_ICPSC_DIV1); + LL_TIM_IC_SetPolarity(RFID_CAPTURE_TIM, RFID_CAPTURE_DIR_CH, LL_TIM_IC_POLARITY_RISING); + LL_TIM_IC_SetFilter(RFID_CAPTURE_TIM, RFID_CAPTURE_DIR_CH, LL_TIM_IC_FILTER_FDIV1); + + furi_hal_interrupt_set_isr(FURI_HAL_RFID_EMULATE_TIMER_IRQ, furi_hal_capture_dma_isr, NULL); + + LL_TIM_EnableIT_CC3(RFID_CAPTURE_TIM); + LL_TIM_EnableIT_CC4(RFID_CAPTURE_TIM); + LL_TIM_CC_EnableChannel(RFID_CAPTURE_TIM, RFID_CAPTURE_IND_CH); + LL_TIM_CC_EnableChannel(RFID_CAPTURE_TIM, RFID_CAPTURE_DIR_CH); + LL_TIM_SetCounter(RFID_CAPTURE_TIM, 0); + LL_TIM_EnableCounter(RFID_CAPTURE_TIM); + + furi_hal_rfid_comp_start(); +} + +void furi_hal_rfid_tim_read_capture_stop() { + furi_hal_rfid_comp_stop(); + + furi_hal_interrupt_set_isr(FURI_HAL_RFID_EMULATE_TIMER_IRQ, NULL, NULL); + + FURI_CRITICAL_ENTER(); + LL_TIM_DeInit(RFID_CAPTURE_TIM); + FURI_CRITICAL_EXIT(); +} + +static void furi_hal_rfid_dma_isr() { + if(LL_DMA_IsActiveFlag_HT1(DMA1)) { + LL_DMA_ClearFlag_HT1(DMA1); + furi_hal_rfid->dma_callback(true, furi_hal_rfid->context); + } + + if(LL_DMA_IsActiveFlag_TC1(DMA1)) { + LL_DMA_ClearFlag_TC1(DMA1); + furi_hal_rfid->dma_callback(false, furi_hal_rfid->context); + } +} + +void furi_hal_rfid_tim_emulate_dma_start( + uint32_t* duration, + uint32_t* pulse, + size_t length, + FuriHalRfidDMACallback callback, + void* context) { + furi_assert(furi_hal_rfid); + + // setup interrupts + furi_hal_rfid->dma_callback = callback; + furi_hal_rfid->context = context; + + // setup pins + furi_hal_rfid_pins_emulate(); + + // configure timer + furi_hal_rfid_tim_emulate(125000); + LL_TIM_OC_SetPolarity( + FURI_HAL_RFID_EMULATE_TIMER, FURI_HAL_RFID_EMULATE_TIMER_CHANNEL, LL_TIM_OCPOLARITY_HIGH); + LL_TIM_EnableDMAReq_UPDATE(FURI_HAL_RFID_EMULATE_TIMER); + + // configure DMA "mem -> ARR" channel + LL_DMA_InitTypeDef dma_config = {0}; + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (FURI_HAL_RFID_EMULATE_TIMER->ARR); + dma_config.MemoryOrM2MDstAddress = (uint32_t)duration; + 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 = length; + dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + dma_config.Priority = LL_DMA_MODE_NORMAL; + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &dma_config); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); + + // configure DMA "mem -> CCR3" channel +#if FURI_HAL_RFID_EMULATE_TIMER_CHANNEL == LL_TIM_CHANNEL_CH3 + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (FURI_HAL_RFID_EMULATE_TIMER->CCR3); +#else +#error Update this code. Would you kindly? +#endif + dma_config.MemoryOrM2MDstAddress = (uint32_t)pulse; + 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 = length; + dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + dma_config.Priority = LL_DMA_MODE_NORMAL; + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); + + // attach interrupt to one of DMA channels + furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, furi_hal_rfid_dma_isr, NULL); + LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_EnableIT_HT(DMA1, LL_DMA_CHANNEL_1); + + // start + LL_TIM_EnableAllOutputs(FURI_HAL_RFID_EMULATE_TIMER); + + LL_TIM_SetCounter(FURI_HAL_RFID_EMULATE_TIMER, 0); + LL_TIM_EnableCounter(FURI_HAL_RFID_EMULATE_TIMER); +} + +void furi_hal_rfid_tim_emulate_dma_stop() { + LL_TIM_DisableCounter(FURI_HAL_RFID_EMULATE_TIMER); + LL_TIM_DisableAllOutputs(FURI_HAL_RFID_EMULATE_TIMER); + + furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, NULL, NULL); + LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_DisableIT_HT(DMA1, LL_DMA_CHANNEL_1); + + FURI_CRITICAL_ENTER(); + + LL_DMA_DeInit(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_DeInit(DMA1, LL_DMA_CHANNEL_2); + LL_TIM_DeInit(FURI_HAL_RFID_EMULATE_TIMER); + + FURI_CRITICAL_EXIT(); +} + void furi_hal_rfid_tim_reset() { FURI_CRITICAL_ENTER(); diff --git a/firmware/targets/furi_hal_include/furi_hal_rfid.h b/firmware/targets/furi_hal_include/furi_hal_rfid.h index d26ba53fee..36563c1d16 100644 --- a/firmware/targets/furi_hal_include/furi_hal_rfid.h +++ b/firmware/targets/furi_hal_include/furi_hal_rfid.h @@ -7,6 +7,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -63,6 +64,23 @@ typedef void (*FuriHalRfidEmulateCallback)(void* context); */ void furi_hal_rfid_tim_emulate_start(FuriHalRfidEmulateCallback callback, void* context); +typedef void (*FuriHalRfidReadCaptureCallback)(bool level, uint32_t duration, void* context); + +void furi_hal_rfid_tim_read_capture_start(FuriHalRfidReadCaptureCallback callback, void* context); + +void furi_hal_rfid_tim_read_capture_stop(); + +typedef void (*FuriHalRfidDMACallback)(bool half, void* context); + +void furi_hal_rfid_tim_emulate_dma_start( + uint32_t* duration, + uint32_t* pulse, + size_t length, + FuriHalRfidDMACallback callback, + void* context); + +void furi_hal_rfid_tim_emulate_dma_stop(); + /** Stop emulation timer */ void furi_hal_rfid_tim_emulate_stop(); diff --git a/furi/core/core_defines.h b/furi/core/core_defines.h index 9ed05b2107..801810f6a1 100644 --- a/furi/core/core_defines.h +++ b/furi/core/core_defines.h @@ -92,6 +92,8 @@ extern "C" { #define FURI_BIT_CLEAR(x, n) ((x) &= ~(1 << (n))) #endif +#define FURI_SW_MEMBARRIER() asm volatile("" : : : "memory") + #ifdef __cplusplus } #endif diff --git a/lib/SConscript b/lib/SConscript index 5e5bb2eaa7..4498c4c9c6 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -77,6 +77,7 @@ libs = env.BuildModules( "appframe", "misc", "loclass", + "lfrfid", ], ) diff --git a/lib/flipper_format/flipper_format.h b/lib/flipper_format/flipper_format.h index 6163dee0e6..9e82bb3110 100644 --- a/lib/flipper_format/flipper_format.h +++ b/lib/flipper_format/flipper_format.h @@ -41,7 +41,7 @@ * Writing: * * ~~~~~~~~~~~~~~~~~~~~~ - * FlipperFormat format = flipper_format_file_alloc(storage); + * FlipperFormat* format = flipper_format_file_alloc(storage); * * do { * const uint32_t version = 1; @@ -66,7 +66,7 @@ * Reading: * * ~~~~~~~~~~~~~~~~~~~~~ - * FlipperFormat file = flipper_format_file_alloc(storage); + * FlipperFormat* file = flipper_format_file_alloc(storage); * * do { * uint32_t version = 1; diff --git a/lib/lfrfid/SConscript b/lib/lfrfid/SConscript new file mode 100644 index 0000000000..8d35428832 --- /dev/null +++ b/lib/lfrfid/SConscript @@ -0,0 +1,19 @@ +Import("env") + +env.Append( + LINT_SOURCES=[ + "#/lib/lfrfid", + ], + CPPPATH=[ + "#/lib/lfrfid", + ], +) + +libenv = env.Clone(FW_LIB_NAME="lfrfid") +libenv.ApplyLibFlags() + +sources = libenv.GlobRecursive("*.c*") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/lfrfid/lfrfid_dict_file.c b/lib/lfrfid/lfrfid_dict_file.c new file mode 100644 index 0000000000..bb6af39a49 --- /dev/null +++ b/lib/lfrfid/lfrfid_dict_file.c @@ -0,0 +1,182 @@ +#include "lfrfid_dict_file.h" +#include +#include +#include + +#define LFRFID_DICT_FILETYPE "Flipper RFID key" + +bool lfrfid_dict_file_save(ProtocolDict* dict, ProtocolId protocol, const char* filename) { + furi_check(protocol != PROTOCOL_NO); + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* file = flipper_format_file_alloc(storage); + size_t data_size = protocol_dict_get_data_size(dict, protocol); + uint8_t* data = malloc(data_size); + bool result = false; + + do { + if(!flipper_format_file_open_always(file, filename)) break; + if(!flipper_format_write_header_cstr(file, LFRFID_DICT_FILETYPE, 1)) break; + + // TODO: write comment about protocol types into file + + if(!flipper_format_write_string_cstr( + file, "Key type", protocol_dict_get_name(dict, protocol))) + break; + + // TODO: write comment about protocol sizes into file + + protocol_dict_get_data(dict, protocol, data, data_size); + + if(!flipper_format_write_hex(file, "Data", data, data_size)) break; + result = true; + } while(false); + + flipper_format_free(file); + furi_record_close(RECORD_STORAGE); + free(data); + + return result; +} + +static void lfrfid_dict_protocol_indala_data( + uint8_t* data, + size_t data_size, + uint8_t* protocol_data, + size_t protocol_data_size) { + UNUSED(data_size); + memset(protocol_data, 0, protocol_data_size); + + // fc + bit_lib_set_bit(protocol_data, 24, bit_lib_get_bit(data, 0)); + bit_lib_set_bit(protocol_data, 16, bit_lib_get_bit(data, 1)); + bit_lib_set_bit(protocol_data, 11, bit_lib_get_bit(data, 2)); + bit_lib_set_bit(protocol_data, 14, bit_lib_get_bit(data, 3)); + bit_lib_set_bit(protocol_data, 15, bit_lib_get_bit(data, 4)); + bit_lib_set_bit(protocol_data, 20, bit_lib_get_bit(data, 5)); + bit_lib_set_bit(protocol_data, 6, bit_lib_get_bit(data, 6)); + bit_lib_set_bit(protocol_data, 25, bit_lib_get_bit(data, 7)); + + // cn + bit_lib_set_bit(protocol_data, 9, bit_lib_get_bit(data, 8 + 0)); + bit_lib_set_bit(protocol_data, 12, bit_lib_get_bit(data, 8 + 1)); + bit_lib_set_bit(protocol_data, 10, bit_lib_get_bit(data, 8 + 2)); + bit_lib_set_bit(protocol_data, 7, bit_lib_get_bit(data, 8 + 3)); + bit_lib_set_bit(protocol_data, 19, bit_lib_get_bit(data, 8 + 4)); + bit_lib_set_bit(protocol_data, 3, bit_lib_get_bit(data, 8 + 5)); + bit_lib_set_bit(protocol_data, 2, bit_lib_get_bit(data, 8 + 6)); + bit_lib_set_bit(protocol_data, 18, bit_lib_get_bit(data, 8 + 7)); + bit_lib_set_bit(protocol_data, 13, bit_lib_get_bit(data, 8 + 8)); + bit_lib_set_bit(protocol_data, 0, bit_lib_get_bit(data, 8 + 9)); + bit_lib_set_bit(protocol_data, 4, bit_lib_get_bit(data, 8 + 10)); + bit_lib_set_bit(protocol_data, 21, bit_lib_get_bit(data, 8 + 11)); + bit_lib_set_bit(protocol_data, 23, bit_lib_get_bit(data, 8 + 12)); + bit_lib_set_bit(protocol_data, 26, bit_lib_get_bit(data, 8 + 13)); + bit_lib_set_bit(protocol_data, 17, bit_lib_get_bit(data, 8 + 14)); + bit_lib_set_bit(protocol_data, 8, bit_lib_get_bit(data, 8 + 15)); + + const uint32_t fc_and_card = data[0] << 16 | data[1] << 8 | data[2]; + + // indala checksum + uint8_t checksum_sum = 0; + checksum_sum += ((fc_and_card >> 14) & 1); + checksum_sum += ((fc_and_card >> 12) & 1); + checksum_sum += ((fc_and_card >> 9) & 1); + checksum_sum += ((fc_and_card >> 8) & 1); + checksum_sum += ((fc_and_card >> 6) & 1); + checksum_sum += ((fc_and_card >> 5) & 1); + checksum_sum += ((fc_and_card >> 2) & 1); + checksum_sum += ((fc_and_card >> 0) & 1); + checksum_sum = checksum_sum & 0b1; + + if(checksum_sum) { + bit_lib_set_bit(protocol_data, 27, 0); + bit_lib_set_bit(protocol_data, 28, 1); + } else { + bit_lib_set_bit(protocol_data, 27, 1); + bit_lib_set_bit(protocol_data, 28, 0); + } + + // wiegand parity + uint8_t even_parity_sum = 0; + for(int8_t i = 12; i < 24; i++) { + if(((fc_and_card >> i) & 1) == 1) { + even_parity_sum++; + } + } + bit_lib_set_bit(protocol_data, 1, even_parity_sum % 2); + + uint8_t odd_parity_sum = 1; + for(int8_t i = 0; i < 12; i++) { + if(((fc_and_card >> i) & 1) == 1) { + odd_parity_sum++; + } + } + bit_lib_set_bit(protocol_data, 5, odd_parity_sum % 2); +} + +static ProtocolId lfrfid_dict_protocol_fallback( + ProtocolDict* dict, + const char* protocol_name, + FlipperFormat* file) { + ProtocolId result = PROTOCOL_NO; + if(strcmp(protocol_name, "I40134") == 0) { + ProtocolId protocol = LFRFIDProtocolIndala26; + + size_t data_size = 3; + size_t protocol_data_size = protocol_dict_get_data_size(dict, protocol); + uint8_t* data = malloc(data_size); + uint8_t* protocol_data = malloc(protocol_data_size); + if(flipper_format_read_hex(file, "Data", data, data_size)) { + lfrfid_dict_protocol_indala_data(data, data_size, protocol_data, protocol_data_size); + protocol_dict_set_data(dict, protocol, protocol_data, protocol_data_size); + result = protocol; + } + free(protocol_data); + free(data); + } + + return result; +} + +ProtocolId lfrfid_dict_file_load(ProtocolDict* dict, const char* filename) { + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* file = flipper_format_file_alloc(storage); + ProtocolId result = PROTOCOL_NO; + uint8_t* data = malloc(protocol_dict_get_max_data_size(dict)); + string_t str_result; + string_init(str_result); + + do { + if(!flipper_format_file_open_existing(file, filename)) break; + + // header + uint32_t version; + if(!flipper_format_read_header(file, str_result, &version)) break; + if(string_cmp_str(str_result, LFRFID_DICT_FILETYPE) != 0) break; + if(version != 1) break; + + // type + if(!flipper_format_read_string(file, "Key type", str_result)) break; + ProtocolId protocol; + protocol = protocol_dict_get_protocol_by_name(dict, string_get_cstr(str_result)); + + if(protocol == PROTOCOL_NO) { + protocol = lfrfid_dict_protocol_fallback(dict, string_get_cstr(str_result), file); + if(protocol == PROTOCOL_NO) break; + } else { + // data + size_t data_size = protocol_dict_get_data_size(dict, protocol); + if(!flipper_format_read_hex(file, "Data", data, data_size)) break; + protocol_dict_set_data(dict, protocol, data, data_size); + } + + result = protocol; + } while(false); + + free(data); + string_clear(str_result); + flipper_format_free(file); + furi_record_close(RECORD_STORAGE); + + return result; +} \ No newline at end of file diff --git a/lib/lfrfid/lfrfid_dict_file.h b/lib/lfrfid/lfrfid_dict_file.h new file mode 100644 index 0000000000..077bb0ba13 --- /dev/null +++ b/lib/lfrfid/lfrfid_dict_file.h @@ -0,0 +1,31 @@ +#pragma once +#include +#include "protocols/lfrfid_protocols.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Save protocol from dictionary to file + * + * @param dict + * @param protocol + * @param filename + * @return true + * @return false + */ +bool lfrfid_dict_file_save(ProtocolDict* dict, ProtocolId protocol, const char* filename); + +/** + * @brief Load protocol from file to dictionary + * + * @param dict + * @param filename + * @return ProtocolId + */ +ProtocolId lfrfid_dict_file_load(ProtocolDict* dict, const char* filename); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/lfrfid/lfrfid_raw_file.c b/lib/lfrfid/lfrfid_raw_file.c new file mode 100644 index 0000000000..27c6f24754 --- /dev/null +++ b/lib/lfrfid/lfrfid_raw_file.c @@ -0,0 +1,145 @@ +#include "lfrfid_raw_file.h" +#include "tools/varint_pair.h" +#include +#include + +#define LFRFID_RAW_FILE_MAGIC 0x4C464952 +#define LFRFID_RAW_FILE_VERSION 1 + +#define TAG "RFID RAW File" + +typedef struct { + uint32_t magic; + uint32_t version; + float frequency; + float duty_cycle; + uint32_t max_buffer_size; +} LFRFIDRawFileHeader; + +struct LFRFIDRawFile { + Stream* stream; + uint32_t max_buffer_size; + + uint8_t* buffer; + uint32_t buffer_size; + size_t buffer_counter; +}; + +LFRFIDRawFile* lfrfid_raw_file_alloc(Storage* storage) { + LFRFIDRawFile* file = malloc(sizeof(LFRFIDRawFile)); + file->stream = file_stream_alloc(storage); + file->buffer = NULL; + return file; +} + +void lfrfid_raw_file_free(LFRFIDRawFile* file) { + if(file->buffer) free(file->buffer); + stream_free(file->stream); + free(file); +} + +bool lfrfid_raw_file_open_write(LFRFIDRawFile* file, const char* file_path) { + return file_stream_open(file->stream, file_path, FSAM_READ_WRITE, FSOM_CREATE_ALWAYS); +} + +bool lfrfid_raw_file_open_read(LFRFIDRawFile* file, const char* file_path) { + return file_stream_open(file->stream, file_path, FSAM_READ, FSOM_OPEN_EXISTING); +} + +bool lfrfid_raw_file_write_header( + LFRFIDRawFile* file, + float frequency, + float duty_cycle, + uint32_t max_buffer_size) { + LFRFIDRawFileHeader header = { + .magic = LFRFID_RAW_FILE_MAGIC, + .version = LFRFID_RAW_FILE_VERSION, + .frequency = frequency, + .duty_cycle = duty_cycle, + .max_buffer_size = max_buffer_size}; + + size_t size = stream_write(file->stream, (uint8_t*)&header, sizeof(LFRFIDRawFileHeader)); + return (size == sizeof(LFRFIDRawFileHeader)); +} + +bool lfrfid_raw_file_write_buffer(LFRFIDRawFile* file, uint8_t* buffer_data, size_t buffer_size) { + size_t size; + size = stream_write(file->stream, (uint8_t*)&buffer_size, sizeof(size_t)); + if(size != sizeof(size_t)) return false; + + size = stream_write(file->stream, buffer_data, buffer_size); + if(size != buffer_size) return false; + + return true; +} + +bool lfrfid_raw_file_read_header(LFRFIDRawFile* file, float* frequency, float* duty_cycle) { + LFRFIDRawFileHeader header; + size_t size = stream_read(file->stream, (uint8_t*)&header, sizeof(LFRFIDRawFileHeader)); + if(size == sizeof(LFRFIDRawFileHeader)) { + if(header.magic == LFRFID_RAW_FILE_MAGIC && header.version == LFRFID_RAW_FILE_VERSION) { + *frequency = header.frequency; + *duty_cycle = header.duty_cycle; + file->max_buffer_size = header.max_buffer_size; + file->buffer = malloc(file->max_buffer_size); + file->buffer_size = 0; + file->buffer_counter = 0; + return true; + } else { + return false; + } + } else { + return false; + } +} + +bool lfrfid_raw_file_read_pair( + LFRFIDRawFile* file, + uint32_t* duration, + uint32_t* pulse, + bool* pass_end) { + size_t length = 0; + if(file->buffer_counter >= file->buffer_size) { + if(stream_eof(file->stream)) { + // rewind stream and pass header + stream_seek(file->stream, sizeof(LFRFIDRawFileHeader), StreamOffsetFromStart); + if(pass_end) *pass_end = true; + } + + length = stream_read(file->stream, (uint8_t*)&file->buffer_size, sizeof(size_t)); + if(length != sizeof(size_t)) { + FURI_LOG_E(TAG, "read pair: failed to read size"); + return false; + } + + if(file->buffer_size > file->max_buffer_size) { + FURI_LOG_E(TAG, "read pair: buffer size is too big"); + return false; + } + + length = stream_read(file->stream, file->buffer, file->buffer_size); + if(length != file->buffer_size) { + FURI_LOG_E(TAG, "read pair: failed to read data"); + return false; + } + + file->buffer_counter = 0; + } + + size_t size = 0; + bool result = varint_pair_unpack( + &file->buffer[file->buffer_counter], + (size_t)(file->buffer_size - file->buffer_counter), + pulse, + duration, + &size); + + if(result) { + file->buffer_counter += size; + } else { + FURI_LOG_E(TAG, "read pair: buffer is too small"); + return false; + } + + return true; +} \ No newline at end of file diff --git a/lib/lfrfid/lfrfid_raw_file.h b/lib/lfrfid/lfrfid_raw_file.h new file mode 100644 index 0000000000..3f2f14e09f --- /dev/null +++ b/lib/lfrfid/lfrfid_raw_file.h @@ -0,0 +1,95 @@ +#pragma once +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct LFRFIDRawFile LFRFIDRawFile; + +/** + * @brief Allocate a new LFRFIDRawFile instance + * + * @param storage + * @return LFRFIDRawFile* + */ +LFRFIDRawFile* lfrfid_raw_file_alloc(Storage* storage); + +/** + * @brief Free a LFRFIDRawFile instance + * + * @param file + */ +void lfrfid_raw_file_free(LFRFIDRawFile* file); + +/** + * @brief Open RAW file for writing + * + * @param file + * @param file_path + * @return bool + */ +bool lfrfid_raw_file_open_write(LFRFIDRawFile* file, const char* file_path); + +/** + * @brief Open RAW file for reading + * @param file + * @param file_path + * @return bool + */ +bool lfrfid_raw_file_open_read(LFRFIDRawFile* file, const char* file_path); + +/** + * @brief Write RAW file header + * + * @param file + * @param frequency + * @param duty_cycle + * @param max_buffer_size + * @return bool + */ +bool lfrfid_raw_file_write_header( + LFRFIDRawFile* file, + float frequency, + float duty_cycle, + uint32_t max_buffer_size); + +/** + * @brief Write data to RAW file + * + * @param file + * @param buffer_data + * @param buffer_size + * @return bool + */ +bool lfrfid_raw_file_write_buffer(LFRFIDRawFile* file, uint8_t* buffer_data, size_t buffer_size); + +/** + * @brief Read RAW file header + * + * @param file + * @param frequency + * @param duty_cycle + * @return bool + */ +bool lfrfid_raw_file_read_header(LFRFIDRawFile* file, float* frequency, float* duty_cycle); + +/** + * @brief Read varint-encoded pair from RAW file + * + * @param file + * @param duration + * @param pulse + * @param pass_end file was wrapped around, can be NULL + * @return bool + */ +bool lfrfid_raw_file_read_pair( + LFRFIDRawFile* file, + uint32_t* duration, + uint32_t* pulse, + bool* pass_end); + +#ifdef __cplusplus +} +#endif diff --git a/lib/lfrfid/lfrfid_raw_worker.c b/lib/lfrfid/lfrfid_raw_worker.c new file mode 100644 index 0000000000..4050a8ca8a --- /dev/null +++ b/lib/lfrfid/lfrfid_raw_worker.c @@ -0,0 +1,357 @@ +#include +#include +#include +#include +#include +#include "lfrfid_raw_worker.h" +#include "lfrfid_raw_file.h" +#include "tools/varint_pair.h" + +#define EMULATE_BUFFER_SIZE 1024 +#define RFID_DATA_BUFFER_SIZE 2048 +#define READ_DATA_BUFFER_COUNT 4 + +#define TAG_EMULATE "RAW EMULATE" + +// emulate mode +typedef struct { + size_t overrun_count; + StreamBufferHandle_t stream; +} RfidEmulateCtx; + +typedef struct { + uint32_t emulate_buffer_arr[EMULATE_BUFFER_SIZE]; + uint32_t emulate_buffer_ccr[EMULATE_BUFFER_SIZE]; + RfidEmulateCtx ctx; +} LFRFIDRawWorkerEmulateData; + +typedef enum { + HalfTransfer, + TransferComplete, +} LFRFIDRawEmulateDMAEvent; + +// read mode +#define READ_TEMP_DATA_SIZE 10 + +typedef struct { + BufferStream* stream; + VarintPair* pair; +} LFRFIDRawWorkerReadData; + +// main worker +struct LFRFIDRawWorker { + string_t file_path; + FuriThread* thread; + FuriEventFlag* events; + + LFRFIDWorkerEmulateRawCallback emulate_callback; + LFRFIDWorkerReadRawCallback read_callback; + void* context; + + float frequency; + float duty_cycle; +}; + +typedef enum { + LFRFIDRawWorkerEventStop, +} LFRFIDRawWorkerEvent; + +static int32_t lfrfid_raw_read_worker_thread(void* thread_context); +static int32_t lfrfid_raw_emulate_worker_thread(void* thread_context); + +LFRFIDRawWorker* lfrfid_raw_worker_alloc() { + LFRFIDRawWorker* worker = malloc(sizeof(LFRFIDRawWorker)); + + worker->thread = furi_thread_alloc(); + furi_thread_set_name(worker->thread, "lfrfid_raw_worker"); + furi_thread_set_context(worker->thread, worker); + furi_thread_set_stack_size(worker->thread, 2048); + + worker->events = furi_event_flag_alloc(NULL); + + string_init(worker->file_path); + return worker; +} + +void lfrfid_raw_worker_free(LFRFIDRawWorker* worker) { + furi_thread_free(worker->thread); + furi_event_flag_free(worker->events); + string_clear(worker->file_path); + free(worker); +} + +void lfrfid_raw_worker_start_read( + LFRFIDRawWorker* worker, + const char* file_path, + float freq, + float duty_cycle, + LFRFIDWorkerReadRawCallback callback, + void* context) { + furi_check(furi_thread_get_state(worker->thread) == FuriThreadStateStopped); + + string_set(worker->file_path, file_path); + + worker->frequency = freq; + worker->duty_cycle = duty_cycle; + worker->read_callback = callback; + worker->context = context; + + furi_thread_set_callback(worker->thread, lfrfid_raw_read_worker_thread); + + furi_thread_start(worker->thread); +} + +void lfrfid_raw_worker_start_emulate( + LFRFIDRawWorker* worker, + const char* file_path, + LFRFIDWorkerEmulateRawCallback callback, + void* context) { + furi_check(furi_thread_get_state(worker->thread) == FuriThreadStateStopped); + string_set(worker->file_path, file_path); + worker->emulate_callback = callback; + worker->context = context; + furi_thread_set_callback(worker->thread, lfrfid_raw_emulate_worker_thread); + furi_thread_start(worker->thread); +} + +void lfrfid_raw_worker_stop(LFRFIDRawWorker* worker) { + worker->emulate_callback = NULL; + worker->context = NULL; + worker->read_callback = NULL; + worker->context = NULL; + furi_event_flag_set(worker->events, 1 << LFRFIDRawWorkerEventStop); + furi_thread_join(worker->thread); +} + +static void lfrfid_raw_worker_capture(bool level, uint32_t duration, void* context) { + LFRFIDRawWorkerReadData* ctx = context; + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + bool need_to_send = varint_pair_pack(ctx->pair, level, duration); + + if(need_to_send) { + buffer_stream_send_from_isr( + ctx->stream, + varint_pair_get_data(ctx->pair), + varint_pair_get_size(ctx->pair), + &xHigherPriorityTaskWoken); + varint_pair_reset(ctx->pair); + } + + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} + +static int32_t lfrfid_raw_read_worker_thread(void* thread_context) { + LFRFIDRawWorker* worker = (LFRFIDRawWorker*)thread_context; + + Storage* storage = furi_record_open(RECORD_STORAGE); + LFRFIDRawFile* file = lfrfid_raw_file_alloc(storage); + const char* filename = string_get_cstr(worker->file_path); + bool file_valid = lfrfid_raw_file_open_write(file, filename); + + LFRFIDRawWorkerReadData* data = malloc(sizeof(LFRFIDRawWorkerReadData)); + + data->stream = buffer_stream_alloc(RFID_DATA_BUFFER_SIZE, READ_DATA_BUFFER_COUNT); + data->pair = varint_pair_alloc(); + + if(file_valid) { + // write header + file_valid = lfrfid_raw_file_write_header( + file, worker->frequency, worker->duty_cycle, RFID_DATA_BUFFER_SIZE); + } + + if(file_valid) { + // setup carrier + furi_hal_rfid_pins_read(); + furi_hal_rfid_tim_read(worker->frequency, worker->duty_cycle); + furi_hal_rfid_tim_read_start(); + + // stabilize detector + furi_delay_ms(1500); + + // start capture + furi_hal_rfid_tim_read_capture_start(lfrfid_raw_worker_capture, data); + + while(1) { + Buffer* buffer = buffer_stream_receive(data->stream, 100); + + if(buffer != NULL) { + file_valid = lfrfid_raw_file_write_buffer( + file, buffer_get_data(buffer), buffer_get_size(buffer)); + buffer_reset(buffer); + } + + if(!file_valid) { + if(worker->read_callback != NULL) { + // message file_error to worker + worker->read_callback(LFRFIDWorkerReadRawFileError, worker->context); + } + break; + } + + if(buffer_stream_get_overrun_count(data->stream) > 0 && + worker->read_callback != NULL) { + // message overrun to worker + worker->read_callback(LFRFIDWorkerReadRawOverrun, worker->context); + } + + uint32_t flags = furi_event_flag_get(worker->events); + if(FURI_BIT(flags, LFRFIDRawWorkerEventStop)) { + break; + } + } + + furi_hal_rfid_tim_read_capture_stop(); + furi_hal_rfid_tim_read_stop(); + } else { + if(worker->read_callback != NULL) { + // message file_error to worker + worker->read_callback(LFRFIDWorkerReadRawFileError, worker->context); + } + } + + if(!file_valid) { + const uint32_t available_flags = (1 << LFRFIDRawWorkerEventStop); + while(true) { + uint32_t flags = furi_event_flag_wait( + worker->events, available_flags, FuriFlagWaitAny, FuriWaitForever); + + if(FURI_BIT(flags, LFRFIDRawWorkerEventStop)) { + break; + } + } + } + + varint_pair_free(data->pair); + buffer_stream_free(data->stream); + lfrfid_raw_file_free(file); + furi_record_close(RECORD_STORAGE); + free(data); + + return 0; +} + +static void rfid_emulate_dma_isr(bool half, void* context) { + RfidEmulateCtx* ctx = context; + + uint32_t flag = half ? HalfTransfer : TransferComplete; + size_t len = xStreamBufferSendFromISR(ctx->stream, &flag, sizeof(uint32_t), pdFALSE); + if(len != sizeof(uint32_t)) { + ctx->overrun_count++; + } +} + +static int32_t lfrfid_raw_emulate_worker_thread(void* thread_context) { + LFRFIDRawWorker* worker = thread_context; + + bool file_valid = true; + + LFRFIDRawWorkerEmulateData* data = malloc(sizeof(LFRFIDRawWorkerEmulateData)); + + Storage* storage = furi_record_open(RECORD_STORAGE); + data->ctx.overrun_count = 0; + data->ctx.stream = xStreamBufferCreate(sizeof(uint32_t), sizeof(uint32_t)); + + LFRFIDRawFile* file = lfrfid_raw_file_alloc(storage); + + do { + file_valid = lfrfid_raw_file_open_read(file, string_get_cstr(worker->file_path)); + if(!file_valid) break; + file_valid = lfrfid_raw_file_read_header(file, &worker->frequency, &worker->duty_cycle); + if(!file_valid) break; + + for(size_t i = 0; i < EMULATE_BUFFER_SIZE; i++) { + file_valid = lfrfid_raw_file_read_pair( + file, &data->emulate_buffer_arr[i], &data->emulate_buffer_ccr[i], NULL); + if(!file_valid) break; + data->emulate_buffer_arr[i] /= 8; + data->emulate_buffer_arr[i] -= 1; + data->emulate_buffer_ccr[i] /= 8; + } + } while(false); + + furi_hal_rfid_tim_emulate_dma_start( + data->emulate_buffer_arr, + data->emulate_buffer_ccr, + EMULATE_BUFFER_SIZE, + rfid_emulate_dma_isr, + &data->ctx); + + if(!file_valid && worker->emulate_callback != NULL) { + // message file_error to worker + worker->emulate_callback(LFRFIDWorkerEmulateRawFileError, worker->context); + } + + if(file_valid) { + uint32_t flag = 0; + + while(true) { + size_t size = xStreamBufferReceive(data->ctx.stream, &flag, sizeof(uint32_t), 100); + + if(size == sizeof(uint32_t)) { + size_t start = 0; + if(flag == TransferComplete) { + start = (EMULATE_BUFFER_SIZE / 2); + } + + for(size_t i = 0; i < (EMULATE_BUFFER_SIZE / 2); i++) { + file_valid = lfrfid_raw_file_read_pair( + file, + &data->emulate_buffer_arr[start + i], + &data->emulate_buffer_ccr[start + i], + NULL); + if(!file_valid) break; + data->emulate_buffer_arr[i] /= 8; + data->emulate_buffer_arr[i] -= 1; + data->emulate_buffer_ccr[i] /= 8; + } + } else if(size != 0) { + data->ctx.overrun_count++; + } + + if(!file_valid) { + if(worker->emulate_callback != NULL) { + // message file_error to worker + worker->emulate_callback(LFRFIDWorkerEmulateRawFileError, worker->context); + } + break; + } + + if(data->ctx.overrun_count > 0 && worker->emulate_callback != NULL) { + // message overrun to worker + worker->emulate_callback(LFRFIDWorkerEmulateRawOverrun, worker->context); + } + + uint32_t flags = furi_event_flag_get(worker->events); + if(FURI_BIT(flags, LFRFIDRawWorkerEventStop)) { + break; + }; + } + } + + furi_hal_rfid_tim_emulate_dma_stop(); + + if(!file_valid) { + const uint32_t available_flags = (1 << LFRFIDRawWorkerEventStop); + while(true) { + uint32_t flags = furi_event_flag_wait( + worker->events, available_flags, FuriFlagWaitAny, FuriWaitForever); + + if(FURI_BIT(flags, LFRFIDRawWorkerEventStop)) { + break; + }; + } + } + + if(data->ctx.overrun_count) { + FURI_LOG_E(TAG_EMULATE, "overruns: %lu", data->ctx.overrun_count); + } + + vStreamBufferDelete(data->ctx.stream); + lfrfid_raw_file_free(file); + furi_record_close(RECORD_STORAGE); + free(data); + + return 0; +} \ No newline at end of file diff --git a/lib/lfrfid/lfrfid_raw_worker.h b/lib/lfrfid/lfrfid_raw_worker.h new file mode 100644 index 0000000000..1195dd5879 --- /dev/null +++ b/lib/lfrfid/lfrfid_raw_worker.h @@ -0,0 +1,68 @@ +#pragma once +#include +#include "lfrfid_worker.h" +#include +#include "protocols/lfrfid_protocols.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct LFRFIDRawWorker LFRFIDRawWorker; + +/** + * @brief Allocate a new LFRFIDRawWorker instance + * + * @return LFRFIDRawWorker* + */ +LFRFIDRawWorker* lfrfid_raw_worker_alloc(); + +/** + * @brief Free a LFRFIDRawWorker instance + * + * @param worker LFRFIDRawWorker instance + */ +void lfrfid_raw_worker_free(LFRFIDRawWorker* worker); + +/** + * @brief Start reading + * + * @param worker LFRFIDRawWorker instance + * @param file_path path where file will be saved + * @param frequency HW frequency + * @param duty_cycle HW duty cycle + * @param callback callback for read event + * @param context context for callback + */ +void lfrfid_raw_worker_start_read( + LFRFIDRawWorker* worker, + const char* file_path, + float frequency, + float duty_cycle, + LFRFIDWorkerReadRawCallback callback, + void* context); + +/** + * @brief Start emulate + * + * @param worker LFRFIDRawWorker instance + * @param file_path path to file that will be emulated + * @param callback callback for emulate event + * @param context context for callback + */ +void lfrfid_raw_worker_start_emulate( + LFRFIDRawWorker* worker, + const char* file_path, + LFRFIDWorkerEmulateRawCallback callback, + void* context); + +/** + * @brief Stop worker + * + * @param worker + */ +void lfrfid_raw_worker_stop(LFRFIDRawWorker* worker); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/lfrfid/lfrfid_worker.c b/lib/lfrfid/lfrfid_worker.c new file mode 100644 index 0000000000..8b4f8b6a98 --- /dev/null +++ b/lib/lfrfid/lfrfid_worker.c @@ -0,0 +1,169 @@ +#include +#include +#include +#include "lfrfid_worker_i.h" + +typedef enum { + LFRFIDEventStopThread = (1 << 0), + LFRFIDEventStopMode = (1 << 1), + LFRFIDEventRead = (1 << 2), + LFRFIDEventWrite = (1 << 3), + LFRFIDEventEmulate = (1 << 4), + LFRFIDEventReadRaw = (1 << 5), + LFRFIDEventEmulateRaw = (1 << 6), + LFRFIDEventAll = + (LFRFIDEventStopThread | LFRFIDEventStopMode | LFRFIDEventRead | LFRFIDEventWrite | + LFRFIDEventEmulate | LFRFIDEventReadRaw | LFRFIDEventEmulateRaw), +} LFRFIDEventType; + +static int32_t lfrfid_worker_thread(void* thread_context); + +LFRFIDWorker* lfrfid_worker_alloc(ProtocolDict* dict) { + furi_assert(dict); + + LFRFIDWorker* worker = malloc(sizeof(LFRFIDWorker)); + worker->mode_index = LFRFIDWorkerIdle; + worker->read_cb = NULL; + worker->write_cb = NULL; + worker->cb_ctx = NULL; + worker->raw_filename = NULL; + worker->mode_storage = NULL; + + worker->thread = furi_thread_alloc(); + furi_thread_set_name(worker->thread, "lfrfid_worker"); + furi_thread_set_callback(worker->thread, lfrfid_worker_thread); + furi_thread_set_context(worker->thread, worker); + furi_thread_set_stack_size(worker->thread, 2048); + + worker->protocols = dict; + + return worker; +} + +void lfrfid_worker_free(LFRFIDWorker* worker) { + if(worker->raw_filename) { + free(worker->raw_filename); + } + + furi_thread_free(worker->thread); + free(worker); +} + +void lfrfid_worker_read_start( + LFRFIDWorker* worker, + LFRFIDWorkerReadType type, + LFRFIDWorkerReadCallback callback, + void* context) { + furi_assert(worker->mode_index == LFRFIDWorkerIdle); + worker->read_type = type; + worker->read_cb = callback; + worker->cb_ctx = context; + furi_thread_flags_set(furi_thread_get_id(worker->thread), LFRFIDEventRead); +} + +void lfrfid_worker_write_start( + LFRFIDWorker* worker, + LFRFIDProtocol protocol, + LFRFIDWorkerWriteCallback callback, + void* context) { + furi_assert(worker->mode_index == LFRFIDWorkerIdle); + worker->protocol = protocol; + worker->write_cb = callback; + worker->cb_ctx = context; + furi_thread_flags_set(furi_thread_get_id(worker->thread), LFRFIDEventWrite); +} + +void lfrfid_worker_emulate_start(LFRFIDWorker* worker, LFRFIDProtocol protocol) { + furi_assert(worker->mode_index == LFRFIDWorkerIdle); + worker->protocol = protocol; + furi_thread_flags_set(furi_thread_get_id(worker->thread), LFRFIDEventEmulate); +} + +void lfrfid_worker_set_filename(LFRFIDWorker* worker, const char* filename) { + if(worker->raw_filename) { + free(worker->raw_filename); + } + + worker->raw_filename = strdup(filename); +} + +void lfrfid_worker_read_raw_start( + LFRFIDWorker* worker, + const char* filename, + LFRFIDWorkerReadType type, + LFRFIDWorkerReadRawCallback callback, + void* context) { + furi_assert(worker->mode_index == LFRFIDWorkerIdle); + worker->read_type = type; + worker->read_raw_cb = callback; + worker->cb_ctx = context; + lfrfid_worker_set_filename(worker, filename); + furi_thread_flags_set(furi_thread_get_id(worker->thread), LFRFIDEventReadRaw); +} + +void lfrfid_worker_emulate_raw_start( + LFRFIDWorker* worker, + const char* filename, + LFRFIDWorkerEmulateRawCallback callback, + void* context) { + furi_assert(worker->mode_index == LFRFIDWorkerIdle); + lfrfid_worker_set_filename(worker, filename); + worker->emulate_raw_cb = callback; + worker->cb_ctx = context; + furi_thread_flags_set(furi_thread_get_id(worker->thread), LFRFIDEventEmulateRaw); +} + +void lfrfid_worker_stop(LFRFIDWorker* worker) { + furi_thread_flags_set(furi_thread_get_id(worker->thread), LFRFIDEventStopMode); +} + +void lfrfid_worker_start_thread(LFRFIDWorker* worker) { + furi_thread_start(worker->thread); +} + +void lfrfid_worker_stop_thread(LFRFIDWorker* worker) { + furi_assert(worker->mode_index == LFRFIDWorkerIdle); + furi_thread_flags_set(furi_thread_get_id(worker->thread), LFRFIDEventStopThread); + furi_thread_join(worker->thread); +} + +bool lfrfid_worker_check_for_stop(LFRFIDWorker* worker) { + UNUSED(worker); + uint32_t flags = furi_thread_flags_get(); + return (flags & LFRFIDEventStopMode); +} + +size_t lfrfid_worker_dict_get_data_size(LFRFIDWorker* worker, LFRFIDProtocol protocol) { + furi_assert(worker->mode_index == LFRFIDWorkerIdle); + return protocol_dict_get_data_size(worker->protocols, protocol); +} + +static int32_t lfrfid_worker_thread(void* thread_context) { + LFRFIDWorker* worker = thread_context; + bool running = true; + + while(running) { + uint32_t flags = furi_thread_flags_wait(LFRFIDEventAll, FuriFlagWaitAny, FuriWaitForever); + if(flags != FuriFlagErrorTimeout) { + // stop thread + if(flags & LFRFIDEventStopThread) break; + + // switch mode + if(flags & LFRFIDEventRead) worker->mode_index = LFRFIDWorkerRead; + if(flags & LFRFIDEventWrite) worker->mode_index = LFRFIDWorkerWrite; + if(flags & LFRFIDEventEmulate) worker->mode_index = LFRFIDWorkerEmulate; + if(flags & LFRFIDEventReadRaw) worker->mode_index = LFRFIDWorkerReadRaw; + if(flags & LFRFIDEventEmulateRaw) worker->mode_index = LFRFIDWorkerEmulateRaw; + + // do mode, if it exists + if(lfrfid_worker_modes[worker->mode_index].process) { + lfrfid_worker_modes[worker->mode_index].process(worker); + } + + // reset mode + worker->mode_index = LFRFIDWorkerIdle; + } + } + + return 0; +} \ No newline at end of file diff --git a/lib/lfrfid/lfrfid_worker.h b/lib/lfrfid/lfrfid_worker.h new file mode 100644 index 0000000000..def9f89a47 --- /dev/null +++ b/lib/lfrfid/lfrfid_worker.h @@ -0,0 +1,152 @@ +/** + * @file lfrfid_worker.h + * + * LFRFID worker + */ + +#pragma once +#include +#include "protocols/lfrfid_protocols.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + LFRFIDWorkerWriteOK, + LFRFIDWorkerWriteProtocolCannotBeWritten, + LFRFIDWorkerWriteFobCannotBeWritten, + LFRFIDWorkerWriteTooLongToWrite, +} LFRFIDWorkerWriteResult; + +typedef enum { + LFRFIDWorkerReadTypeAuto, + LFRFIDWorkerReadTypeASKOnly, + LFRFIDWorkerReadTypePSKOnly, +} LFRFIDWorkerReadType; + +typedef enum { + LFRFIDWorkerReadSenseStart, // TODO: not implemented + LFRFIDWorkerReadSenseEnd, // TODO: not implemented + LFRFIDWorkerReadSenseCardStart, + LFRFIDWorkerReadSenseCardEnd, + LFRFIDWorkerReadStartASK, + LFRFIDWorkerReadStartPSK, + LFRFIDWorkerReadDone, +} LFRFIDWorkerReadResult; + +typedef enum { + LFRFIDWorkerReadRawFileError, + LFRFIDWorkerReadRawOverrun, +} LFRFIDWorkerReadRawResult; + +typedef enum { + LFRFIDWorkerEmulateRawFileError, + LFRFIDWorkerEmulateRawOverrun, +} LFRFIDWorkerEmulateRawResult; + +typedef void ( + *LFRFIDWorkerReadCallback)(LFRFIDWorkerReadResult result, ProtocolId protocol, void* context); +typedef void (*LFRFIDWorkerWriteCallback)(LFRFIDWorkerWriteResult result, void* context); + +typedef void (*LFRFIDWorkerReadRawCallback)(LFRFIDWorkerReadRawResult result, void* context); +typedef void (*LFRFIDWorkerEmulateRawCallback)(LFRFIDWorkerEmulateRawResult result, void* context); + +typedef struct LFRFIDWorker LFRFIDWorker; + +/** + * Allocate LF-RFID worker + * @return LFRFIDWorker* + */ +LFRFIDWorker* lfrfid_worker_alloc(ProtocolDict* dict); + +/** + * Free LF-RFID worker + * @param worker + */ +void lfrfid_worker_free(LFRFIDWorker* worker); + +/** + * Start LF-RFID worker thread + * @param worker + */ +void lfrfid_worker_start_thread(LFRFIDWorker* worker); + +/** + * Stop LF-RFID worker thread + * @param worker + */ +void lfrfid_worker_stop_thread(LFRFIDWorker* worker); + +/** + * @brief Start read mode + * + * @param worker + * @param type + * @param callback + * @param context + */ +void lfrfid_worker_read_start( + LFRFIDWorker* worker, + LFRFIDWorkerReadType type, + LFRFIDWorkerReadCallback callback, + void* context); + +/** + * @brief Start write mode + * + * @param worker + * @param protocol + * @param callback + * @param context + */ +void lfrfid_worker_write_start( + LFRFIDWorker* worker, + LFRFIDProtocol protocol, + LFRFIDWorkerWriteCallback callback, + void* context); + +/** + * Start emulate mode + * @param worker + */ +void lfrfid_worker_emulate_start(LFRFIDWorker* worker, LFRFIDProtocol protocol); + +/** + * @brief Start raw read mode + * + * @param worker + * @param filename + * @param type + * @param callback + * @param context + */ +void lfrfid_worker_read_raw_start( + LFRFIDWorker* worker, + const char* filename, + LFRFIDWorkerReadType type, + LFRFIDWorkerReadRawCallback callback, + void* context); + +/** + * Emulate raw read mode + * @param worker + * @param filename + * @param callback + * @param context + */ +void lfrfid_worker_emulate_raw_start( + LFRFIDWorker* worker, + const char* filename, + LFRFIDWorkerEmulateRawCallback callback, + void* context); + +/** + * Stop all modes + * @param worker + */ +void lfrfid_worker_stop(LFRFIDWorker* worker); + +#ifdef __cplusplus +} +#endif diff --git a/lib/lfrfid/lfrfid_worker_i.h b/lib/lfrfid/lfrfid_worker_i.h new file mode 100644 index 0000000000..33c0bff085 --- /dev/null +++ b/lib/lfrfid/lfrfid_worker_i.h @@ -0,0 +1,64 @@ +/** + * @file lfrfid_worker_i.h + * + * lfrfid worker, internal definitions + */ + +#pragma once +#include +#include "lfrfid_worker.h" +#include "lfrfid_raw_worker.h" +#include "protocols/lfrfid_protocols.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + void (*const process)(LFRFIDWorker* worker); +} LFRFIDWorkerModeType; + +typedef enum { + LFRFIDWorkerIdle, + LFRFIDWorkerRead, + LFRFIDWorkerWrite, + LFRFIDWorkerEmulate, + LFRFIDWorkerReadRaw, + LFRFIDWorkerEmulateRaw, +} LFRFIDWorkerMode; + +struct LFRFIDWorker { + char* raw_filename; + + LFRFIDWorkerMode mode_index; + void* mode_storage; + + FuriEventFlag* events; + FuriThread* thread; + + LFRFIDWorkerReadType read_type; + + LFRFIDWorkerReadCallback read_cb; + LFRFIDWorkerWriteCallback write_cb; + LFRFIDWorkerReadRawCallback read_raw_cb; + LFRFIDWorkerEmulateRawCallback emulate_raw_cb; + + void* cb_ctx; + + ProtocolDict* protocols; + LFRFIDProtocol protocol; +}; + +extern const LFRFIDWorkerModeType lfrfid_worker_modes[]; + +/** + * @brief Check for stop flag + * + * @param worker + * @return bool + */ +bool lfrfid_worker_check_for_stop(LFRFIDWorker* worker); + +#ifdef __cplusplus +} +#endif diff --git a/lib/lfrfid/lfrfid_worker_modes.c b/lib/lfrfid/lfrfid_worker_modes.c new file mode 100644 index 0000000000..f41a7194a1 --- /dev/null +++ b/lib/lfrfid/lfrfid_worker_modes.c @@ -0,0 +1,624 @@ +#include +#include +#include "lfrfid_worker_i.h" +#include "tools/t5577.h" +#include +#include +#include +#include "tools/varint_pair.h" +#include "tools/bit_lib.h" + +#define TAG "LFRFIDWorker" + +/** + * if READ_DEBUG_GPIO is defined: + * gpio_ext_pa7 will repeat signal coming from the comparator + * gpio_ext_pa6 will show load on the decoder + */ +// #define LFRFID_WORKER_READ_DEBUG_GPIO 1 + +#ifdef LFRFID_WORKER_READ_DEBUG_GPIO +#define LFRFID_WORKER_READ_DEBUG_GPIO_VALUE &gpio_ext_pa7 +#define LFRFID_WORKER_READ_DEBUG_GPIO_LOAD &gpio_ext_pa6 +#endif + +#define LFRFID_WORKER_READ_AVERAGE_COUNT 64 +#define LFRFID_WORKER_READ_MIN_TIME_US 16 + +#define LFRFID_WORKER_READ_DROP_TIME_MS 50 +#define LFRFID_WORKER_READ_STABILIZE_TIME_MS 450 +#define LFRFID_WORKER_READ_SWITCH_TIME_MS 1500 + +#define LFRFID_WORKER_WRITE_VERIFY_TIME_MS 1500 +#define LFRFID_WORKER_WRITE_DROP_TIME_MS 50 +#define LFRFID_WORKER_WRITE_TOO_LONG_TIME_MS 10000 + +#define LFRFID_WORKER_WRITE_MAX_UNSUCCESSFUL_READS 5 + +#define LFRFID_WORKER_READ_BUFFER_SIZE 512 +#define LFRFID_WORKER_READ_BUFFER_COUNT 8 + +#define LFRFID_WORKER_EMULATE_BUFFER_SIZE 1024 + +#define LFRFID_WORKER_DELAY_QUANT 50 + +void lfrfid_worker_delay(LFRFIDWorker* worker, uint32_t milliseconds) { + for(uint32_t i = 0; i < (milliseconds / LFRFID_WORKER_DELAY_QUANT); i++) { + if(lfrfid_worker_check_for_stop(worker)) break; + furi_delay_ms(LFRFID_WORKER_DELAY_QUANT); + } +} + +/**************************************************************************************************/ +/********************************************** READ **********************************************/ +/**************************************************************************************************/ + +typedef struct { + BufferStream* stream; + VarintPair* pair; + bool ignore_next_pulse; +} LFRFIDWorkerReadContext; + +static void lfrfid_worker_read_capture(bool level, uint32_t duration, void* context) { + LFRFIDWorkerReadContext* ctx = context; + + // ignore pulse if last pulse was noise + if(ctx->ignore_next_pulse) { + ctx->ignore_next_pulse = false; + return; + } + + // ignore noise spikes + if(duration <= LFRFID_WORKER_READ_MIN_TIME_US) { + if(level) { + ctx->ignore_next_pulse = true; + } + varint_pair_reset(ctx->pair); + return; + } + +#ifdef LFRFID_WORKER_READ_DEBUG_GPIO + furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_VALUE, level); +#endif + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + bool need_to_send = varint_pair_pack(ctx->pair, level, duration); + if(need_to_send) { + buffer_stream_send_from_isr( + ctx->stream, + varint_pair_get_data(ctx->pair), + varint_pair_get_size(ctx->pair), + &xHigherPriorityTaskWoken); + varint_pair_reset(ctx->pair); + } + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} + +typedef enum { + LFRFIDWorkerReadOK, + LFRFIDWorkerReadExit, + LFRFIDWorkerReadTimeout, +} LFRFIDWorkerReadState; + +static LFRFIDWorkerReadState lfrfid_worker_read_internal( + LFRFIDWorker* worker, + LFRFIDFeature feature, + uint32_t timeout, + ProtocolId* result_protocol) { + LFRFIDWorkerReadState state = LFRFIDWorkerReadTimeout; + furi_hal_rfid_pins_read(); + + if(feature & LFRFIDFeatureASK) { + furi_hal_rfid_tim_read(125000, 0.5); + FURI_LOG_D(TAG, "Start ASK"); + if(worker->read_cb) { + worker->read_cb(LFRFIDWorkerReadStartASK, PROTOCOL_NO, worker->cb_ctx); + } + } else { + furi_hal_rfid_tim_read(62500, 0.25); + FURI_LOG_D(TAG, "Start PSK"); + if(worker->read_cb) { + worker->read_cb(LFRFIDWorkerReadStartPSK, PROTOCOL_NO, worker->cb_ctx); + } + } + + furi_hal_rfid_tim_read_start(); + + // stabilize detector + lfrfid_worker_delay(worker, LFRFID_WORKER_READ_STABILIZE_TIME_MS); + + protocol_dict_decoders_start(worker->protocols); + +#ifdef LFRFID_WORKER_READ_DEBUG_GPIO + furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_VALUE, GpioModeOutputPushPull); + furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, GpioModeOutputPushPull); +#endif + + LFRFIDWorkerReadContext ctx; + ctx.pair = varint_pair_alloc(); + ctx.stream = + buffer_stream_alloc(LFRFID_WORKER_READ_BUFFER_SIZE, LFRFID_WORKER_READ_BUFFER_COUNT); + + furi_hal_rfid_tim_read_capture_start(lfrfid_worker_read_capture, &ctx); + + *result_protocol = PROTOCOL_NO; + ProtocolId last_protocol = PROTOCOL_NO; + size_t last_size = protocol_dict_get_max_data_size(worker->protocols); + uint8_t* last_data = malloc(last_size); + uint8_t* protocol_data = malloc(last_size); + size_t last_read_count = 0; + + uint32_t switch_os_tick_last = furi_get_tick(); + + uint32_t average_duration = 0; + uint32_t average_pulse = 0; + size_t average_index = 0; + bool card_detected = false; + + FURI_LOG_D(TAG, "Read started"); + while(true) { + if(lfrfid_worker_check_for_stop(worker)) { + state = LFRFIDWorkerReadExit; + break; + } + + Buffer* buffer = buffer_stream_receive(ctx.stream, 100); + +#ifdef LFRFID_WORKER_READ_DEBUG_GPIO + furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, true); +#endif + + if(buffer_stream_get_overrun_count(ctx.stream) > 0) { + FURI_LOG_E(TAG, "Read overrun, recovering"); + buffer_stream_reset(ctx.stream); + continue; + } + + if(buffer == NULL) { + continue; + } + + size_t size = buffer_get_size(buffer); + uint8_t* data = buffer_get_data(buffer); + size_t index = 0; + + while(index < size) { + uint32_t duration; + uint32_t pulse; + size_t tmp_size; + + if(!varint_pair_unpack(&data[index], size - index, &pulse, &duration, &tmp_size)) { + FURI_LOG_E(TAG, "can't unpack varint pair"); + break; + } else { + index += tmp_size; + + average_duration += duration; + average_pulse += pulse; + average_index++; + if(average_index >= LFRFID_WORKER_READ_AVERAGE_COUNT) { + float average = (float)average_pulse / (float)average_duration; + average_pulse = 0; + average_duration = 0; + average_index = 0; + + if(worker->read_cb) { + if(average > 0.2 && average < 0.8) { + if(!card_detected) { + card_detected = true; + worker->read_cb( + LFRFIDWorkerReadSenseStart, PROTOCOL_NO, worker->cb_ctx); + } + } else { + if(card_detected) { + card_detected = false; + worker->read_cb( + LFRFIDWorkerReadSenseEnd, PROTOCOL_NO, worker->cb_ctx); + } + } + } + } + + ProtocolId protocol = PROTOCOL_NO; + + protocol = protocol_dict_decoders_feed_by_feature( + worker->protocols, feature, true, pulse); + if(protocol == PROTOCOL_NO) { + protocol = protocol_dict_decoders_feed_by_feature( + worker->protocols, feature, false, duration - pulse); + } + + if(protocol != PROTOCOL_NO) { + // reset switch timer + switch_os_tick_last = furi_get_tick(); + + size_t protocol_data_size = + protocol_dict_get_data_size(worker->protocols, protocol); + protocol_dict_get_data( + worker->protocols, protocol, protocol_data, protocol_data_size); + + // validate protocol + if(protocol == last_protocol && + memcmp(last_data, protocol_data, protocol_data_size) == 0) { + last_read_count = last_read_count + 1; + + size_t validation_count = + protocol_dict_get_validate_count(worker->protocols, protocol); + + if(last_read_count >= validation_count) { + state = LFRFIDWorkerReadOK; + *result_protocol = protocol; + break; + } + } else { + if(last_protocol == PROTOCOL_NO && worker->read_cb) { + worker->read_cb( + LFRFIDWorkerReadSenseCardStart, protocol, worker->cb_ctx); + } + + last_protocol = protocol; + memcpy(last_data, protocol_data, protocol_data_size); + last_read_count = 0; + } + + string_t string_info; + string_init(string_info); + for(uint8_t i = 0; i < protocol_data_size; i++) { + if(i != 0) { + string_cat_printf(string_info, " "); + } + + string_cat_printf(string_info, "%02X", protocol_data[i]); + } + + FURI_LOG_D( + TAG, + "%s, %d, [%s]", + protocol_dict_get_name(worker->protocols, protocol), + last_read_count, + string_get_cstr(string_info)); + string_clear(string_info); + + protocol_dict_decoders_start(worker->protocols); + } + } + } + + buffer_reset(buffer); + +#ifdef LFRFID_WORKER_READ_DEBUG_GPIO + furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, false); +#endif + + if(*result_protocol != PROTOCOL_NO) { + break; + } + + if((furi_get_tick() - switch_os_tick_last) > timeout) { + state = LFRFIDWorkerReadTimeout; + break; + } + } + + FURI_LOG_D(TAG, "Read stopped"); + + if(last_protocol != PROTOCOL_NO && worker->read_cb) { + worker->read_cb(LFRFIDWorkerReadSenseCardEnd, last_protocol, worker->cb_ctx); + } + + if(card_detected && worker->read_cb) { + worker->read_cb(LFRFIDWorkerReadSenseEnd, last_protocol, worker->cb_ctx); + } + + furi_hal_rfid_tim_read_capture_stop(); + furi_hal_rfid_tim_read_stop(); + furi_hal_rfid_pins_reset(); + + varint_pair_free(ctx.pair); + buffer_stream_free(ctx.stream); + + free(protocol_data); + free(last_data); + +#ifdef LFRFID_WORKER_READ_DEBUG_GPIO + furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_VALUE, GpioModeAnalog); + furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, GpioModeAnalog); +#endif + + return state; +} + +static void lfrfid_worker_mode_read_process(LFRFIDWorker* worker) { + LFRFIDFeature feature = LFRFIDFeatureASK; + ProtocolId read_result = PROTOCOL_NO; + LFRFIDWorkerReadState state; + + if(worker->read_type == LFRFIDWorkerReadTypePSKOnly) { + feature = LFRFIDFeaturePSK; + } else { + feature = LFRFIDFeatureASK; + } + + if(worker->read_type == LFRFIDWorkerReadTypeAuto) { + while(1) { + // read for a while + state = lfrfid_worker_read_internal( + worker, feature, LFRFID_WORKER_READ_SWITCH_TIME_MS, &read_result); + + if(state == LFRFIDWorkerReadOK || state == LFRFIDWorkerReadExit) { + break; + } + + // switch to next feature + if(feature == LFRFIDFeatureASK) { + feature = LFRFIDFeaturePSK; + } else { + feature = LFRFIDFeatureASK; + } + + lfrfid_worker_delay(worker, LFRFID_WORKER_READ_DROP_TIME_MS); + } + } else { + while(1) { + if(worker->read_type == LFRFIDWorkerReadTypeASKOnly) { + state = lfrfid_worker_read_internal(worker, feature, UINT32_MAX, &read_result); + } else { + state = lfrfid_worker_read_internal( + worker, feature, LFRFID_WORKER_READ_SWITCH_TIME_MS, &read_result); + } + + if(state == LFRFIDWorkerReadOK || state == LFRFIDWorkerReadExit) { + break; + } + + lfrfid_worker_delay(worker, LFRFID_WORKER_READ_DROP_TIME_MS); + } + } + + if(state == LFRFIDWorkerReadOK && worker->read_cb) { + worker->read_cb(LFRFIDWorkerReadDone, read_result, worker->cb_ctx); + } +} + +/**************************************************************************************************/ +/******************************************** EMULATE *********************************************/ +/**************************************************************************************************/ + +typedef struct { + uint32_t duration[LFRFID_WORKER_EMULATE_BUFFER_SIZE]; + uint32_t pulse[LFRFID_WORKER_EMULATE_BUFFER_SIZE]; +} LFRFIDWorkerEmulateBuffer; + +typedef enum { + HalfTransfer, + TransferComplete, +} LFRFIDWorkerEmulateDMAEvent; + +static void lfrfid_worker_emulate_dma_isr(bool half, void* context) { + StreamBufferHandle_t stream = context; + uint32_t flag = half ? HalfTransfer : TransferComplete; + xStreamBufferSendFromISR(stream, &flag, sizeof(uint32_t), pdFALSE); +} + +static void lfrfid_worker_mode_emulate_process(LFRFIDWorker* worker) { + LFRFIDWorkerEmulateBuffer* buffer = malloc(sizeof(LFRFIDWorkerEmulateBuffer)); + StreamBufferHandle_t stream = xStreamBufferCreate(sizeof(uint32_t), sizeof(uint32_t)); + LFRFIDProtocol protocol = worker->protocol; + PulseGlue* pulse_glue = pulse_glue_alloc(); + + protocol_dict_encoder_start(worker->protocols, protocol); + + for(size_t i = 0; i < LFRFID_WORKER_EMULATE_BUFFER_SIZE; i++) { + bool pulse_pop = false; + while(!pulse_pop) { + LevelDuration level_duration = + protocol_dict_encoder_yield(worker->protocols, protocol); + pulse_pop = pulse_glue_push( + pulse_glue, + level_duration_get_level(level_duration), + level_duration_get_duration(level_duration)); + } + uint32_t duration, pulse; + pulse_glue_pop(pulse_glue, &duration, &pulse); + buffer->duration[i] = duration - 1; + buffer->pulse[i] = pulse; + } + +#ifdef LFRFID_WORKER_READ_DEBUG_GPIO + furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, GpioModeOutputPushPull); +#endif + + furi_hal_rfid_tim_emulate_dma_start( + buffer->duration, + buffer->pulse, + LFRFID_WORKER_EMULATE_BUFFER_SIZE, + lfrfid_worker_emulate_dma_isr, + stream); + + while(true) { + uint32_t flag = 0; + size_t size = xStreamBufferReceive(stream, &flag, sizeof(uint32_t), 100); + +#ifdef LFRFID_WORKER_READ_DEBUG_GPIO + furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, true); +#endif + + if(size == sizeof(uint32_t)) { + size_t start = 0; + + if(flag == HalfTransfer) { + start = 0; + } else if(flag == TransferComplete) { + start = (LFRFID_WORKER_EMULATE_BUFFER_SIZE / 2); + } + + for(size_t i = 0; i < (LFRFID_WORKER_EMULATE_BUFFER_SIZE / 2); i++) { + bool pulse_pop = false; + while(!pulse_pop) { + LevelDuration level_duration = + protocol_dict_encoder_yield(worker->protocols, protocol); + pulse_pop = pulse_glue_push( + pulse_glue, + level_duration_get_level(level_duration), + level_duration_get_duration(level_duration)); + } + uint32_t duration, pulse; + pulse_glue_pop(pulse_glue, &duration, &pulse); + buffer->duration[start + i] = duration - 1; + buffer->pulse[start + i] = pulse; + } + } + + if(lfrfid_worker_check_for_stop(worker)) { + break; + } + +#ifdef LFRFID_WORKER_READ_DEBUG_GPIO + furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, false); +#endif + } + + furi_hal_rfid_tim_emulate_dma_stop(); + +#ifdef LFRFID_WORKER_READ_DEBUG_GPIO + furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, GpioModeAnalog); +#endif + + free(buffer); + vStreamBufferDelete(stream); + pulse_glue_free(pulse_glue); +} + +/**************************************************************************************************/ +/********************************************* WRITE **********************************************/ +/**************************************************************************************************/ + +static void lfrfid_worker_mode_write_process(LFRFIDWorker* worker) { + LFRFIDProtocol protocol = worker->protocol; + LFRFIDWriteRequest* request = malloc(sizeof(LFRFIDWriteRequest)); + request->write_type = LFRFIDWriteTypeT5577; + + bool can_be_written = protocol_dict_get_write_data(worker->protocols, protocol, request); + + uint32_t write_start_time = furi_get_tick(); + bool too_long = false; + size_t unsuccessful_reads = 0; + + size_t data_size = protocol_dict_get_data_size(worker->protocols, protocol); + uint8_t* verify_data = malloc(data_size); + uint8_t* read_data = malloc(data_size); + protocol_dict_get_data(worker->protocols, protocol, verify_data, data_size); + + if(can_be_written) { + while(!lfrfid_worker_check_for_stop(worker)) { + FURI_LOG_D(TAG, "Data write"); + t5577_write(&request->t5577); + + ProtocolId read_result = PROTOCOL_NO; + LFRFIDWorkerReadState state = lfrfid_worker_read_internal( + worker, + protocol_dict_get_features(worker->protocols, protocol), + LFRFID_WORKER_WRITE_VERIFY_TIME_MS, + &read_result); + + if(state == LFRFIDWorkerReadOK) { + protocol_dict_get_data(worker->protocols, protocol, read_data, data_size); + + if(memcmp(read_data, verify_data, data_size) == 0) { + if(worker->write_cb) { + worker->write_cb(LFRFIDWorkerWriteOK, worker->cb_ctx); + } + break; + } else { + unsuccessful_reads++; + + if(unsuccessful_reads == LFRFID_WORKER_WRITE_MAX_UNSUCCESSFUL_READS) { + if(worker->write_cb) { + worker->write_cb(LFRFIDWorkerWriteFobCannotBeWritten, worker->cb_ctx); + } + } + } + } else if(state == LFRFIDWorkerReadExit) { + break; + } + + if(!too_long && + (furi_get_tick() - write_start_time) > LFRFID_WORKER_WRITE_TOO_LONG_TIME_MS) { + too_long = true; + if(worker->write_cb) { + worker->write_cb(LFRFIDWorkerWriteTooLongToWrite, worker->cb_ctx); + } + } + + lfrfid_worker_delay(worker, LFRFID_WORKER_WRITE_DROP_TIME_MS); + } + } else { + if(worker->write_cb) { + worker->write_cb(LFRFIDWorkerWriteProtocolCannotBeWritten, worker->cb_ctx); + } + } + + free(request); + free(verify_data); + free(read_data); +} + +/**************************************************************************************************/ +/******************************************* READ RAW *********************************************/ +/**************************************************************************************************/ + +static void lfrfid_worker_mode_read_raw_process(LFRFIDWorker* worker) { + LFRFIDRawWorker* raw_worker = lfrfid_raw_worker_alloc(); + + switch(worker->read_type) { + case LFRFIDWorkerReadTypePSKOnly: + lfrfid_raw_worker_start_read( + raw_worker, worker->raw_filename, 62500, 0.25, worker->read_raw_cb, worker->cb_ctx); + break; + case LFRFIDWorkerReadTypeASKOnly: + lfrfid_raw_worker_start_read( + raw_worker, worker->raw_filename, 125000, 0.5, worker->read_raw_cb, worker->cb_ctx); + break; + default: + furi_crash("RAW can be only PSK or ASK"); + break; + } + + while(!lfrfid_worker_check_for_stop(worker)) { + furi_delay_ms(100); + } + + lfrfid_raw_worker_stop(raw_worker); + lfrfid_raw_worker_free(raw_worker); +} + +/**************************************************************************************************/ +/***************************************** EMULATE RAW ********************************************/ +/**************************************************************************************************/ + +static void lfrfid_worker_mode_emulate_raw_process(LFRFIDWorker* worker) { + LFRFIDRawWorker* raw_worker = lfrfid_raw_worker_alloc(); + + lfrfid_raw_worker_start_emulate( + raw_worker, worker->raw_filename, worker->emulate_raw_cb, worker->cb_ctx); + + while(!lfrfid_worker_check_for_stop(worker)) { + furi_delay_ms(100); + } + + lfrfid_raw_worker_stop(raw_worker); + lfrfid_raw_worker_free(raw_worker); +} + +/**************************************************************************************************/ +/******************************************** MODES ***********************************************/ +/**************************************************************************************************/ + +const LFRFIDWorkerModeType lfrfid_worker_modes[] = { + [LFRFIDWorkerIdle] = {.process = NULL}, + [LFRFIDWorkerRead] = {.process = lfrfid_worker_mode_read_process}, + [LFRFIDWorkerWrite] = {.process = lfrfid_worker_mode_write_process}, + [LFRFIDWorkerEmulate] = {.process = lfrfid_worker_mode_emulate_process}, + [LFRFIDWorkerReadRaw] = {.process = lfrfid_worker_mode_read_raw_process}, + [LFRFIDWorkerEmulateRaw] = {.process = lfrfid_worker_mode_emulate_raw_process}, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/lfrfid_protocols.c b/lib/lfrfid/protocols/lfrfid_protocols.c new file mode 100644 index 0000000000..5df01b19e5 --- /dev/null +++ b/lib/lfrfid/protocols/lfrfid_protocols.c @@ -0,0 +1,22 @@ +#include "lfrfid_protocols.h" +#include "protocol_em4100.h" +#include "protocol_h10301.h" +#include "protocol_indala26.h" +#include "protocol_io_prox_xsf.h" +#include "protocol_awid.h" +#include "protocol_fdx_a.h" +#include "protocol_fdx_b.h" +#include "protocol_hid_generic.h" +#include "protocol_hid_ex_generic.h" + +const ProtocolBase* lfrfid_protocols[] = { + [LFRFIDProtocolEM4100] = &protocol_em4100, + [LFRFIDProtocolH10301] = &protocol_h10301, + [LFRFIDProtocolIndala26] = &protocol_indala26, + [LFRFIDProtocolIOProxXSF] = &protocol_io_prox_xsf, + [LFRFIDProtocolAwid] = &protocol_awid, + [LFRFIDProtocolFDXA] = &protocol_fdx_a, + [LFRFIDProtocolFDXB] = &protocol_fdx_b, + [LFRFIDProtocolHidGeneric] = &protocol_hid_generic, + [LFRFIDProtocolHidExGeneric] = &protocol_hid_ex_generic, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/lfrfid_protocols.h b/lib/lfrfid/protocols/lfrfid_protocols.h new file mode 100644 index 0000000000..4b8f6573d1 --- /dev/null +++ b/lib/lfrfid/protocols/lfrfid_protocols.h @@ -0,0 +1,35 @@ +#pragma once +#include +#include "../tools/t5577.h" + +typedef enum { + LFRFIDFeatureASK = 1 << 0, /** ASK Demodulation */ + LFRFIDFeaturePSK = 1 << 1, /** PSK Demodulation */ +} LFRFIDFeature; + +typedef enum { + LFRFIDProtocolEM4100, + LFRFIDProtocolH10301, + LFRFIDProtocolIndala26, + LFRFIDProtocolIOProxXSF, + LFRFIDProtocolAwid, + LFRFIDProtocolFDXA, + LFRFIDProtocolFDXB, + LFRFIDProtocolHidGeneric, + LFRFIDProtocolHidExGeneric, + + LFRFIDProtocolMax, +} LFRFIDProtocol; + +extern const ProtocolBase* lfrfid_protocols[]; + +typedef enum { + LFRFIDWriteTypeT5577, +} LFRFIDWriteType; + +typedef struct { + LFRFIDWriteType write_type; + union { + LFRFIDT5577 t5577; + }; +} LFRFIDWriteRequest; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_awid.c b/lib/lfrfid/protocols/protocol_awid.c new file mode 100644 index 0000000000..243b5edeb4 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_awid.c @@ -0,0 +1,239 @@ +#include +#include +#include +#include +#include +#include "lfrfid_protocols.h" + +#define JITTER_TIME (20) +#define MIN_TIME (64 - JITTER_TIME) +#define MAX_TIME (80 + JITTER_TIME) + +#define AWID_DECODED_DATA_SIZE (9) + +#define AWID_ENCODED_BIT_SIZE (96) +#define AWID_ENCODED_DATA_SIZE (((AWID_ENCODED_BIT_SIZE) / 8) + 1) +#define AWID_ENCODED_DATA_LAST (AWID_ENCODED_DATA_SIZE - 1) + +typedef struct { + FSKDemod* fsk_demod; +} ProtocolAwidDecoder; + +typedef struct { + FSKOsc* fsk_osc; + uint8_t encoded_index; +} ProtocolAwidEncoder; + +typedef struct { + ProtocolAwidDecoder decoder; + ProtocolAwidEncoder encoder; + uint8_t encoded_data[AWID_ENCODED_DATA_SIZE]; + uint8_t data[AWID_DECODED_DATA_SIZE]; +} ProtocolAwid; + +ProtocolAwid* protocol_awid_alloc(void) { + ProtocolAwid* protocol = malloc(sizeof(ProtocolAwid)); + protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5); + protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50); + + return protocol; +}; + +void protocol_awid_free(ProtocolAwid* protocol) { + fsk_demod_free(protocol->decoder.fsk_demod); + fsk_osc_free(protocol->encoder.fsk_osc); + free(protocol); +}; + +uint8_t* protocol_awid_get_data(ProtocolAwid* protocol) { + return protocol->data; +}; + +void protocol_awid_decoder_start(ProtocolAwid* protocol) { + memset(protocol->encoded_data, 0, AWID_ENCODED_DATA_SIZE); +}; + +static bool protocol_awid_can_be_decoded(const uint8_t* data) { + bool result = false; + + // Index map + // 0 10 20 30 40 50 60 + // | | | | | | | + // 01234567 890 1 234 5 678 9 012 3 456 7 890 1 234 5 678 9 012 3 456 7 890 1 234 5 678 9 012 3 - to 96 + // ----------------------------------------------------------------------------- + // 00000001 000 1 110 1 101 1 011 1 101 1 010 0 000 1 000 1 010 0 001 0 110 1 100 0 000 1 000 1 + // preamble bbb o bbb o bbw o fff o fff o ffc o ccc o ccc o ccc o ccc o ccc o wxx o xxx o xxx o - to 96 + // |---26 bit---| |-----117----||-------------142-------------| + // b = format bit len, o = odd parity of last 3 bits + // f = facility code, c = card number + // w = wiegand parity + // (26 bit format shown) + + do { + // check preamble and spacing + if(data[0] != 0b00000001 || data[AWID_ENCODED_DATA_LAST] != 0b00000001) break; + + // check odd parity for every 4 bits starting from the second byte + bool parity_error = bit_lib_test_parity(data, 8, 88, BitLibParityOdd, 4); + if(parity_error) break; + + result = true; + } while(false); + + return result; +} + +static void protocol_awid_decode(uint8_t* encoded_data, uint8_t* decoded_data) { + bit_lib_remove_bit_every_nth(encoded_data, 8, 88, 4); + bit_lib_copy_bits(decoded_data, 0, 66, encoded_data, 8); +} + +bool protocol_awid_decoder_feed(ProtocolAwid* protocol, bool level, uint32_t duration) { + bool value; + uint32_t count; + bool result = false; + + fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count); + if(count > 0) { + for(size_t i = 0; i < count; i++) { + bit_lib_push_bit(protocol->encoded_data, AWID_ENCODED_DATA_SIZE, value); + if(protocol_awid_can_be_decoded(protocol->encoded_data)) { + protocol_awid_decode(protocol->encoded_data, protocol->data); + + result = true; + break; + } + } + } + + return result; +}; + +static void protocol_awid_encode(const uint8_t* decoded_data, uint8_t* encoded_data) { + memset(encoded_data, 0, AWID_ENCODED_DATA_SIZE); + + // preamble + bit_lib_set_bits(encoded_data, 0, 0b00000001, 8); + + for(size_t i = 0; i < 88 / 4; i++) { + uint8_t value = bit_lib_get_bits(decoded_data, i * 3, 3) << 1; + value |= bit_lib_test_parity_32(value, BitLibParityOdd); + bit_lib_set_bits(encoded_data, 8 + i * 4, value, 4); + } +}; + +bool protocol_awid_encoder_start(ProtocolAwid* protocol) { + protocol_awid_encode(protocol->data, (uint8_t*)protocol->encoded_data); + protocol->encoder.encoded_index = 0; + fsk_osc_reset(protocol->encoder.fsk_osc); + return true; +}; + +LevelDuration protocol_awid_encoder_yield(ProtocolAwid* protocol) { + bool level; + uint32_t duration; + + bool bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index); + bool advance = fsk_osc_next_half(protocol->encoder.fsk_osc, bit, &level, &duration); + + if(advance) { + bit_lib_increment_index(protocol->encoder.encoded_index, AWID_ENCODED_BIT_SIZE); + } + return level_duration_make(level, duration); +}; + +void protocol_awid_render_data(ProtocolAwid* protocol, string_t result) { + // Index map + // 0 10 20 30 40 50 60 + // | | | | | | | + // 01234567 8 90123456 7890123456789012 3 456789012345678901234567890123456 + // ------------------------------------------------------------------------ + // 00011010 1 01110101 0000000010001110 1 000000000000000000000000000000000 + // bbbbbbbb w ffffffff cccccccccccccccc w xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + // |26 bit| |-117--| |-----142------| + // b = format bit len, o = odd parity of last 3 bits + // f = facility code, c = card number + // w = wiegand parity + // (26 bit format shown) + + uint8_t* decoded_data = protocol->data; + uint8_t format_length = decoded_data[0]; + + string_cat_printf(result, "Format: %d\r\n", format_length); + if(format_length == 26) { + uint8_t facility; + bit_lib_copy_bits(&facility, 0, 8, decoded_data, 9); + + uint16_t card_id; + bit_lib_copy_bits((uint8_t*)&card_id, 8, 8, decoded_data, 17); + bit_lib_copy_bits((uint8_t*)&card_id, 0, 8, decoded_data, 25); + string_cat_printf(result, "Facility: %d\r\n", facility); + string_cat_printf(result, "Card: %d", card_id); + } else { + // print 66 bits as hex + string_cat_printf(result, "Data: "); + for(size_t i = 0; i < AWID_DECODED_DATA_SIZE; i++) { + string_cat_printf(result, "%02X", decoded_data[i]); + } + } +}; + +void protocol_awid_render_brief_data(ProtocolAwid* protocol, string_t result) { + uint8_t* decoded_data = protocol->data; + uint8_t format_length = decoded_data[0]; + + string_cat_printf(result, "Format: %d\r\n", format_length); + if(format_length == 26) { + uint8_t facility; + bit_lib_copy_bits(&facility, 0, 8, decoded_data, 9); + + uint16_t card_id; + bit_lib_copy_bits((uint8_t*)&card_id, 8, 8, decoded_data, 17); + bit_lib_copy_bits((uint8_t*)&card_id, 0, 8, decoded_data, 25); + string_cat_printf(result, "ID: %03u,%05u", facility, card_id); + } else { + string_cat_printf(result, "Data: unknown"); + } +}; + +bool protocol_awid_write_data(ProtocolAwid* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_awid_encode(protocol->data, (uint8_t*)protocol->encoded_data); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 | + (3 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32); + request->t5577.blocks_to_write = 4; + result = true; + } + return result; +}; + +const ProtocolBase protocol_awid = { + .name = "AWID", + .manufacturer = "AWIG", + .data_size = AWID_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_awid_alloc, + .free = (ProtocolFree)protocol_awid_free, + .get_data = (ProtocolGetData)protocol_awid_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_awid_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_awid_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_awid_encoder_start, + .yield = (ProtocolEncoderYield)protocol_awid_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_awid_render_data, + .render_brief_data = (ProtocolRenderData)protocol_awid_render_brief_data, + .write_data = (ProtocolWriteData)protocol_awid_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_awid.h b/lib/lfrfid/protocols/protocol_awid.h new file mode 100644 index 0000000000..51a4ea52f5 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_awid.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_awid; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_em4100.c b/lib/lfrfid/protocols/protocol_em4100.c new file mode 100644 index 0000000000..92721fcdc1 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_em4100.c @@ -0,0 +1,292 @@ +#include +#include +#include +#include "lfrfid_protocols.h" + +typedef uint64_t EM4100DecodedData; + +#define EM_HEADER_POS (55) +#define EM_HEADER_MASK (0x1FFLLU << EM_HEADER_POS) + +#define EM_FIRST_ROW_POS (50) + +#define EM_ROW_COUNT (10) +#define EM_COLUMN_COUNT (4) +#define EM_BITS_PER_ROW_COUNT (EM_COLUMN_COUNT + 1) + +#define EM_COLUMN_POS (4) +#define EM_STOP_POS (0) +#define EM_STOP_MASK (0x1LLU << EM_STOP_POS) + +#define EM_HEADER_AND_STOP_MASK (EM_HEADER_MASK | EM_STOP_MASK) +#define EM_HEADER_AND_STOP_DATA (EM_HEADER_MASK) + +#define EM4100_DECODED_DATA_SIZE (5) +#define EM4100_ENCODED_DATA_SIZE (sizeof(EM4100DecodedData)) + +#define EM4100_CLOCK_PER_BIT (64) + +#define EM_READ_SHORT_TIME (256) +#define EM_READ_LONG_TIME (512) +#define EM_READ_JITTER_TIME (100) + +#define EM_READ_SHORT_TIME_LOW (EM_READ_SHORT_TIME - EM_READ_JITTER_TIME) +#define EM_READ_SHORT_TIME_HIGH (EM_READ_SHORT_TIME + EM_READ_JITTER_TIME) +#define EM_READ_LONG_TIME_LOW (EM_READ_LONG_TIME - EM_READ_JITTER_TIME) +#define EM_READ_LONG_TIME_HIGH (EM_READ_LONG_TIME + EM_READ_JITTER_TIME) + +typedef struct { + uint8_t data[EM4100_DECODED_DATA_SIZE]; + + EM4100DecodedData encoded_data; + uint8_t encoded_data_index; + bool encoded_polarity; + + ManchesterState decoder_manchester_state; +} ProtocolEM4100; + +ProtocolEM4100* protocol_em4100_alloc(void) { + ProtocolEM4100* proto = malloc(sizeof(ProtocolEM4100)); + return (void*)proto; +}; + +void protocol_em4100_free(ProtocolEM4100* proto) { + free(proto); +}; + +uint8_t* protocol_em4100_get_data(ProtocolEM4100* proto) { + return proto->data; +}; + +static void em4100_decode( + const uint8_t* encoded_data, + const uint8_t encoded_data_size, + uint8_t* decoded_data, + const uint8_t decoded_data_size) { + furi_check(decoded_data_size >= EM4100_DECODED_DATA_SIZE); + furi_check(encoded_data_size >= EM4100_ENCODED_DATA_SIZE); + + uint8_t decoded_data_index = 0; + EM4100DecodedData card_data = *((EM4100DecodedData*)(encoded_data)); + + // clean result + memset(decoded_data, 0, decoded_data_size); + + // header + for(uint8_t i = 0; i < 9; i++) { + card_data = card_data << 1; + } + + // nibbles + uint8_t value = 0; + for(uint8_t r = 0; r < EM_ROW_COUNT; r++) { + uint8_t nibble = 0; + for(uint8_t i = 0; i < 5; i++) { + if(i < 4) nibble = (nibble << 1) | (card_data & (1LLU << 63) ? 1 : 0); + card_data = card_data << 1; + } + value = (value << 4) | nibble; + if(r % 2) { + decoded_data[decoded_data_index] |= value; + decoded_data_index++; + value = 0; + } + } +} + +static bool em4100_can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) { + furi_check(encoded_data_size >= EM4100_ENCODED_DATA_SIZE); + const EM4100DecodedData* card_data = (EM4100DecodedData*)encoded_data; + + // check header and stop bit + if((*card_data & EM_HEADER_AND_STOP_MASK) != EM_HEADER_AND_STOP_DATA) return false; + + // check row parity + for(uint8_t i = 0; i < EM_ROW_COUNT; i++) { + uint8_t parity_sum = 0; + + for(uint8_t j = 0; j < EM_BITS_PER_ROW_COUNT; j++) { + parity_sum += (*card_data >> (EM_FIRST_ROW_POS - i * EM_BITS_PER_ROW_COUNT + j)) & 1; + } + + if((parity_sum % 2)) { + return false; + } + } + + // check columns parity + for(uint8_t i = 0; i < EM_COLUMN_COUNT; i++) { + uint8_t parity_sum = 0; + + for(uint8_t j = 0; j < EM_ROW_COUNT + 1; j++) { + parity_sum += (*card_data >> (EM_COLUMN_POS - i + j * EM_BITS_PER_ROW_COUNT)) & 1; + } + + if((parity_sum % 2)) { + return false; + } + } + + return true; +} + +void protocol_em4100_decoder_start(ProtocolEM4100* proto) { + memset(proto->data, 0, EM4100_DECODED_DATA_SIZE); + proto->encoded_data = 0; + manchester_advance( + proto->decoder_manchester_state, + ManchesterEventReset, + &proto->decoder_manchester_state, + NULL); +}; + +bool protocol_em4100_decoder_feed(ProtocolEM4100* proto, bool level, uint32_t duration) { + bool result = false; + + ManchesterEvent event = ManchesterEventReset; + + if(duration > EM_READ_SHORT_TIME_LOW && duration < EM_READ_SHORT_TIME_HIGH) { + if(!level) { + event = ManchesterEventShortHigh; + } else { + event = ManchesterEventShortLow; + } + } else if(duration > EM_READ_LONG_TIME_LOW && duration < EM_READ_LONG_TIME_HIGH) { + if(!level) { + event = ManchesterEventLongHigh; + } else { + event = ManchesterEventLongLow; + } + } + + if(event != ManchesterEventReset) { + bool data; + bool data_ok = manchester_advance( + proto->decoder_manchester_state, event, &proto->decoder_manchester_state, &data); + + if(data_ok) { + proto->encoded_data = (proto->encoded_data << 1) | data; + + if(em4100_can_be_decoded((uint8_t*)&proto->encoded_data, sizeof(EM4100DecodedData))) { + em4100_decode( + (uint8_t*)&proto->encoded_data, + sizeof(EM4100DecodedData), + proto->data, + EM4100_DECODED_DATA_SIZE); + result = true; + } + } + } + + return result; +}; + +static void em4100_write_nibble(bool low_nibble, uint8_t data, EM4100DecodedData* encoded_data) { + uint8_t parity_sum = 0; + uint8_t start = 0; + if(!low_nibble) start = 4; + + for(int8_t i = (start + 3); i >= start; i--) { + parity_sum += (data >> i) & 1; + *encoded_data = (*encoded_data << 1) | ((data >> i) & 1); + } + + *encoded_data = (*encoded_data << 1) | ((parity_sum % 2) & 1); +} + +bool protocol_em4100_encoder_start(ProtocolEM4100* proto) { + // header + proto->encoded_data = 0b111111111; + + // data + for(uint8_t i = 0; i < EM4100_DECODED_DATA_SIZE; i++) { + em4100_write_nibble(false, proto->data[i], &proto->encoded_data); + em4100_write_nibble(true, proto->data[i], &proto->encoded_data); + } + + // column parity and stop bit + uint8_t parity_sum; + + for(uint8_t c = 0; c < EM_COLUMN_COUNT; c++) { + parity_sum = 0; + for(uint8_t i = 1; i <= EM_ROW_COUNT; i++) { + uint8_t parity_bit = (proto->encoded_data >> (i * EM_BITS_PER_ROW_COUNT - 1)) & 1; + parity_sum += parity_bit; + } + proto->encoded_data = (proto->encoded_data << 1) | ((parity_sum % 2) & 1); + } + + // stop bit + proto->encoded_data = (proto->encoded_data << 1) | 0; + + proto->encoded_data_index = 0; + proto->encoded_polarity = true; + + return true; +}; + +LevelDuration protocol_em4100_encoder_yield(ProtocolEM4100* proto) { + bool level = (proto->encoded_data >> (63 - proto->encoded_data_index)) & 1; + uint32_t duration = EM4100_CLOCK_PER_BIT / 2; + + if(proto->encoded_polarity) { + proto->encoded_polarity = false; + } else { + level = !level; + + proto->encoded_polarity = true; + proto->encoded_data_index++; + if(proto->encoded_data_index >= 64) { + proto->encoded_data_index = 0; + } + } + + return level_duration_make(level, duration); +}; + +bool protocol_em4100_write_data(ProtocolEM4100* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_em4100_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = + (LFRFID_T5577_MODULATION_MANCHESTER | LFRFID_T5577_BITRATE_RF_64 | + (2 << LFRFID_T5577_MAXBLOCK_SHIFT)); + request->t5577.block[1] = protocol->encoded_data; + request->t5577.block[2] = protocol->encoded_data >> 32; + request->t5577.blocks_to_write = 3; + result = true; + } + return result; +}; + +void protocol_em4100_render_data(ProtocolEM4100* protocol, string_t result) { + uint8_t* data = protocol->data; + string_printf(result, "ID: %03u,%05u", data[2], (uint16_t)((data[3] << 8) | (data[4]))); +}; + +const ProtocolBase protocol_em4100 = { + .name = "EM4100", + .manufacturer = "EM-Micro", + .data_size = EM4100_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK | LFRFIDFeaturePSK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_em4100_alloc, + .free = (ProtocolFree)protocol_em4100_free, + .get_data = (ProtocolGetData)protocol_em4100_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_em4100_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_em4100_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_em4100_encoder_start, + .yield = (ProtocolEncoderYield)protocol_em4100_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_em4100_render_data, + .render_brief_data = (ProtocolRenderData)protocol_em4100_render_data, + .write_data = (ProtocolWriteData)protocol_em4100_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_em4100.h b/lib/lfrfid/protocols/protocol_em4100.h new file mode 100644 index 0000000000..6e1e25b937 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_em4100.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_em4100; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_fdx_a.c b/lib/lfrfid/protocols/protocol_fdx_a.c new file mode 100644 index 0000000000..23f9e2857f --- /dev/null +++ b/lib/lfrfid/protocols/protocol_fdx_a.c @@ -0,0 +1,239 @@ +#include +#include +#include +#include +#include "lfrfid_protocols.h" +#include + +#define JITTER_TIME (20) +#define MIN_TIME (64 - JITTER_TIME) +#define MAX_TIME (80 + JITTER_TIME) + +#define FDXA_DATA_SIZE 10 +#define FDXA_PREAMBLE_SIZE 2 + +#define FDXA_ENCODED_DATA_SIZE (FDXA_PREAMBLE_SIZE + FDXA_DATA_SIZE + FDXA_PREAMBLE_SIZE) +#define FDXA_ENCODED_BIT_SIZE ((FDXA_PREAMBLE_SIZE + FDXA_DATA_SIZE) * 8) +#define FDXA_DECODED_DATA_SIZE (5) +#define FDXA_DECODED_BIT_SIZE ((FDXA_ENCODED_BIT_SIZE - FDXA_PREAMBLE_SIZE * 8) / 2) + +#define FDXA_PREAMBLE_0 0x55 +#define FDXA_PREAMBLE_1 0x1D + +typedef struct { + FSKDemod* fsk_demod; +} ProtocolFDXADecoder; + +typedef struct { + FSKOsc* fsk_osc; + uint8_t encoded_index; + uint32_t pulse; +} ProtocolFDXAEncoder; + +typedef struct { + ProtocolFDXADecoder decoder; + ProtocolFDXAEncoder encoder; + uint8_t encoded_data[FDXA_ENCODED_DATA_SIZE]; + uint8_t data[FDXA_DECODED_DATA_SIZE]; + size_t protocol_size; +} ProtocolFDXA; + +ProtocolFDXA* protocol_fdx_a_alloc(void) { + ProtocolFDXA* protocol = malloc(sizeof(ProtocolFDXA)); + protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5); + protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50); + + return protocol; +}; + +void protocol_fdx_a_free(ProtocolFDXA* protocol) { + fsk_demod_free(protocol->decoder.fsk_demod); + fsk_osc_free(protocol->encoder.fsk_osc); + free(protocol); +}; + +uint8_t* protocol_fdx_a_get_data(ProtocolFDXA* protocol) { + return protocol->data; +}; + +void protocol_fdx_a_decoder_start(ProtocolFDXA* protocol) { + memset(protocol->encoded_data, 0, FDXA_ENCODED_DATA_SIZE); +}; + +static bool protocol_fdx_a_decode(const uint8_t* from, uint8_t* to) { + size_t bit_index = 0; + for(size_t i = FDXA_PREAMBLE_SIZE; i < (FDXA_PREAMBLE_SIZE + FDXA_DATA_SIZE); i++) { + for(size_t n = 0; n < 4; n++) { + uint8_t bit_pair = (from[i] >> (6 - (n * 2))) & 0b11; + if(bit_pair == 0b01) { + bit_lib_set_bit(to, bit_index, 0); + } else if(bit_pair == 0b10) { + bit_lib_set_bit(to, bit_index, 1); + } else { + return false; + } + bit_index++; + } + } + + return true; +} + +static bool protocol_fdx_a_can_be_decoded(const uint8_t* data) { + // check preamble + if(data[0] != FDXA_PREAMBLE_0 || data[1] != FDXA_PREAMBLE_1 || data[12] != FDXA_PREAMBLE_0 || + data[13] != FDXA_PREAMBLE_1) { + return false; + } + + // check for manchester encoding + uint8_t decoded_data[FDXA_DECODED_DATA_SIZE]; + if(!protocol_fdx_a_decode(data, decoded_data)) return false; + + uint8_t parity_sum = 0; + for(size_t i = 0; i < FDXA_DECODED_DATA_SIZE; i++) { + parity_sum += bit_lib_test_parity_32(decoded_data[i], BitLibParityOdd); + decoded_data[i] &= 0x7F; + } + + return (parity_sum == 0); +} + +bool protocol_fdx_a_decoder_feed(ProtocolFDXA* protocol, bool level, uint32_t duration) { + bool value; + uint32_t count; + bool result = false; + + fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count); + if(count > 0) { + for(size_t i = 0; i < count; i++) { + bit_lib_push_bit(protocol->encoded_data, FDXA_ENCODED_DATA_SIZE, value); + if(protocol_fdx_a_can_be_decoded(protocol->encoded_data)) { + protocol_fdx_a_decode(protocol->encoded_data, protocol->data); + result = true; + } + } + } + + return result; +}; + +static void protocol_fdx_a_encode(ProtocolFDXA* protocol) { + protocol->encoded_data[0] = FDXA_PREAMBLE_0; + protocol->encoded_data[1] = FDXA_PREAMBLE_1; + + size_t bit_index = 0; + for(size_t i = 0; i < FDXA_DECODED_BIT_SIZE; i++) { + bool bit = bit_lib_get_bit(protocol->data, i); + if(bit) { + bit_lib_set_bit(protocol->encoded_data, 16 + bit_index, 1); + bit_lib_set_bit(protocol->encoded_data, 16 + bit_index + 1, 0); + } else { + bit_lib_set_bit(protocol->encoded_data, 16 + bit_index, 0); + bit_lib_set_bit(protocol->encoded_data, 16 + bit_index + 1, 1); + } + bit_index += 2; + } +} + +bool protocol_fdx_a_encoder_start(ProtocolFDXA* protocol) { + protocol->encoder.encoded_index = 0; + protocol->encoder.pulse = 0; + protocol_fdx_a_encode(protocol); + + return true; +}; + +LevelDuration protocol_fdx_a_encoder_yield(ProtocolFDXA* protocol) { + bool level = 0; + uint32_t duration = 0; + + // if pulse is zero, we need to output high, otherwise we need to output low + if(protocol->encoder.pulse == 0) { + // get bit + uint8_t bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index); + + // get pulse from oscillator + bool advance = fsk_osc_next(protocol->encoder.fsk_osc, bit, &duration); + + if(advance) { + bit_lib_increment_index(protocol->encoder.encoded_index, FDXA_ENCODED_BIT_SIZE); + } + + // duration diveded by 2 because we need to output high and low + duration = duration / 2; + protocol->encoder.pulse = duration; + level = true; + } else { + // output low half and reset pulse + duration = protocol->encoder.pulse; + protocol->encoder.pulse = 0; + level = false; + } + + return level_duration_make(level, duration); +}; + +bool protocol_fdx_a_write_data(ProtocolFDXA* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_fdx_a_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 | + (3 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32); + request->t5577.blocks_to_write = 4; + result = true; + } + return result; +}; + +void protocol_fdx_a_render_data(ProtocolFDXA* protocol, string_t result) { + uint8_t data[FDXA_DECODED_DATA_SIZE]; + memcpy(data, protocol->data, FDXA_DECODED_DATA_SIZE); + + uint8_t parity_sum = 0; + for(size_t i = 0; i < FDXA_DECODED_DATA_SIZE; i++) { + parity_sum += bit_lib_test_parity_32(data[i], BitLibParityOdd); + data[i] &= 0x7F; + } + + string_printf( + result, + "ID: %02X%02X%02X%02X%02X\r\n" + "Parity: %s", + data[0], + data[1], + data[2], + data[3], + data[4], + parity_sum == 0 ? "+" : "-"); +}; + +const ProtocolBase protocol_fdx_a = { + .name = "FDX-A", + .manufacturer = "FECAVA", + .data_size = FDXA_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_fdx_a_alloc, + .free = (ProtocolFree)protocol_fdx_a_free, + .get_data = (ProtocolGetData)protocol_fdx_a_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_fdx_a_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_fdx_a_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_fdx_a_encoder_start, + .yield = (ProtocolEncoderYield)protocol_fdx_a_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_fdx_a_render_data, + .render_brief_data = (ProtocolRenderData)protocol_fdx_a_render_data, + .write_data = (ProtocolWriteData)protocol_fdx_a_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_fdx_a.h b/lib/lfrfid/protocols/protocol_fdx_a.h new file mode 100644 index 0000000000..355544881c --- /dev/null +++ b/lib/lfrfid/protocols/protocol_fdx_a.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_fdx_a; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_fdx_b.c b/lib/lfrfid/protocols/protocol_fdx_b.c new file mode 100644 index 0000000000..f68a884e85 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_fdx_b.c @@ -0,0 +1,374 @@ +#include +#include "toolbox/level_duration.h" +#include "protocol_fdx_b.h" +#include +#include +#include "lfrfid_protocols.h" + +#define FDX_B_ENCODED_BIT_SIZE (128) +#define FDX_B_ENCODED_BYTE_SIZE (((FDX_B_ENCODED_BIT_SIZE) / 8)) +#define FDX_B_PREAMBLE_BIT_SIZE (11) +#define FDX_B_PREAMBLE_BYTE_SIZE (2) +#define FDX_B_ENCODED_BYTE_FULL_SIZE (FDX_B_ENCODED_BYTE_SIZE + FDX_B_PREAMBLE_BYTE_SIZE) + +#define FDXB_DECODED_DATA_SIZE (11) + +#define FDX_B_SHORT_TIME (128) +#define FDX_B_LONG_TIME (256) +#define FDX_B_JITTER_TIME (60) + +#define FDX_B_SHORT_TIME_LOW (FDX_B_SHORT_TIME - FDX_B_JITTER_TIME) +#define FDX_B_SHORT_TIME_HIGH (FDX_B_SHORT_TIME + FDX_B_JITTER_TIME) +#define FDX_B_LONG_TIME_LOW (FDX_B_LONG_TIME - FDX_B_JITTER_TIME) +#define FDX_B_LONG_TIME_HIGH (FDX_B_LONG_TIME + FDX_B_JITTER_TIME) + +typedef struct { + bool last_short; + bool last_level; + size_t encoded_index; + uint8_t encoded_data[FDX_B_ENCODED_BYTE_FULL_SIZE]; + uint8_t data[FDXB_DECODED_DATA_SIZE]; +} ProtocolFDXB; + +ProtocolFDXB* protocol_fdx_b_alloc(void) { + ProtocolFDXB* protocol = malloc(sizeof(ProtocolFDXB)); + return protocol; +}; + +void protocol_fdx_b_free(ProtocolFDXB* protocol) { + free(protocol); +}; + +uint8_t* protocol_fdx_b_get_data(ProtocolFDXB* proto) { + return proto->data; +}; + +void protocol_fdx_b_decoder_start(ProtocolFDXB* protocol) { + memset(protocol->encoded_data, 0, FDX_B_ENCODED_BYTE_FULL_SIZE); + protocol->last_short = false; +}; + +static bool protocol_fdx_b_can_be_decoded(ProtocolFDXB* protocol) { + bool result = false; + + /* + msb lsb + 0 10000000000 Header pattern. 11 bits. + 11 1nnnnnnnn + 20 1nnnnnnnn 38 bit (12 digit) National code. + 29 1nnnnnnnn eg. 000000001008 (decimal). + 38 1nnnnnnnn + 47 1nnnnnncc 10 bit (3 digit) Country code. + 56 1cccccccc eg. 999 (decimal). + 65 1s------- 1 bit data block status flag. + 74 1-------a 1 bit animal application indicator. + 83 1xxxxxxxx 16 bit checksum. + 92 1xxxxxxxx + 101 1eeeeeeee 24 bits of extra data if present. + 110 1eeeeeeee eg. $123456. + 119 1eeeeeeee + */ + + do { + // check 11 bits preamble + if(bit_lib_get_bits_16(protocol->encoded_data, 0, 11) != 0b10000000000) break; + // check next 11 bits preamble + if(bit_lib_get_bits_16(protocol->encoded_data, 128, 11) != 0b10000000000) break; + // check control bits + if(!bit_lib_test_parity(protocol->encoded_data, 3, 13 * 9, BitLibParityAlways1, 9)) break; + + // compute checksum + uint8_t crc_data[8]; + for(size_t i = 0; i < 8; i++) { + bit_lib_copy_bits(crc_data, i * 8, 8, protocol->encoded_data, 12 + 9 * i); + } + uint16_t crc_res = bit_lib_crc16(crc_data, 8, 0x1021, 0x0000, false, false, 0x0000); + + // read checksum + uint16_t crc_ex = 0; + bit_lib_copy_bits((uint8_t*)&crc_ex, 8, 8, protocol->encoded_data, 84); + bit_lib_copy_bits((uint8_t*)&crc_ex, 0, 8, protocol->encoded_data, 93); + + // compare checksum + if(crc_res != crc_ex) break; + + result = true; + } while(false); + + return result; +} + +void protocol_fdx_b_decode(ProtocolFDXB* protocol) { + // remove parity + bit_lib_remove_bit_every_nth(protocol->encoded_data, 3, 13 * 9, 9); + + // remove header pattern + for(size_t i = 0; i < 11; i++) + bit_lib_push_bit(protocol->encoded_data, FDX_B_ENCODED_BYTE_FULL_SIZE, 0); + + // 0 nnnnnnnn + // 8 nnnnnnnn 38 bit (12 digit) National code. + // 16 nnnnnnnn eg. 000000001008 (decimal). + // 24 nnnnnnnn + // 32 nnnnnncc 10 bit (3 digit) Country code. + // 40 cccccccc eg. 999 (decimal). + // 48 s------- 1 bit data block status flag. + // 56 -------a 1 bit animal application indicator. + // 64 xxxxxxxx 16 bit checksum. + // 72 xxxxxxxx + // 80 eeeeeeee 24 bits of extra data if present. + // 88 eeeeeeee eg. $123456. + // 92 eeeeeeee + + // copy data without checksum + bit_lib_copy_bits(protocol->data, 0, 64, protocol->encoded_data, 0); + bit_lib_copy_bits(protocol->data, 64, 24, protocol->encoded_data, 80); + + // const BitLibRegion regions_encoded[] = { + // {'n', 0, 38}, + // {'c', 38, 10}, + // {'b', 48, 16}, + // {'x', 64, 16}, + // {'e', 80, 24}, + // }; + + // bit_lib_print_regions(regions_encoded, 5, protocol->encoded_data, FDX_B_ENCODED_BIT_SIZE); + + // const BitLibRegion regions_decoded[] = { + // {'n', 0, 38}, + // {'c', 38, 10}, + // {'b', 48, 16}, + // {'e', 64, 24}, + // }; + + // bit_lib_print_regions(regions_decoded, 4, protocol->data, FDXB_DECODED_DATA_SIZE * 8); +} + +bool protocol_fdx_b_decoder_feed(ProtocolFDXB* protocol, bool level, uint32_t duration) { + bool result = false; + UNUSED(level); + + bool pushed = false; + + // Bi-Phase Manchester decoding + if(duration >= FDX_B_SHORT_TIME_LOW && duration <= FDX_B_SHORT_TIME_HIGH) { + if(protocol->last_short == false) { + protocol->last_short = true; + } else { + pushed = true; + bit_lib_push_bit(protocol->encoded_data, FDX_B_ENCODED_BYTE_FULL_SIZE, false); + protocol->last_short = false; + } + } else if(duration >= FDX_B_LONG_TIME_LOW && duration <= FDX_B_LONG_TIME_HIGH) { + if(protocol->last_short == false) { + pushed = true; + bit_lib_push_bit(protocol->encoded_data, FDX_B_ENCODED_BYTE_FULL_SIZE, true); + } else { + // reset + protocol->last_short = false; + } + } else { + // reset + protocol->last_short = false; + } + + if(pushed && protocol_fdx_b_can_be_decoded(protocol)) { + protocol_fdx_b_decode(protocol); + result = true; + } + + return result; +}; + +bool protocol_fdx_b_encoder_start(ProtocolFDXB* protocol) { + memset(protocol->encoded_data, 0, FDX_B_ENCODED_BYTE_FULL_SIZE); + bit_lib_set_bit(protocol->encoded_data, 0, 1); + for(size_t i = 0; i < 13; i++) { + bit_lib_set_bit(protocol->encoded_data, 11 + 9 * i, 1); + if(i == 8 || i == 9) continue; + + if(i < 8) { + bit_lib_copy_bits(protocol->encoded_data, 12 + 9 * i, 8, protocol->data, i * 8); + } else { + bit_lib_copy_bits(protocol->encoded_data, 12 + 9 * i, 8, protocol->data, (i - 2) * 8); + } + } + + uint16_t crc_res = bit_lib_crc16(protocol->data, 8, 0x1021, 0x0000, false, false, 0x0000); + bit_lib_copy_bits(protocol->encoded_data, 84, 8, (uint8_t*)&crc_res, 8); + bit_lib_copy_bits(protocol->encoded_data, 93, 8, (uint8_t*)&crc_res, 0); + + protocol->encoded_index = 0; + protocol->last_short = false; + protocol->last_level = false; + return true; +}; + +LevelDuration protocol_fdx_b_encoder_yield(ProtocolFDXB* protocol) { + uint32_t duration; + protocol->last_level = !protocol->last_level; + + bool bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoded_index); + + // Bi-Phase Manchester encoder + if(bit) { + // one long pulse for 1 + duration = FDX_B_LONG_TIME / 8; + bit_lib_increment_index(protocol->encoded_index, FDX_B_ENCODED_BIT_SIZE); + } else { + // two short pulses for 0 + duration = FDX_B_SHORT_TIME / 8; + if(protocol->last_short) { + bit_lib_increment_index(protocol->encoded_index, FDX_B_ENCODED_BIT_SIZE); + protocol->last_short = false; + } else { + protocol->last_short = true; + } + } + + return level_duration_make(protocol->last_level, duration); +}; + +// 0 nnnnnnnn +// 8 nnnnnnnn 38 bit (12 digit) National code. +// 16 nnnnnnnn eg. 000000001008 (decimal). +// 24 nnnnnnnn +// 32 nnnnnnnn 10 bit (3 digit) Country code. +// 40 cccccccc eg. 999 (decimal). +// 48 s------- 1 bit data block status flag. +// 56 -------a 1 bit animal application indicator. +// 64 eeeeeeee 24 bits of extra data if present. +// 72 eeeeeeee eg. $123456. +// 80 eeeeeeee + +static uint64_t protocol_fdx_b_get_national_code(const uint8_t* data) { + uint64_t national_code = bit_lib_get_bits_32(data, 0, 32); + national_code = national_code << 32; + national_code |= bit_lib_get_bits_32(data, 32, 6) << (32 - 6); + bit_lib_reverse_bits((uint8_t*)&national_code, 0, 64); + return national_code; +} + +static uint16_t protocol_fdx_b_get_country_code(const uint8_t* data) { + uint16_t country_code = bit_lib_get_bits_16(data, 38, 10) << 6; + bit_lib_reverse_bits((uint8_t*)&country_code, 0, 16); + return country_code; +} + +static bool protocol_fdx_b_get_temp(const uint8_t* data, float* temp) { + uint32_t extended = bit_lib_get_bits_32(data, 64, 24) << 8; + bit_lib_reverse_bits((uint8_t*)&extended, 0, 32); + + uint8_t ex_parity = (extended & 0x100) >> 8; + uint8_t ex_temperature = extended & 0xff; + uint8_t ex_calc_parity = bit_lib_test_parity_32(ex_temperature, BitLibParityOdd); + bool ex_temperature_present = (ex_calc_parity == ex_parity) && !(extended & 0xe00); + + if(ex_temperature_present) { + float temperature_f = 74 + ex_temperature * 0.2; + *temp = temperature_f; + return true; + } else { + return false; + } +} + +void protocol_fdx_b_render_data(ProtocolFDXB* protocol, string_t result) { + // 38 bits of national code + uint64_t national_code = protocol_fdx_b_get_national_code(protocol->data); + + // 10 bit of country code + uint16_t country_code = protocol_fdx_b_get_country_code(protocol->data); + + bool block_status = bit_lib_get_bit(protocol->data, 48); + bool rudi_bit = bit_lib_get_bit(protocol->data, 49); + uint8_t reserved = bit_lib_get_bits(protocol->data, 50, 5); + uint8_t user_info = bit_lib_get_bits(protocol->data, 55, 5); + uint8_t replacement_number = bit_lib_get_bits(protocol->data, 60, 3); + bool animal_flag = bit_lib_get_bit(protocol->data, 63); + + string_printf(result, "ID: %03u-%012llu\r\n", country_code, national_code); + string_cat_printf(result, "Animal: %s, ", animal_flag ? "Yes" : "No"); + + float temperature; + if(protocol_fdx_b_get_temp(protocol->data, &temperature)) { + float temperature_c = (temperature - 32) / 1.8; + string_cat_printf( + result, "T: %.2fF, %.2fC\r\n", (double)temperature, (double)temperature_c); + } else { + string_cat_printf(result, "T: ---\r\n"); + } + + string_cat_printf( + result, + "Bits: %X-%X-%X-%X-%X", + block_status, + rudi_bit, + reserved, + user_info, + replacement_number); +}; + +void protocol_fdx_b_render_brief_data(ProtocolFDXB* protocol, string_t result) { + // 38 bits of national code + uint64_t national_code = protocol_fdx_b_get_national_code(protocol->data); + + // 10 bit of country code + uint16_t country_code = protocol_fdx_b_get_country_code(protocol->data); + + bool animal_flag = bit_lib_get_bit(protocol->data, 63); + + string_printf(result, "ID: %03u-%012llu\r\n", country_code, national_code); + string_cat_printf(result, "Animal: %s, ", animal_flag ? "Yes" : "No"); + + float temperature; + if(protocol_fdx_b_get_temp(protocol->data, &temperature)) { + float temperature_c = (temperature - 32) / 1.8; + string_cat_printf(result, "T: %.2fC", (double)temperature_c); + } else { + string_cat_printf(result, "T: ---"); + } +}; + +bool protocol_fdx_b_write_data(ProtocolFDXB* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_fdx_b_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_DIPHASE | LFRFID_T5577_BITRATE_RF_32 | + (4 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32); + request->t5577.block[4] = bit_lib_get_bits_32(protocol->encoded_data, 96, 32); + request->t5577.blocks_to_write = 5; + result = true; + } + return result; +}; + +const ProtocolBase protocol_fdx_b = { + .name = "FDX-B", + .manufacturer = "ISO", + .data_size = FDXB_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_fdx_b_alloc, + .free = (ProtocolFree)protocol_fdx_b_free, + .get_data = (ProtocolGetData)protocol_fdx_b_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_fdx_b_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_fdx_b_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_fdx_b_encoder_start, + .yield = (ProtocolEncoderYield)protocol_fdx_b_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_fdx_b_render_data, + .render_brief_data = (ProtocolRenderData)protocol_fdx_b_render_brief_data, + .write_data = (ProtocolWriteData)protocol_fdx_b_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_fdx_b.h b/lib/lfrfid/protocols/protocol_fdx_b.h new file mode 100644 index 0000000000..549c862e38 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_fdx_b.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_fdx_b; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_h10301.c b/lib/lfrfid/protocols/protocol_h10301.c new file mode 100644 index 0000000000..f30f75facf --- /dev/null +++ b/lib/lfrfid/protocols/protocol_h10301.c @@ -0,0 +1,386 @@ +#include +#include +#include +#include +#include "lfrfid_protocols.h" + +#define JITTER_TIME (20) +#define MIN_TIME (64 - JITTER_TIME) +#define MAX_TIME (80 + JITTER_TIME) + +#define H10301_DECODED_DATA_SIZE (3) +#define H10301_ENCODED_DATA_SIZE_U32 (3) +#define H10301_ENCODED_DATA_SIZE (sizeof(uint32_t) * H10301_ENCODED_DATA_SIZE_U32) + +#define H10301_BIT_SIZE (sizeof(uint32_t) * 8) +#define H10301_BIT_MAX_SIZE (H10301_BIT_SIZE * H10301_DECODED_DATA_SIZE) + +typedef struct { + FSKDemod* fsk_demod; +} ProtocolH10301Decoder; + +typedef struct { + FSKOsc* fsk_osc; + uint8_t encoded_index; + uint32_t pulse; +} ProtocolH10301Encoder; + +typedef struct { + ProtocolH10301Decoder decoder; + ProtocolH10301Encoder encoder; + uint32_t encoded_data[H10301_ENCODED_DATA_SIZE_U32]; + uint8_t data[H10301_DECODED_DATA_SIZE]; +} ProtocolH10301; + +ProtocolH10301* protocol_h10301_alloc(void) { + ProtocolH10301* protocol = malloc(sizeof(ProtocolH10301)); + protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5); + protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50); + + return protocol; +}; + +void protocol_h10301_free(ProtocolH10301* protocol) { + fsk_demod_free(protocol->decoder.fsk_demod); + fsk_osc_free(protocol->encoder.fsk_osc); + free(protocol); +}; + +uint8_t* protocol_h10301_get_data(ProtocolH10301* protocol) { + return protocol->data; +}; + +void protocol_h10301_decoder_start(ProtocolH10301* protocol) { + memset(protocol->encoded_data, 0, sizeof(uint32_t) * 3); +}; + +static void protocol_h10301_decoder_store_data(ProtocolH10301* protocol, bool data) { + protocol->encoded_data[0] = (protocol->encoded_data[0] << 1) | + ((protocol->encoded_data[1] >> 31) & 1); + protocol->encoded_data[1] = (protocol->encoded_data[1] << 1) | + ((protocol->encoded_data[2] >> 31) & 1); + protocol->encoded_data[2] = (protocol->encoded_data[2] << 1) | data; +} + +static bool protocol_h10301_can_be_decoded(const uint32_t* card_data) { + const uint8_t* encoded_data = (const uint8_t*)card_data; + + // packet preamble + // raw data + if(*(encoded_data + 3) != 0x1D) { + return false; + } + + // encoded company/oem + // coded with 01 = 0, 10 = 1 transitions + // stored in word 0 + if((*card_data >> 10 & 0x3FFF) != 0x1556) { + return false; + } + + // encoded format/length + // coded with 01 = 0, 10 = 1 transitions + // stored in word 0 and word 1 + if((((*card_data & 0x3FF) << 12) | ((*(card_data + 1) >> 20) & 0xFFF)) != 0x155556) { + return false; + } + + // data decoding + uint32_t result = 0; + + // decode from word 1 + // coded with 01 = 0, 10 = 1 transitions + for(int8_t i = 9; i >= 0; i--) { + switch((*(card_data + 1) >> (2 * i)) & 0b11) { + case 0b01: + result = (result << 1) | 0; + break; + case 0b10: + result = (result << 1) | 1; + break; + default: + return false; + break; + } + } + + // decode from word 2 + // coded with 01 = 0, 10 = 1 transitions + for(int8_t i = 15; i >= 0; i--) { + switch((*(card_data + 2) >> (2 * i)) & 0b11) { + case 0b01: + result = (result << 1) | 0; + break; + case 0b10: + result = (result << 1) | 1; + break; + default: + return false; + break; + } + } + + // trailing parity (odd) test + uint8_t parity_sum = 0; + for(int8_t i = 0; i < 13; i++) { + if(((result >> i) & 1) == 1) { + parity_sum++; + } + } + + if((parity_sum % 2) != 1) { + return false; + } + + // leading parity (even) test + parity_sum = 0; + for(int8_t i = 13; i < 26; i++) { + if(((result >> i) & 1) == 1) { + parity_sum++; + } + } + + if((parity_sum % 2) == 1) { + return false; + } + + return true; +} + +static void protocol_h10301_decode(const uint32_t* card_data, uint8_t* decoded_data) { + // data decoding + uint32_t result = 0; + + // decode from word 1 + // coded with 01 = 0, 10 = 1 transitions + for(int8_t i = 9; i >= 0; i--) { + switch((*(card_data + 1) >> (2 * i)) & 0b11) { + case 0b01: + result = (result << 1) | 0; + break; + case 0b10: + result = (result << 1) | 1; + break; + default: + break; + } + } + + // decode from word 2 + // coded with 01 = 0, 10 = 1 transitions + for(int8_t i = 15; i >= 0; i--) { + switch((*(card_data + 2) >> (2 * i)) & 0b11) { + case 0b01: + result = (result << 1) | 0; + break; + case 0b10: + result = (result << 1) | 1; + break; + default: + break; + } + } + + uint8_t data[H10301_DECODED_DATA_SIZE] = { + (uint8_t)(result >> 17), (uint8_t)(result >> 9), (uint8_t)(result >> 1)}; + + memcpy(decoded_data, &data, H10301_DECODED_DATA_SIZE); +} + +bool protocol_h10301_decoder_feed(ProtocolH10301* protocol, bool level, uint32_t duration) { + bool value; + uint32_t count; + bool result = false; + + fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count); + if(count > 0) { + for(size_t i = 0; i < count; i++) { + protocol_h10301_decoder_store_data(protocol, value); + if(protocol_h10301_can_be_decoded(protocol->encoded_data)) { + protocol_h10301_decode(protocol->encoded_data, protocol->data); + result = true; + break; + } + } + } + + return result; +}; + +static void protocol_h10301_write_raw_bit(bool bit, uint8_t position, uint32_t* card_data) { + if(bit) { + card_data[position / H10301_BIT_SIZE] |= + 1UL << (H10301_BIT_SIZE - (position % H10301_BIT_SIZE) - 1); + } else { + card_data[position / H10301_BIT_SIZE] &= + ~(1UL << (H10301_BIT_SIZE - (position % H10301_BIT_SIZE) - 1)); + } +} + +static void protocol_h10301_write_bit(bool bit, uint8_t position, uint32_t* card_data) { + protocol_h10301_write_raw_bit(bit, position + 0, card_data); + protocol_h10301_write_raw_bit(!bit, position + 1, card_data); +} + +void protocol_h10301_encode(const uint8_t* decoded_data, uint8_t* encoded_data) { + uint32_t card_data[H10301_DECODED_DATA_SIZE] = {0, 0, 0}; + + uint32_t fc_cn = (decoded_data[0] << 16) | (decoded_data[1] << 8) | decoded_data[2]; + + // even parity sum calculation (high 12 bits of data) + uint8_t even_parity_sum = 0; + for(int8_t i = 12; i < 24; i++) { + if(((fc_cn >> i) & 1) == 1) { + even_parity_sum++; + } + } + + // odd parity sum calculation (low 12 bits of data) + uint8_t odd_parity_sum = 1; + for(int8_t i = 0; i < 12; i++) { + if(((fc_cn >> i) & 1) == 1) { + odd_parity_sum++; + } + } + + // 0x1D preamble + protocol_h10301_write_raw_bit(0, 0, card_data); + protocol_h10301_write_raw_bit(0, 1, card_data); + protocol_h10301_write_raw_bit(0, 2, card_data); + protocol_h10301_write_raw_bit(1, 3, card_data); + protocol_h10301_write_raw_bit(1, 4, card_data); + protocol_h10301_write_raw_bit(1, 5, card_data); + protocol_h10301_write_raw_bit(0, 6, card_data); + protocol_h10301_write_raw_bit(1, 7, card_data); + + // company / OEM code 1 + protocol_h10301_write_bit(0, 8, card_data); + protocol_h10301_write_bit(0, 10, card_data); + protocol_h10301_write_bit(0, 12, card_data); + protocol_h10301_write_bit(0, 14, card_data); + protocol_h10301_write_bit(0, 16, card_data); + protocol_h10301_write_bit(0, 18, card_data); + protocol_h10301_write_bit(1, 20, card_data); + + // card format / length 1 + protocol_h10301_write_bit(0, 22, card_data); + protocol_h10301_write_bit(0, 24, card_data); + protocol_h10301_write_bit(0, 26, card_data); + protocol_h10301_write_bit(0, 28, card_data); + protocol_h10301_write_bit(0, 30, card_data); + protocol_h10301_write_bit(0, 32, card_data); + protocol_h10301_write_bit(0, 34, card_data); + protocol_h10301_write_bit(0, 36, card_data); + protocol_h10301_write_bit(0, 38, card_data); + protocol_h10301_write_bit(0, 40, card_data); + protocol_h10301_write_bit(1, 42, card_data); + + // even parity bit + protocol_h10301_write_bit((even_parity_sum % 2), 44, card_data); + + // data + for(uint8_t i = 0; i < 24; i++) { + protocol_h10301_write_bit((fc_cn >> (23 - i)) & 1, 46 + (i * 2), card_data); + } + + // odd parity bit + protocol_h10301_write_bit((odd_parity_sum % 2), 94, card_data); + + memcpy(encoded_data, &card_data, H10301_ENCODED_DATA_SIZE); +} + +bool protocol_h10301_encoder_start(ProtocolH10301* protocol) { + protocol_h10301_encode(protocol->data, (uint8_t*)protocol->encoded_data); + protocol->encoder.encoded_index = 0; + protocol->encoder.pulse = 0; + + return true; +}; + +LevelDuration protocol_h10301_encoder_yield(ProtocolH10301* protocol) { + bool level = 0; + uint32_t duration = 0; + + // if pulse is zero, we need to output high, otherwise we need to output low + if(protocol->encoder.pulse == 0) { + // get bit + uint8_t bit = + (protocol->encoded_data[protocol->encoder.encoded_index / H10301_BIT_SIZE] >> + ((H10301_BIT_SIZE - 1) - (protocol->encoder.encoded_index % H10301_BIT_SIZE))) & + 1; + + // get pulse from oscillator + bool advance = fsk_osc_next(protocol->encoder.fsk_osc, bit, &duration); + + if(advance) { + protocol->encoder.encoded_index++; + if(protocol->encoder.encoded_index >= (H10301_BIT_MAX_SIZE)) { + protocol->encoder.encoded_index = 0; + } + } + + // duration diveded by 2 because we need to output high and low + duration = duration / 2; + protocol->encoder.pulse = duration; + level = true; + } else { + // output low half and reset pulse + duration = protocol->encoder.pulse; + protocol->encoder.pulse = 0; + level = false; + } + + return level_duration_make(level, duration); +}; + +bool protocol_h10301_write_data(ProtocolH10301* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_h10301_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 | + (3 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = protocol->encoded_data[0]; + request->t5577.block[2] = protocol->encoded_data[1]; + request->t5577.block[3] = protocol->encoded_data[2]; + request->t5577.blocks_to_write = 4; + result = true; + } + return result; +}; + +void protocol_h10301_render_data(ProtocolH10301* protocol, string_t result) { + uint8_t* data = protocol->data; + string_printf( + result, + "FC: %u\r\n" + "Card: %u", + data[0], + (uint16_t)((data[1] << 8) | (data[2]))); +}; + +const ProtocolBase protocol_h10301 = { + .name = "H10301", + .manufacturer = "HID", + .data_size = H10301_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_h10301_alloc, + .free = (ProtocolFree)protocol_h10301_free, + .get_data = (ProtocolGetData)protocol_h10301_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_h10301_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_h10301_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_h10301_encoder_start, + .yield = (ProtocolEncoderYield)protocol_h10301_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_h10301_render_data, + .render_brief_data = (ProtocolRenderData)protocol_h10301_render_data, + .write_data = (ProtocolWriteData)protocol_h10301_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_h10301.h b/lib/lfrfid/protocols/protocol_h10301.h new file mode 100644 index 0000000000..b7ee5ad57d --- /dev/null +++ b/lib/lfrfid/protocols/protocol_h10301.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_h10301; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_hid_ex_generic.c b/lib/lfrfid/protocols/protocol_hid_ex_generic.c new file mode 100644 index 0000000000..e0a8526618 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_hid_ex_generic.c @@ -0,0 +1,219 @@ +#include +#include +#include +#include +#include "lfrfid_protocols.h" +#include + +#define JITTER_TIME (20) +#define MIN_TIME (64 - JITTER_TIME) +#define MAX_TIME (80 + JITTER_TIME) + +#define HID_DATA_SIZE 23 +#define HID_PREAMBLE_SIZE 1 + +#define HID_ENCODED_DATA_SIZE (HID_PREAMBLE_SIZE + HID_DATA_SIZE + HID_PREAMBLE_SIZE) +#define HID_ENCODED_BIT_SIZE ((HID_PREAMBLE_SIZE + HID_DATA_SIZE) * 8) +#define HID_DECODED_DATA_SIZE (12) +#define HID_DECODED_BIT_SIZE ((HID_ENCODED_BIT_SIZE - HID_PREAMBLE_SIZE * 8) / 2) + +#define HID_PREAMBLE 0x1D + +typedef struct { + FSKDemod* fsk_demod; +} ProtocolHIDExDecoder; + +typedef struct { + FSKOsc* fsk_osc; + uint8_t encoded_index; + uint32_t pulse; +} ProtocolHIDExEncoder; + +typedef struct { + ProtocolHIDExDecoder decoder; + ProtocolHIDExEncoder encoder; + uint8_t encoded_data[HID_ENCODED_DATA_SIZE]; + uint8_t data[HID_DECODED_DATA_SIZE]; + size_t protocol_size; +} ProtocolHIDEx; + +ProtocolHIDEx* protocol_hid_ex_generic_alloc(void) { + ProtocolHIDEx* protocol = malloc(sizeof(ProtocolHIDEx)); + protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5); + protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50); + + return protocol; +}; + +void protocol_hid_ex_generic_free(ProtocolHIDEx* protocol) { + fsk_demod_free(protocol->decoder.fsk_demod); + fsk_osc_free(protocol->encoder.fsk_osc); + free(protocol); +}; + +uint8_t* protocol_hid_ex_generic_get_data(ProtocolHIDEx* protocol) { + return protocol->data; +}; + +void protocol_hid_ex_generic_decoder_start(ProtocolHIDEx* protocol) { + memset(protocol->encoded_data, 0, HID_ENCODED_DATA_SIZE); +}; + +static bool protocol_hid_ex_generic_can_be_decoded(const uint8_t* data) { + // check preamble + if(data[0] != HID_PREAMBLE || data[HID_PREAMBLE_SIZE + HID_DATA_SIZE] != HID_PREAMBLE) { + return false; + } + + // check for manchester encoding + for(size_t i = HID_PREAMBLE_SIZE; i < (HID_PREAMBLE_SIZE + HID_DATA_SIZE); i++) { + for(size_t n = 0; n < 4; n++) { + uint8_t bit_pair = (data[i] >> (n * 2)) & 0b11; + if(bit_pair == 0b11 || bit_pair == 0b00) { + return false; + } + } + } + + return true; +} + +static void protocol_hid_ex_generic_decode(const uint8_t* from, uint8_t* to) { + size_t bit_index = 0; + for(size_t i = HID_PREAMBLE_SIZE; i < (HID_PREAMBLE_SIZE + HID_DATA_SIZE); i++) { + for(size_t n = 0; n < 4; n++) { + uint8_t bit_pair = (from[i] >> (6 - (n * 2))) & 0b11; + if(bit_pair == 0b01) { + bit_lib_set_bit(to, bit_index, 0); + } else if(bit_pair == 0b10) { + bit_lib_set_bit(to, bit_index, 1); + } + bit_index++; + } + } +} + +bool protocol_hid_ex_generic_decoder_feed(ProtocolHIDEx* protocol, bool level, uint32_t duration) { + bool value; + uint32_t count; + bool result = false; + + fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count); + if(count > 0) { + for(size_t i = 0; i < count; i++) { + bit_lib_push_bit(protocol->encoded_data, HID_ENCODED_DATA_SIZE, value); + if(protocol_hid_ex_generic_can_be_decoded(protocol->encoded_data)) { + protocol_hid_ex_generic_decode(protocol->encoded_data, protocol->data); + result = true; + } + } + } + + return result; +}; + +static void protocol_hid_ex_generic_encode(ProtocolHIDEx* protocol) { + protocol->encoded_data[0] = HID_PREAMBLE; + + size_t bit_index = 0; + for(size_t i = 0; i < HID_DECODED_BIT_SIZE; i++) { + bool bit = bit_lib_get_bit(protocol->data, i); + if(bit) { + bit_lib_set_bit(protocol->encoded_data, 8 + bit_index, 1); + bit_lib_set_bit(protocol->encoded_data, 8 + bit_index + 1, 0); + } else { + bit_lib_set_bit(protocol->encoded_data, 8 + bit_index, 0); + bit_lib_set_bit(protocol->encoded_data, 8 + bit_index + 1, 1); + } + bit_index += 2; + } +} + +bool protocol_hid_ex_generic_encoder_start(ProtocolHIDEx* protocol) { + protocol->encoder.encoded_index = 0; + protocol->encoder.pulse = 0; + protocol_hid_ex_generic_encode(protocol); + + return true; +}; + +LevelDuration protocol_hid_ex_generic_encoder_yield(ProtocolHIDEx* protocol) { + bool level = 0; + uint32_t duration = 0; + + // if pulse is zero, we need to output high, otherwise we need to output low + if(protocol->encoder.pulse == 0) { + // get bit + uint8_t bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index); + + // get pulse from oscillator + bool advance = fsk_osc_next(protocol->encoder.fsk_osc, bit, &duration); + + if(advance) { + bit_lib_increment_index(protocol->encoder.encoded_index, HID_ENCODED_BIT_SIZE); + } + + // duration diveded by 2 because we need to output high and low + duration = duration / 2; + protocol->encoder.pulse = duration; + level = true; + } else { + // output low half and reset pulse + duration = protocol->encoder.pulse; + protocol->encoder.pulse = 0; + level = false; + } + + return level_duration_make(level, duration); +}; + +bool protocol_hid_ex_generic_write_data(ProtocolHIDEx* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_hid_ex_generic_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 | + (6 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32); + request->t5577.block[4] = bit_lib_get_bits_32(protocol->encoded_data, 96, 32); + request->t5577.block[5] = bit_lib_get_bits_32(protocol->encoded_data, 128, 32); + request->t5577.block[6] = bit_lib_get_bits_32(protocol->encoded_data, 160, 32); + request->t5577.blocks_to_write = 7; + result = true; + } + return result; +}; + +void protocol_hid_ex_generic_render_data(ProtocolHIDEx* protocol, string_t result) { + // TODO: parser and render functions + UNUSED(protocol); + string_printf(result, "Generic HID Extended\r\nData: Unknown"); +}; + +const ProtocolBase protocol_hid_ex_generic = { + .name = "HIDExt", + .manufacturer = "Generic", + .data_size = HID_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_hid_ex_generic_alloc, + .free = (ProtocolFree)protocol_hid_ex_generic_free, + .get_data = (ProtocolGetData)protocol_hid_ex_generic_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_hid_ex_generic_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_hid_ex_generic_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_hid_ex_generic_encoder_start, + .yield = (ProtocolEncoderYield)protocol_hid_ex_generic_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_hid_ex_generic_render_data, + .render_brief_data = (ProtocolRenderData)protocol_hid_ex_generic_render_data, + .write_data = (ProtocolWriteData)protocol_hid_ex_generic_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_hid_ex_generic.h b/lib/lfrfid/protocols/protocol_hid_ex_generic.h new file mode 100644 index 0000000000..9c4ddffff3 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_hid_ex_generic.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_hid_ex_generic; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_hid_generic.c b/lib/lfrfid/protocols/protocol_hid_generic.c new file mode 100644 index 0000000000..2516d68105 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_hid_generic.c @@ -0,0 +1,280 @@ +#include +#include +#include +#include +#include "lfrfid_protocols.h" +#include + +#define JITTER_TIME (20) +#define MIN_TIME (64 - JITTER_TIME) +#define MAX_TIME (80 + JITTER_TIME) + +#define HID_DATA_SIZE 11 +#define HID_PREAMBLE_SIZE 1 +#define HID_PROTOCOL_SIZE_UNKNOWN 0 + +#define HID_ENCODED_DATA_SIZE (HID_PREAMBLE_SIZE + HID_DATA_SIZE + HID_PREAMBLE_SIZE) +#define HID_ENCODED_BIT_SIZE ((HID_PREAMBLE_SIZE + HID_DATA_SIZE) * 8) +#define HID_DECODED_DATA_SIZE (6) +#define HID_DECODED_BIT_SIZE ((HID_ENCODED_BIT_SIZE - HID_PREAMBLE_SIZE * 8) / 2) + +#define HID_PREAMBLE 0x1D + +typedef struct { + FSKDemod* fsk_demod; +} ProtocolHIDDecoder; + +typedef struct { + FSKOsc* fsk_osc; + uint8_t encoded_index; + uint32_t pulse; +} ProtocolHIDEncoder; + +typedef struct { + ProtocolHIDDecoder decoder; + ProtocolHIDEncoder encoder; + uint8_t encoded_data[HID_ENCODED_DATA_SIZE]; + uint8_t data[HID_DECODED_DATA_SIZE]; +} ProtocolHID; + +ProtocolHID* protocol_hid_generic_alloc(void) { + ProtocolHID* protocol = malloc(sizeof(ProtocolHID)); + protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5); + protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50); + + return protocol; +}; + +void protocol_hid_generic_free(ProtocolHID* protocol) { + fsk_demod_free(protocol->decoder.fsk_demod); + fsk_osc_free(protocol->encoder.fsk_osc); + free(protocol); +}; + +uint8_t* protocol_hid_generic_get_data(ProtocolHID* protocol) { + return protocol->data; +}; + +void protocol_hid_generic_decoder_start(ProtocolHID* protocol) { + memset(protocol->encoded_data, 0, HID_ENCODED_DATA_SIZE); +}; + +static bool protocol_hid_generic_can_be_decoded(const uint8_t* data) { + // check preamble + if(data[0] != HID_PREAMBLE || data[HID_PREAMBLE_SIZE + HID_DATA_SIZE] != HID_PREAMBLE) { + return false; + } + + // check for manchester encoding + for(size_t i = HID_PREAMBLE_SIZE; i < (HID_PREAMBLE_SIZE + HID_DATA_SIZE); i++) { + for(size_t n = 0; n < 4; n++) { + uint8_t bit_pair = (data[i] >> (n * 2)) & 0b11; + if(bit_pair == 0b11 || bit_pair == 0b00) { + return false; + } + } + } + + return true; +} + +static void protocol_hid_generic_decode(const uint8_t* from, uint8_t* to) { + size_t bit_index = 0; + for(size_t i = HID_PREAMBLE_SIZE; i < (HID_PREAMBLE_SIZE + HID_DATA_SIZE); i++) { + for(size_t n = 0; n < 4; n++) { + uint8_t bit_pair = (from[i] >> (6 - (n * 2))) & 0b11; + if(bit_pair == 0b01) { + bit_lib_set_bit(to, bit_index, 0); + } else if(bit_pair == 0b10) { + bit_lib_set_bit(to, bit_index, 1); + } + bit_index++; + } + } +} + +/** + * Decodes size from the HID Proximity header: + * - If any of the first six bits is 1, the key is composed of the bits + * following the first 1 + * - Otherwise, if the first six bits are 0: + * - If the seventh bit is 0, the key is composed of the remaining 37 bits. + * - If the seventh bit is 1, the size header continues until the next 1 bit, + * and the key is composed of however many bits remain. + * + * HID Proximity keys are 26 bits at minimum. If the header implies a key size + * under 26 bits, this function returns HID_PROTOCOL_SIZE_UNKNOWN. + */ +static uint8_t protocol_hid_generic_decode_protocol_size(ProtocolHID* protocol) { + for(size_t bit_index = 0; bit_index < 6; bit_index++) { + if(bit_lib_get_bit(protocol->data, bit_index)) { + return HID_DECODED_BIT_SIZE - bit_index - 1; + } + } + + if(!bit_lib_get_bit(protocol->data, 6)) { + return 37; + } + + size_t bit_index = 7; + uint8_t size = 36; + while(!bit_lib_get_bit(protocol->data, bit_index) && size >= 26) { + size--; + bit_index++; + } + return size < 26 ? HID_PROTOCOL_SIZE_UNKNOWN : size; +} + +bool protocol_hid_generic_decoder_feed(ProtocolHID* protocol, bool level, uint32_t duration) { + bool value; + uint32_t count; + bool result = false; + + fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count); + if(count > 0) { + for(size_t i = 0; i < count; i++) { + bit_lib_push_bit(protocol->encoded_data, HID_ENCODED_DATA_SIZE, value); + if(protocol_hid_generic_can_be_decoded(protocol->encoded_data)) { + protocol_hid_generic_decode(protocol->encoded_data, protocol->data); + result = true; + } + } + } + + return result; +}; + +static void protocol_hid_generic_encode(ProtocolHID* protocol) { + protocol->encoded_data[0] = HID_PREAMBLE; + + size_t bit_index = 0; + for(size_t i = 0; i < HID_DECODED_BIT_SIZE; i++) { + bool bit = bit_lib_get_bit(protocol->data, i); + if(bit) { + bit_lib_set_bit(protocol->encoded_data, 8 + bit_index, 1); + bit_lib_set_bit(protocol->encoded_data, 8 + bit_index + 1, 0); + } else { + bit_lib_set_bit(protocol->encoded_data, 8 + bit_index, 0); + bit_lib_set_bit(protocol->encoded_data, 8 + bit_index + 1, 1); + } + bit_index += 2; + } +} + +bool protocol_hid_generic_encoder_start(ProtocolHID* protocol) { + protocol->encoder.encoded_index = 0; + protocol->encoder.pulse = 0; + protocol_hid_generic_encode(protocol); + + return true; +}; + +LevelDuration protocol_hid_generic_encoder_yield(ProtocolHID* protocol) { + bool level = 0; + uint32_t duration = 0; + + // if pulse is zero, we need to output high, otherwise we need to output low + if(protocol->encoder.pulse == 0) { + // get bit + uint8_t bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index); + + // get pulse from oscillator + bool advance = fsk_osc_next(protocol->encoder.fsk_osc, bit, &duration); + + if(advance) { + bit_lib_increment_index(protocol->encoder.encoded_index, HID_ENCODED_BIT_SIZE); + } + + // duration diveded by 2 because we need to output high and low + duration = duration / 2; + protocol->encoder.pulse = duration; + level = true; + } else { + // output low half and reset pulse + duration = protocol->encoder.pulse; + protocol->encoder.pulse = 0; + level = false; + } + + return level_duration_make(level, duration); +}; + +bool protocol_hid_generic_write_data(ProtocolHID* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_hid_generic_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 | + (3 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32); + request->t5577.blocks_to_write = 4; + result = true; + } + return result; +}; + +static void protocol_hid_generic_string_cat_protocol_bits(ProtocolHID* protocol, uint8_t protocol_size, string_t result) { + // round up to the nearest nibble + const uint8_t hex_character_count = (protocol_size + 3) / 4; + const uint8_t protocol_bit_index = HID_DECODED_BIT_SIZE - protocol_size; + + for(size_t i = 0; i < hex_character_count; i++) { + uint8_t nibble = + i == 0 ? bit_lib_get_bits( + protocol->data, protocol_bit_index, protocol_size % 4 == 0 ? 4 : protocol_size % 4) : + bit_lib_get_bits(protocol->data, protocol_bit_index + i * 4, 4); + string_cat_printf(result, "%X", nibble & 0xF); + } +} + +void protocol_hid_generic_render_data(ProtocolHID* protocol, string_t result) { + const uint8_t protocol_size = protocol_hid_generic_decode_protocol_size(protocol); + + if(protocol_size == HID_PROTOCOL_SIZE_UNKNOWN) { + string_printf( + result, + "Generic HID Proximity\r\n" + "Data: %02X%02X%02X%02X%02X%X", + protocol->data[0], + protocol->data[1], + protocol->data[2], + protocol->data[3], + protocol->data[4], + protocol->data[5] >> 4); + } else { + string_printf( + result, + "%hhu-bit HID Proximity\r\n" + "Data: ", + protocol_size); + protocol_hid_generic_string_cat_protocol_bits(protocol, protocol_size, result); + } +}; + +const ProtocolBase protocol_hid_generic = { + .name = "HIDProx", + .manufacturer = "Generic", + .data_size = HID_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 6, + .alloc = (ProtocolAlloc)protocol_hid_generic_alloc, + .free = (ProtocolFree)protocol_hid_generic_free, + .get_data = (ProtocolGetData)protocol_hid_generic_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_hid_generic_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_hid_generic_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_hid_generic_encoder_start, + .yield = (ProtocolEncoderYield)protocol_hid_generic_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_hid_generic_render_data, + .render_brief_data = (ProtocolRenderData)protocol_hid_generic_render_data, + .write_data = (ProtocolWriteData)protocol_hid_generic_write_data, +}; diff --git a/lib/lfrfid/protocols/protocol_hid_generic.h b/lib/lfrfid/protocols/protocol_hid_generic.h new file mode 100644 index 0000000000..22e78a4d34 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_hid_generic.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_hid_generic; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_indala26.c b/lib/lfrfid/protocols/protocol_indala26.c new file mode 100644 index 0000000000..136ececf8d --- /dev/null +++ b/lib/lfrfid/protocols/protocol_indala26.c @@ -0,0 +1,353 @@ +#include +#include +#include +#include "lfrfid_protocols.h" + +#define INDALA26_PREAMBLE_BIT_SIZE (33) +#define INDALA26_PREAMBLE_DATA_SIZE (5) + +#define INDALA26_ENCODED_BIT_SIZE (64) +#define INDALA26_ENCODED_DATA_SIZE \ + (((INDALA26_ENCODED_BIT_SIZE) / 8) + INDALA26_PREAMBLE_DATA_SIZE) +#define INDALA26_ENCODED_DATA_LAST ((INDALA26_ENCODED_BIT_SIZE) / 8) + +#define INDALA26_DECODED_BIT_SIZE (28) +#define INDALA26_DECODED_DATA_SIZE (4) + +#define INDALA26_US_PER_BIT (255) +#define INDALA26_ENCODER_PULSES_PER_BIT (16) + +typedef struct { + uint8_t data_index; + uint8_t bit_clock_index; + bool last_bit; + bool current_polarity; + bool pulse_phase; +} ProtocolIndalaEncoder; + +typedef struct { + uint8_t encoded_data[INDALA26_ENCODED_DATA_SIZE]; + uint8_t negative_encoded_data[INDALA26_ENCODED_DATA_SIZE]; + uint8_t corrupted_encoded_data[INDALA26_ENCODED_DATA_SIZE]; + uint8_t corrupted_negative_encoded_data[INDALA26_ENCODED_DATA_SIZE]; + + uint8_t data[INDALA26_DECODED_DATA_SIZE]; + ProtocolIndalaEncoder encoder; +} ProtocolIndala; + +ProtocolIndala* protocol_indala26_alloc(void) { + ProtocolIndala* protocol = malloc(sizeof(ProtocolIndala)); + return protocol; +}; + +void protocol_indala26_free(ProtocolIndala* protocol) { + free(protocol); +}; + +uint8_t* protocol_indala26_get_data(ProtocolIndala* protocol) { + return protocol->data; +}; + +void protocol_indala26_decoder_start(ProtocolIndala* protocol) { + memset(protocol->encoded_data, 0, INDALA26_ENCODED_DATA_SIZE); + memset(protocol->negative_encoded_data, 0, INDALA26_ENCODED_DATA_SIZE); + memset(protocol->corrupted_encoded_data, 0, INDALA26_ENCODED_DATA_SIZE); + memset(protocol->corrupted_negative_encoded_data, 0, INDALA26_ENCODED_DATA_SIZE); +}; + +static bool protocol_indala26_check_preamble(uint8_t* data, size_t bit_index) { + // Preamble 10100000 00000000 00000000 00000000 1 + if(*(uint32_t*)&data[bit_index / 8] != 0b00000000000000000000000010100000) return false; + if(bit_lib_get_bit(data, bit_index + 32) != 1) return false; + return true; +} + +static bool protocol_indala26_can_be_decoded(uint8_t* data) { + if(!protocol_indala26_check_preamble(data, 0)) return false; + if(!protocol_indala26_check_preamble(data, 64)) return false; + if(bit_lib_get_bit(data, 61) != 0) return false; + if(bit_lib_get_bit(data, 60) != 0) return false; + return true; +} + +static bool protocol_indala26_decoder_feed_internal(bool polarity, uint32_t time, uint8_t* data) { + time += (INDALA26_US_PER_BIT / 2); + + size_t bit_count = (time / INDALA26_US_PER_BIT); + bool result = false; + + if(bit_count < INDALA26_ENCODED_BIT_SIZE) { + for(size_t i = 0; i < bit_count; i++) { + bit_lib_push_bit(data, INDALA26_ENCODED_DATA_SIZE, polarity); + if(protocol_indala26_can_be_decoded(data)) { + result = true; + break; + } + } + } + + return result; +} + +static void protocol_indala26_decoder_save(uint8_t* data_to, const uint8_t* data_from) { + bit_lib_copy_bits(data_to, 0, 22, data_from, 33); + bit_lib_copy_bits(data_to, 22, 5, data_from, 55); + bit_lib_copy_bits(data_to, 27, 2, data_from, 62); +} + +bool protocol_indala26_decoder_feed(ProtocolIndala* protocol, bool level, uint32_t duration) { + bool result = false; + + if(duration > (INDALA26_US_PER_BIT / 2)) { + if(protocol_indala26_decoder_feed_internal(level, duration, protocol->encoded_data)) { + protocol_indala26_decoder_save(protocol->data, protocol->encoded_data); + FURI_LOG_D("Indala26", "Positive"); + result = true; + return result; + } + + if(protocol_indala26_decoder_feed_internal( + !level, duration, protocol->negative_encoded_data)) { + protocol_indala26_decoder_save(protocol->data, protocol->negative_encoded_data); + FURI_LOG_D("Indala26", "Negative"); + result = true; + return result; + } + } + + if(duration > (INDALA26_US_PER_BIT / 4)) { + // Try to decode wrong phase synced data + if(level) { + duration += 120; + } else { + if(duration > 120) { + duration -= 120; + } + } + + if(protocol_indala26_decoder_feed_internal( + level, duration, protocol->corrupted_encoded_data)) { + protocol_indala26_decoder_save(protocol->data, protocol->corrupted_encoded_data); + FURI_LOG_D("Indala26", "Positive Corrupted"); + + result = true; + return result; + } + + if(protocol_indala26_decoder_feed_internal( + !level, duration, protocol->corrupted_negative_encoded_data)) { + protocol_indala26_decoder_save( + protocol->data, protocol->corrupted_negative_encoded_data); + FURI_LOG_D("Indala26", "Negative Corrupted"); + + result = true; + return result; + } + } + + return result; +}; + +bool protocol_indala26_encoder_start(ProtocolIndala* protocol) { + memset(protocol->encoded_data, 0, INDALA26_ENCODED_DATA_SIZE); + *(uint32_t*)&protocol->encoded_data[0] = 0b00000000000000000000000010100000; + bit_lib_set_bit(protocol->encoded_data, 32, 1); + bit_lib_copy_bits(protocol->encoded_data, 33, 22, protocol->data, 0); + bit_lib_copy_bits(protocol->encoded_data, 55, 5, protocol->data, 22); + bit_lib_copy_bits(protocol->encoded_data, 62, 2, protocol->data, 27); + + protocol->encoder.last_bit = + bit_lib_get_bit(protocol->encoded_data, INDALA26_ENCODED_BIT_SIZE - 1); + protocol->encoder.data_index = 0; + protocol->encoder.current_polarity = true; + protocol->encoder.pulse_phase = true; + protocol->encoder.bit_clock_index = 0; + + return true; +}; + +LevelDuration protocol_indala26_encoder_yield(ProtocolIndala* protocol) { + LevelDuration level_duration; + ProtocolIndalaEncoder* encoder = &protocol->encoder; + + if(encoder->pulse_phase) { + level_duration = level_duration_make(encoder->current_polarity, 1); + encoder->pulse_phase = false; + } else { + level_duration = level_duration_make(!encoder->current_polarity, 1); + encoder->pulse_phase = true; + + encoder->bit_clock_index++; + if(encoder->bit_clock_index >= INDALA26_ENCODER_PULSES_PER_BIT) { + encoder->bit_clock_index = 0; + + bool current_bit = bit_lib_get_bit(protocol->encoded_data, encoder->data_index); + + if(current_bit != encoder->last_bit) { + encoder->current_polarity = !encoder->current_polarity; + } + + encoder->last_bit = current_bit; + + bit_lib_increment_index(encoder->data_index, INDALA26_ENCODED_BIT_SIZE); + } + } + + return level_duration; +}; + +// factory code +static uint8_t get_fc(const uint8_t* data) { + uint8_t fc = 0; + + fc = fc << 1 | bit_lib_get_bit(data, 24); + fc = fc << 1 | bit_lib_get_bit(data, 16); + fc = fc << 1 | bit_lib_get_bit(data, 11); + fc = fc << 1 | bit_lib_get_bit(data, 14); + fc = fc << 1 | bit_lib_get_bit(data, 15); + fc = fc << 1 | bit_lib_get_bit(data, 20); + fc = fc << 1 | bit_lib_get_bit(data, 6); + fc = fc << 1 | bit_lib_get_bit(data, 25); + + return fc; +} + +// card number +static uint16_t get_cn(const uint8_t* data) { + uint16_t cn = 0; + + cn = cn << 1 | bit_lib_get_bit(data, 9); + cn = cn << 1 | bit_lib_get_bit(data, 12); + cn = cn << 1 | bit_lib_get_bit(data, 10); + cn = cn << 1 | bit_lib_get_bit(data, 7); + cn = cn << 1 | bit_lib_get_bit(data, 19); + cn = cn << 1 | bit_lib_get_bit(data, 3); + cn = cn << 1 | bit_lib_get_bit(data, 2); + cn = cn << 1 | bit_lib_get_bit(data, 18); + cn = cn << 1 | bit_lib_get_bit(data, 13); + cn = cn << 1 | bit_lib_get_bit(data, 0); + cn = cn << 1 | bit_lib_get_bit(data, 4); + cn = cn << 1 | bit_lib_get_bit(data, 21); + cn = cn << 1 | bit_lib_get_bit(data, 23); + cn = cn << 1 | bit_lib_get_bit(data, 26); + cn = cn << 1 | bit_lib_get_bit(data, 17); + cn = cn << 1 | bit_lib_get_bit(data, 8); + + return cn; +} + +void protocol_indala26_render_data_internal(ProtocolIndala* protocol, string_t result, bool brief) { + bool wiegand_correct = true; + bool checksum_correct = true; + + const uint8_t fc = get_fc(protocol->data); + const uint16_t card = get_cn(protocol->data); + const uint32_t fc_and_card = fc << 16 | card; + const uint8_t checksum = bit_lib_get_bit(protocol->data, 27) << 1 | + bit_lib_get_bit(protocol->data, 28); + const bool even_parity = bit_lib_get_bit(protocol->data, 1); + const bool odd_parity = bit_lib_get_bit(protocol->data, 5); + + // indala checksum + uint8_t checksum_sum = 0; + checksum_sum += ((fc_and_card >> 14) & 1); + checksum_sum += ((fc_and_card >> 12) & 1); + checksum_sum += ((fc_and_card >> 9) & 1); + checksum_sum += ((fc_and_card >> 8) & 1); + checksum_sum += ((fc_and_card >> 6) & 1); + checksum_sum += ((fc_and_card >> 5) & 1); + checksum_sum += ((fc_and_card >> 2) & 1); + checksum_sum += ((fc_and_card >> 0) & 1); + checksum_sum = checksum_sum & 0b1; + + if(checksum_sum == 1 && checksum == 0b01) { + } else if(checksum_sum == 0 && checksum == 0b10) { + } else { + checksum_correct = false; + } + + // wiegand parity + uint8_t even_parity_sum = 0; + for(int8_t i = 12; i < 24; i++) { + if(((fc_and_card >> i) & 1) == 1) { + even_parity_sum++; + } + } + if(even_parity_sum % 2 != even_parity) wiegand_correct = false; + + uint8_t odd_parity_sum = 1; + for(int8_t i = 0; i < 12; i++) { + if(((fc_and_card >> i) & 1) == 1) { + odd_parity_sum++; + } + } + if(odd_parity_sum % 2 != odd_parity) wiegand_correct = false; + + if(brief) { + string_printf( + result, + "FC: %u\r\nCard: %u, Parity:%s%s", + fc, + card, + (checksum_correct ? "+" : "-"), + (wiegand_correct ? "+" : "-")); + } else { + string_printf( + result, + "FC: %u\r\n" + "Card: %u\r\n" + "Checksum: %s\r\n" + "W26 Parity: %s", + fc, + card, + (checksum_correct ? "+" : "-"), + (wiegand_correct ? "+" : "-")); + } +} +void protocol_indala26_render_data(ProtocolIndala* protocol, string_t result) { + protocol_indala26_render_data_internal(protocol, result, false); +} +void protocol_indala26_render_brief_data(ProtocolIndala* protocol, string_t result) { + protocol_indala26_render_data_internal(protocol, result, true); +} + +bool protocol_indala26_write_data(ProtocolIndala* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_indala26_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_BITRATE_RF_32 | LFRFID_T5577_MODULATION_PSK1 | + (2 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.blocks_to_write = 3; + result = true; + } + return result; +}; + +const ProtocolBase protocol_indala26 = { + .name = "Indala26", + .manufacturer = "Motorola", + .data_size = INDALA26_DECODED_DATA_SIZE, + .features = LFRFIDFeaturePSK, + .validate_count = 6, + .alloc = (ProtocolAlloc)protocol_indala26_alloc, + .free = (ProtocolFree)protocol_indala26_free, + .get_data = (ProtocolGetData)protocol_indala26_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_indala26_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_indala26_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_indala26_encoder_start, + .yield = (ProtocolEncoderYield)protocol_indala26_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_indala26_render_data, + .render_brief_data = (ProtocolRenderData)protocol_indala26_render_brief_data, + .write_data = (ProtocolWriteData)protocol_indala26_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_indala26.h b/lib/lfrfid/protocols/protocol_indala26.h new file mode 100644 index 0000000000..c0c61784b7 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_indala26.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_indala26; diff --git a/lib/lfrfid/protocols/protocol_io_prox_xsf.c b/lib/lfrfid/protocols/protocol_io_prox_xsf.c new file mode 100644 index 0000000000..66b1610bf2 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_io_prox_xsf.c @@ -0,0 +1,297 @@ +#include +#include +#include +#include +#include +#include "lfrfid_protocols.h" + +#define JITTER_TIME (20) +#define MIN_TIME (64 - JITTER_TIME) +#define MAX_TIME (80 + JITTER_TIME) + +#define IOPROXXSF_DECODED_DATA_SIZE (4) +#define IOPROXXSF_ENCODED_DATA_SIZE (8) + +#define IOPROXXSF_BIT_SIZE (8) +#define IOPROXXSF_BIT_MAX_SIZE (IOPROXXSF_BIT_SIZE * IOPROXXSF_ENCODED_DATA_SIZE) + +typedef struct { + FSKDemod* fsk_demod; +} ProtocolIOProxXSFDecoder; + +typedef struct { + FSKOsc* fsk_osc; + uint8_t encoded_index; +} ProtocolIOProxXSFEncoder; + +typedef struct { + ProtocolIOProxXSFEncoder encoder; + ProtocolIOProxXSFDecoder decoder; + uint8_t encoded_data[IOPROXXSF_ENCODED_DATA_SIZE]; + uint8_t data[IOPROXXSF_DECODED_DATA_SIZE]; +} ProtocolIOProxXSF; + +ProtocolIOProxXSF* protocol_io_prox_xsf_alloc(void) { + ProtocolIOProxXSF* protocol = malloc(sizeof(ProtocolIOProxXSF)); + protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 8, MAX_TIME, 6); + protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 64); + return protocol; +}; + +void protocol_io_prox_xsf_free(ProtocolIOProxXSF* protocol) { + fsk_demod_free(protocol->decoder.fsk_demod); + fsk_osc_free(protocol->encoder.fsk_osc); + free(protocol); +}; + +uint8_t* protocol_io_prox_xsf_get_data(ProtocolIOProxXSF* protocol) { + return protocol->data; +}; + +void protocol_io_prox_xsf_decoder_start(ProtocolIOProxXSF* protocol) { + memset(protocol->encoded_data, 0, IOPROXXSF_ENCODED_DATA_SIZE); +}; + +static uint8_t protocol_io_prox_xsf_compute_checksum(const uint8_t* data) { + // Packet structure: + // + //0 1 2 3 4 5 6 7 + //v v v v v v v v + //01234567 8 9ABCDEF0 1 23456789 A BCDEF012 3 456789AB C DEF01234 5 6789ABCD EF + //00000000 0 VVVVVVVV 1 WWWWWWWW 1 XXXXXXXX 1 YYYYYYYY 1 ZZZZZZZZ 1 CHECKSUM 11 + // + // algorithm as observed by the proxmark3 folks + // CHECKSUM == 0xFF - (V + W + X + Y + Z) + + uint8_t checksum = 0; + + for(size_t i = 1; i <= 5; i++) { + checksum += bit_lib_get_bits(data, 9 * i, 8); + } + + return 0xFF - checksum; +} + +static bool protocol_io_prox_xsf_can_be_decoded(const uint8_t* encoded_data) { + // Packet framing + // + //0 1 2 3 4 5 6 7 + //v v v v v v v v + //01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF + //----------------------------------------------------------------------- + //00000000 01______ _1______ __1_____ ___1____ ____1___ _____1XX XXXXXX11 + // + // _ = variable data + // 0 = preamble 0 + // 1 = framing 1 + // X = checksum + + // Validate the packet preamble is there... + if(encoded_data[0] != 0b00000000) { + return false; + } + if((encoded_data[1] >> 6) != 0b01) { + return false; + } + + // ... check for known ones... + if(bit_lib_bit_is_not_set(encoded_data[2], 6)) { + return false; + } + if(bit_lib_bit_is_not_set(encoded_data[3], 5)) { + return false; + } + if(bit_lib_bit_is_not_set(encoded_data[4], 4)) { + return false; + } + if(bit_lib_bit_is_not_set(encoded_data[5], 3)) { + return false; + } + if(bit_lib_bit_is_not_set(encoded_data[6], 2)) { + return false; + } + if(bit_lib_bit_is_not_set(encoded_data[7], 1)) { + return false; + } + if(bit_lib_bit_is_not_set(encoded_data[7], 0)) { + return false; + } + + // ... and validate our checksums. + uint8_t checksum = protocol_io_prox_xsf_compute_checksum(encoded_data); + uint8_t checkval = bit_lib_get_bits(encoded_data, 54, 8); + + if(checksum != checkval) { + return false; + } + + return true; +} + +void protocol_io_prox_xsf_decode(const uint8_t* encoded_data, uint8_t* decoded_data) { + // Packet structure: + // (Note: the second word seems fixed; but this may not be a guarantee; + // it currently has no meaning.) + // + //0 1 2 3 4 5 6 7 + //v v v v v v v v + //01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF + //----------------------------------------------------------------------- + //00000000 01111000 01FFFFFF FF1VVVVV VVV1CCCC CCCC1CCC CCCCC1XX XXXXXX11 + // + // F = facility code + // V = version + // C = code + // X = checksum + + // Facility code + decoded_data[0] = bit_lib_get_bits(encoded_data, 18, 8); + + // Version code. + decoded_data[1] = bit_lib_get_bits(encoded_data, 27, 8); + + // Code bytes. + decoded_data[2] = bit_lib_get_bits(encoded_data, 36, 8); + decoded_data[3] = bit_lib_get_bits(encoded_data, 45, 8); +} + +bool protocol_io_prox_xsf_decoder_feed(ProtocolIOProxXSF* protocol, bool level, uint32_t duration) { + bool result = false; + + uint32_t count; + bool value; + + fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count); + for(size_t i = 0; i < count; i++) { + bit_lib_push_bit(protocol->encoded_data, IOPROXXSF_ENCODED_DATA_SIZE, value); + if(protocol_io_prox_xsf_can_be_decoded(protocol->encoded_data)) { + protocol_io_prox_xsf_decode(protocol->encoded_data, protocol->data); + result = true; + break; + } + } + + return result; +}; + +static void protocol_io_prox_xsf_encode(const uint8_t* decoded_data, uint8_t* encoded_data) { + // Packet to transmit: + // + // 0 10 20 30 40 50 60 + // v v v v v v v + // 01234567 8 90123456 7 89012345 6 78901234 5 67890123 4 56789012 3 45678901 23 + // ----------------------------------------------------------------------------- + // 00000000 0 11110000 1 facility 1 version_ 1 code-one 1 code-two 1 checksum 11 + + // Preamble. + bit_lib_set_bits(encoded_data, 0, 0b00000000, 8); + bit_lib_set_bit(encoded_data, 8, 0); + + bit_lib_set_bits(encoded_data, 9, 0b11110000, 8); + bit_lib_set_bit(encoded_data, 17, 1); + + // Facility code. + bit_lib_set_bits(encoded_data, 18, decoded_data[0], 8); + bit_lib_set_bit(encoded_data, 26, 1); + + // Version + bit_lib_set_bits(encoded_data, 27, decoded_data[1], 8); + bit_lib_set_bit(encoded_data, 35, 1); + + // Code one + bit_lib_set_bits(encoded_data, 36, decoded_data[2], 8); + bit_lib_set_bit(encoded_data, 44, 1); + + // Code two + bit_lib_set_bits(encoded_data, 45, decoded_data[3], 8); + bit_lib_set_bit(encoded_data, 53, 1); + + // Checksum + bit_lib_set_bits(encoded_data, 54, protocol_io_prox_xsf_compute_checksum(encoded_data), 8); + bit_lib_set_bit(encoded_data, 62, 1); + bit_lib_set_bit(encoded_data, 63, 1); +} + +bool protocol_io_prox_xsf_encoder_start(ProtocolIOProxXSF* protocol) { + protocol_io_prox_xsf_encode(protocol->data, protocol->encoded_data); + protocol->encoder.encoded_index = 0; + fsk_osc_reset(protocol->encoder.fsk_osc); + return true; +}; + +LevelDuration protocol_io_prox_xsf_encoder_yield(ProtocolIOProxXSF* protocol) { + bool level; + uint32_t duration; + + bool bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index); + bool advance = fsk_osc_next_half(protocol->encoder.fsk_osc, bit, &level, &duration); + + if(advance) { + bit_lib_increment_index(protocol->encoder.encoded_index, IOPROXXSF_BIT_MAX_SIZE); + } + return level_duration_make(level, duration); +}; + +void protocol_io_prox_xsf_render_data(ProtocolIOProxXSF* protocol, string_t result) { + uint8_t* data = protocol->data; + string_printf( + result, + "FC: %u\r\n" + "VС: %u\r\n" + "Card: %u", + data[0], + data[1], + (uint16_t)((data[2] << 8) | (data[3]))); +} + +void protocol_io_prox_xsf_render_brief_data(ProtocolIOProxXSF* protocol, string_t result) { + uint8_t* data = protocol->data; + string_printf( + result, + "FC: %u, VС: %u\r\n" + "Card: %u", + data[0], + data[1], + (uint16_t)((data[2] << 8) | (data[3]))); +} + +bool protocol_io_prox_xsf_write_data(ProtocolIOProxXSF* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_io_prox_xsf_encode(protocol->data, protocol->encoded_data); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_64 | + (2 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.blocks_to_write = 3; + result = true; + } + return result; +}; + +const ProtocolBase protocol_io_prox_xsf = { + .name = "IoProxXSF", + .manufacturer = "Kantech", + .data_size = IOPROXXSF_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_io_prox_xsf_alloc, + .free = (ProtocolFree)protocol_io_prox_xsf_free, + .get_data = (ProtocolGetData)protocol_io_prox_xsf_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_io_prox_xsf_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_io_prox_xsf_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_io_prox_xsf_encoder_start, + .yield = (ProtocolEncoderYield)protocol_io_prox_xsf_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_io_prox_xsf_render_data, + .render_brief_data = (ProtocolRenderData)protocol_io_prox_xsf_render_brief_data, + .write_data = (ProtocolWriteData)protocol_io_prox_xsf_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_io_prox_xsf.h b/lib/lfrfid/protocols/protocol_io_prox_xsf.h new file mode 100644 index 0000000000..af94fb4636 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_io_prox_xsf.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_io_prox_xsf; diff --git a/lib/lfrfid/tools/bit_lib.c b/lib/lfrfid/tools/bit_lib.c new file mode 100644 index 0000000000..b57bda8a8a --- /dev/null +++ b/lib/lfrfid/tools/bit_lib.c @@ -0,0 +1,291 @@ +#include "bit_lib.h" +#include +#include + +void bit_lib_push_bit(uint8_t* data, size_t data_size, bool bit) { + size_t last_index = data_size - 1; + + for(size_t i = 0; i < last_index; ++i) { + data[i] = (data[i] << 1) | ((data[i + 1] >> 7) & 1); + } + data[last_index] = (data[last_index] << 1) | bit; +} + +void bit_lib_set_bit(uint8_t* data, size_t position, bool bit) { + if(bit) { + data[position / 8] |= 1UL << (7 - (position % 8)); + } else { + data[position / 8] &= ~(1UL << (7 - (position % 8))); + } +} + +void bit_lib_set_bits(uint8_t* data, size_t position, uint8_t byte, uint8_t length) { + furi_check(length <= 8); + furi_check(length > 0); + + for(uint8_t i = 0; i < length; ++i) { + uint8_t shift = (length - 1) - i; + bit_lib_set_bit(data, position + i, (byte >> shift) & 1); + } +} + +bool bit_lib_get_bit(const uint8_t* data, size_t position) { + return (data[position / 8] >> (7 - (position % 8))) & 1; +} + +uint8_t bit_lib_get_bits(const uint8_t* data, size_t position, uint8_t length) { + uint8_t shift = position % 8; + if(shift == 0) { + return data[position / 8] >> (8 - length); + } else { + // TODO fix read out of bounds + uint8_t value = (data[position / 8] << (shift)); + value |= data[position / 8 + 1] >> (8 - shift); + value = value >> (8 - length); + return value; + } +} + +uint16_t bit_lib_get_bits_16(const uint8_t* data, size_t position, uint8_t length) { + uint16_t value = 0; + if(length <= 8) { + value = bit_lib_get_bits(data, position, length); + } else { + value = bit_lib_get_bits(data, position, 8) << (length - 8); + value |= bit_lib_get_bits(data, position + 8, length - 8); + } + return value; +} + +uint32_t bit_lib_get_bits_32(const uint8_t* data, size_t position, uint8_t length) { + uint32_t value = 0; + if(length <= 8) { + value = bit_lib_get_bits(data, position, length); + } else if(length <= 16) { + value = bit_lib_get_bits(data, position, 8) << (length - 8); + value |= bit_lib_get_bits(data, position + 8, length - 8); + } else if(length <= 24) { + value = bit_lib_get_bits(data, position, 8) << (length - 8); + value |= bit_lib_get_bits(data, position + 8, 8) << (length - 16); + value |= bit_lib_get_bits(data, position + 16, length - 16); + } else { + value = bit_lib_get_bits(data, position, 8) << (length - 8); + value |= bit_lib_get_bits(data, position + 8, 8) << (length - 16); + value |= bit_lib_get_bits(data, position + 16, 8) << (length - 24); + value |= bit_lib_get_bits(data, position + 24, length - 24); + } + + return value; +} + +bool bit_lib_test_parity_32(uint32_t bits, BitLibParity parity) { +#if !defined __GNUC__ +#error Please, implement parity test for non-GCC compilers +#else + switch(parity) { + case BitLibParityEven: + return __builtin_parity(bits); + case BitLibParityOdd: + return !__builtin_parity(bits); + default: + furi_crash("Unknown parity"); + } +#endif +} + +bool bit_lib_test_parity( + const uint8_t* bits, + size_t position, + uint8_t length, + BitLibParity parity, + uint8_t parity_length) { + uint32_t parity_block; + bool result = true; + const size_t parity_blocks_count = length / parity_length; + + for(size_t i = 0; i < parity_blocks_count; ++i) { + switch(parity) { + case BitLibParityEven: + case BitLibParityOdd: + parity_block = bit_lib_get_bits_32(bits, position + i * parity_length, parity_length); + if(!bit_lib_test_parity_32(parity_block, parity)) { + result = false; + } + break; + case BitLibParityAlways0: + if(bit_lib_get_bit(bits, position + i * parity_length + parity_length - 1)) { + result = false; + } + break; + case BitLibParityAlways1: + if(!bit_lib_get_bit(bits, position + i * parity_length + parity_length - 1)) { + result = false; + } + break; + } + + if(!result) break; + } + return result; +} + +size_t bit_lib_remove_bit_every_nth(uint8_t* data, size_t position, uint8_t length, uint8_t n) { + size_t counter = 0; + size_t result_counter = 0; + uint8_t bit_buffer = 0; + uint8_t bit_counter = 0; + + while(counter < length) { + if((counter + 1) % n != 0) { + bit_buffer = (bit_buffer << 1) | bit_lib_get_bit(data, position + counter); + bit_counter++; + } + + if(bit_counter == 8) { + bit_lib_set_bits(data, position + result_counter, bit_buffer, 8); + bit_counter = 0; + bit_buffer = 0; + result_counter += 8; + } + counter++; + } + + if(bit_counter != 0) { + bit_lib_set_bits(data, position + result_counter, bit_buffer, bit_counter); + result_counter += bit_counter; + } + return result_counter; +} + +void bit_lib_copy_bits( + uint8_t* data, + size_t position, + size_t length, + const uint8_t* source, + size_t source_position) { + for(size_t i = 0; i < length; ++i) { + bit_lib_set_bit(data, position + i, bit_lib_get_bit(source, source_position + i)); + } +} + +void bit_lib_reverse_bits(uint8_t* data, size_t position, uint8_t length) { + size_t i = 0; + size_t j = length - 1; + + while(i < j) { + bool tmp = bit_lib_get_bit(data, position + i); + bit_lib_set_bit(data, position + i, bit_lib_get_bit(data, position + j)); + bit_lib_set_bit(data, position + j, tmp); + i++; + j--; + } +} + +uint8_t bit_lib_get_bit_count(uint32_t data) { +#if defined __GNUC__ + return __builtin_popcountl(data); +#else +#error Please, implement popcount for non-GCC compilers +#endif +} + +void bit_lib_print_bits(const uint8_t* data, size_t length) { + for(size_t i = 0; i < length; ++i) { + printf("%u", bit_lib_get_bit(data, i)); + } +} + +void bit_lib_print_regions( + const BitLibRegion* regions, + size_t region_count, + const uint8_t* data, + size_t length) { + // print data + bit_lib_print_bits(data, length); + printf("\r\n"); + + // print regions + for(size_t c = 0; c < length; ++c) { + bool print = false; + + for(size_t i = 0; i < region_count; i++) { + if(regions[i].start <= c && c < regions[i].start + regions[i].length) { + print = true; + printf("%c", regions[i].mark); + break; + } + } + + if(!print) { + printf(" "); + } + } + printf("\r\n"); + + // print regions data + for(size_t c = 0; c < length; ++c) { + bool print = false; + + for(size_t i = 0; i < region_count; i++) { + if(regions[i].start <= c && c < regions[i].start + regions[i].length) { + print = true; + printf("%u", bit_lib_get_bit(data, c)); + break; + } + } + + if(!print) { + printf(" "); + } + } + printf("\r\n"); +} + +uint16_t bit_lib_reverse_16_fast(uint16_t data) { + uint16_t result = 0; + result |= (data & 0x8000) >> 15; + result |= (data & 0x4000) >> 13; + result |= (data & 0x2000) >> 11; + result |= (data & 0x1000) >> 9; + result |= (data & 0x0800) >> 7; + result |= (data & 0x0400) >> 5; + result |= (data & 0x0200) >> 3; + result |= (data & 0x0100) >> 1; + result |= (data & 0x0080) << 1; + result |= (data & 0x0040) << 3; + result |= (data & 0x0020) << 5; + result |= (data & 0x0010) << 7; + result |= (data & 0x0008) << 9; + result |= (data & 0x0004) << 11; + result |= (data & 0x0002) << 13; + result |= (data & 0x0001) << 15; + return result; +} + +uint16_t bit_lib_crc16( + uint8_t const* data, + size_t data_size, + uint16_t polynom, + uint16_t init, + bool ref_in, + bool ref_out, + uint16_t xor_out) { + uint16_t crc = init; + + for(size_t i = 0; i < data_size; ++i) { + uint8_t byte = data[i]; + if(ref_in) byte = bit_lib_reverse_16_fast(byte) >> 8; + + for(size_t j = 0; j < 8; ++j) { + bool c15 = (crc >> 15 & 1); + bool bit = (byte >> (7 - j) & 1); + crc <<= 1; + if(c15 ^ bit) crc ^= polynom; + } + } + + if(ref_out) crc = bit_lib_reverse_16_fast(crc); + crc ^= xor_out; + + return crc; +} \ No newline at end of file diff --git a/lib/lfrfid/tools/bit_lib.h b/lib/lfrfid/tools/bit_lib.h new file mode 100644 index 0000000000..24aae0e9cc --- /dev/null +++ b/lib/lfrfid/tools/bit_lib.h @@ -0,0 +1,220 @@ +#pragma once +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + BitLibParityEven, + BitLibParityOdd, + BitLibParityAlways0, + BitLibParityAlways1, +} BitLibParity; + +/** @brief Increment and wrap around a value. + * @param index value to increment + * @param length wrap-around range + */ +#define bit_lib_increment_index(index, length) (index = (((index) + 1) % (length))) + +/** @brief Test if a bit is set. + * @param data value to test + * @param index bit index to test + */ +#define bit_lib_bit_is_set(data, index) ((data & (1 << (index))) != 0) + +/** @brief Test if a bit is not set. + * @param data value to test + * @param index bit index to test + */ +#define bit_lib_bit_is_not_set(data, index) ((data & (1 << (index))) == 0) + +/** @brief Push a bit into a byte array. + * @param data array to push bit into + * @param data_size array size + * @param bit bit to push + */ +void bit_lib_push_bit(uint8_t* data, size_t data_size, bool bit); + +/** @brief Set a bit in a byte array. + * @param data array to set bit in + * @param position The position of the bit to set. + * @param bit bit value to set + */ +void bit_lib_set_bit(uint8_t* data, size_t position, bool bit); + +/** @brief Set the bit at the given position to the given value. + * @param data The data to set the bit in. + * @param position The position of the bit to set. + * @param byte The data to set the bit to. + * @param length The length of the data. + */ +void bit_lib_set_bits(uint8_t* data, size_t position, uint8_t byte, uint8_t length); + +/** @brief Get the bit of a byte. + * @param data The byte to get the bits from. + * @param position The position of the bit. + * @return The bit. + */ +bool bit_lib_get_bit(const uint8_t* data, size_t position); + +/** + * @brief Get the bits of a data, as uint8_t. + * @param data The data to get the bits from. + * @param position The position of the first bit. + * @param length The length of the bits. + * @return The bits. + */ +uint8_t bit_lib_get_bits(const uint8_t* data, size_t position, uint8_t length); + +/** + * @brief Get the bits of a data, as uint16_t. + * @param data The data to get the bits from. + * @param position The position of the first bit. + * @param length The length of the bits. + * @return The bits. + */ +uint16_t bit_lib_get_bits_16(const uint8_t* data, size_t position, uint8_t length); + +/** + * @brief Get the bits of a data, as uint32_t. + * @param data The data to get the bits from. + * @param position The position of the first bit. + * @param length The length of the bits. + * @return The bits. + */ +uint32_t bit_lib_get_bits_32(const uint8_t* data, size_t position, uint8_t length); + +/** + * @brief Test parity of given bits + * @param bits Bits to test parity of + * @param parity Parity to test against + * @return true if parity is correct, false otherwise + */ +bool bit_lib_test_parity_32(uint32_t bits, BitLibParity parity); + +/** + * @brief Test parity of bit array, check parity for every parity_length block from start + * + * @param data Bit array + * @param position Start position + * @param length Bit count + * @param parity Parity to test against + * @param parity_length Parity block length + * @return true + * @return false + */ +bool bit_lib_test_parity( + const uint8_t* data, + size_t position, + uint8_t length, + BitLibParity parity, + uint8_t parity_length); + +/** + * @brief Remove bit every n in array and shift array left. Useful to remove parity. + * + * @param data Bit array + * @param position Start position + * @param length Bit count + * @param n every n bit will be removed + * @return size_t + */ +size_t bit_lib_remove_bit_every_nth(uint8_t* data, size_t position, uint8_t length, uint8_t n); + +/** + * @brief Copy bits from source to destination. + * + * @param data destination array + * @param position position in destination array + * @param length length of bits to copy + * @param source source array + * @param source_position position in source array + */ +void bit_lib_copy_bits( + uint8_t* data, + size_t position, + size_t length, + const uint8_t* source, + size_t source_position); + +/** + * @brief Reverse bits in bit array + * + * @param data Bit array + * @param position start position + * @param length length of bits to reverse + */ +void bit_lib_reverse_bits(uint8_t* data, size_t position, uint8_t length); + +/** + * @brief Count 1 bits in data + * + * @param data + * @return uint8_t set bit count + */ +uint8_t bit_lib_get_bit_count(uint32_t data); + +/** + * @brief Print data as bit array + * + * @param data + * @param length + */ +void bit_lib_print_bits(const uint8_t* data, size_t length); + +typedef struct { + const char mark; + const size_t start; + const size_t length; +} BitLibRegion; + +/** + * @brief Print data as bit array and mark regions. Regions needs to be sorted by start position. + * + * @param regions + * @param region_count + * @param data + * @param length + */ +void bit_lib_print_regions( + const BitLibRegion* regions, + size_t region_count, + const uint8_t* data, + size_t length); + +/** + * @brief Reverse bits in uint16_t, faster than generic bit_lib_reverse_bits. + * + * @param data + * @return uint16_t + */ +uint16_t bit_lib_reverse_16_fast(uint16_t data); + +/** + * @brief Slow, but generic CRC16 implementation + * + * @param data + * @param data_size + * @param polynom CRC polynom + * @param init init value + * @param ref_in true if the right bit is older + * @param ref_out true to reverse output + * @param xor_out xor output with this value + * @return uint16_t + */ +uint16_t bit_lib_crc16( + uint8_t const* data, + size_t data_size, + uint16_t polynom, + uint16_t init, + bool ref_in, + bool ref_out, + uint16_t xor_out); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/lfrfid/tools/fsk_demod.c b/lib/lfrfid/tools/fsk_demod.c new file mode 100644 index 0000000000..a5155d88e5 --- /dev/null +++ b/lib/lfrfid/tools/fsk_demod.c @@ -0,0 +1,93 @@ +#include +#include "fsk_demod.h" + +struct FSKDemod { + uint32_t low_time; + uint32_t low_pulses; + uint32_t hi_time; + uint32_t hi_pulses; + + bool invert; + uint32_t mid_time; + uint32_t time; + uint32_t count; + bool last_pulse; +}; + +FSKDemod* + fsk_demod_alloc(uint32_t low_time, uint32_t low_pulses, uint32_t hi_time, uint32_t hi_pulses) { + FSKDemod* demod = malloc(sizeof(FSKDemod)); + demod->invert = false; + + if(low_time > hi_time) { + uint32_t tmp; + tmp = hi_time; + hi_time = low_time; + low_time = tmp; + + tmp = hi_pulses; + hi_pulses = low_pulses; + low_pulses = tmp; + + demod->invert = true; + } + + demod->low_time = low_time; + demod->low_pulses = low_pulses; + demod->hi_time = hi_time; + demod->hi_pulses = hi_pulses; + + demod->mid_time = (hi_time - low_time) / 2 + low_time; + demod->time = 0; + demod->count = 0; + demod->last_pulse = false; + + return demod; +} + +void fsk_demod_free(FSKDemod* demod) { + free(demod); +} + +void fsk_demod_feed(FSKDemod* demod, bool polarity, uint32_t time, bool* value, uint32_t* count) { + *count = 0; + + if(polarity) { + // accumulate time + demod->time = time; + } else { + demod->time += time; + + // check for valid pulse + if(demod->time >= demod->low_time && demod->time < demod->hi_time) { + bool pulse; + + if(demod->time < demod->mid_time) { + pulse = false; + } else { + pulse = true; + } + + demod->count++; + + // check for edge transition + if(demod->last_pulse != pulse) { + uint32_t data_count = demod->count + 1; + + if(demod->last_pulse) { + data_count /= demod->hi_pulses; + *value = !demod->invert; + } else { + data_count /= demod->low_pulses; + *value = demod->invert; + } + + *count = data_count; + demod->count = 0; + demod->last_pulse = pulse; + } + } else { + demod->count = 0; + } + } +} diff --git a/lib/lfrfid/tools/fsk_demod.h b/lib/lfrfid/tools/fsk_demod.h new file mode 100644 index 0000000000..d816b0dac1 --- /dev/null +++ b/lib/lfrfid/tools/fsk_demod.h @@ -0,0 +1,44 @@ +#pragma once +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct FSKDemod FSKDemod; + +/** + * @brief Allocate a new FSKDemod instance + * FSKDemod is a demodulator that can decode FSK encoded data + * + * @param low_time time between rising edges for the 0 bit + * @param low_pulses rising edges count for the 0 bit + * @param hi_time time between rising edges for the 1 bit + * @param hi_pulses rising edges count for the 1 bit + * @return FSKDemod* + */ +FSKDemod* + fsk_demod_alloc(uint32_t low_time, uint32_t low_pulses, uint32_t hi_time, uint32_t hi_pulses); + +/** + * @brief Free a FSKDemod instance + * + * @param fsk_demod + */ +void fsk_demod_free(FSKDemod* fsk_demod); + +/** + * @brief Feed sample to demodulator + * + * @param demod FSKDemod instance + * @param polarity sample polarity + * @param time sample time + * @param value demodulated bit value + * @param count demodulated bit count + */ +void fsk_demod_feed(FSKDemod* demod, bool polarity, uint32_t time, bool* value, uint32_t* count); + +#ifdef __cplusplus +} +#endif diff --git a/lib/lfrfid/tools/fsk_ocs.c b/lib/lfrfid/tools/fsk_ocs.c new file mode 100644 index 0000000000..1fd46cf179 --- /dev/null +++ b/lib/lfrfid/tools/fsk_ocs.c @@ -0,0 +1,62 @@ +#include "fsk_osc.h" +#include + +struct FSKOsc { + uint16_t freq[2]; + uint16_t osc_phase_max; + int32_t osc_phase_current; + + uint32_t pulse; +}; + +FSKOsc* fsk_osc_alloc(uint32_t freq_low, uint32_t freq_hi, uint32_t osc_phase_max) { + FSKOsc* osc = malloc(sizeof(FSKOsc)); + osc->freq[0] = freq_low; + osc->freq[1] = freq_hi; + osc->osc_phase_max = osc_phase_max; + osc->osc_phase_current = 0; + osc->pulse = 0; + return osc; +} + +void fsk_osc_free(FSKOsc* osc) { + free(osc); +} + +void fsk_osc_reset(FSKOsc* osc) { + osc->osc_phase_current = 0; + osc->pulse = 0; +} + +bool fsk_osc_next(FSKOsc* osc, bool bit, uint32_t* period) { + bool advance = false; + *period = osc->freq[bit]; + osc->osc_phase_current += *period; + + if(osc->osc_phase_current > osc->osc_phase_max) { + advance = true; + osc->osc_phase_current -= osc->osc_phase_max; + } + + return advance; +} + +bool fsk_osc_next_half(FSKOsc* osc, bool bit, bool* level, uint32_t* duration) { + bool advance = false; + + // if pulse is zero, we need to output high, otherwise we need to output low + if(osc->pulse == 0) { + uint32_t length; + advance = fsk_osc_next(osc, bit, &length); + *duration = length / 2; + osc->pulse = *duration; + *level = true; + } else { + // output low half and reset pulse + *duration = osc->pulse; + osc->pulse = 0; + *level = false; + } + + return advance; +} \ No newline at end of file diff --git a/lib/lfrfid/tools/fsk_osc.h b/lib/lfrfid/tools/fsk_osc.h new file mode 100644 index 0000000000..ed7d436c85 --- /dev/null +++ b/lib/lfrfid/tools/fsk_osc.h @@ -0,0 +1,60 @@ +#pragma once +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct FSKOsc FSKOsc; + +/** + * @brief Allocate a new FSKOsc instance + * FSKOsc is a oscillator that can provide FSK encoding + * + * @param freq_low + * @param freq_hi + * @param osc_phase_max + * @return FSKOsc* + */ +FSKOsc* fsk_osc_alloc(uint32_t freq_low, uint32_t freq_hi, uint32_t osc_phase_max); + +/** + * @brief Free a FSKOsc instance + * + * @param osc + */ +void fsk_osc_free(FSKOsc* osc); + +/** + * @brief Reset ocillator + * + * @param osc + */ +void fsk_osc_reset(FSKOsc* osc); + +/** + * @brief Get next duration sample from oscillator + * + * @param osc + * @param bit + * @param period + * @return bool + */ +bool fsk_osc_next(FSKOsc* osc, bool bit, uint32_t* period); + +/** + * @brief Get next half of sample from oscillator + * Useful when encoding high and low levels separately. + * + * @param osc + * @param bit + * @param level + * @param duration + * @return bool + */ +bool fsk_osc_next_half(FSKOsc* osc, bool bit, bool* level, uint32_t* duration); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/lfrfid/tools/t5577.c b/lib/lfrfid/tools/t5577.c new file mode 100644 index 0000000000..3444afea3e --- /dev/null +++ b/lib/lfrfid/tools/t5577.c @@ -0,0 +1,94 @@ +#include "t5577.h" +#include +#include + +#define T5577_TIMING_WAIT_TIME 400 +#define T5577_TIMING_START_GAP 30 +#define T5577_TIMING_WRITE_GAP 18 +#define T5577_TIMING_DATA_0 24 +#define T5577_TIMING_DATA_1 56 +#define T5577_TIMING_PROGRAM 700 + +#define T5577_OPCODE_PAGE_0 0b10 +#define T5577_OPCODE_PAGE_1 0b11 +#define T5577_OPCODE_RESET 0b00 + +static void t5577_start() { + furi_hal_rfid_tim_read(125000, 0.5); + furi_hal_rfid_pins_read(); + furi_hal_rfid_tim_read_start(); + + // do not ground the antenna + furi_hal_rfid_pin_pull_release(); +} + +static void t5577_stop() { + furi_hal_rfid_tim_read_stop(); + furi_hal_rfid_tim_reset(); + furi_hal_rfid_pins_reset(); +} + +static void t5577_write_gap(uint32_t gap_time) { + furi_hal_rfid_tim_read_stop(); + furi_delay_us(gap_time * 8); + furi_hal_rfid_tim_read_start(); +} + +static void t5577_write_bit(bool value) { + if(value) { + furi_delay_us(T5577_TIMING_DATA_1 * 8); + } else { + furi_delay_us(T5577_TIMING_DATA_0 * 8); + } + t5577_write_gap(T5577_TIMING_WRITE_GAP); +} + +static void t5577_write_opcode(uint8_t value) { + t5577_write_bit((value >> 1) & 1); + t5577_write_bit((value >> 0) & 1); +} + +static void t5577_write_reset() { + t5577_write_gap(T5577_TIMING_START_GAP); + t5577_write_bit(1); + t5577_write_bit(0); +} + +static void t5577_write_block(uint8_t block, bool lock_bit, uint32_t data) { + furi_delay_us(T5577_TIMING_WAIT_TIME * 8); + + // start gap + t5577_write_gap(T5577_TIMING_START_GAP); + + // opcode for page 0 + t5577_write_opcode(T5577_OPCODE_PAGE_0); + + // lock bit + t5577_write_bit(lock_bit); + + // data + for(uint8_t i = 0; i < 32; i++) { + t5577_write_bit((data >> (31 - i)) & 1); + } + + // block address + t5577_write_bit((block >> 2) & 1); + t5577_write_bit((block >> 1) & 1); + t5577_write_bit((block >> 0) & 1); + + furi_delay_us(T5577_TIMING_PROGRAM * 8); + + furi_delay_us(T5577_TIMING_WAIT_TIME * 8); + t5577_write_reset(); +} + +void t5577_write(LFRFIDT5577* data) { + t5577_start(); + FURI_CRITICAL_ENTER(); + for(size_t i = 0; i < data->blocks_to_write; i++) { + t5577_write_block(i, false, data->block[i]); + } + t5577_write_reset(); + FURI_CRITICAL_EXIT(); + t5577_stop(); +} \ No newline at end of file diff --git a/lib/lfrfid/tools/t5577.h b/lib/lfrfid/tools/t5577.h new file mode 100644 index 0000000000..6d53b5dc74 --- /dev/null +++ b/lib/lfrfid/tools/t5577.h @@ -0,0 +1,56 @@ +#pragma once +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define LFRFID_T5577_BLOCK_COUNT 8 + +// T5577 block 0 definitions, thanks proxmark3! +#define LFRFID_T5577_POR_DELAY 0x00000001 +#define LFRFID_T5577_ST_TERMINATOR 0x00000008 +#define LFRFID_T5577_PWD 0x00000010 +#define LFRFID_T5577_MAXBLOCK_SHIFT 5 +#define LFRFID_T5577_AOR 0x00000200 +#define LFRFID_T5577_PSKCF_RF_2 0 +#define LFRFID_T5577_PSKCF_RF_4 0x00000400 +#define LFRFID_T5577_PSKCF_RF_8 0x00000800 +#define LFRFID_T5577_MODULATION_DIRECT 0 +#define LFRFID_T5577_MODULATION_PSK1 0x00001000 +#define LFRFID_T5577_MODULATION_PSK2 0x00002000 +#define LFRFID_T5577_MODULATION_PSK3 0x00003000 +#define LFRFID_T5577_MODULATION_FSK1 0x00004000 +#define LFRFID_T5577_MODULATION_FSK2 0x00005000 +#define LFRFID_T5577_MODULATION_FSK1a 0x00006000 +#define LFRFID_T5577_MODULATION_FSK2a 0x00007000 +#define LFRFID_T5577_MODULATION_MANCHESTER 0x00008000 +#define LFRFID_T5577_MODULATION_BIPHASE 0x00010000 +#define LFRFID_T5577_MODULATION_DIPHASE 0x00018000 +#define LFRFID_T5577_X_MODE 0x00020000 +#define LFRFID_T5577_BITRATE_RF_8 0 +#define LFRFID_T5577_BITRATE_RF_16 0x00040000 +#define LFRFID_T5577_BITRATE_RF_32 0x00080000 +#define LFRFID_T5577_BITRATE_RF_40 0x000C0000 +#define LFRFID_T5577_BITRATE_RF_50 0x00100000 +#define LFRFID_T5577_BITRATE_RF_64 0x00140000 +#define LFRFID_T5577_BITRATE_RF_100 0x00180000 +#define LFRFID_T5577_BITRATE_RF_128 0x001C0000 +#define LFRFID_T5577_TESTMODE_DISABLED 0x60000000 + +typedef struct { + uint32_t block[LFRFID_T5577_BLOCK_COUNT]; + uint32_t blocks_to_write; +} LFRFIDT5577; + +/** + * @brief Write T5577 tag data to tag + * + * @param data + */ +void t5577_write(LFRFIDT5577* data); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/lfrfid/tools/varint_pair.c b/lib/lfrfid/tools/varint_pair.c new file mode 100644 index 0000000000..c59ba55b40 --- /dev/null +++ b/lib/lfrfid/tools/varint_pair.c @@ -0,0 +1,77 @@ +#include "varint_pair.h" +#include + +#define VARINT_PAIR_SIZE 10 + +struct VarintPair { + size_t data_length; + uint8_t data[VARINT_PAIR_SIZE]; +}; + +VarintPair* varint_pair_alloc() { + VarintPair* pair = malloc(sizeof(VarintPair)); + pair->data_length = 0; + return pair; +} + +void varint_pair_free(VarintPair* pair) { + free(pair); +} + +bool varint_pair_pack(VarintPair* pair, bool first, uint32_t value) { + bool result = false; + + if(first) { + if(pair->data_length == 0) { + pair->data_length = varint_uint32_pack(value, pair->data); + } else { + pair->data_length = 0; + } + } else { + if(pair->data_length > 0) { + pair->data_length += varint_uint32_pack(value, pair->data + pair->data_length); + result = true; + } else { + pair->data_length = 0; + } + } + + return result; +} + +bool varint_pair_unpack( + uint8_t* data, + size_t data_length, + uint32_t* value_1, + uint32_t* value_2, + size_t* length) { + size_t size = 0; + uint32_t tmp_value_1; + uint32_t tmp_value_2; + + size += varint_uint32_unpack(&tmp_value_1, &data[size], data_length); + + if(size >= data_length) { + return false; + } + + size += varint_uint32_unpack(&tmp_value_2, &data[size], (size_t)(data_length - size)); + + *value_1 = tmp_value_1; + *value_2 = tmp_value_2; + *length = size; + + return true; +} + +uint8_t* varint_pair_get_data(VarintPair* pair) { + return pair->data; +} + +size_t varint_pair_get_size(VarintPair* pair) { + return pair->data_length; +} + +void varint_pair_reset(VarintPair* pair) { + pair->data_length = 0; +} diff --git a/lib/lfrfid/tools/varint_pair.h b/lib/lfrfid/tools/varint_pair.h new file mode 100644 index 0000000000..3c8386423e --- /dev/null +++ b/lib/lfrfid/tools/varint_pair.h @@ -0,0 +1,79 @@ +#pragma once +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct VarintPair VarintPair; + +/** + * @brief Allocate a new VarintPair instance + * + * VarintPair is a buffer that holds pair of varint values + * @return VarintPair* + */ +VarintPair* varint_pair_alloc(); + +/** + * @brief Free a VarintPair instance + * + * @param pair + */ +void varint_pair_free(VarintPair* pair); + +/** + * @brief Write varint pair to buffer + * + * @param pair + * @param first + * @param value + * @return bool pair complete and needs to be written + */ +bool varint_pair_pack(VarintPair* pair, bool first, uint32_t value); + +/** + * @brief Get pointer to varint pair buffer + * + * @param pair + * @return uint8_t* + */ +uint8_t* varint_pair_get_data(VarintPair* pair); + +/** + * @brief Get size of varint pair buffer + * + * @param pair + * @return size_t + */ +size_t varint_pair_get_size(VarintPair* pair); + +/** + * @brief Reset varint pair buffer + * + * @param pair + */ +void varint_pair_reset(VarintPair* pair); + +/** + * @brief Unpack varint pair to uint32_t pair from buffer + * + * @param data + * @param data_length + * @param value_1 + * @param value_2 + * @param length + * @return bool + */ +bool varint_pair_unpack( + uint8_t* data, + size_t data_length, + uint32_t* value_1, + uint32_t* value_2, + size_t* length); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/one_wire/ibutton/encoder/encoder_cyfral.c b/lib/one_wire/ibutton/encoder/encoder_cyfral.c deleted file mode 100644 index 0b506b2b04..0000000000 --- a/lib/one_wire/ibutton/encoder/encoder_cyfral.c +++ /dev/null @@ -1,126 +0,0 @@ -#include "encoder_cyfral.h" -#include - -#define CYFRAL_DATA_SIZE sizeof(uint16_t) -#define CYFRAL_PERIOD (125 * furi_hal_cortex_instructions_per_microsecond()) -#define CYFRAL_0_LOW (CYFRAL_PERIOD * 0.66f) -#define CYFRAL_0_HI (CYFRAL_PERIOD * 0.33f) -#define CYFRAL_1_LOW (CYFRAL_PERIOD * 0.33f) -#define CYFRAL_1_HI (CYFRAL_PERIOD * 0.66f) - -#define CYFRAL_SET_DATA(level, len) \ - *polarity = level; \ - *length = len; - -struct EncoderCyfral { - uint32_t data; - uint32_t index; -}; - -EncoderCyfral* encoder_cyfral_alloc() { - EncoderCyfral* cyfral = malloc(sizeof(EncoderCyfral)); - encoder_cyfral_reset(cyfral); - return cyfral; -} - -void encoder_cyfral_free(EncoderCyfral* cyfral) { - free(cyfral); -} - -void encoder_cyfral_reset(EncoderCyfral* cyfral) { - cyfral->data = 0; - cyfral->index = 0; -} - -uint32_t cyfral_encoder_encode(const uint16_t data) { - uint32_t value = 0; - for(int8_t i = 0; i <= 7; i++) { - switch((data >> (i * 2)) & 0b00000011) { - case 0b11: - value = value << 4; - value += 0b00000111; - break; - case 0b10: - value = value << 4; - value += 0b00001011; - break; - case 0b01: - value = value << 4; - value += 0b00001101; - break; - case 0b00: - value = value << 4; - value += 0b00001110; - break; - default: - break; - } - } - - return value; -} - -void encoder_cyfral_set_data(EncoderCyfral* cyfral, const uint8_t* data, size_t data_size) { - furi_assert(cyfral); - furi_check(data_size >= CYFRAL_DATA_SIZE); - uint16_t intermediate; - memcpy(&intermediate, data, CYFRAL_DATA_SIZE); - cyfral->data = cyfral_encoder_encode(intermediate); -} - -void encoder_cyfral_get_pulse(EncoderCyfral* cyfral, bool* polarity, uint32_t* length) { - if(cyfral->index < 8) { - // start word (0b0001) - switch(cyfral->index) { - case 0: - CYFRAL_SET_DATA(false, CYFRAL_0_LOW); - break; - case 1: - CYFRAL_SET_DATA(true, CYFRAL_0_HI); - break; - case 2: - CYFRAL_SET_DATA(false, CYFRAL_0_LOW); - break; - case 3: - CYFRAL_SET_DATA(true, CYFRAL_0_HI); - break; - case 4: - CYFRAL_SET_DATA(false, CYFRAL_0_LOW); - break; - case 5: - CYFRAL_SET_DATA(true, CYFRAL_0_HI); - break; - case 6: - CYFRAL_SET_DATA(false, CYFRAL_1_LOW); - break; - case 7: - CYFRAL_SET_DATA(true, CYFRAL_1_HI); - break; - } - } else { - // data - uint8_t data_start_index = cyfral->index - 8; - bool clock_polarity = (data_start_index) % 2; - uint8_t bit_index = (data_start_index) / 2; - bool bit_value = ((cyfral->data >> bit_index) & 1); - - if(!clock_polarity) { - if(bit_value) { - CYFRAL_SET_DATA(false, CYFRAL_1_LOW); - } else { - CYFRAL_SET_DATA(false, CYFRAL_0_LOW); - } - } else { - if(bit_value) { - CYFRAL_SET_DATA(true, CYFRAL_1_HI); - } else { - CYFRAL_SET_DATA(true, CYFRAL_0_HI); - } - } - } - - cyfral->index++; - if(cyfral->index >= (9 * 4 * 2)) { - cyfral->index = 0; - } -} diff --git a/lib/one_wire/ibutton/encoder/encoder_cyfral.h b/lib/one_wire/ibutton/encoder/encoder_cyfral.h deleted file mode 100644 index 4fc7be5ed8..0000000000 --- a/lib/one_wire/ibutton/encoder/encoder_cyfral.h +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @file encoder_cyfral.h - * - * Cyfral pulse format encoder - */ - -#pragma once -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct EncoderCyfral EncoderCyfral; - -/** - * Allocate Cyfral encoder - * @return EncoderCyfral* - */ -EncoderCyfral* encoder_cyfral_alloc(); - -/** - * Deallocate Cyfral encoder - * @param cyfral - */ -void encoder_cyfral_free(EncoderCyfral* cyfral); - -/** - * Reset Cyfral encoder - * @param cyfral - */ -void encoder_cyfral_reset(EncoderCyfral* cyfral); - -/** - * Set data to be encoded to Cyfral pulse format, 2 bytes - * @param cyfral - * @param data - * @param data_size - */ -void encoder_cyfral_set_data(EncoderCyfral* cyfral, const uint8_t* data, size_t data_size); - -/** - * Pop pulse from Cyfral encoder - * @param cyfral - * @param polarity - * @param length - */ -void encoder_cyfral_get_pulse(EncoderCyfral* cyfral, bool* polarity, uint32_t* length); - -#ifdef __cplusplus -} -#endif diff --git a/lib/one_wire/ibutton/encoder/encoder_metakom.c b/lib/one_wire/ibutton/encoder/encoder_metakom.c deleted file mode 100644 index 5b978ebe28..0000000000 --- a/lib/one_wire/ibutton/encoder/encoder_metakom.c +++ /dev/null @@ -1,93 +0,0 @@ -#include "encoder_metakom.h" -#include - -#define METAKOM_DATA_SIZE sizeof(uint32_t) -#define METAKOM_PERIOD (125 * furi_hal_cortex_instructions_per_microsecond()) -#define METAKOM_0_LOW (METAKOM_PERIOD * 0.33f) -#define METAKOM_0_HI (METAKOM_PERIOD * 0.66f) -#define METAKOM_1_LOW (METAKOM_PERIOD * 0.66f) -#define METAKOM_1_HI (METAKOM_PERIOD * 0.33f) - -#define METAKOM_SET_DATA(level, len) \ - *polarity = !level; \ - *length = len; - -struct EncoderMetakom { - uint32_t data; - uint32_t index; -}; - -EncoderMetakom* encoder_metakom_alloc() { - EncoderMetakom* metakom = malloc(sizeof(EncoderMetakom)); - encoder_metakom_reset(metakom); - return metakom; -} - -void encoder_metakom_free(EncoderMetakom* metakom) { - free(metakom); -} - -void encoder_metakom_reset(EncoderMetakom* metakom) { - metakom->data = 0; - metakom->index = 0; -} - -void encoder_metakom_set_data(EncoderMetakom* metakom, const uint8_t* data, size_t data_size) { - furi_assert(metakom); - furi_check(data_size >= METAKOM_DATA_SIZE); - memcpy(&metakom->data, data, METAKOM_DATA_SIZE); -} - -void encoder_metakom_get_pulse(EncoderMetakom* metakom, bool* polarity, uint32_t* length) { - if(metakom->index == 0) { - // sync bit - METAKOM_SET_DATA(true, METAKOM_PERIOD); - } else if(metakom->index >= 1 && metakom->index <= 6) { - // start word (0b010) - switch(metakom->index) { - case 1: - METAKOM_SET_DATA(false, METAKOM_0_LOW); - break; - case 2: - METAKOM_SET_DATA(true, METAKOM_0_HI); - break; - case 3: - METAKOM_SET_DATA(false, METAKOM_1_LOW); - break; - case 4: - METAKOM_SET_DATA(true, METAKOM_1_HI); - break; - case 5: - METAKOM_SET_DATA(false, METAKOM_0_LOW); - break; - case 6: - METAKOM_SET_DATA(true, METAKOM_0_HI); - break; - } - } else { - // data - uint8_t data_start_index = metakom->index - 7; - bool clock_polarity = (data_start_index) % 2; - uint8_t bit_index = (data_start_index) / 2; - bool bit_value = (metakom->data >> (32 - 1 - bit_index)) & 1; - - if(!clock_polarity) { - if(bit_value) { - METAKOM_SET_DATA(false, METAKOM_1_LOW); - } else { - METAKOM_SET_DATA(false, METAKOM_0_LOW); - } - } else { - if(bit_value) { - METAKOM_SET_DATA(true, METAKOM_1_HI); - } else { - METAKOM_SET_DATA(true, METAKOM_0_HI); - } - } - } - - metakom->index++; - if(metakom->index >= (1 + 3 * 2 + 32 * 2)) { - metakom->index = 0; - } -} diff --git a/lib/one_wire/ibutton/encoder/encoder_metakom.h b/lib/one_wire/ibutton/encoder/encoder_metakom.h deleted file mode 100644 index 50ff11a243..0000000000 --- a/lib/one_wire/ibutton/encoder/encoder_metakom.h +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @file encoder_metakom.h - * - * Metakom pulse format encoder - */ - -#pragma once -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct EncoderMetakom EncoderMetakom; - -/** - * Allocate Metakom encoder - * @return EncoderMetakom* - */ -EncoderMetakom* encoder_metakom_alloc(); - -/** - * Deallocate Metakom encoder - * @param metakom - */ -void encoder_metakom_free(EncoderMetakom* metakom); - -/** - * Reset Metakom encoder - * @param metakom - */ -void encoder_metakom_reset(EncoderMetakom* metakom); - -/** - * Set data to be encoded to Metakom pulse format, 4 bytes - * @param metakom - * @param data - * @param data_size - */ -void encoder_metakom_set_data(EncoderMetakom* metakom, const uint8_t* data, size_t data_size); - -/** - * Pop pulse from Metakom encoder - * @param cyfral - * @param polarity - * @param length - */ -void encoder_metakom_get_pulse(EncoderMetakom* metakom, bool* polarity, uint32_t* length); - -#ifdef __cplusplus -} -#endif diff --git a/lib/one_wire/ibutton/ibutton_key.h b/lib/one_wire/ibutton/ibutton_key.h index f66537d7ea..d682555a86 100644 --- a/lib/one_wire/ibutton/ibutton_key.h +++ b/lib/one_wire/ibutton/ibutton_key.h @@ -5,6 +5,7 @@ */ #pragma once +#include #ifdef __cplusplus extern "C" { diff --git a/lib/one_wire/ibutton/ibutton_worker.c b/lib/one_wire/ibutton/ibutton_worker.c index 755ed32f3e..26982bcb67 100644 --- a/lib/one_wire/ibutton/ibutton_worker.c +++ b/lib/one_wire/ibutton/ibutton_worker.c @@ -29,34 +29,21 @@ iButtonWorker* ibutton_worker_alloc() { worker->slave = onewire_slave_alloc(); worker->writer = ibutton_writer_alloc(worker->host); worker->device = onewire_device_alloc(0, 0, 0, 0, 0, 0, 0, 0); - worker->pulse_decoder = pulse_decoder_alloc(); - worker->protocol_cyfral = protocol_cyfral_alloc(); - worker->protocol_metakom = protocol_metakom_alloc(); worker->messages = furi_message_queue_alloc(1, sizeof(iButtonMessage)); + worker->mode_index = iButtonWorkerIdle; - worker->last_dwt_value = 0; worker->read_cb = NULL; worker->write_cb = NULL; worker->emulate_cb = NULL; worker->cb_ctx = NULL; - worker->encoder_cyfral = encoder_cyfral_alloc(); - worker->encoder_metakom = encoder_metakom_alloc(); - worker->thread = furi_thread_alloc(); furi_thread_set_name(worker->thread, "ibutton_worker"); furi_thread_set_callback(worker->thread, ibutton_worker_thread); furi_thread_set_context(worker->thread, worker); furi_thread_set_stack_size(worker->thread, 2048); - pulse_decoder_add_protocol( - worker->pulse_decoder, - protocol_cyfral_get_protocol(worker->protocol_cyfral), - PulseProtocolCyfral); - pulse_decoder_add_protocol( - worker->pulse_decoder, - protocol_metakom_get_protocol(worker->protocol_metakom), - PulseProtocolMetakom); + worker->protocols = protocol_dict_alloc(ibutton_protocols, iButtonProtocolMax); return worker; } @@ -113,10 +100,6 @@ void ibutton_worker_stop(iButtonWorker* worker) { } void ibutton_worker_free(iButtonWorker* worker) { - pulse_decoder_free(worker->pulse_decoder); - protocol_metakom_free(worker->protocol_metakom); - protocol_cyfral_free(worker->protocol_cyfral); - ibutton_writer_free(worker->writer); onewire_slave_free(worker->slave); @@ -124,8 +107,7 @@ void ibutton_worker_free(iButtonWorker* worker) { onewire_host_free(worker->host); onewire_device_free(worker->device); - encoder_cyfral_free(worker->encoder_cyfral); - encoder_metakom_free(worker->encoder_metakom); + protocol_dict_free(worker->protocols); furi_message_queue_free(worker->messages); diff --git a/lib/one_wire/ibutton/ibutton_worker_i.h b/lib/one_wire/ibutton/ibutton_worker_i.h index 2858844394..2396fbd61c 100644 --- a/lib/one_wire/ibutton/ibutton_worker_i.h +++ b/lib/one_wire/ibutton/ibutton_worker_i.h @@ -10,21 +10,13 @@ #include "../one_wire_host.h" #include "../one_wire_slave.h" #include "../one_wire_device.h" -#include "../pulse_protocols/pulse_decoder.h" -#include "pulse_protocols/protocol_cyfral.h" -#include "pulse_protocols/protocol_metakom.h" -#include "encoder/encoder_cyfral.h" -#include "encoder/encoder_metakom.h" +#include +#include "protocols/ibutton_protocols.h" #ifdef __cplusplus extern "C" { #endif -typedef enum { - PulseProtocolCyfral, - PulseProtocolMetakom, -} PulseProtocols; - typedef struct { const uint32_t quant; void (*const start)(iButtonWorker* worker); @@ -39,11 +31,6 @@ typedef enum { iButtonWorkerEmulate = 3, } iButtonWorkerMode; -typedef enum { - iButtonEmulateModeCyfral, - iButtonEmulateModeMetakom, -} iButtonEmulateMode; - struct iButtonWorker { iButtonKey* key_p; uint8_t* key_data; @@ -55,19 +42,13 @@ struct iButtonWorker { FuriMessageQueue* messages; FuriThread* thread; - PulseDecoder* pulse_decoder; - ProtocolCyfral* protocol_cyfral; - ProtocolMetakom* protocol_metakom; - uint32_t last_dwt_value; - iButtonWorkerReadCallback read_cb; iButtonWorkerWriteCallback write_cb; iButtonWorkerEmulateCallback emulate_cb; void* cb_ctx; - EncoderCyfral* encoder_cyfral; - EncoderMetakom* encoder_metakom; - iButtonEmulateMode emulate_mode; + ProtocolDict* protocols; + iButtonProtocol protocol_to_encode; }; extern const iButtonWorkerModeType ibutton_worker_modes[]; diff --git a/lib/one_wire/ibutton/ibutton_worker_modes.c b/lib/one_wire/ibutton/ibutton_worker_modes.c index 78e05d0ee3..d585e27f4d 100644 --- a/lib/one_wire/ibutton/ibutton_worker_modes.c +++ b/lib/one_wire/ibutton/ibutton_worker_modes.c @@ -2,6 +2,7 @@ #include #include "ibutton_worker_i.h" #include "ibutton_key_command.h" +#include void ibutton_worker_mode_idle_start(iButtonWorker* worker); void ibutton_worker_mode_idle_tick(iButtonWorker* worker); @@ -62,59 +63,86 @@ void ibutton_worker_mode_idle_stop(iButtonWorker* worker) { /*********************** READ ***********************/ +typedef struct { + uint32_t last_dwt_value; + StreamBufferHandle_t stream; +} iButtonReadContext; + void ibutton_worker_comparator_callback(bool level, void* context) { - iButtonWorker* worker = context; + iButtonReadContext* read_context = context; uint32_t current_dwt_value = DWT->CYCCNT; - pulse_decoder_process_pulse( - worker->pulse_decoder, level, current_dwt_value - worker->last_dwt_value); + LevelDuration data = + level_duration_make(level, current_dwt_value - read_context->last_dwt_value); + xStreamBufferSend(read_context->stream, &data, sizeof(LevelDuration), 0); - worker->last_dwt_value = current_dwt_value; + read_context->last_dwt_value = current_dwt_value; } bool ibutton_worker_read_comparator(iButtonWorker* worker) { bool result = false; - pulse_decoder_reset(worker->pulse_decoder); + protocol_dict_decoders_start(worker->protocols); furi_hal_rfid_pins_reset(); // pulldown pull pin, we sense the signal through the analog part of the RFID schematic furi_hal_rfid_pin_pull_pulldown(); - furi_hal_rfid_comp_set_callback(ibutton_worker_comparator_callback, worker); - worker->last_dwt_value = DWT->CYCCNT; + + iButtonReadContext read_context = { + .last_dwt_value = DWT->CYCCNT, + .stream = xStreamBufferCreate(sizeof(LevelDuration) * 512, 1), + }; + + furi_hal_rfid_comp_set_callback(ibutton_worker_comparator_callback, &read_context); furi_hal_rfid_comp_start(); - // TODO: rework with thread events, "pulse_decoder_get_decoded_index_with_timeout" - furi_delay_ms(100); - int32_t decoded_index = pulse_decoder_get_decoded_index(worker->pulse_decoder); - if(decoded_index >= 0) { - pulse_decoder_get_data( - worker->pulse_decoder, decoded_index, worker->key_data, ibutton_key_get_max_size()); - } + uint32_t tick_start = furi_get_tick(); + while(true) { + LevelDuration level; + size_t ret = xStreamBufferReceive(read_context.stream, &level, sizeof(LevelDuration), 100); - switch(decoded_index) { - case PulseProtocolCyfral: - furi_check(worker->key_p != NULL); - ibutton_key_set_type(worker->key_p, iButtonKeyCyfral); - ibutton_key_set_data(worker->key_p, worker->key_data, ibutton_key_get_max_size()); - result = true; - break; - case PulseProtocolMetakom: - furi_check(worker->key_p != NULL); - ibutton_key_set_type(worker->key_p, iButtonKeyMetakom); - ibutton_key_set_data(worker->key_p, worker->key_data, ibutton_key_get_max_size()); - result = true; - break; - break; - default: - break; + if((furi_get_tick() - tick_start) > 100) { + break; + } + + if(ret > 0) { + ProtocolId decoded_index = protocol_dict_decoders_feed( + worker->protocols, + level_duration_get_level(level), + level_duration_get_duration(level)); + + if(decoded_index == PROTOCOL_NO) continue; + + protocol_dict_get_data( + worker->protocols, decoded_index, worker->key_data, ibutton_key_get_max_size()); + + switch(decoded_index) { + case iButtonProtocolCyfral: + furi_check(worker->key_p != NULL); + ibutton_key_set_type(worker->key_p, iButtonKeyCyfral); + ibutton_key_set_data(worker->key_p, worker->key_data, ibutton_key_get_max_size()); + result = true; + break; + case iButtonProtocolMetakom: + furi_check(worker->key_p != NULL); + ibutton_key_set_type(worker->key_p, iButtonKeyMetakom); + ibutton_key_set_data(worker->key_p, worker->key_data, ibutton_key_get_max_size()); + result = true; + break; + break; + default: + break; + } + } } furi_hal_rfid_comp_stop(); furi_hal_rfid_comp_set_callback(NULL, NULL); furi_hal_rfid_pins_reset(); + vStreamBufferDelete(read_context.stream); + return result; } @@ -207,21 +235,12 @@ void ibutton_worker_emulate_timer_cb(void* context) { furi_assert(context); iButtonWorker* worker = context; - bool polarity; - uint32_t length; + LevelDuration level = + protocol_dict_encoder_yield(worker->protocols, worker->protocol_to_encode); - switch(worker->emulate_mode) { - case iButtonEmulateModeCyfral: - encoder_cyfral_get_pulse(worker->encoder_cyfral, &polarity, &length); - break; - case iButtonEmulateModeMetakom: - encoder_metakom_get_pulse(worker->encoder_metakom, &polarity, &length); - break; - } - - furi_hal_ibutton_emulate_set_next(length); + furi_hal_ibutton_emulate_set_next(level_duration_get_duration(level)); - if(polarity) { + if(level_duration_get_level(level)) { furi_hal_ibutton_pin_high(); } else { furi_hal_ibutton_pin_low(); @@ -238,17 +257,16 @@ void ibutton_worker_emulate_timer_start(iButtonWorker* worker) { return; break; case iButtonKeyCyfral: - worker->emulate_mode = iButtonEmulateModeCyfral; - encoder_cyfral_reset(worker->encoder_cyfral); - encoder_cyfral_set_data(worker->encoder_cyfral, key_id, key_size); + worker->protocol_to_encode = iButtonProtocolCyfral; break; case iButtonKeyMetakom: - worker->emulate_mode = iButtonEmulateModeMetakom; - encoder_metakom_reset(worker->encoder_metakom); - encoder_metakom_set_data(worker->encoder_metakom, key_id, key_size); + worker->protocol_to_encode = iButtonProtocolMetakom; break; } + protocol_dict_set_data(worker->protocols, worker->protocol_to_encode, key_id, key_size); + protocol_dict_encoder_start(worker->protocols, worker->protocol_to_encode); + furi_hal_ibutton_start_drive(); furi_hal_ibutton_emulate_start(0, ibutton_worker_emulate_timer_cb, worker); } diff --git a/lib/one_wire/ibutton/protocols/ibutton_protocols.c b/lib/one_wire/ibutton/protocols/ibutton_protocols.c new file mode 100644 index 0000000000..b07d68b33c --- /dev/null +++ b/lib/one_wire/ibutton/protocols/ibutton_protocols.c @@ -0,0 +1,8 @@ +#include "ibutton_protocols.h" +#include "protocol_cyfral.h" +#include "protocol_metakom.h" + +const ProtocolBase* ibutton_protocols[] = { + [iButtonProtocolCyfral] = &protocol_cyfral, + [iButtonProtocolMetakom] = &protocol_metakom, +}; \ No newline at end of file diff --git a/lib/one_wire/ibutton/protocols/ibutton_protocols.h b/lib/one_wire/ibutton/protocols/ibutton_protocols.h new file mode 100644 index 0000000000..cdaa3ab6fa --- /dev/null +++ b/lib/one_wire/ibutton/protocols/ibutton_protocols.h @@ -0,0 +1,11 @@ +#pragma once +#include "toolbox/protocols/protocol.h" + +typedef enum { + iButtonProtocolCyfral, + iButtonProtocolMetakom, + + iButtonProtocolMax, +} iButtonProtocol; + +extern const ProtocolBase* ibutton_protocols[]; \ No newline at end of file diff --git a/lib/one_wire/ibutton/protocols/protocol_cyfral.c b/lib/one_wire/ibutton/protocols/protocol_cyfral.c new file mode 100644 index 0000000000..51c42824fc --- /dev/null +++ b/lib/one_wire/ibutton/protocols/protocol_cyfral.c @@ -0,0 +1,344 @@ +#include +#include +#include "protocol_cyfral.h" + +#define CYFRAL_DATA_SIZE sizeof(uint16_t) +#define CYFRAL_PERIOD (125 * furi_hal_cortex_instructions_per_microsecond()) +#define CYFRAL_0_LOW (CYFRAL_PERIOD * 0.66f) +#define CYFRAL_0_HI (CYFRAL_PERIOD * 0.33f) +#define CYFRAL_1_LOW (CYFRAL_PERIOD * 0.33f) +#define CYFRAL_1_HI (CYFRAL_PERIOD * 0.66f) + +#define CYFRAL_MAX_PERIOD_US 230 + +typedef enum { + CYFRAL_BIT_WAIT_FRONT_HIGH, + CYFRAL_BIT_WAIT_FRONT_LOW, +} CyfralBitState; + +typedef enum { + CYFRAL_WAIT_START_NIBBLE, + CYFRAL_READ_NIBBLE, + CYFRAL_READ_STOP_NIBBLE, +} CyfralState; + +typedef struct { + CyfralState state; + CyfralBitState bit_state; + + // high + low period time + uint32_t period_time; + // temporary nibble storage + uint8_t nibble; + // data valid flag + // MUST be checked only in READ_STOP_NIBBLE state + bool data_valid; + // nibble index, we expect 8 nibbles + uint8_t index; + // bit index in nibble, 4 bit per nibble + uint8_t bit_index; + // max period, 230us x clock per us + uint32_t max_period; +} ProtocolCyfralDecoder; + +typedef struct { + uint32_t data; + uint32_t index; +} ProtocolCyfralEncoder; + +typedef struct { + uint16_t data; + + ProtocolCyfralDecoder decoder; + ProtocolCyfralEncoder encoder; +} ProtocolCyfral; + +static void* protocol_cyfral_alloc(void) { + ProtocolCyfral* proto = malloc(sizeof(ProtocolCyfral)); + return (void*)proto; +} + +static void protocol_cyfral_free(ProtocolCyfral* proto) { + free(proto); +} + +static uint8_t* protocol_cyfral_get_data(ProtocolCyfral* proto) { + return (uint8_t*)&proto->data; +} + +static void protocol_cyfral_decoder_start(ProtocolCyfral* proto) { + ProtocolCyfralDecoder* cyfral = &proto->decoder; + + cyfral->state = CYFRAL_WAIT_START_NIBBLE; + cyfral->bit_state = CYFRAL_BIT_WAIT_FRONT_LOW; + cyfral->period_time = 0; + cyfral->bit_index = 0; + cyfral->index = 0; + cyfral->nibble = 0; + cyfral->data_valid = true; + cyfral->max_period = CYFRAL_MAX_PERIOD_US * furi_hal_cortex_instructions_per_microsecond(); + + proto->data = 0; +} + +static bool protocol_cyfral_decoder_process_bit( + ProtocolCyfralDecoder* cyfral, + bool polarity, + uint32_t length, + bool* bit_ready, + bool* bit_value) { + bool result = true; + *bit_ready = false; + + // bit start from low + switch(cyfral->bit_state) { + case CYFRAL_BIT_WAIT_FRONT_LOW: + if(polarity == true) { + cyfral->period_time += length; + + *bit_ready = true; + if(cyfral->period_time <= cyfral->max_period) { + if((cyfral->period_time / 2) > length) { + *bit_value = false; + } else { + *bit_value = true; + } + } else { + result = false; + } + + cyfral->bit_state = CYFRAL_BIT_WAIT_FRONT_HIGH; + } else { + result = false; + } + break; + case CYFRAL_BIT_WAIT_FRONT_HIGH: + if(polarity == false) { + cyfral->period_time = length; + cyfral->bit_state = CYFRAL_BIT_WAIT_FRONT_LOW; + } else { + result = false; + } + break; + } + + return result; +} + +static bool protocol_cyfral_decoder_feed(ProtocolCyfral* proto, bool level, uint32_t duration) { + ProtocolCyfralDecoder* cyfral = &proto->decoder; + + bool bit_ready; + bool bit_value; + bool decoded = false; + + switch(cyfral->state) { + case CYFRAL_WAIT_START_NIBBLE: + // wait for start word + if(protocol_cyfral_decoder_process_bit(cyfral, level, duration, &bit_ready, &bit_value)) { + if(bit_ready) { + cyfral->nibble = ((cyfral->nibble << 1) | bit_value) & 0x0F; + if(cyfral->nibble == 0b0001) { + cyfral->nibble = 0; + cyfral->state = CYFRAL_READ_NIBBLE; + } + } + } else { + protocol_cyfral_decoder_start(proto); + } + + break; + case CYFRAL_READ_NIBBLE: + // read nibbles + if(protocol_cyfral_decoder_process_bit(cyfral, level, duration, &bit_ready, &bit_value)) { + if(bit_ready) { + cyfral->nibble = (cyfral->nibble << 1) | bit_value; + + cyfral->bit_index++; + + //convert every nibble to 2-bit index + if(cyfral->bit_index == 4) { + switch(cyfral->nibble) { + case 0b1110: + proto->data = (proto->data << 2) | 0b11; + break; + case 0b1101: + proto->data = (proto->data << 2) | 0b10; + break; + case 0b1011: + proto->data = (proto->data << 2) | 0b01; + break; + case 0b0111: + proto->data = (proto->data << 2) | 0b00; + break; + default: + cyfral->data_valid = false; + break; + } + + cyfral->nibble = 0; + cyfral->bit_index = 0; + cyfral->index++; + } + + // succefully read 8 nibbles + if(cyfral->index == 8) { + cyfral->state = CYFRAL_READ_STOP_NIBBLE; + } + } + } else { + protocol_cyfral_decoder_start(proto); + } + break; + case CYFRAL_READ_STOP_NIBBLE: + // read stop nibble + if(protocol_cyfral_decoder_process_bit(cyfral, level, duration, &bit_ready, &bit_value)) { + if(bit_ready) { + cyfral->nibble = ((cyfral->nibble << 1) | bit_value) & 0x0F; + cyfral->bit_index++; + + switch(cyfral->bit_index) { + case 0: + case 1: + case 2: + case 3: + break; + case 4: + if(cyfral->nibble == 0b0001) { + // validate data + if(cyfral->data_valid) { + decoded = true; + } else { + protocol_cyfral_decoder_start(proto); + } + } else { + protocol_cyfral_decoder_start(proto); + } + break; + default: + protocol_cyfral_decoder_start(proto); + break; + } + } + } else { + protocol_cyfral_decoder_start(proto); + } + break; + } + + return decoded; +} + +static uint32_t protocol_cyfral_encoder_encode(const uint16_t data) { + uint32_t value = 0; + for(int8_t i = 0; i <= 7; i++) { + switch((data >> (i * 2)) & 0b00000011) { + case 0b11: + value = value << 4; + value += 0b00000111; + break; + case 0b10: + value = value << 4; + value += 0b00001011; + break; + case 0b01: + value = value << 4; + value += 0b00001101; + break; + case 0b00: + value = value << 4; + value += 0b00001110; + break; + default: + break; + } + } + + return value; +} + +static bool protocol_cyfral_encoder_start(ProtocolCyfral* proto) { + proto->encoder.index = 0; + proto->encoder.data = protocol_cyfral_encoder_encode(proto->data); + return true; +} + +static LevelDuration protocol_cyfral_encoder_yield(ProtocolCyfral* proto) { + LevelDuration result; + + if(proto->encoder.index < 8) { + // start word (0b0001) + switch(proto->encoder.index) { + case 0: + result = level_duration_make(false, CYFRAL_0_LOW); + break; + case 1: + result = level_duration_make(true, CYFRAL_0_HI); + break; + case 2: + result = level_duration_make(false, CYFRAL_0_LOW); + break; + case 3: + result = level_duration_make(true, CYFRAL_0_HI); + break; + case 4: + result = level_duration_make(false, CYFRAL_0_LOW); + break; + case 5: + result = level_duration_make(true, CYFRAL_0_HI); + break; + case 6: + result = level_duration_make(false, CYFRAL_1_LOW); + break; + case 7: + result = level_duration_make(true, CYFRAL_1_HI); + break; + } + } else { + // data + uint8_t data_start_index = proto->encoder.index - 8; + bool clock_polarity = (data_start_index) % 2; + uint8_t bit_index = (data_start_index) / 2; + bool bit_value = ((proto->encoder.data >> bit_index) & 1); + + if(!clock_polarity) { + if(bit_value) { + result = level_duration_make(false, CYFRAL_1_LOW); + } else { + result = level_duration_make(false, CYFRAL_0_LOW); + } + } else { + if(bit_value) { + result = level_duration_make(true, CYFRAL_1_HI); + } else { + result = level_duration_make(true, CYFRAL_0_HI); + } + } + } + + proto->encoder.index++; + if(proto->encoder.index >= (9 * 4 * 2)) { + proto->encoder.index = 0; + } + + return result; +} + +const ProtocolBase protocol_cyfral = { + .name = "Cyfral", + .manufacturer = "Cyfral", + .data_size = CYFRAL_DATA_SIZE, + .alloc = (ProtocolAlloc)protocol_cyfral_alloc, + .free = (ProtocolFree)protocol_cyfral_free, + .get_data = (ProtocolGetData)protocol_cyfral_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_cyfral_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_cyfral_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_cyfral_encoder_start, + .yield = (ProtocolEncoderYield)protocol_cyfral_encoder_yield, + }, +}; \ No newline at end of file diff --git a/lib/one_wire/ibutton/protocols/protocol_cyfral.h b/lib/one_wire/ibutton/protocols/protocol_cyfral.h new file mode 100644 index 0000000000..97a98e485e --- /dev/null +++ b/lib/one_wire/ibutton/protocols/protocol_cyfral.h @@ -0,0 +1,4 @@ +#pragma once +#include "toolbox/protocols/protocol.h" + +extern const ProtocolBase protocol_cyfral; \ No newline at end of file diff --git a/lib/one_wire/ibutton/pulse_protocols/protocol_metakom.c b/lib/one_wire/ibutton/protocols/protocol_metakom.c similarity index 51% rename from lib/one_wire/ibutton/pulse_protocols/protocol_metakom.c rename to lib/one_wire/ibutton/protocols/protocol_metakom.c index 9df9e20bed..00f16e4557 100644 --- a/lib/one_wire/ibutton/pulse_protocols/protocol_metakom.c +++ b/lib/one_wire/ibutton/protocols/protocol_metakom.c @@ -1,9 +1,14 @@ +#include +#include #include "protocol_metakom.h" -#include -#include -#include -#define METAKOM_DATA_SIZE 4 +#define METAKOM_DATA_SIZE sizeof(uint32_t) +#define METAKOM_PERIOD (125 * furi_hal_cortex_instructions_per_microsecond()) +#define METAKOM_0_LOW (METAKOM_PERIOD * 0.33f) +#define METAKOM_0_HI (METAKOM_PERIOD * 0.66f) +#define METAKOM_1_LOW (METAKOM_PERIOD * 0.66f) +#define METAKOM_1_HI (METAKOM_PERIOD * 0.33f) + #define METAKOM_PERIOD_SAMPLE_COUNT 10 typedef enum { @@ -19,79 +24,49 @@ typedef enum { METAKOM_BIT_WAIT_FRONT_LOW, } MetakomBitState; -struct ProtocolMetakom { - PulseProtocol* protocol; - +typedef struct { // high + low period time uint32_t period_time; uint32_t low_time_storage; uint8_t period_sample_index; uint32_t period_sample_data[METAKOM_PERIOD_SAMPLE_COUNT]; - // ready flag - // TODO: atomic access - bool ready; - uint8_t tmp_data; uint8_t tmp_counter; - uint32_t key_data; uint8_t key_data_index; MetakomBitState bit_state; MetakomState state; -}; - -static void metakom_pulse(void* context, bool polarity, uint32_t length); -static void metakom_reset(void* context); -static void metakom_get_data(void* context, uint8_t* data, size_t length); -static bool metakom_decoded(void* context); +} ProtocolMetakomDecoder; -ProtocolMetakom* protocol_metakom_alloc() { - ProtocolMetakom* metakom = malloc(sizeof(ProtocolMetakom)); - metakom_reset(metakom); +typedef struct { + uint32_t index; +} ProtocolMetakomEncoder; - metakom->protocol = pulse_protocol_alloc(); +typedef struct { + uint32_t data; - pulse_protocol_set_context(metakom->protocol, metakom); - pulse_protocol_set_pulse_cb(metakom->protocol, metakom_pulse); - pulse_protocol_set_reset_cb(metakom->protocol, metakom_reset); - pulse_protocol_set_get_data_cb(metakom->protocol, metakom_get_data); - pulse_protocol_set_decoded_cb(metakom->protocol, metakom_decoded); + ProtocolMetakomDecoder decoder; + ProtocolMetakomEncoder encoder; +} ProtocolMetakom; - return metakom; +static ProtocolMetakom* protocol_metakom_alloc(void) { + ProtocolMetakom* proto = malloc(sizeof(ProtocolMetakom)); + return (void*)proto; } -void protocol_metakom_free(ProtocolMetakom* metakom) { - furi_assert(metakom); - pulse_protocol_free(metakom->protocol); - free(metakom); +static void protocol_metakom_free(ProtocolMetakom* proto) { + free(proto); } -PulseProtocol* protocol_metakom_get_protocol(ProtocolMetakom* metakom) { - furi_assert(metakom); - return metakom->protocol; +static uint8_t* protocol_metakom_get_data(ProtocolMetakom* proto) { + return (uint8_t*)&proto->data; } -static void metakom_get_data(void* context, uint8_t* data, size_t length) { - furi_assert(context); - furi_check(length >= METAKOM_DATA_SIZE); - ProtocolMetakom* metakom = context; - memcpy(data, &metakom->key_data, METAKOM_DATA_SIZE); -} - -static bool metakom_decoded(void* context) { - furi_assert(context); - ProtocolMetakom* metakom = context; - bool decoded = metakom->ready; - return decoded; -} +static void protocol_metakom_decoder_start(ProtocolMetakom* proto) { + ProtocolMetakomDecoder* metakom = &proto->decoder; -static void metakom_reset(void* context) { - furi_assert(context); - ProtocolMetakom* metakom = context; - - metakom->ready = false; metakom->period_sample_index = 0; metakom->period_time = 0; metakom->tmp_counter = 0; @@ -101,9 +76,10 @@ static void metakom_reset(void* context) { }; metakom->state = METAKOM_WAIT_PERIOD_SYNC; metakom->bit_state = METAKOM_BIT_WAIT_FRONT_LOW; - metakom->key_data = 0; metakom->key_data_index = 0; metakom->low_time_storage = 0; + + proto->data = 0; } static bool metakom_parity_check(uint8_t data) { @@ -122,7 +98,7 @@ static bool metakom_parity_check(uint8_t data) { } static bool metakom_process_bit( - ProtocolMetakom* metakom, + ProtocolMetakomDecoder* metakom, bool polarity, uint32_t time, uint32_t* high_time, @@ -149,18 +125,17 @@ static bool metakom_process_bit( return result; } -static void metakom_pulse(void* context, bool polarity, uint32_t time) { - furi_assert(context); - ProtocolMetakom* metakom = context; +static bool protocol_metakom_decoder_feed(ProtocolMetakom* proto, bool level, uint32_t duration) { + ProtocolMetakomDecoder* metakom = &proto->decoder; - if(metakom->ready) return; + bool ready = false; uint32_t high_time = 0; uint32_t low_time = 0; switch(metakom->state) { case METAKOM_WAIT_PERIOD_SYNC: - if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) { + if(metakom_process_bit(metakom, level, duration, &high_time, &low_time)) { metakom->period_sample_data[metakom->period_sample_index] = high_time + low_time; metakom->period_sample_index++; @@ -176,7 +151,7 @@ static void metakom_pulse(void* context, bool polarity, uint32_t time) { break; case METAKOM_WAIT_START_BIT: - if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) { + if(metakom_process_bit(metakom, level, duration, &high_time, &low_time)) { metakom->tmp_counter++; if(high_time > metakom->period_time) { metakom->tmp_counter = 0; @@ -184,13 +159,13 @@ static void metakom_pulse(void* context, bool polarity, uint32_t time) { } if(metakom->tmp_counter > 40) { - metakom_reset(metakom); + protocol_metakom_decoder_start(proto); } } break; case METAKOM_WAIT_START_WORD: - if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) { + if(metakom_process_bit(metakom, level, duration, &high_time, &low_time)) { if(low_time < (metakom->period_time / 2)) { metakom->tmp_data = (metakom->tmp_data << 1) | 0b0; } else { @@ -204,13 +179,13 @@ static void metakom_pulse(void* context, bool polarity, uint32_t time) { metakom->tmp_data = 0; metakom->state = METAKOM_READ_WORD; } else { - metakom_reset(metakom); + protocol_metakom_decoder_start(proto); } } } break; case METAKOM_READ_WORD: - if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) { + if(metakom_process_bit(metakom, level, duration, &high_time, &low_time)) { if(low_time < (metakom->period_time / 2)) { metakom->tmp_data = (metakom->tmp_data << 1) | 0b0; } else { @@ -220,7 +195,7 @@ static void metakom_pulse(void* context, bool polarity, uint32_t time) { if(metakom->tmp_counter == 8) { if(metakom_parity_check(metakom->tmp_data)) { - metakom->key_data = (metakom->key_data << 8) | metakom->tmp_data; + proto->data = (proto->data << 8) | metakom->tmp_data; metakom->key_data_index++; metakom->tmp_data = 0; metakom->tmp_counter = 0; @@ -230,17 +205,17 @@ static void metakom_pulse(void* context, bool polarity, uint32_t time) { if(high_time > metakom->period_time) { metakom->state = METAKOM_READ_STOP_WORD; } else { - metakom_reset(metakom); + protocol_metakom_decoder_start(proto); } } } else { - metakom_reset(metakom); + protocol_metakom_decoder_start(proto); } } } break; case METAKOM_READ_STOP_WORD: - if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) { + if(metakom_process_bit(metakom, level, duration, &high_time, &low_time)) { if(low_time < (metakom->period_time / 2)) { metakom->tmp_data = (metakom->tmp_data << 1) | 0b0; } else { @@ -250,12 +225,96 @@ static void metakom_pulse(void* context, bool polarity, uint32_t time) { if(metakom->tmp_counter == 3) { if(metakom->tmp_data == 0b010) { - metakom->ready = true; + ready = true; } else { - metakom_reset(metakom); + protocol_metakom_decoder_start(proto); } } } break; } + + return ready; +} + +static bool protocol_metakom_encoder_start(ProtocolMetakom* proto) { + proto->encoder.index = 0; + return true; +} + +static LevelDuration protocol_metakom_encoder_yield(ProtocolMetakom* proto) { + LevelDuration result; + + if(proto->encoder.index == 0) { + // sync bit + result = level_duration_make(false, METAKOM_PERIOD); + } else if(proto->encoder.index >= 1 && proto->encoder.index <= 6) { + // start word (0b010) + switch(proto->encoder.index) { + case 1: + result = level_duration_make(true, METAKOM_0_LOW); + break; + case 2: + result = level_duration_make(false, METAKOM_0_HI); + break; + case 3: + result = level_duration_make(true, METAKOM_1_LOW); + break; + case 4: + result = level_duration_make(false, METAKOM_1_HI); + break; + case 5: + result = level_duration_make(true, METAKOM_0_LOW); + break; + case 6: + result = level_duration_make(false, METAKOM_0_HI); + break; + } + } else { + // data + uint8_t data_start_index = proto->encoder.index - 7; + bool clock_polarity = (data_start_index) % 2; + uint8_t bit_index = (data_start_index) / 2; + bool bit_value = (proto->data >> (32 - 1 - bit_index)) & 1; + + if(!clock_polarity) { + if(bit_value) { + result = level_duration_make(true, METAKOM_1_LOW); + } else { + result = level_duration_make(true, METAKOM_0_LOW); + } + } else { + if(bit_value) { + result = level_duration_make(false, METAKOM_1_HI); + } else { + result = level_duration_make(false, METAKOM_0_HI); + } + } + } + + proto->encoder.index++; + if(proto->encoder.index >= (1 + 3 * 2 + 32 * 2)) { + proto->encoder.index = 0; + } + + return result; } + +const ProtocolBase protocol_metakom = { + .name = "Metakom", + .manufacturer = "Metakom", + .data_size = METAKOM_DATA_SIZE, + .alloc = (ProtocolAlloc)protocol_metakom_alloc, + .free = (ProtocolFree)protocol_metakom_free, + .get_data = (ProtocolGetData)protocol_metakom_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_metakom_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_metakom_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_metakom_encoder_start, + .yield = (ProtocolEncoderYield)protocol_metakom_encoder_yield, + }, +}; \ No newline at end of file diff --git a/lib/one_wire/ibutton/protocols/protocol_metakom.h b/lib/one_wire/ibutton/protocols/protocol_metakom.h new file mode 100644 index 0000000000..5e44a2a8ce --- /dev/null +++ b/lib/one_wire/ibutton/protocols/protocol_metakom.h @@ -0,0 +1,4 @@ +#pragma once +#include "toolbox/protocols/protocol.h" + +extern const ProtocolBase protocol_metakom; \ No newline at end of file diff --git a/lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.c b/lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.c deleted file mode 100644 index 7c2897907b..0000000000 --- a/lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.c +++ /dev/null @@ -1,256 +0,0 @@ -#include "protocol_cyfral.h" -#include -#include -#include -#include - -#define CYFRAL_DATA_SIZE 2 -#define CYFRAL_MAX_PERIOD_US 230 - -typedef enum { - CYFRAL_BIT_WAIT_FRONT_HIGH, - CYFRAL_BIT_WAIT_FRONT_LOW, -} CyfralBitState; - -typedef enum { - CYFRAL_WAIT_START_NIBBLE, - CYFRAL_READ_NIBBLE, - CYFRAL_READ_STOP_NIBBLE, -} CyfralState; - -struct ProtocolCyfral { - PulseProtocol* protocol; - - CyfralState state; - CyfralBitState bit_state; - - // ready flag, key is read and valid - // TODO: atomic access - bool ready; - // key data storage - uint16_t key_data; - // high + low period time - uint32_t period_time; - // temporary nibble storage - uint8_t nibble; - // data valid flag - // MUST be checked only in READ_STOP_NIBBLE state - bool data_valid; - // nibble index, we expect 8 nibbles - uint8_t index; - // bit index in nibble, 4 bit per nibble - uint8_t bit_index; - // max period, 230us x clock per us - uint32_t max_period; -}; - -static void cyfral_pulse(void* context, bool polarity, uint32_t length); -static void cyfral_reset(void* context); -static void cyfral_get_data(void* context, uint8_t* data, size_t length); -static bool cyfral_decoded(void* context); - -ProtocolCyfral* protocol_cyfral_alloc() { - ProtocolCyfral* cyfral = malloc(sizeof(ProtocolCyfral)); - cyfral_reset(cyfral); - - cyfral->protocol = pulse_protocol_alloc(); - - pulse_protocol_set_context(cyfral->protocol, cyfral); - pulse_protocol_set_pulse_cb(cyfral->protocol, cyfral_pulse); - pulse_protocol_set_reset_cb(cyfral->protocol, cyfral_reset); - pulse_protocol_set_get_data_cb(cyfral->protocol, cyfral_get_data); - pulse_protocol_set_decoded_cb(cyfral->protocol, cyfral_decoded); - - return cyfral; -} - -void protocol_cyfral_free(ProtocolCyfral* cyfral) { - furi_assert(cyfral); - pulse_protocol_free(cyfral->protocol); - free(cyfral); -} - -PulseProtocol* protocol_cyfral_get_protocol(ProtocolCyfral* cyfral) { - furi_assert(cyfral); - return cyfral->protocol; -} - -static void cyfral_get_data(void* context, uint8_t* data, size_t length) { - furi_assert(context); - furi_check(length >= CYFRAL_DATA_SIZE); - ProtocolCyfral* cyfral = context; - memcpy(data, &cyfral->key_data, CYFRAL_DATA_SIZE); -} - -static bool cyfral_decoded(void* context) { - furi_assert(context); - ProtocolCyfral* cyfral = context; - bool decoded = cyfral->ready; - return decoded; -} - -static void cyfral_reset(void* context) { - furi_assert(context); - ProtocolCyfral* cyfral = context; - cyfral->state = CYFRAL_WAIT_START_NIBBLE; - cyfral->bit_state = CYFRAL_BIT_WAIT_FRONT_LOW; - - cyfral->period_time = 0; - cyfral->bit_index = 0; - cyfral->ready = false; - cyfral->index = 0; - - cyfral->key_data = 0; - cyfral->nibble = 0; - cyfral->data_valid = true; - - cyfral->max_period = CYFRAL_MAX_PERIOD_US * furi_hal_cortex_instructions_per_microsecond(); -} - -static bool cyfral_process_bit( - ProtocolCyfral* cyfral, - bool polarity, - uint32_t length, - bool* bit_ready, - bool* bit_value) { - bool result = true; - *bit_ready = false; - - // bit start from low - switch(cyfral->bit_state) { - case CYFRAL_BIT_WAIT_FRONT_LOW: - if(polarity == true) { - cyfral->period_time += length; - - *bit_ready = true; - if(cyfral->period_time <= cyfral->max_period) { - if((cyfral->period_time / 2) > length) { - *bit_value = false; - } else { - *bit_value = true; - } - } else { - result = false; - } - - cyfral->bit_state = CYFRAL_BIT_WAIT_FRONT_HIGH; - } else { - result = false; - } - break; - case CYFRAL_BIT_WAIT_FRONT_HIGH: - if(polarity == false) { - cyfral->period_time = length; - cyfral->bit_state = CYFRAL_BIT_WAIT_FRONT_LOW; - } else { - result = false; - } - break; - } - - return result; -} - -static void cyfral_pulse(void* context, bool polarity, uint32_t length) { - furi_assert(context); - ProtocolCyfral* cyfral = context; - - bool bit_ready; - bool bit_value; - - if(cyfral->ready) return; - - switch(cyfral->state) { - case CYFRAL_WAIT_START_NIBBLE: - // wait for start word - if(cyfral_process_bit(cyfral, polarity, length, &bit_ready, &bit_value)) { - if(bit_ready) { - cyfral->nibble = ((cyfral->nibble << 1) | bit_value) & 0x0F; - if(cyfral->nibble == 0b0001) { - cyfral->nibble = 0; - cyfral->state = CYFRAL_READ_NIBBLE; - } - } - } else { - cyfral_reset(cyfral); - } - - break; - case CYFRAL_READ_NIBBLE: - // read nibbles - if(cyfral_process_bit(cyfral, polarity, length, &bit_ready, &bit_value)) { - if(bit_ready) { - cyfral->nibble = (cyfral->nibble << 1) | bit_value; - - cyfral->bit_index++; - - //convert every nibble to 2-bit index - if(cyfral->bit_index == 4) { - switch(cyfral->nibble) { - case 0b1110: - cyfral->key_data = (cyfral->key_data << 2) | 0b11; - break; - case 0b1101: - cyfral->key_data = (cyfral->key_data << 2) | 0b10; - break; - case 0b1011: - cyfral->key_data = (cyfral->key_data << 2) | 0b01; - break; - case 0b0111: - cyfral->key_data = (cyfral->key_data << 2) | 0b00; - break; - default: - cyfral->data_valid = false; - break; - } - - cyfral->nibble = 0; - cyfral->bit_index = 0; - cyfral->index++; - } - - // succefully read 8 nibbles - if(cyfral->index == 8) { - cyfral->state = CYFRAL_READ_STOP_NIBBLE; - } - } - } else { - cyfral_reset(cyfral); - } - break; - case CYFRAL_READ_STOP_NIBBLE: - // read stop nibble - if(cyfral_process_bit(cyfral, polarity, length, &bit_ready, &bit_value)) { - if(bit_ready) { - cyfral->nibble = ((cyfral->nibble << 1) | bit_value) & 0x0F; - cyfral->bit_index++; - - switch(cyfral->bit_index) { - case 0: - case 1: - case 2: - case 3: - break; - case 4: - if(cyfral->nibble == 0b0001) { - // validate data - if(cyfral->data_valid) { - cyfral->ready = true; - } else { - cyfral_reset(cyfral); - } - } else { - cyfral_reset(cyfral); - } - break; - default: - cyfral_reset(cyfral); - break; - } - } - } else { - cyfral_reset(cyfral); - } - break; - } -} diff --git a/lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.h b/lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.h deleted file mode 100644 index 10305da12f..0000000000 --- a/lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @file protocol_cyfral.h - * - * Cyfral pulse format decoder - */ - -#pragma once -#include -#include "../../pulse_protocols/pulse_protocol.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct ProtocolCyfral ProtocolCyfral; - -/** - * Allocate decoder - * @return ProtocolCyfral* - */ -ProtocolCyfral* protocol_cyfral_alloc(); - -/** - * Deallocate decoder - * @param cyfral - */ -void protocol_cyfral_free(ProtocolCyfral* cyfral); - -/** - * Get protocol interface - * @param cyfral - * @return PulseProtocol* - */ -PulseProtocol* protocol_cyfral_get_protocol(ProtocolCyfral* cyfral); - -#ifdef __cplusplus -} -#endif diff --git a/lib/one_wire/ibutton/pulse_protocols/protocol_metakom.h b/lib/one_wire/ibutton/pulse_protocols/protocol_metakom.h deleted file mode 100644 index fdc4576953..0000000000 --- a/lib/one_wire/ibutton/pulse_protocols/protocol_metakom.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @file protocol_metakom.h - * - * Metakom pulse format decoder - */ - -#pragma once -#include -#include "../../pulse_protocols/pulse_protocol.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct ProtocolMetakom ProtocolMetakom; - -/** - * Allocate decoder - * @return ProtocolMetakom* - */ -ProtocolMetakom* protocol_metakom_alloc(); - -/** - * Free decoder - * @param metakom - */ -void protocol_metakom_free(ProtocolMetakom* metakom); - -/** - * Get protocol interface - * @param metakom - * @return PulseProtocol* - */ -PulseProtocol* protocol_metakom_get_protocol(ProtocolMetakom* metakom); - -#ifdef __cplusplus -} -#endif diff --git a/lib/one_wire/pulse_protocols/pulse_decoder.c b/lib/one_wire/pulse_protocols/pulse_decoder.c deleted file mode 100644 index c7d3b09ecb..0000000000 --- a/lib/one_wire/pulse_protocols/pulse_decoder.c +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include "pulse_decoder.h" -#include -#include - -#define MAX_PROTOCOL 5 - -struct PulseDecoder { - PulseProtocol* protocols[MAX_PROTOCOL]; -}; - -PulseDecoder* pulse_decoder_alloc() { - PulseDecoder* decoder = malloc(sizeof(PulseDecoder)); - memset(decoder, 0, sizeof(PulseDecoder)); - return decoder; -} - -void pulse_decoder_free(PulseDecoder* reader) { - furi_assert(reader); - free(reader); -} - -void pulse_decoder_add_protocol(PulseDecoder* reader, PulseProtocol* protocol, int32_t index) { - furi_check(index < MAX_PROTOCOL); - furi_check(reader->protocols[index] == NULL); - reader->protocols[index] = protocol; -} - -void pulse_decoder_process_pulse(PulseDecoder* reader, bool polarity, uint32_t length) { - furi_assert(reader); - for(size_t index = 0; index < MAX_PROTOCOL; index++) { - if(reader->protocols[index] != NULL) { - pulse_protocol_process_pulse(reader->protocols[index], polarity, length); - } - } -} - -int32_t pulse_decoder_get_decoded_index(PulseDecoder* reader) { - furi_assert(reader); - int32_t decoded = -1; - for(size_t index = 0; index < MAX_PROTOCOL; index++) { - if(reader->protocols[index] != NULL) { - if(pulse_protocol_decoded(reader->protocols[index])) { - decoded = index; - break; - } - } - } - - return decoded; -} - -void pulse_decoder_reset(PulseDecoder* reader) { - furi_assert(reader); - for(size_t index = 0; index < MAX_PROTOCOL; index++) { - if(reader->protocols[index] != NULL) { - pulse_protocol_reset(reader->protocols[index]); - } - } -} - -void pulse_decoder_get_data(PulseDecoder* reader, int32_t index, uint8_t* data, size_t length) { - furi_assert(reader); - furi_check(reader->protocols[index] != NULL); - pulse_protocol_get_data(reader->protocols[index], data, length); -} diff --git a/lib/one_wire/pulse_protocols/pulse_decoder.h b/lib/one_wire/pulse_protocols/pulse_decoder.h deleted file mode 100644 index dbaef52b5e..0000000000 --- a/lib/one_wire/pulse_protocols/pulse_decoder.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * @file pulse_decoder.h - * - * Generic pulse protocol decoder library - */ - -#pragma once -#include -#include -#include "pulse_protocol.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct PulseDecoder PulseDecoder; - -/** - * Allocate decoder - * @return PulseDecoder* - */ -PulseDecoder* pulse_decoder_alloc(); - -/** - * Deallocate decoder - * @param decoder - */ -void pulse_decoder_free(PulseDecoder* decoder); - -/** - * Add protocol to decoder - * @param decoder - * @param protocol protocol implementation - * @param index protocol index, should not be repeated - */ -void pulse_decoder_add_protocol(PulseDecoder* decoder, PulseProtocol* protocol, int32_t index); - -/** - * Push and process pulse with decoder - * @param decoder - * @param polarity - * @param length - */ -void pulse_decoder_process_pulse(PulseDecoder* decoder, bool polarity, uint32_t length); - -/** - * Get indec of decoded protocol - * @param decoder - * @return int32_t, -1 if nothing decoded, or index of decoded protocol - */ -int32_t pulse_decoder_get_decoded_index(PulseDecoder* decoder); - -/** - * Reset all protocols in decoder - * @param decoder - */ -void pulse_decoder_reset(PulseDecoder* decoder); - -/** - * Get decoded data from protocol - * @param decoder - * @param index - * @param data - * @param length - */ -void pulse_decoder_get_data(PulseDecoder* decoder, int32_t index, uint8_t* data, size_t length); - -#ifdef __cplusplus -} -#endif diff --git a/lib/one_wire/pulse_protocols/pulse_protocol.c b/lib/one_wire/pulse_protocols/pulse_protocol.c deleted file mode 100644 index 76feba1135..0000000000 --- a/lib/one_wire/pulse_protocols/pulse_protocol.c +++ /dev/null @@ -1,67 +0,0 @@ -#include "pulse_protocol.h" -#include -#include - -struct PulseProtocol { - void* context; - PulseProtocolPulseCallback pulse_cb; - PulseProtocolResetCallback reset_cb; - PulseProtocolGetDataCallback get_data_cb; - PulseProtocolDecodedCallback decoded_cb; -}; - -PulseProtocol* pulse_protocol_alloc() { - PulseProtocol* protocol = malloc(sizeof(PulseProtocol)); - memset(protocol, 0, sizeof(PulseProtocol)); - return protocol; -} - -void pulse_protocol_set_context(PulseProtocol* protocol, void* context) { - protocol->context = context; -} - -void pulse_protocol_set_pulse_cb(PulseProtocol* protocol, PulseProtocolPulseCallback callback) { - protocol->pulse_cb = callback; -} - -void pulse_protocol_set_reset_cb(PulseProtocol* protocol, PulseProtocolResetCallback callback) { - protocol->reset_cb = callback; -} - -void pulse_protocol_set_get_data_cb(PulseProtocol* protocol, PulseProtocolGetDataCallback callback) { - protocol->get_data_cb = callback; -} - -void pulse_protocol_set_decoded_cb(PulseProtocol* protocol, PulseProtocolDecodedCallback callback) { - protocol->decoded_cb = callback; -} - -void pulse_protocol_free(PulseProtocol* protocol) { - free(protocol); -} - -void pulse_protocol_process_pulse(PulseProtocol* protocol, bool polarity, uint32_t length) { - if(protocol->pulse_cb != NULL) { - protocol->pulse_cb(protocol->context, polarity, length); - } -} - -void pulse_protocol_reset(PulseProtocol* protocol) { - if(protocol->reset_cb != NULL) { - protocol->reset_cb(protocol->context); - } -} - -bool pulse_protocol_decoded(PulseProtocol* protocol) { - bool result = false; - if(protocol->decoded_cb != NULL) { - result = protocol->decoded_cb(protocol->context); - } - return result; -} - -void pulse_protocol_get_data(PulseProtocol* protocol, uint8_t* data, size_t length) { - if(protocol->get_data_cb != NULL) { - protocol->get_data_cb(protocol->context, data, length); - } -} diff --git a/lib/one_wire/pulse_protocols/pulse_protocol.h b/lib/one_wire/pulse_protocols/pulse_protocol.h deleted file mode 100644 index bfce0e76d8..0000000000 --- a/lib/one_wire/pulse_protocols/pulse_protocol.h +++ /dev/null @@ -1,122 +0,0 @@ -/** - * @file pulse_protocol.h - * - * Generic pulse protocol decoder library, protocol interface - */ - -#pragma once -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Anonymous PulseProtocol struct - */ -typedef struct PulseProtocol PulseProtocol; - -/** - * Process pulse callback - */ -typedef void (*PulseProtocolPulseCallback)(void* context, bool polarity, uint32_t length); - -/** - * Reset protocol callback - */ -typedef void (*PulseProtocolResetCallback)(void* context); - -/** - * Get decoded data callback - */ -typedef void (*PulseProtocolGetDataCallback)(void* context, uint8_t* data, size_t length); - -/** - * Is protocol decoded callback - */ -typedef bool (*PulseProtocolDecodedCallback)(void* context); - -/** - * Allocate protocol - * @return PulseProtocol* - */ -PulseProtocol* pulse_protocol_alloc(); - -/** - * Deallocate protocol - * @param protocol - */ -void pulse_protocol_free(PulseProtocol* protocol); - -/** - * Set context for callbacks - * @param protocol - * @param context - */ -void pulse_protocol_set_context(PulseProtocol* protocol, void* context); - -/** - * Set "Process pulse" callback. Called from the decoder when a new pulse is received. - * @param protocol - * @param callback - */ -void pulse_protocol_set_pulse_cb(PulseProtocol* protocol, PulseProtocolPulseCallback callback); - -/** - * Set "Reset protocol" callback. Called from the decoder when the decoder is reset. - * @param protocol - * @param callback - */ -void pulse_protocol_set_reset_cb(PulseProtocol* protocol, PulseProtocolResetCallback callback); - -/** - * Set "Get decoded data" callback. Called from the decoder when the decoder wants to get decoded data. - * @param protocol - * @param callback - */ -void pulse_protocol_set_get_data_cb(PulseProtocol* protocol, PulseProtocolGetDataCallback callback); - -/** - * Set "Is protocol decoded" callback. Called from the decoder when the decoder wants to know if a protocol has been decoded. - * @param protocol - * @param callback - */ -void pulse_protocol_set_decoded_cb(PulseProtocol* protocol, PulseProtocolDecodedCallback callback); - -/** - * Part of decoder interface. - * @param protocol - * @param polarity - * @param length - */ -void pulse_protocol_process_pulse(PulseProtocol* protocol, bool polarity, uint32_t length); - -/** - * Part of decoder interface. - * @param protocol - * @return true - * @return false - */ -bool pulse_protocol_decoded(PulseProtocol* protocol); - -/** - * Part of decoder interface. - * @param protocol - * @return true - * @return false - */ -void pulse_protocol_get_data(PulseProtocol* protocol, uint8_t* data, size_t length); - -/** - * Part of decoder interface. - * @param protocol - * @return true - * @return false - */ -void pulse_protocol_reset(PulseProtocol* protocol); - -#ifdef __cplusplus -} -#endif diff --git a/lib/subghz/protocols/keeloq_common.c b/lib/subghz/protocols/keeloq_common.c index 7e864a325b..0f8c763db2 100644 --- a/lib/subghz/protocols/keeloq_common.c +++ b/lib/subghz/protocols/keeloq_common.c @@ -5,6 +5,10 @@ #include #include +#define bit(x, n) (((x) >> (n)) & 1) +#define g5(x, a, b, c, d, e) \ + (bit(x, a) + bit(x, b) * 2 + bit(x, c) * 4 + bit(x, d) * 8 + bit(x, e) * 16) + /** Simple Learning Encrypt * @param data - 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter * @param key - manufacture (64bit) diff --git a/lib/subghz/protocols/keeloq_common.h b/lib/subghz/protocols/keeloq_common.h index 50d447ed72..aa07a7f585 100644 --- a/lib/subghz/protocols/keeloq_common.h +++ b/lib/subghz/protocols/keeloq_common.h @@ -11,9 +11,6 @@ * */ #define KEELOQ_NLF 0x3A5C742E -#define bit(x, n) (((x) >> (n)) & 1) -#define g5(x, a, b, c, d, e) \ - (bit(x, a) + bit(x, b) * 2 + bit(x, c) * 4 + bit(x, d) * 8 + bit(x, e) * 16) /* * KeeLoq learning types diff --git a/lib/toolbox/buffer_stream.c b/lib/toolbox/buffer_stream.c new file mode 100644 index 0000000000..66d2109630 --- /dev/null +++ b/lib/toolbox/buffer_stream.c @@ -0,0 +1,145 @@ +#include "buffer_stream.h" +#include + +struct Buffer { + volatile bool occupied; + volatile size_t size; + uint8_t* data; + size_t max_data_size; +}; + +struct BufferStream { + size_t stream_overrun_count; + StreamBufferHandle_t stream; + + size_t index; + Buffer* buffers; + size_t max_buffers_count; +}; + +bool buffer_write(Buffer* buffer, const uint8_t* data, size_t size) { + if(buffer->occupied) { + return false; + } + if((buffer->size + size) > buffer->max_data_size) { + return false; + } + memcpy(buffer->data + buffer->size, data, size); + buffer->size += size; + return true; +} + +uint8_t* buffer_get_data(Buffer* buffer) { + return buffer->data; +} + +size_t buffer_get_size(Buffer* buffer) { + return buffer->size; +} + +void buffer_reset(Buffer* buffer) { + buffer->occupied = false; + buffer->size = 0; +} + +BufferStream* buffer_stream_alloc(size_t buffer_size, size_t buffers_count) { + furi_assert(buffer_size > 0); + furi_assert(buffers_count > 0); + BufferStream* buffer_stream = malloc(sizeof(BufferStream)); + buffer_stream->max_buffers_count = buffers_count; + buffer_stream->buffers = malloc(sizeof(Buffer) * buffer_stream->max_buffers_count); + for(size_t i = 0; i < buffer_stream->max_buffers_count; i++) { + buffer_stream->buffers[i].occupied = false; + buffer_stream->buffers[i].size = 0; + buffer_stream->buffers[i].data = malloc(buffer_size); + buffer_stream->buffers[i].max_data_size = buffer_size; + } + buffer_stream->stream = xStreamBufferCreate( + sizeof(BufferStream*) * buffer_stream->max_buffers_count, sizeof(BufferStream*)); + buffer_stream->stream_overrun_count = 0; + buffer_stream->index = 0; + + return buffer_stream; +} + +void buffer_stream_free(BufferStream* buffer_stream) { + for(size_t i = 0; i < buffer_stream->max_buffers_count; i++) { + free(buffer_stream->buffers[i].data); + } + vStreamBufferDelete(buffer_stream->stream); + free(buffer_stream->buffers); + free(buffer_stream); +} + +static inline int8_t buffer_stream_get_free_buffer(BufferStream* buffer_stream) { + int8_t id = -1; + for(size_t i = 0; i < buffer_stream->max_buffers_count; i++) { + if(buffer_stream->buffers[i].occupied == false) { + id = i; + break; + } + } + + return id; +} + +bool buffer_stream_send_from_isr( + BufferStream* buffer_stream, + const uint8_t* data, + size_t size, + BaseType_t* const task_woken) { + Buffer* buffer = &buffer_stream->buffers[buffer_stream->index]; + bool result = true; + + // write to buffer + if(!buffer_write(buffer, data, size)) { + // if buffer is full - send it + buffer->occupied = true; + // we always have space for buffer in stream + xStreamBufferSendFromISR(buffer_stream->stream, &buffer, sizeof(Buffer*), task_woken); + + // get new buffer from the pool + int8_t index = buffer_stream_get_free_buffer(buffer_stream); + + // check that we have valid buffer + if(index == -1) { + // no free buffer + buffer_stream->stream_overrun_count++; + result = false; + } else { + // write to new buffer + buffer_stream->index = index; + buffer = &buffer_stream->buffers[buffer_stream->index]; + buffer_write(buffer, data, size); + } + } + + return result; +} + +Buffer* buffer_stream_receive(BufferStream* buffer_stream, TickType_t timeout) { + Buffer* buffer; + size_t size = xStreamBufferReceive(buffer_stream->stream, &buffer, sizeof(Buffer*), timeout); + + if(size == sizeof(Buffer*)) { + return buffer; + } else { + return NULL; + } +} + +size_t buffer_stream_get_overrun_count(BufferStream* buffer_stream) { + return buffer_stream->stream_overrun_count; +} + +void buffer_stream_reset(BufferStream* buffer_stream) { + FURI_CRITICAL_ENTER(); + BaseType_t xReturn = xStreamBufferReset(buffer_stream->stream); + furi_assert(xReturn == pdPASS); + UNUSED(xReturn); + buffer_stream->stream_overrun_count = 0; + for(size_t i = 0; i < buffer_stream->max_buffers_count; i++) { + buffer_reset(&buffer_stream->buffers[i]); + } + FURI_CRITICAL_EXIT(); +} \ No newline at end of file diff --git a/lib/toolbox/buffer_stream.h b/lib/toolbox/buffer_stream.h new file mode 100644 index 0000000000..d4c3cddf7c --- /dev/null +++ b/lib/toolbox/buffer_stream.h @@ -0,0 +1,94 @@ +/** + * @file buffer_stream.h + * + * This file implements the concept of a buffer stream. + * Data is written to the buffer until the buffer is full. + * Then the buffer pointer is written to the stream, and the new write buffer is taken from the buffer pool. + * After the buffer has been read by the receiving thread, it is sent to the free buffer pool. + * + * This will speed up sending large chunks of data between threads, compared to using a stream directly. + */ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Buffer Buffer; + +/** + * @brief Get buffer data pointer + * @param buffer + * @return uint8_t* + */ +uint8_t* buffer_get_data(Buffer* buffer); + +/** + * @brief Get buffer size + * @param buffer + * @return size_t + */ +size_t buffer_get_size(Buffer* buffer); + +/** + * @brief Reset buffer and send to free buffer pool + * @param buffer + */ +void buffer_reset(Buffer* buffer); + +typedef struct BufferStream BufferStream; + +/** + * @brief Allocate a new BufferStream instance + * @param buffer_size + * @param buffers_count + * @return BufferStream* + */ +BufferStream* buffer_stream_alloc(size_t buffer_size, size_t buffers_count); + +/** + * @brief Free a BufferStream instance + * @param buffer_stream + */ +void buffer_stream_free(BufferStream* buffer_stream); + +/** + * @brief Write data to buffer stream, from ISR context + * Data will be written to the buffer until the buffer is full, and only then will the buffer be sent. + * @param buffer_stream + * @param data + * @param size + * @param task_woken + * @return bool + */ +bool buffer_stream_send_from_isr( + BufferStream* buffer_stream, + const uint8_t* data, + size_t size, + BaseType_t* const task_woken); + +/** + * @brief Receive buffer from stream + * @param buffer_stream + * @param timeout + * @return Buffer* + */ +Buffer* buffer_stream_receive(BufferStream* buffer_stream, TickType_t timeout); + +/** + * @brief Get stream overrun count + * @param buffer_stream + * @return size_t + */ +size_t buffer_stream_get_overrun_count(BufferStream* buffer_stream); + +/** + * @brief Reset stream and buffer pool + * @param buffer_stream + */ +void buffer_stream_reset(BufferStream* buffer_stream); + +#ifdef __cplusplus +} +#endif diff --git a/lib/toolbox/profiler.c b/lib/toolbox/profiler.c new file mode 100644 index 0000000000..96f38dce2c --- /dev/null +++ b/lib/toolbox/profiler.c @@ -0,0 +1,87 @@ +#include "profiler.h" +#include +#include +#include +#include + +typedef struct { + uint32_t start; + uint32_t length; + uint32_t count; +} ProfilerRecord; + +DICT_DEF2(ProfilerRecordDict, const char*, M_CSTR_OPLIST, ProfilerRecord, M_POD_OPLIST) +#define M_OPL_ProfilerRecord_t() DICT_OPLIST(ProfilerRecord, M_CSTR_OPLIST, M_POD_OPLIST) + +struct Profiler { + ProfilerRecordDict_t records; +}; + +Profiler* profiler_alloc() { + Profiler* profiler = malloc(sizeof(Profiler)); + ProfilerRecordDict_init(profiler->records); + return profiler; +} + +void profiler_free(Profiler* profiler) { + ProfilerRecordDict_clear(profiler->records); + free(profiler); +} + +void profiler_prealloc(Profiler* profiler, const char* key) { + ProfilerRecord record = { + .start = 0, + .length = 0, + .count = 0, + }; + + ProfilerRecordDict_set_at(profiler->records, key, record); +} + +void profiler_start(Profiler* profiler, const char* key) { + ProfilerRecord* record = ProfilerRecordDict_get(profiler->records, key); + if(record == NULL) { + profiler_prealloc(profiler, key); + record = ProfilerRecordDict_get(profiler->records, key); + } + + furi_check(record->start == 0); + record->start = DWT->CYCCNT; +} + +void profiler_stop(Profiler* profiler, const char* key) { + ProfilerRecord* record = ProfilerRecordDict_get(profiler->records, key); + furi_check(record != NULL); + + record->length += DWT->CYCCNT - record->start; + record->start = 0; + record->count++; +} + +void profiler_dump(Profiler* profiler) { + printf("Profiler:\r\n"); + + ProfilerRecordDict_it_t it; + for(ProfilerRecordDict_it(it, profiler->records); !ProfilerRecordDict_end_p(it); + ProfilerRecordDict_next(it)) { + const ProfilerRecordDict_itref_t* itref = ProfilerRecordDict_cref(it); + + uint32_t count = itref->value.count; + + uint32_t clocks = itref->value.length; + double us = (double)clocks / (double)64.0; + double ms = (double)clocks / (double)64000.0; + double s = (double)clocks / (double)64000000.0; + + printf("\t%s[%lu]: %f s, %f ms, %f us, %lu clk\r\n", itref->key, count, s, ms, us, clocks); + + if(count > 1) { + us /= (double)count; + ms /= (double)count; + s /= (double)count; + clocks /= count; + + printf("\t%s[1]: %f s, %f ms, %f us, %lu clk\r\n", itref->key, s, ms, us, clocks); + } + } +} diff --git a/lib/toolbox/profiler.h b/lib/toolbox/profiler.h new file mode 100644 index 0000000000..840146332c --- /dev/null +++ b/lib/toolbox/profiler.h @@ -0,0 +1,23 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Profiler Profiler; + +Profiler* profiler_alloc(); + +void profiler_free(Profiler* profiler); + +void profiler_prealloc(Profiler* profiler, const char* key); + +void profiler_start(Profiler* profiler, const char* key); + +void profiler_stop(Profiler* profiler, const char* key); + +void profiler_dump(Profiler* profiler); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/toolbox/protocols/protocol.h b/lib/toolbox/protocols/protocol.h new file mode 100644 index 0000000000..56bb1b74ca --- /dev/null +++ b/lib/toolbox/protocols/protocol.h @@ -0,0 +1,46 @@ +#pragma once +#include +#include +#include +#include +#include + +typedef void* (*ProtocolAlloc)(void); +typedef void (*ProtocolFree)(void* protocol); +typedef uint8_t* (*ProtocolGetData)(void* protocol); + +typedef void (*ProtocolDecoderStart)(void* protocol); +typedef bool (*ProtocolDecoderFeed)(void* protocol, bool level, uint32_t duration); + +typedef bool (*ProtocolEncoderStart)(void* protocol); +typedef LevelDuration (*ProtocolEncoderYield)(void* protocol); + +typedef void (*ProtocolRenderData)(void* protocol, string_t result); +typedef bool (*ProtocolWriteData)(void* protocol, void* data); + +typedef struct { + ProtocolDecoderStart start; + ProtocolDecoderFeed feed; +} ProtocolDecoder; + +typedef struct { + ProtocolEncoderStart start; + ProtocolEncoderYield yield; +} ProtocolEncoder; + +typedef struct { + const size_t data_size; + const char* name; + const char* manufacturer; + const uint32_t features; + const uint8_t validate_count; + + ProtocolAlloc alloc; + ProtocolFree free; + ProtocolGetData get_data; + ProtocolDecoder decoder; + ProtocolEncoder encoder; + ProtocolRenderData render_data; + ProtocolRenderData render_brief_data; + ProtocolWriteData write_data; +} ProtocolBase; \ No newline at end of file diff --git a/lib/toolbox/protocols/protocol_dict.c b/lib/toolbox/protocols/protocol_dict.c new file mode 100644 index 0000000000..2a022cc406 --- /dev/null +++ b/lib/toolbox/protocols/protocol_dict.c @@ -0,0 +1,226 @@ +#include +#include "protocol_dict.h" + +struct ProtocolDict { + const ProtocolBase** base; + size_t count; + void** data; +}; + +ProtocolDict* protocol_dict_alloc(const ProtocolBase** protocols, size_t count) { + ProtocolDict* dict = malloc(sizeof(ProtocolDict)); + dict->base = protocols; + dict->count = count; + dict->data = malloc(sizeof(void*) * dict->count); + + for(size_t i = 0; i < dict->count; i++) { + dict->data[i] = dict->base[i]->alloc(); + } + + return dict; +} + +void protocol_dict_free(ProtocolDict* dict) { + for(size_t i = 0; i < dict->count; i++) { + dict->base[i]->free(dict->data[i]); + } + + free(dict->data); + free(dict); +} + +void protocol_dict_set_data( + ProtocolDict* dict, + size_t protocol_index, + const uint8_t* data, + size_t data_size) { + furi_assert(protocol_index < dict->count); + furi_assert(dict->base[protocol_index]->get_data != NULL); + uint8_t* protocol_data = dict->base[protocol_index]->get_data(dict->data[protocol_index]); + size_t protocol_data_size = dict->base[protocol_index]->data_size; + furi_check(data_size >= protocol_data_size); + memcpy(protocol_data, data, protocol_data_size); +} + +void protocol_dict_get_data( + ProtocolDict* dict, + size_t protocol_index, + uint8_t* data, + size_t data_size) { + furi_assert(protocol_index < dict->count); + furi_assert(dict->base[protocol_index]->get_data != NULL); + uint8_t* protocol_data = dict->base[protocol_index]->get_data(dict->data[protocol_index]); + size_t protocol_data_size = dict->base[protocol_index]->data_size; + furi_check(data_size >= protocol_data_size); + memcpy(data, protocol_data, protocol_data_size); +} + +size_t protocol_dict_get_data_size(ProtocolDict* dict, size_t protocol_index) { + furi_assert(protocol_index < dict->count); + return dict->base[protocol_index]->data_size; +} + +size_t protocol_dict_get_max_data_size(ProtocolDict* dict) { + size_t max_data_size = 0; + for(size_t i = 0; i < dict->count; i++) { + size_t data_size = dict->base[i]->data_size; + if(data_size > max_data_size) { + max_data_size = data_size; + } + } + + return max_data_size; +} + +const char* protocol_dict_get_name(ProtocolDict* dict, size_t protocol_index) { + furi_assert(protocol_index < dict->count); + return dict->base[protocol_index]->name; +} + +const char* protocol_dict_get_manufacturer(ProtocolDict* dict, size_t protocol_index) { + furi_assert(protocol_index < dict->count); + return dict->base[protocol_index]->manufacturer; +} + +void protocol_dict_decoders_start(ProtocolDict* dict) { + for(size_t i = 0; i < dict->count; i++) { + ProtocolDecoderStart fn = dict->base[i]->decoder.start; + + if(fn) { + fn(dict->data[i]); + } + } +} + +uint32_t protocol_dict_get_features(ProtocolDict* dict, size_t protocol_index) { + furi_assert(protocol_index < dict->count); + return dict->base[protocol_index]->features; +} + +ProtocolId protocol_dict_decoders_feed(ProtocolDict* dict, bool level, uint32_t duration) { + bool done = false; + ProtocolId ready_protocol_id = PROTOCOL_NO; + + for(size_t i = 0; i < dict->count; i++) { + ProtocolDecoderFeed fn = dict->base[i]->decoder.feed; + + if(fn) { + if(fn(dict->data[i], level, duration)) { + if(!done) { + ready_protocol_id = i; + done = true; + } + } + } + } + + return ready_protocol_id; +} + +ProtocolId protocol_dict_decoders_feed_by_feature( + ProtocolDict* dict, + uint32_t feature, + bool level, + uint32_t duration) { + bool done = false; + ProtocolId ready_protocol_id = PROTOCOL_NO; + + for(size_t i = 0; i < dict->count; i++) { + uint32_t features = dict->base[i]->features; + if(features & feature) { + ProtocolDecoderFeed fn = dict->base[i]->decoder.feed; + + if(fn) { + if(fn(dict->data[i], level, duration)) { + if(!done) { + ready_protocol_id = i; + done = true; + } + } + } + } + } + + return ready_protocol_id; +} + +ProtocolId protocol_dict_decoders_feed_by_id( + ProtocolDict* dict, + size_t protocol_index, + bool level, + uint32_t duration) { + furi_assert(protocol_index < dict->count); + + ProtocolId ready_protocol_id = PROTOCOL_NO; + ProtocolDecoderFeed fn = dict->base[protocol_index]->decoder.feed; + + if(fn) { + if(fn(dict->data[protocol_index], level, duration)) { + ready_protocol_id = protocol_index; + } + } + + return ready_protocol_id; +} + +bool protocol_dict_encoder_start(ProtocolDict* dict, size_t protocol_index) { + furi_assert(protocol_index < dict->count); + ProtocolEncoderStart fn = dict->base[protocol_index]->encoder.start; + + if(fn) { + return fn(dict->data[protocol_index]); + } else { + return false; + } +} + +LevelDuration protocol_dict_encoder_yield(ProtocolDict* dict, size_t protocol_index) { + furi_assert(protocol_index < dict->count); + ProtocolEncoderYield fn = dict->base[protocol_index]->encoder.yield; + + if(fn) { + return fn(dict->data[protocol_index]); + } else { + return level_duration_reset(); + } +} + +void protocol_dict_render_data(ProtocolDict* dict, string_t result, size_t protocol_index) { + furi_assert(protocol_index < dict->count); + ProtocolRenderData fn = dict->base[protocol_index]->render_data; + + if(fn) { + return fn(dict->data[protocol_index], result); + } +} + +void protocol_dict_render_brief_data(ProtocolDict* dict, string_t result, size_t protocol_index) { + furi_assert(protocol_index < dict->count); + ProtocolRenderData fn = dict->base[protocol_index]->render_brief_data; + + if(fn) { + return fn(dict->data[protocol_index], result); + } +} + +uint32_t protocol_dict_get_validate_count(ProtocolDict* dict, size_t protocol_index) { + furi_assert(protocol_index < dict->count); + return dict->base[protocol_index]->validate_count; +} + +ProtocolId protocol_dict_get_protocol_by_name(ProtocolDict* dict, const char* name) { + for(size_t i = 0; i < dict->count; i++) { + if(strcmp(name, protocol_dict_get_name(dict, i)) == 0) { + return i; + } + } + return PROTOCOL_NO; +} + +bool protocol_dict_get_write_data(ProtocolDict* dict, size_t protocol_index, void* data) { + furi_assert(protocol_index < dict->count); + ProtocolWriteData fn = dict->base[protocol_index]->write_data; + + furi_assert(fn); + return fn(dict->data[protocol_index], data); +} \ No newline at end of file diff --git a/lib/toolbox/protocols/protocol_dict.h b/lib/toolbox/protocols/protocol_dict.h new file mode 100644 index 0000000000..3037ddd5e4 --- /dev/null +++ b/lib/toolbox/protocols/protocol_dict.h @@ -0,0 +1,73 @@ +#pragma once +#include "protocol.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ProtocolDict ProtocolDict; + +typedef int32_t ProtocolId; + +#define PROTOCOL_NO (-1) +#define PROTOCOL_ALL_FEATURES (0xFFFFFFFF) + +ProtocolDict* protocol_dict_alloc(const ProtocolBase** protocols, size_t protocol_count); + +void protocol_dict_free(ProtocolDict* dict); + +void protocol_dict_set_data( + ProtocolDict* dict, + size_t protocol_index, + const uint8_t* data, + size_t data_size); + +void protocol_dict_get_data( + ProtocolDict* dict, + size_t protocol_index, + uint8_t* data, + size_t data_size); + +size_t protocol_dict_get_data_size(ProtocolDict* dict, size_t protocol_index); + +size_t protocol_dict_get_max_data_size(ProtocolDict* dict); + +const char* protocol_dict_get_name(ProtocolDict* dict, size_t protocol_index); + +const char* protocol_dict_get_manufacturer(ProtocolDict* dict, size_t protocol_index); + +void protocol_dict_decoders_start(ProtocolDict* dict); + +uint32_t protocol_dict_get_features(ProtocolDict* dict, size_t protocol_index); + +ProtocolId protocol_dict_decoders_feed(ProtocolDict* dict, bool level, uint32_t duration); + +ProtocolId protocol_dict_decoders_feed_by_feature( + ProtocolDict* dict, + uint32_t feature, + bool level, + uint32_t duration); + +ProtocolId protocol_dict_decoders_feed_by_id( + ProtocolDict* dict, + size_t protocol_index, + bool level, + uint32_t duration); + +bool protocol_dict_encoder_start(ProtocolDict* dict, size_t protocol_index); + +LevelDuration protocol_dict_encoder_yield(ProtocolDict* dict, size_t protocol_index); + +void protocol_dict_render_data(ProtocolDict* dict, string_t result, size_t protocol_index); + +void protocol_dict_render_brief_data(ProtocolDict* dict, string_t result, size_t protocol_index); + +uint32_t protocol_dict_get_validate_count(ProtocolDict* dict, size_t protocol_index); + +ProtocolId protocol_dict_get_protocol_by_name(ProtocolDict* dict, const char* name); + +bool protocol_dict_get_write_data(ProtocolDict* dict, size_t protocol_index, void* data); + +#ifdef __cplusplus +} +#endif diff --git a/lib/toolbox/pulse_joiner.c b/lib/toolbox/pulse_joiner.c new file mode 100644 index 0000000000..b6206486c9 --- /dev/null +++ b/lib/toolbox/pulse_joiner.c @@ -0,0 +1,117 @@ +#include "pulse_joiner.h" +#include + +#define PULSE_MAX_COUNT 6 + +typedef struct { + bool polarity; + uint16_t time; +} Pulse; + +struct PulseJoiner { + size_t pulse_index; + Pulse pulses[PULSE_MAX_COUNT]; +}; + +PulseJoiner* pulse_joiner_alloc() { + PulseJoiner* pulse_joiner = malloc(sizeof(PulseJoiner)); + + pulse_joiner->pulse_index = 0; + for(uint8_t i = 0; i < PULSE_MAX_COUNT; i++) { + pulse_joiner->pulses[i].polarity = false; + pulse_joiner->pulses[i].time = 0; + } + + return pulse_joiner; +} + +void pulse_joiner_free(PulseJoiner* pulse_joiner) { + free(pulse_joiner); +} + +bool pulse_joiner_push_pulse(PulseJoiner* pulse_joiner, bool polarity, size_t period, size_t pulse) { + bool result = false; + furi_check((pulse_joiner->pulse_index + 1) < PULSE_MAX_COUNT); + + if(polarity == false && pulse_joiner->pulse_index == 0) { + // first negative pulse is omitted + + } else { + pulse_joiner->pulses[pulse_joiner->pulse_index].polarity = polarity; + pulse_joiner->pulses[pulse_joiner->pulse_index].time = pulse; + pulse_joiner->pulse_index++; + } + + if(period > pulse) { + pulse_joiner->pulses[pulse_joiner->pulse_index].polarity = !polarity; + pulse_joiner->pulses[pulse_joiner->pulse_index].time = period - pulse; + pulse_joiner->pulse_index++; + } + + if(pulse_joiner->pulse_index >= 4) { + // we know that first pulse is always high + // so we wait 2 edges, hi2low and next low2hi + + uint8_t edges_count = 0; + bool last_polarity = pulse_joiner->pulses[0].polarity; + + for(uint8_t i = 1; i < pulse_joiner->pulse_index; i++) { + if(pulse_joiner->pulses[i].polarity != last_polarity) { + edges_count++; + last_polarity = pulse_joiner->pulses[i].polarity; + } + } + + if(edges_count >= 2) { + result = true; + } + } + + return result; +} + +void pulse_joiner_pop_pulse(PulseJoiner* pulse_joiner, size_t* period, size_t* pulse) { + furi_check(pulse_joiner->pulse_index <= (PULSE_MAX_COUNT + 1)); + + uint16_t tmp_period = 0; + uint16_t tmp_pulse = 0; + uint8_t edges_count = 0; + bool last_polarity = pulse_joiner->pulses[0].polarity; + uint8_t next_fist_pulse = 0; + + for(uint8_t i = 0; i < PULSE_MAX_COUNT; i++) { + // count edges + if(pulse_joiner->pulses[i].polarity != last_polarity) { + edges_count++; + last_polarity = pulse_joiner->pulses[i].polarity; + } + + // wait for 2 edges + if(edges_count == 2) { + next_fist_pulse = i; + break; + } + + // sum pulse time + if(pulse_joiner->pulses[i].polarity) { + tmp_period += pulse_joiner->pulses[i].time; + tmp_pulse += pulse_joiner->pulses[i].time; + } else { + tmp_period += pulse_joiner->pulses[i].time; + } + pulse_joiner->pulse_index--; + } + + *period = tmp_period; + *pulse = tmp_pulse; + + // remove counted periods and shift data + for(uint8_t i = 0; i < PULSE_MAX_COUNT; i++) { + if((next_fist_pulse + i) < PULSE_MAX_COUNT) { + pulse_joiner->pulses[i].polarity = pulse_joiner->pulses[next_fist_pulse + i].polarity; + pulse_joiner->pulses[i].time = pulse_joiner->pulses[next_fist_pulse + i].time; + } else { + break; + } + } +} \ No newline at end of file diff --git a/lib/toolbox/pulse_joiner.h b/lib/toolbox/pulse_joiner.h new file mode 100644 index 0000000000..25f702e729 --- /dev/null +++ b/lib/toolbox/pulse_joiner.h @@ -0,0 +1,46 @@ +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct PulseJoiner PulseJoiner; + +/** + * @brief Alloc PulseJoiner + * + * @return PulseJoiner* + */ +PulseJoiner* pulse_joiner_alloc(); + +/** + * @brief Free PulseJoiner + * + * @param pulse_joiner + */ +void pulse_joiner_free(PulseJoiner* pulse_joiner); + +/** + * @brief Push timer pulse. First negative pulse is ommited. + * + * @param polarity pulse polarity: true = high2low, false = low2high + * @param period overall period time in timer clicks + * @param pulse pulse time in timer clicks + * + * @return true - next pulse can and must be popped immediatly + */ +bool pulse_joiner_push_pulse(PulseJoiner* pulse_joiner, bool polarity, size_t period, size_t pulse); + +/** + * @brief Get the next timer pulse. Call only if push_pulse returns true. + * + * @param period overall period time in timer clicks + * @param pulse pulse time in timer clicks + */ +void pulse_joiner_pop_pulse(PulseJoiner* pulse_joiner, size_t* period, size_t* pulse); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/one_wire/pulse_protocols/pulse_glue.c b/lib/toolbox/pulse_protocols/pulse_glue.c similarity index 100% rename from lib/one_wire/pulse_protocols/pulse_glue.c rename to lib/toolbox/pulse_protocols/pulse_glue.c diff --git a/lib/one_wire/pulse_protocols/pulse_glue.h b/lib/toolbox/pulse_protocols/pulse_glue.h similarity index 100% rename from lib/one_wire/pulse_protocols/pulse_glue.h rename to lib/toolbox/pulse_protocols/pulse_glue.h diff --git a/lib/toolbox/varint.c b/lib/toolbox/varint.c new file mode 100644 index 0000000000..ee2f5c3af9 --- /dev/null +++ b/lib/toolbox/varint.c @@ -0,0 +1,76 @@ +#include "varint.h" + +size_t varint_uint32_pack(uint32_t value, uint8_t* output) { + uint8_t* start = output; + while(value >= 0x80) { + *output++ = (value | 0x80); + value >>= 7; + } + *output++ = value; + return output - start; +} + +size_t varint_uint32_unpack(uint32_t* value, const uint8_t* input, size_t input_size) { + size_t i; + uint32_t parsed = 0; + + for(i = 0; i < input_size; i++) { + parsed |= (input[i] & 0x7F) << (7 * i); + + if(!(input[i] & 0x80)) { + break; + } + } + + *value = parsed; + + return i + 1; +} + +size_t varint_uint32_length(uint32_t value) { + size_t size = 0; + while(value >= 0x80) { + value >>= 7; + size++; + } + size++; + + return size; +} + +size_t varint_int32_pack(int32_t value, uint8_t* output) { + uint32_t v; + + if(value >= 0) { + v = value * 2; + } else { + v = (value * -2) - 1; + } + + return varint_uint32_pack(v, output); +} + +size_t varint_int32_unpack(int32_t* value, const uint8_t* input, size_t input_size) { + uint32_t v; + size_t size = varint_uint32_unpack(&v, input, input_size); + + if(v & 1) { + *value = (int32_t)(v + 1) / (-2); + } else { + *value = v / 2; + } + + return size; +} + +size_t varint_int32_length(int32_t value) { + uint32_t v; + + if(value >= 0) { + v = value * 2; + } else { + v = (value * -2) - 1; + } + + return varint_uint32_length(v); +} \ No newline at end of file diff --git a/lib/toolbox/varint.h b/lib/toolbox/varint.h new file mode 100644 index 0000000000..bf4681d4dc --- /dev/null +++ b/lib/toolbox/varint.h @@ -0,0 +1,35 @@ +#pragma once +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Pack uint32 to varint + * @param value value from UINT32_MIN to UINT32_MAX + * @param output output array, need to be at least 5 bytes long + * @return size_t + */ +size_t varint_uint32_pack(uint32_t value, uint8_t* output); + +size_t varint_uint32_unpack(uint32_t* value, const uint8_t* input, size_t input_size); + +size_t varint_uint32_length(uint32_t value); + +/** + * Pack int32 to varint + * @param value value from (INT32_MIN / 2 + 1) to INT32_MAX + * @param output output array, need to be at least 5 bytes long + * @return size_t + */ +size_t varint_int32_pack(int32_t value, uint8_t* output); + +size_t varint_int32_unpack(int32_t* value, const uint8_t* input, size_t input_size); + +size_t varint_int32_length(int32_t value); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index d9d3cbe89b..b06c582aeb 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -5,7 +5,7 @@ # public variables DEFAULT_SCRIPT_PATH="$(pwd -P)"; SCRIPT_PATH="${SCRIPT_PATH:-$DEFAULT_SCRIPT_PATH}"; -FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"9"}"; +FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"8"}"; FBT_TOOLCHAIN_PATH="${FBT_TOOLCHAIN_PATH:-$SCRIPT_PATH}"; fbtenv_check_sourced() @@ -199,7 +199,7 @@ fbtenv_main() fbtenv_check_script_path || return 1; fbtenv_get_kernel_type || return 1; fbtenv_check_download_toolchain || return 1; - PS1="[FBT]$PS1"; + PS1="[FBT]${PS1-}"; PATH="$TOOLCHAIN_ARCH_DIR/python/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/protobuf/bin:$PATH"; From baffcc5cf424220d9f362dac16261a6ab3160990 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 23 Aug 2022 19:14:30 +0300 Subject: [PATCH 23/78] added multiconverter / removed hid analyzer hid analyzer won't needed anymore because of new lfrfid system adds support for multiple hid protocols --- ReadMe.md | 12 +- .../dec_hex_converter/dec_hex_converter.c | 404 ------------------ applications/hid_analyzer/application.fam | 9 - .../hid_analyzer/helpers/decoder_hid.cpp | 98 ----- .../hid_analyzer/helpers/decoder_hid.h | 24 -- .../hid_analyzer/helpers/hid_reader.cpp | 143 ------- .../hid_analyzer/helpers/hid_reader.h | 47 -- .../hid_analyzer/helpers/hid_worker.cpp | 38 -- .../hid_analyzer/helpers/hid_worker.h | 21 - applications/hid_analyzer/helpers/key_info.h | 16 - applications/hid_analyzer/helpers/osc_fsk.h | 30 -- .../helpers/protocols/protocol_generic.h | 60 --- .../helpers/protocols/protocol_hid.cpp | 155 ------- .../helpers/protocols/protocol_hid.h | 25 -- .../hid_analyzer/helpers/pulse_joiner.h | 36 -- applications/hid_analyzer/helpers/rfid_key.h | 27 -- .../helpers/rfid_timer_emulator.h | 29 -- .../hid_analyzer/helpers/rfid_writer.h | 20 - .../hid_analyzer/helpers/state_sequencer.h | 25 -- .../hid_analyzer/hid_analyzer_app.cpp | 23 - applications/hid_analyzer/hid_analyzer_app.h | 65 --- .../hid_analyzer_app_launcher.cpp | 10 - .../scene/hid_analyzer_app_scene_read.cpp | 40 -- .../scene/hid_analyzer_app_scene_read.h | 9 - .../hid_analyzer_app_scene_read_success.cpp | 78 ---- .../hid_analyzer_app_scene_read_success.h | 14 - applications/hid_analyzer/view/container_vm.h | 17 - .../view/elements/button_element.h | 28 -- .../view/elements/generic_element.h | 21 - .../hid_analyzer/view/elements/icon_element.h | 17 - .../view/elements/string_element.h | 28 -- applications/meta/application.fam | 3 +- .../application.fam | 6 +- .../multi_converter/multi_converter.c | 162 +++++++ .../multi_converter_definitions.h | 82 ++++ .../multi_converter_mode_display.c | 284 ++++++++++++ .../multi_converter_mode_display.h | 55 +++ .../multi_converter_mode_select.c | 160 +++++++ .../multi_converter_mode_select.h | 58 +++ .../multi_converter/multi_converter_units.c | 230 ++++++++++ .../multi_converter/multi_converter_units.h | 71 +++ documentation/MultiConverter.md | 61 +++ 42 files changed, 1175 insertions(+), 1566 deletions(-) delete mode 100644 applications/dec_hex_converter/dec_hex_converter.c delete mode 100644 applications/hid_analyzer/application.fam delete mode 100644 applications/hid_analyzer/helpers/decoder_hid.cpp delete mode 100644 applications/hid_analyzer/helpers/decoder_hid.h delete mode 100644 applications/hid_analyzer/helpers/hid_reader.cpp delete mode 100644 applications/hid_analyzer/helpers/hid_reader.h delete mode 100644 applications/hid_analyzer/helpers/hid_worker.cpp delete mode 100644 applications/hid_analyzer/helpers/hid_worker.h delete mode 100644 applications/hid_analyzer/helpers/key_info.h delete mode 100644 applications/hid_analyzer/helpers/osc_fsk.h delete mode 100644 applications/hid_analyzer/helpers/protocols/protocol_generic.h delete mode 100644 applications/hid_analyzer/helpers/protocols/protocol_hid.cpp delete mode 100644 applications/hid_analyzer/helpers/protocols/protocol_hid.h delete mode 100644 applications/hid_analyzer/helpers/pulse_joiner.h delete mode 100644 applications/hid_analyzer/helpers/rfid_key.h delete mode 100644 applications/hid_analyzer/helpers/rfid_timer_emulator.h delete mode 100644 applications/hid_analyzer/helpers/rfid_writer.h delete mode 100644 applications/hid_analyzer/helpers/state_sequencer.h delete mode 100644 applications/hid_analyzer/hid_analyzer_app.cpp delete mode 100644 applications/hid_analyzer/hid_analyzer_app.h delete mode 100644 applications/hid_analyzer/hid_analyzer_app_launcher.cpp delete mode 100644 applications/hid_analyzer/scene/hid_analyzer_app_scene_read.cpp delete mode 100644 applications/hid_analyzer/scene/hid_analyzer_app_scene_read.h delete mode 100644 applications/hid_analyzer/scene/hid_analyzer_app_scene_read_success.cpp delete mode 100644 applications/hid_analyzer/scene/hid_analyzer_app_scene_read_success.h delete mode 100644 applications/hid_analyzer/view/container_vm.h delete mode 100644 applications/hid_analyzer/view/elements/button_element.h delete mode 100644 applications/hid_analyzer/view/elements/generic_element.h delete mode 100644 applications/hid_analyzer/view/elements/icon_element.h delete mode 100644 applications/hid_analyzer/view/elements/string_element.h rename applications/{dec_hex_converter => multi_converter}/application.fam (58%) create mode 100644 applications/multi_converter/multi_converter.c create mode 100644 applications/multi_converter/multi_converter_definitions.h create mode 100644 applications/multi_converter/multi_converter_mode_display.c create mode 100644 applications/multi_converter/multi_converter_mode_display.h create mode 100644 applications/multi_converter/multi_converter_mode_select.c create mode 100644 applications/multi_converter/multi_converter_mode_select.h create mode 100644 applications/multi_converter/multi_converter_units.c create mode 100644 applications/multi_converter/multi_converter_units.h create mode 100644 documentation/MultiConverter.md diff --git a/ReadMe.md b/ReadMe.md index 927369e07c..01f1542960 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1,6 +1,8 @@ -# Flipper Zero Unleashed Firmware - -fzCUSTOM +

+ +fzCUSTOM + +

Welcome to Flipper Zero's Custom Firmware repo! Our goal is to make any features possible in this device without any limitations! @@ -57,7 +59,7 @@ See changelog in releases for latest updates! - ESP8266 Deauther plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-Wifi-ESP8266-Deauther-Module) - WiFi Scanner plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module) -- Dec/Hex Converter plugin [(by theisolinearchip)](https://github.com/theisolinearchip/flipperzero_stuff/tree/main/applications/dec_hex_converter) +- MultiConverter plugin [(by theisolinearchip)](https://github.com/theisolinearchip/flipperzero_stuff) - WAV player plugin (fixed) [(OFW: DrZlo13)](https://github.com/flipperdevices/flipperzero-firmware/tree/zlo/wav-player) - UPC-A Barcode generator plugin [(by McAzzaMan)](https://github.com/McAzzaMan/flipperzero-firmware/tree/UPC-A_Barcode_Generator/applications/barcode_generator) - GPIO: Sentry Safe plugin [(by H4ckd4ddy)](https://github.com/H4ckd4ddy/flipperzero-sentry-safe-plugin) @@ -91,6 +93,8 @@ See changelog in releases for latest updates! ## [- Barcode Generator](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/BarcodeGenerator.md) +## [- Multi Converter](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/MultiConverter.md) + ## [- WAV Player sample files & how to convert](https://github.com/UberGuidoZ/Flipper/tree/main/Wav_Player#readme) ### **Plugins that works with external hardware** diff --git a/applications/dec_hex_converter/dec_hex_converter.c b/applications/dec_hex_converter/dec_hex_converter.c deleted file mode 100644 index 98a090a820..0000000000 --- a/applications/dec_hex_converter/dec_hex_converter.c +++ /dev/null @@ -1,404 +0,0 @@ -#include -#include -#include -#include - -#define DEC_HEX_CONVERTER_NUMBER_DIGITS 9 -#define DEC_HEX_CONVERTER_KEYS 18 -#define DEC_HEX_CONVERTER_KEY_DEL 16 -// #define DEC_HEX_CONVERTER_KEY_SWAP 17 // actually not used... - -#define DEC_HEX_CONVERTER_CHAR_DEL '<' -#define DEC_HEX_CONVERTER_CHAR_SWAP 's' -#define DEC_HEX_CONVERTER_CHAR_MODE '#' -#define DEC_HEX_CONVERTER_CHAR_OVERFLOW '#' - -#define DEC_HEX_CONVERTER_KEY_FRAME_MARGIN 3 -#define DEC_HEX_CONVERTER_KEY_CHAR_HEIGHT 8 - -#define DEC_HEX_MAX_SUPORTED_DEC_INT 999999999 - -typedef enum { - EventTypeKey, -} EventType; - -typedef struct { - InputEvent input; - EventType type; -} DecHexConverterEvent; - -typedef enum { - ModeDec, - ModeHex, -} Mode; - -// setting up one char array next to the other one causes the canvas_draw_str to display both of them -// when addressing the first one if there's no string terminator or similar indicator. Adding a \0 seems -// to work fine to prevent that, so add a final last char outside the size constants (added on init -// and NEVER changed nor referenced again) -// -// (as a reference, canvas_draw_str ends up calling u8g2_DrawStr from u8g2_font.c, -// that finally ends up calling u8g2_draw_string) -typedef struct { - char dec_number[DEC_HEX_CONVERTER_NUMBER_DIGITS + 1]; - char hex_number[DEC_HEX_CONVERTER_NUMBER_DIGITS + 1]; - Mode mode; // dec / hex - int8_t cursor; // position on keyboard (includes digit letters and other options) - int8_t digit_pos; // current digit on selected mode -} DecHexConverterState; - -// move cursor left / right (TODO: implement menu nav in a more "standard" and reusable way?) -void dec_hex_converter_logic_move_cursor_lr( - DecHexConverterState* const dec_hex_converter_state, - int8_t d) { - dec_hex_converter_state->cursor += d; - - if(dec_hex_converter_state->cursor > DEC_HEX_CONVERTER_KEYS - 1) - dec_hex_converter_state->cursor = 0; - else if(dec_hex_converter_state->cursor < 0) - dec_hex_converter_state->cursor = DEC_HEX_CONVERTER_KEYS - 1; - - // if we're moving left / right to the letters keys on ModeDec just go to the closest available key - if(dec_hex_converter_state->mode == ModeDec) { - if(dec_hex_converter_state->cursor == 10) - dec_hex_converter_state->cursor = 16; - else if(dec_hex_converter_state->cursor == 15) - dec_hex_converter_state->cursor = 9; - } -} - -// move cursor up / down; there're two lines, so we basically toggle -void dec_hex_converter_logic_move_cursor_ud(DecHexConverterState* const dec_hex_converter_state) { - if(dec_hex_converter_state->cursor < 9) { - // move to second line ("down") - dec_hex_converter_state->cursor += 9; - - // if we're reaching the letter keys while ModeDec, just move left / right for the first available key - if(dec_hex_converter_state->mode == ModeDec && - (dec_hex_converter_state->cursor >= 10 && dec_hex_converter_state->cursor <= 15)) { - if(dec_hex_converter_state->cursor <= 12) - dec_hex_converter_state->cursor = 9; - else - dec_hex_converter_state->cursor = 16; - } - } else { - // move to first line ("up") - dec_hex_converter_state->cursor -= 9; - } -} - -// fetch number from current mode and modifies the destination one, RM dnt stel pls -// (if destination is shorter than the output value, overried with "-" chars or something similar) -void dec_hex_converter_logic_convert_number(DecHexConverterState* const dec_hex_converter_state) { - char* s_ptr; - char* d_ptr; - - char dest[DEC_HEX_CONVERTER_NUMBER_DIGITS]; - int i = 0; // current index on destination array - - if(dec_hex_converter_state->mode == ModeDec) { - // DEC to HEX cannot overflow if they're, at least, the same size - - s_ptr = dec_hex_converter_state->dec_number; - d_ptr = dec_hex_converter_state->hex_number; - - int a = atoi(s_ptr); - int r; - while(a != 0) { - r = a % 16; - dest[i] = r + (r < 10 ? '0' : ('A' - 10)); - a /= 16; - i++; - } - - } else { - s_ptr = dec_hex_converter_state->hex_number; - d_ptr = dec_hex_converter_state->dec_number; - - int a = strtol(s_ptr, NULL, 16); - if(a > DEC_HEX_MAX_SUPORTED_DEC_INT) { - // draw all "###" if there's an overflow - for(int j = 0; j < DEC_HEX_CONVERTER_NUMBER_DIGITS; j++) { - d_ptr[j] = DEC_HEX_CONVERTER_CHAR_OVERFLOW; - } - return; - } else { - while(a > 0) { - dest[i++] = (a % 10) + '0'; - a /= 10; - } - } - } - - // dest is reversed, copy to destination pointer and append empty chars at the end - for(int j = 0; j < DEC_HEX_CONVERTER_NUMBER_DIGITS; j++) { - if(i >= 1) - d_ptr[j] = dest[--i]; - else - d_ptr[j] = ' '; - } -} - -// change from DEC to HEX or HEX to DEC, set the digit_pos to the last position not empty on the destination mode -void dec_hex_converter_logic_swap_mode(DecHexConverterState* const dec_hex_converter_state) { - char* n_ptr; - if(dec_hex_converter_state->mode == ModeDec) { - dec_hex_converter_state->mode = ModeHex; - n_ptr = dec_hex_converter_state->hex_number; - } else { - dec_hex_converter_state->mode = ModeDec; - n_ptr = dec_hex_converter_state->dec_number; - } - - dec_hex_converter_state->digit_pos = DEC_HEX_CONVERTER_NUMBER_DIGITS; - for(int i = 0; i < DEC_HEX_CONVERTER_NUMBER_DIGITS; i++) { - if(n_ptr[i] == ' ') { - dec_hex_converter_state->digit_pos = i; - break; - } - } -} - -// removes the number on current digit on current mode -static void - dec_hex_converter_logic_del_number(DecHexConverterState* const dec_hex_converter_state) { - if(dec_hex_converter_state->digit_pos > 0) dec_hex_converter_state->digit_pos--; - - if(dec_hex_converter_state->mode == ModeDec) { - dec_hex_converter_state->dec_number[dec_hex_converter_state->digit_pos] = ' '; - } else { - dec_hex_converter_state->hex_number[dec_hex_converter_state->digit_pos] = ' '; - } -} - -// append a number to the digit on the current mode -static void dec_hex_converter_logic_add_number( - DecHexConverterState* const dec_hex_converter_state, - int8_t number) { - // ignore HEX values on DEC mode (probably button nav will be disabled too, so cannot reach); - // also do not add anything if we're out of bound - if((number > 9 && dec_hex_converter_state->mode == ModeDec) || - dec_hex_converter_state->digit_pos >= DEC_HEX_CONVERTER_NUMBER_DIGITS) - return; - - char* s_ptr; - - if(dec_hex_converter_state->mode == ModeDec) { - s_ptr = dec_hex_converter_state->dec_number; - } else { - s_ptr = dec_hex_converter_state->hex_number; - } - - if(number < 10) { - s_ptr[dec_hex_converter_state->digit_pos] = number + '0'; - } else { - s_ptr[dec_hex_converter_state->digit_pos] = (number - 10) + 'A'; // A-F (HEX only) - } - - dec_hex_converter_state->digit_pos++; -} - -// --------------- - -static void dec_hex_converter_render_callback(Canvas* const canvas, void* ctx) { - const DecHexConverterState* dec_hex_converter_state = acquire_mutex((ValueMutex*)ctx, 25); - if(dec_hex_converter_state == NULL) { - return; - } - - canvas_set_color(canvas, ColorBlack); - - // DEC - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 2, 10, "DEC: "); - - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 2 + 30, 10, dec_hex_converter_state->dec_number); - - // HEX - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 2, 10 + 12, "HEX: "); - - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 2 + 30, 10 + 12, dec_hex_converter_state->hex_number); - - // current mode indicator - // char buffer[4]; - // snprintf(buffer, sizeof(buffer), "%u", dec_hex_converter_state->digit_pos); // debug: show digit position instead of selected mode - if(dec_hex_converter_state->mode == ModeDec) { - canvas_draw_glyph(canvas, 128 - 10, 10, DEC_HEX_CONVERTER_CHAR_MODE); - } else { - canvas_draw_glyph(canvas, 128 - 10, 10 + 12, DEC_HEX_CONVERTER_CHAR_MODE); - } - - // draw the line - canvas_draw_line(canvas, 2, 25, 128 - 3, 25); - - // draw the keyboard - uint8_t _x = 5; - uint8_t _y = 25 + 15; // line + 10 - - for(int i = 0; i < DEC_HEX_CONVERTER_KEYS; i++) { - char g; - if(i < 10) - g = (i + '0'); - else if(i < 16) - g = ((i - 10) + 'A'); - else if(i == 16) - g = DEC_HEX_CONVERTER_CHAR_DEL; // '<' - else - g = DEC_HEX_CONVERTER_CHAR_SWAP; // 's' - - uint8_t g_w = canvas_glyph_width(canvas, g); - - // disable letters on DEC mode (but keep the previous width for visual purposes - show "blank keys") - if(dec_hex_converter_state->mode == ModeDec && i > 9 && i < 16) g = ' '; - - if(dec_hex_converter_state->cursor == i) { - canvas_draw_box( - canvas, - _x - DEC_HEX_CONVERTER_KEY_FRAME_MARGIN, - _y - (DEC_HEX_CONVERTER_KEY_CHAR_HEIGHT + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN), - DEC_HEX_CONVERTER_KEY_FRAME_MARGIN + g_w + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN, - DEC_HEX_CONVERTER_KEY_CHAR_HEIGHT + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN * 2); - canvas_set_color(canvas, ColorWhite); - canvas_draw_glyph(canvas, _x, _y, g); - canvas_set_color(canvas, ColorBlack); - } else { - canvas_draw_frame( - canvas, - _x - DEC_HEX_CONVERTER_KEY_FRAME_MARGIN, - _y - (DEC_HEX_CONVERTER_KEY_CHAR_HEIGHT + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN), - DEC_HEX_CONVERTER_KEY_FRAME_MARGIN + g_w + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN, - DEC_HEX_CONVERTER_KEY_CHAR_HEIGHT + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN * 2); - canvas_draw_glyph(canvas, _x, _y, g); - } - - if(i < 8) { - _x += g_w + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN * 2 + 2; - } else if(i == 8) { - _y += (DEC_HEX_CONVERTER_KEY_CHAR_HEIGHT + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN * 2) + 3; - _x = 7; // some padding at the beginning on second line - } else { - _x += g_w + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN * 2 + 1; - } - } - - release_mutex((ValueMutex*)ctx, dec_hex_converter_state); -} - -static void - dec_hex_converter_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - DecHexConverterEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void dec_hex_converter_init(DecHexConverterState* const dec_hex_converter_state) { - dec_hex_converter_state->mode = ModeDec; - dec_hex_converter_state->digit_pos = 0; - - dec_hex_converter_state->dec_number[DEC_HEX_CONVERTER_NUMBER_DIGITS] = '\0'; // null terminator - dec_hex_converter_state->hex_number[DEC_HEX_CONVERTER_NUMBER_DIGITS] = '\0'; // null terminator - - for(int i = 0; i < DEC_HEX_CONVERTER_NUMBER_DIGITS; i++) { - dec_hex_converter_state->dec_number[i] = ' '; - dec_hex_converter_state->hex_number[i] = ' '; - } -} - -// main entry point -int32_t dec_hex_converter_app(void* p) { - UNUSED(p); - - // get event queue - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(DecHexConverterEvent)); - - // allocate state - DecHexConverterState* dec_hex_converter_state = malloc(sizeof(DecHexConverterState)); - - // set mutex for plugin state (different threads can access it) - ValueMutex state_mutex; - if(!init_mutex(&state_mutex, dec_hex_converter_state, sizeof(dec_hex_converter_state))) { - FURI_LOG_E("DecHexConverter", "cannot create mutex\r\n"); - furi_message_queue_free(event_queue); - free(dec_hex_converter_state); - return 255; - } - - // register callbacks for drawing and input processing - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, dec_hex_converter_render_callback, &state_mutex); - view_port_input_callback_set(view_port, dec_hex_converter_input_callback, event_queue); - - // open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - dec_hex_converter_init(dec_hex_converter_state); - - // main loop - DecHexConverterEvent event; - for(bool processing = true; processing;) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - DecHexConverterState* dec_hex_converter_state = - (DecHexConverterState*)acquire_mutex_block(&state_mutex); - - if(event_status == FuriStatusOk) { - // press events - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress) { - switch(event.input.key) { - default: - break; - case InputKeyUp: - case InputKeyDown: - dec_hex_converter_logic_move_cursor_ud(dec_hex_converter_state); - break; - case InputKeyRight: - dec_hex_converter_logic_move_cursor_lr(dec_hex_converter_state, 1); - break; - case InputKeyLeft: - dec_hex_converter_logic_move_cursor_lr(dec_hex_converter_state, -1); - break; - case InputKeyOk: - if(dec_hex_converter_state->cursor < DEC_HEX_CONVERTER_KEY_DEL) { - // positions from 0 to 15 works as regular numbers (DEC / HEX where applicable) - // (logic won't allow add numbers > 9 on ModeDec) - dec_hex_converter_logic_add_number( - dec_hex_converter_state, dec_hex_converter_state->cursor); - } else if(dec_hex_converter_state->cursor == DEC_HEX_CONVERTER_KEY_DEL) { - // del - dec_hex_converter_logic_del_number(dec_hex_converter_state); - } else { - // swap - dec_hex_converter_logic_swap_mode(dec_hex_converter_state); - } - - dec_hex_converter_logic_convert_number(dec_hex_converter_state); - break; - case InputKeyBack: - processing = false; - break; - } - } - } - } else { - // event timeout - } - - view_port_update(view_port); - release_mutex(&state_mutex, dec_hex_converter_state); - } - - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_message_queue_free(event_queue); - delete_mutex(&state_mutex); - free(dec_hex_converter_state); - - return 0; -} \ No newline at end of file diff --git a/applications/hid_analyzer/application.fam b/applications/hid_analyzer/application.fam deleted file mode 100644 index 5005190cce..0000000000 --- a/applications/hid_analyzer/application.fam +++ /dev/null @@ -1,9 +0,0 @@ -App( - appid="hid_analyzer", - name="HID Analyzer", - apptype=FlipperAppType.PLUGIN, - entry_point="hid_analyzer_app", - cdefines=["APP_HID_ANALYZER"], - stack_size=2 * 1024, - order=40, -) diff --git a/applications/hid_analyzer/helpers/decoder_hid.cpp b/applications/hid_analyzer/helpers/decoder_hid.cpp deleted file mode 100644 index 176bfe0b9c..0000000000 --- a/applications/hid_analyzer/helpers/decoder_hid.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "decoder_hid.h" -#include - -constexpr uint32_t clocks_in_us = 64; - -constexpr uint32_t jitter_time_us = 20; -constexpr uint32_t min_time_us = 64; -constexpr uint32_t max_time_us = 80; - -constexpr uint32_t min_time = (min_time_us - jitter_time_us) * clocks_in_us; -constexpr uint32_t mid_time = ((max_time_us - min_time_us) / 2 + min_time_us) * clocks_in_us; -constexpr uint32_t max_time = (max_time_us + jitter_time_us) * clocks_in_us; - -bool DecoderHID::read(uint8_t* data, uint8_t data_size) { - bool result = false; - furi_assert(data_size >= 3); - - if(ready) { - result = true; - hid.decode( - reinterpret_cast(&stored_data), sizeof(uint32_t) * 3, data, data_size); - ready = false; - } - - return result; -} - -void DecoderHID::process_front(bool polarity, uint32_t time) { - if(ready) return; - - if(polarity == true) { - last_pulse_time = time; - } else { - last_pulse_time += time; - - if(last_pulse_time > min_time && last_pulse_time < max_time) { - bool pulse; - - if(last_pulse_time < mid_time) { - // 6 pulses - pulse = false; - } else { - // 5 pulses - pulse = true; - } - - if(last_pulse == pulse) { - pulse_count++; - - if(pulse) { - if(pulse_count > 4) { - pulse_count = 0; - store_data(1); - } - } else { - if(pulse_count > 5) { - pulse_count = 0; - store_data(0); - } - } - } else { - if(last_pulse) { - if(pulse_count > 2) { - store_data(1); - } - } else { - if(pulse_count > 3) { - store_data(0); - } - } - - pulse_count = 0; - last_pulse = pulse; - } - } - } -} - -DecoderHID::DecoderHID() { - reset_state(); -} - -void DecoderHID::store_data(bool data) { - stored_data[0] = (stored_data[0] << 1) | ((stored_data[1] >> 31) & 1); - stored_data[1] = (stored_data[1] << 1) | ((stored_data[2] >> 31) & 1); - stored_data[2] = (stored_data[2] << 1) | data; - - if(hid.can_be_decoded(reinterpret_cast(&stored_data), sizeof(uint32_t) * 3)) { - ready = true; - } -} - -void DecoderHID::reset_state() { - last_pulse = false; - pulse_count = 0; - ready = false; - last_pulse_time = 0; -} diff --git a/applications/hid_analyzer/helpers/decoder_hid.h b/applications/hid_analyzer/helpers/decoder_hid.h deleted file mode 100644 index 5dcb6c2652..0000000000 --- a/applications/hid_analyzer/helpers/decoder_hid.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include -#include -#include "protocols/protocol_hid.h" - -class DecoderHID { -public: - bool read(uint8_t* data, uint8_t data_size); - void process_front(bool polarity, uint32_t time); - DecoderHID(); - -private: - uint32_t last_pulse_time = 0; - bool last_pulse; - uint8_t pulse_count; - - uint32_t stored_data[3] = {0, 0, 0}; - void store_data(bool data); - - std::atomic ready; - - void reset_state(); - ProtocolHID hid; -}; diff --git a/applications/hid_analyzer/helpers/hid_reader.cpp b/applications/hid_analyzer/helpers/hid_reader.cpp deleted file mode 100644 index 890d7c651b..0000000000 --- a/applications/hid_analyzer/helpers/hid_reader.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#include "hid_reader.h" -#include -#include -#include - -/** - * @brief private violation assistant for HIDReader - */ -struct HIDReaderAccessor { - static void decode(HIDReader& hid_reader, bool polarity) { - hid_reader.decode(polarity); - } -}; - -void HIDReader::decode(bool polarity) { - uint32_t current_dwt_value = DWT->CYCCNT; - uint32_t period = current_dwt_value - last_dwt_value; - last_dwt_value = current_dwt_value; - - decoder_hid.process_front(polarity, period); - - detect_ticks++; -} - -bool HIDReader::switch_timer_elapsed() { - const uint32_t seconds_to_switch = furi_kernel_get_tick_frequency() * 2.0f; - return (furi_get_tick() - switch_os_tick_last) > seconds_to_switch; -} - -void HIDReader::switch_timer_reset() { - switch_os_tick_last = furi_get_tick(); -} - -void HIDReader::switch_mode() { - switch(type) { - case Type::Normal: - type = Type::Indala; - furi_hal_rfid_change_read_config(62500.0f, 0.25f); - break; - case Type::Indala: - type = Type::Normal; - furi_hal_rfid_change_read_config(125000.0f, 0.5f); - break; - } - - switch_timer_reset(); -} - -static void comparator_trigger_callback(bool level, void* comp_ctx) { - HIDReader* _this = static_cast(comp_ctx); - - HIDReaderAccessor::decode(*_this, !level); -} - -HIDReader::HIDReader() { -} - -void HIDReader::start() { - type = Type::Normal; - - furi_hal_rfid_pins_read(); - furi_hal_rfid_tim_read(125000, 0.5); - furi_hal_rfid_tim_read_start(); - start_comparator(); - - switch_timer_reset(); - last_read_count = 0; -} - -void HIDReader::start_forced(HIDReader::Type _type) { - start(); - if(_type == Type::Indala) { - switch_mode(); - } -} - -void HIDReader::stop() { - furi_hal_rfid_pins_reset(); - furi_hal_rfid_tim_read_stop(); - furi_hal_rfid_tim_reset(); - stop_comparator(); -} - -bool HIDReader::read(LfrfidKeyType* _type, uint8_t* data, uint8_t data_size, bool switch_enable) { - bool result = false; - bool something_read = false; - - if(decoder_hid.read(data, data_size)) { - *_type = LfrfidKeyType::KeyH10301; // should be an OK temp - something_read = true; - } - - // validation - if(something_read) { - switch_timer_reset(); - - if(last_read_type == *_type && memcmp(last_read_data, data, data_size) == 0) { - last_read_count = last_read_count + 1; - - if(last_read_count > 2) { - result = true; - } - } else { - last_read_type = *_type; - memcpy(last_read_data, data, data_size); - last_read_count = 0; - } - } - - // mode switching - if(switch_enable && switch_timer_elapsed()) { - switch_mode(); - last_read_count = 0; - } - - return result; -} - -bool HIDReader::detect() { - bool detected = false; - if(detect_ticks > 10) { - detected = true; - } - detect_ticks = 0; - - return detected; -} - -bool HIDReader::any_read() { - return last_read_count > 0; -} - -void HIDReader::start_comparator(void) { - furi_hal_rfid_comp_set_callback(comparator_trigger_callback, this); - last_dwt_value = DWT->CYCCNT; - - furi_hal_rfid_comp_start(); -} - -void HIDReader::stop_comparator(void) { - furi_hal_rfid_comp_stop(); - furi_hal_rfid_comp_set_callback(NULL, NULL); -} diff --git a/applications/hid_analyzer/helpers/hid_reader.h b/applications/hid_analyzer/helpers/hid_reader.h deleted file mode 100644 index 99dbeb08db..0000000000 --- a/applications/hid_analyzer/helpers/hid_reader.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once -#include "decoder_hid.h" -#include "key_info.h" - -//#define RFID_GPIO_DEBUG 1 - -class HIDReader { -public: - enum class Type : uint8_t { - Normal, - Indala, - }; - - HIDReader(); - void start(); - void start_forced(HIDReader::Type type); - void stop(); - bool read(LfrfidKeyType* _type, uint8_t* data, uint8_t data_size, bool switch_enable = true); - - bool detect(); - bool any_read(); - -private: - friend struct HIDReaderAccessor; - - DecoderHID decoder_hid; - - uint32_t last_dwt_value; - - void start_comparator(void); - void stop_comparator(void); - - void decode(bool polarity); - - uint32_t detect_ticks; - - uint32_t switch_os_tick_last; - bool switch_timer_elapsed(); - void switch_timer_reset(); - void switch_mode(); - - LfrfidKeyType last_read_type; - uint8_t last_read_data[LFRFID_KEY_SIZE]; - uint8_t last_read_count; - - Type type = Type::Normal; -}; diff --git a/applications/hid_analyzer/helpers/hid_worker.cpp b/applications/hid_analyzer/helpers/hid_worker.cpp deleted file mode 100644 index 42230858c6..0000000000 --- a/applications/hid_analyzer/helpers/hid_worker.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "hid_worker.h" - -HIDWorker::HIDWorker() { -} - -HIDWorker::~HIDWorker() { -} - -void HIDWorker::start_read() { - reader.start(); -} - -bool HIDWorker::read() { - static const uint8_t data_size = LFRFID_KEY_SIZE; - uint8_t data[data_size] = {0}; - LfrfidKeyType type; - - bool result = reader.read(&type, data, data_size); - - if(result) { - key.set_type(type); - key.set_data(data, data_size); - }; - - return result; -} - -bool HIDWorker::detect() { - return reader.detect(); -} - -bool HIDWorker::any_read() { - return reader.any_read(); -} - -void HIDWorker::stop_read() { - reader.stop(); -} diff --git a/applications/hid_analyzer/helpers/hid_worker.h b/applications/hid_analyzer/helpers/hid_worker.h deleted file mode 100644 index e6674bd1b9..0000000000 --- a/applications/hid_analyzer/helpers/hid_worker.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include "key_info.h" -#include "rfid_key.h" -#include "hid_reader.h" - -class HIDWorker { -public: - HIDWorker(); - ~HIDWorker(); - - void start_read(); - bool read(); - bool detect(); - bool any_read(); - void stop_read(); - - RfidKey key; - -private: - HIDReader reader; -}; diff --git a/applications/hid_analyzer/helpers/key_info.h b/applications/hid_analyzer/helpers/key_info.h deleted file mode 100644 index e465011d01..0000000000 --- a/applications/hid_analyzer/helpers/key_info.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include - -static const uint8_t LFRFID_KEY_SIZE = 8; -static const uint8_t LFRFID_KEY_NAME_SIZE = 22; - -enum class LfrfidKeyType : uint8_t { - KeyEM4100, - KeyH10301, - KeyI40134, -}; - -const char* lfrfid_key_get_type_string(LfrfidKeyType type); -const char* lfrfid_key_get_manufacturer_string(LfrfidKeyType type); -bool lfrfid_key_get_string_type(const char* string, LfrfidKeyType* type); -uint8_t lfrfid_key_get_type_data_count(LfrfidKeyType type); diff --git a/applications/hid_analyzer/helpers/osc_fsk.h b/applications/hid_analyzer/helpers/osc_fsk.h deleted file mode 100644 index eaaaa10ad0..0000000000 --- a/applications/hid_analyzer/helpers/osc_fsk.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once -#include - -/** - * This code tries to fit the periods into a given number of cycles (phases) by taking cycles from the next cycle of periods. - */ -class OscFSK { -public: - /** - * Get next period - * @param bit bit value - * @param period return period - * @return bool whether to advance to the next bit - */ - bool next(bool bit, uint16_t* period); - - /** - * FSK ocillator constructor - * - * @param freq_low bit 0 freq - * @param freq_hi bit 1 freq - * @param osc_phase_max max oscillator phase - */ - OscFSK(uint16_t freq_low, uint16_t freq_hi, uint16_t osc_phase_max); - -private: - const uint16_t freq[2]; - const uint16_t osc_phase_max; - int32_t osc_phase_current; -}; diff --git a/applications/hid_analyzer/helpers/protocols/protocol_generic.h b/applications/hid_analyzer/helpers/protocols/protocol_generic.h deleted file mode 100644 index d593f70899..0000000000 --- a/applications/hid_analyzer/helpers/protocols/protocol_generic.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once -#include "stdint.h" -#include "stdbool.h" - -class ProtocolGeneric { -public: - /** - * @brief Get the encoded data size - * - * @return uint8_t size of encoded data in bytes - */ - virtual uint8_t get_encoded_data_size() = 0; - - /** - * @brief Get the decoded data size - * - * @return uint8_t size of decoded data in bytes - */ - virtual uint8_t get_decoded_data_size() = 0; - - /** - * @brief encode decoded data - * - * @param decoded_data - * @param decoded_data_size - * @param encoded_data - * @param encoded_data_size - */ - virtual void encode( - const uint8_t* decoded_data, - const uint8_t decoded_data_size, - uint8_t* encoded_data, - const uint8_t encoded_data_size) = 0; - - /** - * @brief decode encoded data - * - * @param encoded_data - * @param encoded_data_size - * @param decoded_data - * @param decoded_data_size - */ - virtual void decode( - const uint8_t* encoded_data, - const uint8_t encoded_data_size, - uint8_t* decoded_data, - const uint8_t decoded_data_size) = 0; - - /** - * @brief fast check that data can be correctly decoded - * - * @param encoded_data - * @param encoded_data_size - * @return true - can be correctly decoded - * @return false - cannot be correctly decoded - */ - virtual bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) = 0; - - virtual ~ProtocolGeneric(){}; -}; diff --git a/applications/hid_analyzer/helpers/protocols/protocol_hid.cpp b/applications/hid_analyzer/helpers/protocols/protocol_hid.cpp deleted file mode 100644 index e60eafa298..0000000000 --- a/applications/hid_analyzer/helpers/protocols/protocol_hid.cpp +++ /dev/null @@ -1,155 +0,0 @@ -#include "protocol_hid.h" -#include - -typedef uint32_t HIDCardData; -constexpr uint8_t HIDCount = 3; -constexpr uint8_t HIDBitSize = sizeof(HIDCardData) * 8; - -uint8_t ProtocolHID::get_encoded_data_size() { - return sizeof(HIDCardData) * HIDCount; -} - -uint8_t ProtocolHID::get_decoded_data_size() { - return 3; -} - -void ProtocolHID::encode( - const uint8_t* decoded_data, - const uint8_t decoded_data_size, - uint8_t* encoded_data, - const uint8_t encoded_data_size) { - UNUSED(decoded_data); - UNUSED(decoded_data_size); - UNUSED(encoded_data); - UNUSED(encoded_data_size); - // bob! -} - -void ProtocolHID::decode( - const uint8_t* encoded_data, - const uint8_t encoded_data_size, - uint8_t* decoded_data, - const uint8_t decoded_data_size) { - furi_check(decoded_data_size >= get_decoded_data_size()); - furi_check(encoded_data_size >= get_encoded_data_size()); - - // header check - int16_t second1pos = find_second_1(encoded_data); - - if((*(encoded_data + 1) & 0b1100) != 0x08) { - *decoded_data = 37; - } else { - *decoded_data = (36 - (second1pos - 8)); - } -} - -int16_t ProtocolHID::find_second_1(const uint8_t* encoded_data) { - if((*(encoded_data + 1) & 0b11) == 0b10) { - return 8; - } else { - for(int8_t i = 3; i >= 0; i--) { - if(((*(encoded_data + 0) >> (2 * i)) & 0b11) == 0b10) { - return (12 - i); - } - } - for(int8_t i = 3; i >= 0; i--) { - if(((*(encoded_data + 7) >> (2 * i)) & 0b11) == 0b10) { - return (16 - i); - } - } - for(int8_t i = 3; i >= 2; i--) { - if(((*(encoded_data + 6) >> (2 * i)) & 0b11) == 0b10) { - return (20 - i); - } - } - } - - return -1; -} - -bool ProtocolHID::can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) { - furi_check(encoded_data_size >= get_encoded_data_size()); - - const HIDCardData* card_data = reinterpret_cast(encoded_data); - - // header check - int16_t second1pos = -1; - // packet pre-preamble - if(*(encoded_data + 3) != 0x1D) { - return false; - } - - // packet preamble - if(*(encoded_data + 2) != 0x55) { // first four 0s mandatory in preamble - return false; - } - - if((*(encoded_data + 1) & 0xF0) != 0x50) { // next two 0s mandatory in preamble - return false; - } - - if((*(encoded_data + 1) & 0b1100) != 0x08) { // if it's not a 1... - // either it's a 37-bit or invalid - // so just continue with the manchester encoding checks - } else { // it is a 1. so it could be anywhere between 26 and 36 bit encoding. or invalid. - // we need to find the location of the second 1 - second1pos = find_second_1(encoded_data); - } - - if(second1pos == -1) { - // we're 37 bit or invalid - } - - // data decoding. ensure all is properly manchester encoded - uint32_t result = 0; - - // decode from word 0 - // coded with 01 = 0, 10 = 1 transitions - for(int8_t i = 11; i >= 0; i--) { - switch((*(card_data + 0) >> (2 * i)) & 0b11) { - case 0b01: - result = (result << 1) | 0; - break; - case 0b10: - result = (result << 1) | 1; - break; - default: - return false; - break; - } - } - - // decode from word 1 - // coded with 01 = 0, 10 = 1 transitions - for(int8_t i = 15; i >= 0; i--) { - switch((*(card_data + 1) >> (2 * i)) & 0b11) { - case 0b01: - result = (result << 1) | 0; - break; - case 0b10: - result = (result << 1) | 1; - break; - default: - return false; - break; - } - } - - // decode from word 2 - // coded with 01 = 0, 10 = 1 transitions - for(int8_t i = 15; i >= 0; i--) { - switch((*(card_data + 2) >> (2 * i)) & 0b11) { - case 0b01: - result = (result << 1) | 0; - break; - case 0b10: - result = (result << 1) | 1; - break; - default: - return false; - break; - } - } - - return true; -} diff --git a/applications/hid_analyzer/helpers/protocols/protocol_hid.h b/applications/hid_analyzer/helpers/protocols/protocol_hid.h deleted file mode 100644 index 0e2636d5b2..0000000000 --- a/applications/hid_analyzer/helpers/protocols/protocol_hid.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include "protocol_generic.h" - -class ProtocolHID : public ProtocolGeneric { -public: - uint8_t get_encoded_data_size() final; - uint8_t get_decoded_data_size() final; - - void encode( - const uint8_t* decoded_data, - const uint8_t decoded_data_size, - uint8_t* encoded_data, - const uint8_t encoded_data_size) final; - - void decode( - const uint8_t* encoded_data, - const uint8_t encoded_data_size, - uint8_t* decoded_data, - const uint8_t decoded_data_size) final; - - bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) final; - -private: - int16_t find_second_1(const uint8_t* encoded_data); -}; diff --git a/applications/hid_analyzer/helpers/pulse_joiner.h b/applications/hid_analyzer/helpers/pulse_joiner.h deleted file mode 100644 index 1639d83716..0000000000 --- a/applications/hid_analyzer/helpers/pulse_joiner.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include "stdint.h" - -class PulseJoiner { -public: - /** - * @brief Push timer pulse. First negative pulse is ommited. - * - * @param polarity pulse polarity: true = high2low, false = low2high - * @param period overall period time in timer clicks - * @param pulse pulse time in timer clicks - * - * @return true - next pulse can and must be popped immediatly - */ - bool push_pulse(bool polarity, uint16_t period, uint16_t pulse); - - /** - * @brief Get the next timer pulse. Call only if push_pulse returns true. - * - * @param period overall period time in timer clicks - * @param pulse pulse time in timer clicks - */ - void pop_pulse(uint16_t* period, uint16_t* pulse); - - PulseJoiner(); - -private: - struct Pulse { - bool polarity; - uint16_t time; - }; - - uint8_t pulse_index = 0; - static const uint8_t pulse_max = 6; - Pulse pulses[pulse_max]; -}; diff --git a/applications/hid_analyzer/helpers/rfid_key.h b/applications/hid_analyzer/helpers/rfid_key.h deleted file mode 100644 index 29b87cf9c0..0000000000 --- a/applications/hid_analyzer/helpers/rfid_key.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include "key_info.h" -#include - -class RfidKey { -public: - RfidKey(); - ~RfidKey(); - - void set_type(LfrfidKeyType type); - void set_data(const uint8_t* data, const uint8_t data_size); - void set_name(const char* name); - - LfrfidKeyType get_type(); - const uint8_t* get_data(); - const char* get_type_text(); - uint8_t get_type_data_count() const; - char* get_name(); - uint8_t get_name_length(); - void clear(); - RfidKey& operator=(const RfidKey& rhs); - -private: - std::array data; - LfrfidKeyType type; - char name[LFRFID_KEY_NAME_SIZE + 1]; -}; diff --git a/applications/hid_analyzer/helpers/rfid_timer_emulator.h b/applications/hid_analyzer/helpers/rfid_timer_emulator.h deleted file mode 100644 index 874a4c3dde..0000000000 --- a/applications/hid_analyzer/helpers/rfid_timer_emulator.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once -#include -#include "key_info.h" -#include "encoder_generic.h" -#include "encoder_emmarin.h" -#include "encoder_hid_h10301.h" -#include "encoder_indala_40134.h" -#include "pulse_joiner.h" -#include - -class RfidTimerEmulator { -public: - RfidTimerEmulator(); - ~RfidTimerEmulator(); - void start(LfrfidKeyType type, const uint8_t* data, uint8_t data_size); - void stop(); - -private: - EncoderGeneric* current_encoder = nullptr; - - std::map encoders = { - {LfrfidKeyType::KeyEM4100, new EncoderEM()}, - {LfrfidKeyType::KeyH10301, new EncoderHID_H10301()}, - {LfrfidKeyType::KeyI40134, new EncoderIndala_40134()}, - }; - - PulseJoiner pulse_joiner; - static void timer_update_callback(void* ctx); -}; diff --git a/applications/hid_analyzer/helpers/rfid_writer.h b/applications/hid_analyzer/helpers/rfid_writer.h deleted file mode 100644 index 38329877b1..0000000000 --- a/applications/hid_analyzer/helpers/rfid_writer.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include "stdint.h" - -class RfidWriter { -public: - RfidWriter(); - ~RfidWriter(); - void start(); - void stop(); - void write_em(const uint8_t em_data[5]); - void write_hid(const uint8_t hid_data[3]); - void write_indala(const uint8_t indala_data[3]); - -private: - void write_gap(uint32_t gap_time); - void write_bit(bool value); - void write_byte(uint8_t value); - void write_block(uint8_t page, uint8_t block, bool lock_bit, uint32_t data); - void write_reset(); -}; diff --git a/applications/hid_analyzer/helpers/state_sequencer.h b/applications/hid_analyzer/helpers/state_sequencer.h deleted file mode 100644 index 12512ab517..0000000000 --- a/applications/hid_analyzer/helpers/state_sequencer.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include "stdint.h" -#include -#include - -class TickSequencer { -public: - TickSequencer(); - ~TickSequencer(); - - void tick(); - void reset(); - void clear(); - - void do_every_tick(uint32_t tick_count, std::function fn); - void do_after_tick(uint32_t tick_count, std::function fn); - -private: - std::list > > list; - std::list > >::iterator list_it; - - uint32_t tick_count; - - void do_nothing(); -}; diff --git a/applications/hid_analyzer/hid_analyzer_app.cpp b/applications/hid_analyzer/hid_analyzer_app.cpp deleted file mode 100644 index e8d7fd5411..0000000000 --- a/applications/hid_analyzer/hid_analyzer_app.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "hid_analyzer_app.h" -#include "scene/hid_analyzer_app_scene_read.h" -#include "scene/hid_analyzer_app_scene_read_success.h" - -HIDApp::HIDApp() - : scene_controller{this} - , notification{"notification"} - , storage{"storage"} - , dialogs{"dialogs"} - , text_store(40) { -} - -HIDApp::~HIDApp() { -} - -void HIDApp::run(void* _args) { - UNUSED(_args); - - view_controller.attach_to_gui(ViewDispatcherTypeFullscreen); - scene_controller.add_scene(SceneType::Read, new HIDAppSceneRead()); - scene_controller.add_scene(SceneType::ReadSuccess, new HIDAppSceneReadSuccess()); - scene_controller.process(100, SceneType::Read); -} \ No newline at end of file diff --git a/applications/hid_analyzer/hid_analyzer_app.h b/applications/hid_analyzer/hid_analyzer_app.h deleted file mode 100644 index 40374663a0..0000000000 --- a/applications/hid_analyzer/hid_analyzer_app.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include "view/container_vm.h" - -#include -#include -#include - -#include "helpers/hid_worker.h" - -class HIDApp { -public: - enum class EventType : uint8_t { - GENERIC_EVENT_ENUM_VALUES, - Next, - MenuSelected, - Stay, - Retry, - }; - - enum class SceneType : uint8_t { - GENERIC_SCENE_ENUM_VALUES, - Read, - ReadSuccess, - }; - - class Event { - public: - union { - int32_t menu_index; - } payload; - - EventType type; - }; - - HIDApp(); - ~HIDApp(); - - void run(void* args); - - // private: - SceneController, HIDApp> scene_controller; - ViewController - view_controller; - RecordController notification; - RecordController storage; - RecordController dialogs; - TextStore text_store; - - HIDWorker worker; -}; \ No newline at end of file diff --git a/applications/hid_analyzer/hid_analyzer_app_launcher.cpp b/applications/hid_analyzer/hid_analyzer_app_launcher.cpp deleted file mode 100644 index 93e210d6cc..0000000000 --- a/applications/hid_analyzer/hid_analyzer_app_launcher.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "hid_analyzer_app.h" - -// app enter function -extern "C" int32_t hid_analyzer_app(void* args) { - HIDApp* app = new HIDApp(); - app->run(args); - delete app; - - return 0; -} diff --git a/applications/hid_analyzer/scene/hid_analyzer_app_scene_read.cpp b/applications/hid_analyzer/scene/hid_analyzer_app_scene_read.cpp deleted file mode 100644 index 8e78016140..0000000000 --- a/applications/hid_analyzer/scene/hid_analyzer_app_scene_read.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "hid_analyzer_app_scene_read.h" -#include - -void HIDAppSceneRead::on_enter(HIDApp* app, bool /* need_restore */) { - auto popup = app->view_controller.get(); - - DOLPHIN_DEED(DolphinDeedRfidRead); - popup->set_header("Searching for\nLF HID RFID", 89, 34, AlignCenter, AlignTop); - popup->set_icon(0, 3, &I_RFIDDolphinReceive_97x61); - - app->view_controller.switch_to(); - app->worker.start_read(); -} - -bool HIDAppSceneRead::on_event(HIDApp* app, HIDApp::Event* event) { - bool consumed = false; - - if(event->type == HIDApp::EventType::Tick) { - if(app->worker.read()) { - DOLPHIN_DEED(DolphinDeedRfidReadSuccess); - notification_message(app->notification, &sequence_success); - app->scene_controller.switch_to_next_scene(HIDApp::SceneType::ReadSuccess); - } else { - if(app->worker.any_read()) { - notification_message(app->notification, &sequence_blink_green_10); - } else if(app->worker.detect()) { - notification_message(app->notification, &sequence_blink_cyan_10); - } else { - notification_message(app->notification, &sequence_blink_cyan_10); - } - } - } - - return consumed; -} - -void HIDAppSceneRead::on_exit(HIDApp* app) { - app->view_controller.get()->clean(); - app->worker.stop_read(); -} diff --git a/applications/hid_analyzer/scene/hid_analyzer_app_scene_read.h b/applications/hid_analyzer/scene/hid_analyzer_app_scene_read.h deleted file mode 100644 index c486f390e1..0000000000 --- a/applications/hid_analyzer/scene/hid_analyzer_app_scene_read.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "../hid_analyzer_app.h" - -class HIDAppSceneRead : public GenericScene { -public: - void on_enter(HIDApp* app, bool need_restore) final; - bool on_event(HIDApp* app, HIDApp::Event* event) final; - void on_exit(HIDApp* app) final; -}; diff --git a/applications/hid_analyzer/scene/hid_analyzer_app_scene_read_success.cpp b/applications/hid_analyzer/scene/hid_analyzer_app_scene_read_success.cpp deleted file mode 100644 index 30bb639394..0000000000 --- a/applications/hid_analyzer/scene/hid_analyzer_app_scene_read_success.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "hid_analyzer_app_scene_read_success.h" -#include "../view/elements/button_element.h" -#include "../view/elements/icon_element.h" -#include "../view/elements/string_element.h" - -void HIDAppSceneReadSuccess::on_enter(HIDApp* app, bool /* need_restore */) { - string_init(string[0]); - string_init(string[1]); - string_init(string[2]); - - auto container = app->view_controller.get(); - - auto button = container->add(); - button->set_type(ButtonElement::Type::Left, "Retry"); - button->set_callback(app, HIDAppSceneReadSuccess::back_callback); - - auto icon = container->add(); - icon->set_icon(3, 12, &I_RFIDBigChip_37x36); - - auto header = container->add(); - header->set_text("HID", 89, 3, 0, AlignCenter); - - // auto line_1_text = container->add(); - auto line_2_text = container->add(); - // auto line_3_text = container->add(); - - // auto line_1_value = container->add(); - auto line_2_value = container->add(); - // auto line_3_value = container->add(); - - const uint8_t* data = app->worker.key.get_data(); - - // line_1_text->set_text("Hi:", 65, 23, 0, AlignRight, AlignBottom, FontSecondary); - line_2_text->set_text("Bit:", 65, 35, 0, AlignRight, AlignBottom, FontSecondary); - // line_3_text->set_text("Bye:", 65, 47, 0, AlignRight, AlignBottom, FontSecondary); - - string_printf(string[1], "%u", data[0]); - - // line_1_value->set_text( - // string_get_cstr(string[0]), 68, 23, 0, AlignLeft, AlignBottom, FontSecondary); - line_2_value->set_text( - string_get_cstr(string[1]), 68, 35, 0, AlignLeft, AlignBottom, FontSecondary); - // line_3_value->set_text( - // string_get_cstr(string[2]), 68, 47, 0, AlignLeft, AlignBottom, FontSecondary); - - app->view_controller.switch_to(); - - notification_message_block(app->notification, &sequence_set_green_255); -} - -bool HIDAppSceneReadSuccess::on_event(HIDApp* app, HIDApp::Event* event) { - bool consumed = false; - - if(event->type == HIDApp::EventType::Retry) { - app->scene_controller.search_and_switch_to_previous_scene({HIDApp::SceneType::Read}); - consumed = true; - } else if(event->type == HIDApp::EventType::Back) { - app->scene_controller.search_and_switch_to_previous_scene({HIDApp::SceneType::Read}); - consumed = true; - } - - return consumed; -} - -void HIDAppSceneReadSuccess::on_exit(HIDApp* app) { - notification_message_block(app->notification, &sequence_reset_green); - app->view_controller.get()->clean(); - string_clear(string[0]); - string_clear(string[1]); - string_clear(string[2]); -} - -void HIDAppSceneReadSuccess::back_callback(void* context) { - HIDApp* app = static_cast(context); - HIDApp::Event event; - event.type = HIDApp::EventType::Retry; - app->view_controller.send_event(&event); -} diff --git a/applications/hid_analyzer/scene/hid_analyzer_app_scene_read_success.h b/applications/hid_analyzer/scene/hid_analyzer_app_scene_read_success.h deleted file mode 100644 index 2668a57bd4..0000000000 --- a/applications/hid_analyzer/scene/hid_analyzer_app_scene_read_success.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include "../hid_analyzer_app.h" - -class HIDAppSceneReadSuccess : public GenericScene { -public: - void on_enter(HIDApp* app, bool need_restore) final; - bool on_event(HIDApp* app, HIDApp::Event* event) final; - void on_exit(HIDApp* app) final; - -private: - static void back_callback(void* context); - - string_t string[3]; -}; diff --git a/applications/hid_analyzer/view/container_vm.h b/applications/hid_analyzer/view/container_vm.h deleted file mode 100644 index 011baa2e98..0000000000 --- a/applications/hid_analyzer/view/container_vm.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include - -class ContainerVM : public GenericViewModule { -public: - ContainerVM(); - ~ContainerVM() final; - View* get_view() final; - void clean() final; - - template T* add(); - -private: - View* view; - static void view_draw_callback(Canvas* canvas, void* model); - static bool view_input_callback(InputEvent* event, void* context); -}; diff --git a/applications/hid_analyzer/view/elements/button_element.h b/applications/hid_analyzer/view/elements/button_element.h deleted file mode 100644 index eb96442773..0000000000 --- a/applications/hid_analyzer/view/elements/button_element.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include "generic_element.h" - -typedef void (*ButtonElementCallback)(void* context); - -class ButtonElement : public GenericElement { -public: - ButtonElement(); - ~ButtonElement() final; - void draw(Canvas* canvas) final; - bool input(InputEvent* event) final; - - enum class Type : uint8_t { - Left, - Center, - Right, - }; - - void set_type(Type type, const char* text); - void set_callback(void* context, ButtonElementCallback callback); - -private: - Type type = Type::Left; - const char* text = nullptr; - - void* context = nullptr; - ButtonElementCallback callback = nullptr; -}; diff --git a/applications/hid_analyzer/view/elements/generic_element.h b/applications/hid_analyzer/view/elements/generic_element.h deleted file mode 100644 index f5a58b2d92..0000000000 --- a/applications/hid_analyzer/view/elements/generic_element.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include -#include - -class GenericElement { -public: - GenericElement(){}; - virtual ~GenericElement(){}; - virtual void draw(Canvas* canvas) = 0; - virtual bool input(InputEvent* event) = 0; - - // TODO that must be accessible only to ContainerVMData - void set_parent_view(View* view); - - // TODO that must be accessible only to inheritors - void lock_model(); - void unlock_model(bool need_redraw); - -private: - View* view = nullptr; -}; diff --git a/applications/hid_analyzer/view/elements/icon_element.h b/applications/hid_analyzer/view/elements/icon_element.h deleted file mode 100644 index a08202741e..0000000000 --- a/applications/hid_analyzer/view/elements/icon_element.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "generic_element.h" - -class IconElement : public GenericElement { -public: - IconElement(); - ~IconElement() final; - void draw(Canvas* canvas) final; - bool input(InputEvent* event) final; - - void set_icon(uint8_t x = 0, uint8_t y = 0, const Icon* icon = NULL); - -private: - const Icon* icon = NULL; - uint8_t x = 0; - uint8_t y = 0; -}; diff --git a/applications/hid_analyzer/view/elements/string_element.h b/applications/hid_analyzer/view/elements/string_element.h deleted file mode 100644 index 173fdd6019..0000000000 --- a/applications/hid_analyzer/view/elements/string_element.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include "generic_element.h" - -class StringElement : public GenericElement { -public: - StringElement(); - ~StringElement() final; - void draw(Canvas* canvas) final; - bool input(InputEvent* event) final; - - void set_text( - const char* text = NULL, - uint8_t x = 0, - uint8_t y = 0, - uint8_t fit_width = 0, - Align horizontal = AlignLeft, - Align vertical = AlignTop, - Font font = FontPrimary); - -private: - const char* text = NULL; - uint8_t x = 0; - uint8_t y = 0; - uint8_t fit_width = 0; - Align horizontal = AlignLeft; - Align vertical = AlignTop; - Font font = FontPrimary; -}; diff --git a/applications/meta/application.fam b/applications/meta/application.fam index fd8b641313..2859d144d9 100644 --- a/applications/meta/application.fam +++ b/applications/meta/application.fam @@ -68,7 +68,6 @@ App( apptype=FlipperAppType.METAPACKAGE, provides=[ "picopass", - "hid_analyzer", "barcode_generator", "mouse_jacker", "nrf_sniff", @@ -77,6 +76,6 @@ App( "esp8266_deauth", "wifi_scanner", "wav_player", - "dec_hex_converter", + "multi_converter", ], ) \ No newline at end of file diff --git a/applications/dec_hex_converter/application.fam b/applications/multi_converter/application.fam similarity index 58% rename from applications/dec_hex_converter/application.fam rename to applications/multi_converter/application.fam index 062c40b264..9325a3a351 100644 --- a/applications/dec_hex_converter/application.fam +++ b/applications/multi_converter/application.fam @@ -1,8 +1,8 @@ App( - appid="dec_hex_converter", - name="Dec/Hex Converter", + appid="multi_converter", + name="Multi Converter", apptype=FlipperAppType.PLUGIN, - entry_point="dec_hex_converter_app", + entry_point="multi_converter_app", cdefines=["APP_DEC_HEX_CONVERTER"], requires=["gui"], stack_size=1 * 1024, diff --git a/applications/multi_converter/multi_converter.c b/applications/multi_converter/multi_converter.c new file mode 100644 index 0000000000..69b3c71f69 --- /dev/null +++ b/applications/multi_converter/multi_converter.c @@ -0,0 +1,162 @@ +#include +#include +#include +#include + +#include "multi_converter_definitions.h" +#include "multi_converter_mode_display.h" +#include "multi_converter_mode_select.h" + +static void multi_converter_render_callback(Canvas* const canvas, void* ctx) { + + const MultiConverterState* multi_converter_state = acquire_mutex((ValueMutex*)ctx, 25); + if(multi_converter_state == NULL) { + return; + } + + if (multi_converter_state->mode == ModeDisplay) { + multi_converter_mode_display_draw(canvas, multi_converter_state); + } else { + multi_converter_mode_select_draw(canvas, multi_converter_state); + } + + release_mutex((ValueMutex*)ctx, multi_converter_state); +} + +static void multi_converter_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { + furi_assert(event_queue); + + MultiConverterEvent event = {.type = EventTypeKey, .input = *input_event}; + furi_message_queue_put(event_queue, &event, FuriWaitForever); +} + +static void multi_converter_init(MultiConverterState* const multi_converter_state) { + // initial default values + + multi_converter_state->buffer_orig[MULTI_CONVERTER_NUMBER_DIGITS] = '\0'; + multi_converter_state->buffer_dest[MULTI_CONVERTER_NUMBER_DIGITS] = '\0'; // null terminators + + multi_converter_state->unit_type_orig = UnitTypeDec; + multi_converter_state->unit_type_dest = UnitTypeHex; + + multi_converter_state->keyboard_lock = 0; + + // init the display view + multi_converter_mode_display_reset(multi_converter_state); + + // init the select view + multi_converter_mode_select_reset(multi_converter_state); + + // set ModeDisplay as the current mode + multi_converter_state->mode = ModeDisplay; +} + +// main entry point +int32_t multi_converter_app(void* p) { + UNUSED(p); + + // get event queue + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(MultiConverterEvent)); + + // allocate state + MultiConverterState* multi_converter_state = malloc(sizeof(MultiConverterState)); + + // set mutex for plugin state (different threads can access it) + ValueMutex state_mutex; + if(!init_mutex(&state_mutex, multi_converter_state, sizeof(multi_converter_state))) { + FURI_LOG_E("MultiConverter", "cannot create mutex\r\n"); + free(multi_converter_state); + return 255; + } + + // register callbacks for drawing and input processing + ViewPort* view_port = view_port_alloc(); + view_port_draw_callback_set(view_port, multi_converter_render_callback, &state_mutex); + view_port_input_callback_set(view_port, multi_converter_input_callback, event_queue); + + // open GUI and register view_port + Gui* gui = furi_record_open("gui"); + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + + multi_converter_init(multi_converter_state); + + // main loop + MultiConverterEvent event; + for (bool processing = true; processing;) { + FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); + MultiConverterState* multi_converter_state = (MultiConverterState*)acquire_mutex_block(&state_mutex); + + if (event_status == FuriStatusOk) { + // press events + if (event.type == EventTypeKey && !multi_converter_state->keyboard_lock) { + if (multi_converter_state->mode == ModeDisplay) { + + if (event.input.key == InputKeyBack) { + if (event.input.type == InputTypePress) processing = false; + } else if (event.input.key == InputKeyOk) { // the "ok" press can be short or long + MultiConverterModeTrigger t = None; + + if (event.input.type == InputTypeLong) t = multi_converter_mode_display_ok(1, multi_converter_state); + else if (event.input.type == InputTypeShort) t = multi_converter_mode_display_ok(0, multi_converter_state); + + if (t == Reset) { + multi_converter_mode_select_reset(multi_converter_state); + multi_converter_state->mode = ModeSelector; + } + } else { + if (event.input.type == InputTypePress) multi_converter_mode_display_navigation(event.input.key, multi_converter_state); + } + + } else { // ModeSelect + if (event.input.type == InputTypePress) { + switch (event.input.key) { + default: + break; + case InputKeyBack: + case InputKeyOk: { + MultiConverterModeTrigger t = multi_converter_mode_select_exit(event.input.key == InputKeyOk ? 1 : 0, multi_converter_state); + + if (t == Reset) { + multi_converter_mode_display_reset(multi_converter_state); + } else if (t == Convert) { + multi_converter_mode_display_convert(multi_converter_state); + } + + multi_converter_state->keyboard_lock = 1; + multi_converter_state->mode = ModeDisplay; + break; + } + case InputKeyLeft: + case InputKeyRight: + multi_converter_mode_select_switch(multi_converter_state); + break; + case InputKeyUp: + multi_converter_mode_select_change_unit(-1, multi_converter_state); + break; + case InputKeyDown: + multi_converter_mode_select_change_unit(1, multi_converter_state); + break; + } + } + } + } else if (multi_converter_state->keyboard_lock) { + multi_converter_state->keyboard_lock = 0; + } + } else { + // event timeout + } + + view_port_update(view_port); + release_mutex(&state_mutex, multi_converter_state); + } + + view_port_enabled_set(view_port, false); + gui_remove_view_port(gui, view_port); + furi_record_close("gui"); + view_port_free(view_port); + furi_message_queue_free(event_queue); + delete_mutex(&state_mutex); + free(multi_converter_state); + + return 0; +} \ No newline at end of file diff --git a/applications/multi_converter/multi_converter_definitions.h b/applications/multi_converter/multi_converter_definitions.h new file mode 100644 index 0000000000..fe904342d9 --- /dev/null +++ b/applications/multi_converter/multi_converter_definitions.h @@ -0,0 +1,82 @@ +#pragma once + +#define MULTI_CONVERTER_NUMBER_DIGITS 9 + +typedef enum { + EventTypeKey, +} EventType; + +typedef struct { + InputEvent input; + EventType type; +} MultiConverterEvent; + +typedef enum { + ModeDisplay, + ModeSelector, +} MultiConverterMode; + +typedef enum { + None, + Reset, + Convert, +} MultiConverterModeTrigger; + +// new units goes here, used as index to the main multi_converter_available_units array (multi_converter_units.h) +typedef enum { + UnitTypeDec, + UnitTypeHex, + UnitTypeBin, + + UnitTypeCelsius, + UnitTypeFahernheit, + UnitTypeKelvin, + + UnitTypeKilometers, + UnitTypeMeters, + UnitTypeCentimeters, + UnitTypeMiles, + UnitTypeFeet, + UnitTypeInches, + + UnitTypeDegree, + UnitTypeRadian, +} MultiConverterUnitType; + +typedef struct { + MultiConverterUnitType selected_unit_type_orig; + MultiConverterUnitType selected_unit_type_dest; + uint8_t select_orig; +} MultiConverterModeSelect; + +typedef struct { + uint8_t cursor; // cursor position when typing + int8_t key; // hover key + uint8_t comma; // comma already added? (only one comma allowed) + uint8_t negative; // is negative? +} MultiConverterModeDisplay; + +typedef struct MultiConverterUnit MultiConverterUnit; +typedef struct MultiConverterState MultiConverterState; + +struct MultiConverterUnit { + uint8_t allow_comma; + uint8_t allow_negative; + uint8_t max_number_keys; + char mini_name[4]; + char name[12]; + void (*convert_function)(MultiConverterState * const); + uint8_t (*allowed_function)(MultiConverterUnitType); +}; + +struct MultiConverterState { + char buffer_orig[MULTI_CONVERTER_NUMBER_DIGITS + 1]; + char buffer_dest[MULTI_CONVERTER_NUMBER_DIGITS + 1]; + MultiConverterUnitType unit_type_orig; + MultiConverterUnitType unit_type_dest; + MultiConverterMode mode; + MultiConverterModeDisplay display; + MultiConverterModeSelect select; + uint8_t keyboard_lock; // used to create a small lock when switching from SELECT to DISPLAY modes + // (debouncing, basically; otherwise it switch modes twice 'cause it's too fast!) +}; diff --git a/applications/multi_converter/multi_converter_mode_display.c b/applications/multi_converter/multi_converter_mode_display.c new file mode 100644 index 0000000000..2462cf60c8 --- /dev/null +++ b/applications/multi_converter/multi_converter_mode_display.c @@ -0,0 +1,284 @@ +#include "multi_converter_mode_display.h" + +#define MULTI_CONVERTER_DISPLAY_KEYS 18 // [0] to [F] + [BACK] + [SELECT] + +#define MULTI_CONVERTER_DISPLAY_KEY_NEGATIVE 0 // long press +#define MULTI_CONVERTER_DISPLAY_KEY_COMMA 1 // long press +#define MULTI_CONVERTER_DISPLAY_KEY_DEL 16 +#define MULTI_CONVERTER_DISPLAY_KEY_SELECT 17 + +#define MULTI_CONVERTER_DISPLAY_CHAR_COMMA '.' +#define MULTI_CONVERTER_DISPLAY_CHAR_NEGATIVE '-' +#define MULTI_CONVERTER_DISPLAY_CHAR_DEL '<' +#define MULTI_CONVERTER_DISPLAY_CHAR_SELECT '#' +#define MULTI_CONVERTER_DISPLAY_CHAR_BLANK ' ' + +#define MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN 3 +#define MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT 8 + + +void multi_converter_mode_display_convert(MultiConverterState* const multi_converter_state) { + + // 1.- if origin == destination (in theory user won't be allowed to choose the same options, but it's kinda "valid"...) + // just copy buffer_orig to buffer_dest and that's it + + if (multi_converter_state->unit_type_orig == multi_converter_state->unit_type_dest) { + memcpy(multi_converter_state->buffer_dest, multi_converter_state->buffer_orig, MULTI_CONVERTER_NUMBER_DIGITS); + return; + } + + // 2.- origin_buffer has not null functions + if (multi_converter_get_unit(multi_converter_state->unit_type_orig).convert_function == NULL || multi_converter_get_unit(multi_converter_state->unit_type_orig).allowed_function == NULL) return; + + // 3.- valid destination type (using allowed_destinations function) + if (!multi_converter_get_unit(multi_converter_state->unit_type_orig).allowed_function(multi_converter_state->unit_type_dest)) return; + + multi_converter_get_unit(multi_converter_state->unit_type_orig).convert_function(multi_converter_state); + +} + +void multi_converter_mode_display_draw(Canvas* const canvas, const MultiConverterState* multi_converter_state) { + + canvas_set_color(canvas, ColorBlack); + + // ORIGIN + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 2, 10, multi_converter_get_unit(multi_converter_state->unit_type_orig).mini_name); + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 2 + 30, 10, multi_converter_state->buffer_orig); + + // DESTINATION + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 2, 10 + 12, multi_converter_get_unit(multi_converter_state->unit_type_dest).mini_name); + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 2 + 30, 10 + 12, multi_converter_state->buffer_dest); + + // SEPARATOR_LINE + canvas_draw_line(canvas, 2, 25, 128 - 3, 25); + + // KEYBOARD + uint8_t _x = 5; + uint8_t _y = 25 + 15; // line + 10 + + for (int i = 0; i < MULTI_CONVERTER_DISPLAY_KEYS; i++) { + + char g; + if (i < 10) g = (i + '0'); + else if (i < 16) g = ((i - 10) + 'A'); + else if (i == MULTI_CONVERTER_DISPLAY_KEY_DEL) g = MULTI_CONVERTER_DISPLAY_CHAR_DEL; + else g = MULTI_CONVERTER_DISPLAY_CHAR_SELECT; + + uint8_t g_w = canvas_glyph_width(canvas, g); + + if (i < 16 && i > multi_converter_get_unit(multi_converter_state->unit_type_orig).max_number_keys-1) { + // some units won't use the full [0] - [F] keyboard, in those situations just hide the char + // (won't be selectable anyway, so no worries here; this is just about drawing stuff) + g = MULTI_CONVERTER_DISPLAY_CHAR_BLANK; + } + + // currently hover key is highlighted + if ((multi_converter_state->display).key == i) { + canvas_draw_box(canvas, + _x - MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN, + _y - (MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN), + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN + g_w + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN, + MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN * 2 + ); + canvas_set_color(canvas, ColorWhite); + } else { + canvas_draw_frame(canvas, + _x - MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN, + _y - (MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN), + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN + g_w + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN, + MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN * 2 + ); + } + + // draw key + canvas_draw_glyph(canvas, _x, _y, g); + + // certain keys have long_press features, draw whatever they're using there too + if (i == MULTI_CONVERTER_DISPLAY_KEY_NEGATIVE) { + canvas_draw_box(canvas, + _x + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN + g_w - 4, + _y + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN - 2, + 4, + 2 + ); + } else if (i == MULTI_CONVERTER_DISPLAY_KEY_COMMA) { + canvas_draw_box(canvas, + _x + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN + g_w - 2, + _y + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN - 2, + 2, + 2 + ); + } + + // back to black + canvas_set_color(canvas, ColorBlack); + + if (i < 8) { + _x += g_w + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN * 2 + 2; + } else if (i == 8) { + _y += (MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN * 2) + 3; + _x = 8; // some padding at the beginning on second line + } else { + _x += g_w + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN * 2 + 1; + } + } + +} + +void multi_converter_mode_display_navigation(InputKey key, MultiConverterState* const multi_converter_state) { + + // first move to keyboard position, then check if the ORIGIN allows that specific key, if not jump to the "closest one" + switch (key) { + + default: + break; + + case InputKeyUp: + case InputKeyDown: + if ((multi_converter_state->display).key >= 9) (multi_converter_state->display).key -= 9; + else (multi_converter_state->display).key += 9; + break; + + case InputKeyLeft: + case InputKeyRight: + + (multi_converter_state->display).key += (key == InputKeyLeft ? -1 : 1); + + if ((multi_converter_state->display).key > MULTI_CONVERTER_DISPLAY_KEYS-1) (multi_converter_state->display).key = 0; + else if ((multi_converter_state->display).key < 0) (multi_converter_state->display).key = MULTI_CONVERTER_DISPLAY_KEYS-1; + break; + } + + // if destination key is disabled by max_number_keys, move to the closest one + // (this could be improved with more accurate keys movements, probably...) + if (multi_converter_get_unit(multi_converter_state->unit_type_orig).max_number_keys >= 16) return; // weird, since this means "do not show any number on the keyboard, but just in case..." + + int8_t i = -1; + if (key == InputKeyRight || key == InputKeyDown) i = 1; + + while ((multi_converter_state->display).key < 16 && (multi_converter_state->display).key > multi_converter_get_unit(multi_converter_state->unit_type_orig).max_number_keys-1) { + (multi_converter_state->display).key += i; + if ((multi_converter_state->display).key > MULTI_CONVERTER_DISPLAY_KEYS-1) (multi_converter_state->display).key = 0; + else if ((multi_converter_state->display).key < 0) (multi_converter_state->display).key = MULTI_CONVERTER_DISPLAY_KEYS-1; + } + +} + +void multi_converter_mode_display_reset(MultiConverterState* const multi_converter_state) { + + // clean the buffers + for (int i = 0; i < MULTI_CONVERTER_NUMBER_DIGITS; i++) { + multi_converter_state->buffer_orig[i] = MULTI_CONVERTER_DISPLAY_CHAR_BLANK; + multi_converter_state->buffer_dest[i] = MULTI_CONVERTER_DISPLAY_CHAR_BLANK; + } + + // reset the display flags and index + multi_converter_state->display.cursor = 0; + multi_converter_state->display.key = 0; + multi_converter_state->display.comma = 0; + multi_converter_state->display.negative = 0; +} + +void multi_converter_mode_display_toggle_negative(MultiConverterState* const multi_converter_state) { + if (multi_converter_get_unit(multi_converter_state->unit_type_orig).allow_negative) { + + if (!(multi_converter_state->display).negative) { + // shift origin buffer one to right + add the "-" sign (last digit will be lost) + for (int i = MULTI_CONVERTER_NUMBER_DIGITS-1; i > 0; i--) { + // we could avoid the blanks, but nevermind + multi_converter_state->buffer_orig[i] = multi_converter_state->buffer_orig[i-1]; + } + multi_converter_state->buffer_orig[0] = MULTI_CONVERTER_DISPLAY_CHAR_NEGATIVE; + + // only increment cursor if we're not out of bound + if ((multi_converter_state->display).cursor < MULTI_CONVERTER_NUMBER_DIGITS) (multi_converter_state->display).cursor++; + } else { + // shift origin buffer one to left, append ' ' on the end + for (int i = 0; i < MULTI_CONVERTER_NUMBER_DIGITS-1; i++) { + if (multi_converter_state->buffer_orig[i] == MULTI_CONVERTER_DISPLAY_CHAR_BLANK) break; + + multi_converter_state->buffer_orig[i] = multi_converter_state->buffer_orig[i+1]; + } + multi_converter_state->buffer_orig[MULTI_CONVERTER_NUMBER_DIGITS-1] = MULTI_CONVERTER_DISPLAY_CHAR_BLANK; + + (multi_converter_state->display).cursor--; + } + + // toggle flag + (multi_converter_state->display).negative ^= 1; + } +} + +void multi_converter_mode_display_add_comma(MultiConverterState* const multi_converter_state) { + if ( + !multi_converter_get_unit(multi_converter_state->unit_type_orig).allow_comma || + (multi_converter_state->display).comma || + !(multi_converter_state->display).cursor || + ((multi_converter_state->display).cursor == (MULTI_CONVERTER_NUMBER_DIGITS - 1)) + ) return; // maybe not allowerd; or one comma already in place; also cannot add commas as first or last chars + + // set flag to one + (multi_converter_state->display).comma = 1; + + multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] = MULTI_CONVERTER_DISPLAY_CHAR_COMMA; + (multi_converter_state->display).cursor++; +} + +void multi_converter_mode_display_add_number(MultiConverterState* const multi_converter_state) { + if ((multi_converter_state->display).key > multi_converter_get_unit(multi_converter_state->unit_type_orig).max_number_keys-1) return; + + if ((multi_converter_state->display).key < 10) { + multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] = (multi_converter_state->display).key + '0'; + } else { + multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] = ((multi_converter_state->display).key - 10) + 'A'; + } + + (multi_converter_state->display).cursor++; +} + +MultiConverterModeTrigger multi_converter_mode_display_ok(uint8_t long_press, MultiConverterState* const multi_converter_state) { + + if ((multi_converter_state->display).key < MULTI_CONVERTER_DISPLAY_KEY_DEL) { + if ((multi_converter_state->display).cursor >= MULTI_CONVERTER_NUMBER_DIGITS) return None; // limit reached, ignore + + // long press on 0 toggle NEGATIVE if allowed, on 1 adds COMMA if allowed + if (long_press) { + + if ((multi_converter_state->display).key == MULTI_CONVERTER_DISPLAY_KEY_NEGATIVE) { + // toggle negative + multi_converter_mode_display_toggle_negative(multi_converter_state); + } else if ((multi_converter_state->display).key == MULTI_CONVERTER_DISPLAY_KEY_COMMA) { + // add comma + multi_converter_mode_display_add_comma(multi_converter_state); + } + + } else { + // regular keys + multi_converter_mode_display_add_number(multi_converter_state); + } + + multi_converter_mode_display_convert(multi_converter_state); + + } else if ((multi_converter_state->display).key == MULTI_CONVERTER_DISPLAY_KEY_DEL) { + if ((multi_converter_state->display).cursor > 0) (multi_converter_state->display).cursor--; + + if (multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] == MULTI_CONVERTER_DISPLAY_CHAR_COMMA) (multi_converter_state->display).comma = 0; + if (multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] == MULTI_CONVERTER_DISPLAY_CHAR_NEGATIVE) (multi_converter_state->display).negative = 0; + + multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] = MULTI_CONVERTER_DISPLAY_CHAR_BLANK; + + multi_converter_mode_display_convert(multi_converter_state); + + } else { // MULTI_CONVERTER_DISPLAY_KEY_SELECT + return Reset; + } + + return None; + +} \ No newline at end of file diff --git a/applications/multi_converter/multi_converter_mode_display.h b/applications/multi_converter/multi_converter_mode_display.h new file mode 100644 index 0000000000..7c23e230b7 --- /dev/null +++ b/applications/multi_converter/multi_converter_mode_display.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include + +#include "multi_converter_definitions.h" +#include "multi_converter_units.h" + +// +// performs a unit conversion from origin to source buffers, if there's any error, overflow or +// non-compatible format (which shouldn't happen, but just in case) abort conversion and outputs +// some "?" strings on the buffer or something similar +// +void multi_converter_mode_display_convert(MultiConverterState* const multi_converter_state); + +// +// draw the main DISPLAY view with the current multi_converter_state values +// +void multi_converter_mode_display_draw(Canvas* const canvas, const MultiConverterState* multi_converter_state); + +// +// keyboard navigation on DISPLAY mode (NAVIGATION only, no BACK nor OK - InputKey guaranteed to be left/right/up/down) +// +void multi_converter_mode_display_navigation(InputKey key, MultiConverterState* const multi_converter_state); + +// +// reset the DISPLAY mode with the current units, cleaning the buffers and different flags; +// call this when exiting the SELECT mode / changing the units +// +void multi_converter_mode_display_reset(MultiConverterState* const multi_converter_state); + +// +// toggle the negative flag on current selected buffer ONLY if the unit allows negative numbers +// (adding negative number may crop the last char on the buffer; it cannot be recovered) +// +void multi_converter_mode_display_toggle_negative(MultiConverterState* const multi_converter_state); + +// +// add a comma/dot/decimal separator/whatever on current selected buffer ONLY if the unit allows it +// (only ONE comma allowed, not in the beginning nor end) +// +void multi_converter_mode_display_add_comma(MultiConverterState* const multi_converter_state); + +// +// add a regular number to the buffer if it's <= the max_number_keys from the unit (not necessary +// since the draw and navigation functions won't allow a trigger for an invalid number, but still +// to keep the "checks" policy on each "add key" function...) +// +void multi_converter_mode_display_add_number(MultiConverterState* const multi_converter_state); + +// +// handle the OK action when selecting a specific key on the keyboard (add a number, a symbol, change mode...) +// returns a ModeTrigger enum value: may or may not let to a mode change on the main loop (WON'T change the mode here) +// +MultiConverterModeTrigger multi_converter_mode_display_ok(uint8_t long_press, MultiConverterState* const multi_converter_state); \ No newline at end of file diff --git a/applications/multi_converter/multi_converter_mode_select.c b/applications/multi_converter/multi_converter_mode_select.c new file mode 100644 index 0000000000..c30a361e51 --- /dev/null +++ b/applications/multi_converter/multi_converter_mode_select.c @@ -0,0 +1,160 @@ +#include "multi_converter_mode_select.h" + +#define MULTI_CONVERTER_LIST_ENTRIES_COUNT 3 + +#define MULTI_CONVERTER_INFO_STRING_FROM "FROM:" +#define MULTI_CONVERTER_INFO_STRING_TO "TO:" +#define MULTI_CONVERTER_INFO_STRING_OK "OK: Change" +#define MULTI_CONVERTER_INFO_STRING_BACK "BACK: Cancel" + +void multi_converter_mode_select_draw_destination_offset(uint8_t x, uint8_t y, int8_t d, Canvas* const canvas, const MultiConverterState* multi_converter_state) { + int i = 1; + while (i < MULTI_CONVERTER_AVAILABLE_UNITS) { // in case there's no match, to avoid an endless loop (in theory shouldn't happen, but...) + int ut = multi_converter_get_unit_type_offset((multi_converter_state->select).selected_unit_type_dest, i * d); + if ( + multi_converter_available_units[(multi_converter_state->select).selected_unit_type_orig].allowed_function(ut) && + (multi_converter_state->select).selected_unit_type_orig != ut + ) { + canvas_draw_str(canvas, x, y, multi_converter_available_units[ut].name); + break; + } + i++; + } +} + +void multi_converter_mode_select_draw_selected_unit(uint8_t x, uint8_t y, MultiConverterUnitType unit_type, Canvas* const canvas) { + canvas_draw_box(canvas, x - 2 , y - 10, canvas_string_width(canvas, multi_converter_available_units[unit_type].name) + 4, 13); + canvas_set_color(canvas, ColorWhite); + canvas_draw_str(canvas, x, y, multi_converter_available_units[unit_type].name); + canvas_set_color(canvas, ColorBlack); +} + +void multi_converter_mode_select_draw(Canvas* const canvas, const MultiConverterState* multi_converter_state) { + + int y = 10; + int x = 10; + + canvas_set_color(canvas, ColorBlack); + + // FROM + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, x, y, MULTI_CONVERTER_INFO_STRING_FROM); + + canvas_set_font(canvas, FontSecondary); + + // offset -1 + y += 12; + + canvas_draw_str(canvas, x, y, multi_converter_available_units[ multi_converter_get_unit_type_offset((multi_converter_state->select).selected_unit_type_orig, -1) ].name); + + // current selected element + y += 12; + + multi_converter_mode_select_draw_selected_unit(x, y, (multi_converter_state->select).selected_unit_type_orig, canvas); + + if ((multi_converter_state->select).select_orig) canvas_draw_str(canvas, x - 6, y, ">"); + + // offset +1 + y += 12; + + canvas_draw_str(canvas, x, y, multi_converter_available_units[ multi_converter_get_unit_type_offset((multi_converter_state->select).selected_unit_type_orig, 1) ].name); + + // TO + y = 10; + x = 70; + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, x, y, MULTI_CONVERTER_INFO_STRING_TO); + + canvas_set_font(canvas, FontSecondary); + + // offset -1: go back from current selected destination and find the first one valid (even if it's itself) + y += 12; + + multi_converter_mode_select_draw_destination_offset(x, y, -1, canvas, multi_converter_state); + + // current selected element + y += 12; + + multi_converter_mode_select_draw_selected_unit(x, y, (multi_converter_state->select).selected_unit_type_dest, canvas); + + if (!(multi_converter_state->select).select_orig) canvas_draw_str(canvas, x - 6, y, ">"); + + // offset +1: same but on the opposite direction + y += 12; + + multi_converter_mode_select_draw_destination_offset(x, y, 1, canvas, multi_converter_state); + + // OK / CANCEL + + canvas_set_color(canvas, ColorBlack); + canvas_draw_box(canvas, 0, 64 - 12, canvas_string_width(canvas, MULTI_CONVERTER_INFO_STRING_OK) + 4, 12); + canvas_draw_box(canvas, 128 - 4 - canvas_string_width(canvas, MULTI_CONVERTER_INFO_STRING_BACK), 64 - 12, canvas_string_width(canvas, "BACK: Cancel") + 4, 12); + + canvas_set_color(canvas, ColorWhite); + canvas_draw_str(canvas, 2, 64 - 3, MULTI_CONVERTER_INFO_STRING_OK); + canvas_draw_str(canvas, 128 - 2 - canvas_string_width(canvas, MULTI_CONVERTER_INFO_STRING_BACK), 64 - 3, MULTI_CONVERTER_INFO_STRING_BACK); +} + +void multi_converter_mode_select_reset(MultiConverterState* const multi_converter_state) { + + // initial pre-selected values are equal to the current selected values + (multi_converter_state->select).selected_unit_type_orig = multi_converter_state->unit_type_orig; + (multi_converter_state->select).selected_unit_type_dest = multi_converter_state->unit_type_dest; + + (multi_converter_state->select).select_orig = 1; +} + +MultiConverterModeTrigger multi_converter_mode_select_exit(uint8_t save_changes, MultiConverterState* const multi_converter_state) { + if (save_changes) { + + multi_converter_state->unit_type_dest = (multi_converter_state->select).selected_unit_type_dest; + + if (multi_converter_state->unit_type_orig == (multi_converter_state->select).selected_unit_type_orig) { + // if the ORIGIN unit didn't changed, just trigger the convert + + return Convert; + } else { + multi_converter_state->unit_type_orig = (multi_converter_state->select).selected_unit_type_orig; + multi_converter_state->unit_type_dest = (multi_converter_state->select).selected_unit_type_dest; + + return Reset; + } + + } + + return None; +} + +void multi_converter_mode_select_switch(MultiConverterState* const multi_converter_state) { + (multi_converter_state->select).select_orig ^= 1; +} + +void multi_converter_mode_select_change_unit(int8_t direction, MultiConverterState* const multi_converter_state) { + + MultiConverterUnitType d; + if ((multi_converter_state->select).select_orig) { + (multi_converter_state->select).selected_unit_type_orig = multi_converter_get_unit_type_offset((multi_converter_state->select).selected_unit_type_orig, direction); + d = (multi_converter_state->select).selected_unit_type_dest; + } else { + d = ((multi_converter_state->select).selected_unit_type_dest + direction) % MULTI_CONVERTER_AVAILABLE_UNITS; + } + + // check each unit with the ORIGIN allowed_function() to make sure we're selecting a valid DESTINATION + // (when changing the ORIGIN unit the DIRECTION in which we'll switch the DESTINATION will be the SAME); + // also notice that ORIGIN must be DIFFERENT than DESTINATION + int i = 0; + while (i < MULTI_CONVERTER_AVAILABLE_UNITS) { + if ( + multi_converter_available_units[(multi_converter_state->select).selected_unit_type_orig].allowed_function(d) && + (multi_converter_state->select).selected_unit_type_orig != d + ) { + (multi_converter_state->select).selected_unit_type_dest = d; + break; + } + + d = multi_converter_get_unit_type_offset(d, direction); + i++; + } + +} diff --git a/applications/multi_converter/multi_converter_mode_select.h b/applications/multi_converter/multi_converter_mode_select.h new file mode 100644 index 0000000000..2e4a9ec855 --- /dev/null +++ b/applications/multi_converter/multi_converter_mode_select.h @@ -0,0 +1,58 @@ +#pragma once + +#include +#include +#include + +#include "multi_converter_definitions.h" +#include "multi_converter_units.h" + +// +// aux draw function for units offsets and draw stuff +// +void multi_converter_mode_select_draw_destination_offset(uint8_t x, uint8_t y, int8_t d, Canvas* const canvas, const MultiConverterState* multi_converter_state); + +void multi_converter_mode_select_draw_selected_unit(uint8_t x, uint8_t y, MultiConverterUnitType unit_type, Canvas* const canvas); + +// +// draw the main SELECT view with the current multi_converter_state values +// +void multi_converter_mode_select_draw(Canvas* const canvas, const MultiConverterState* multi_converter_state); + +// +// reset the SELECT mode view, showing as "pre-selected" the current working units +// +void multi_converter_mode_select_reset(MultiConverterState* const multi_converter_state); + +// +// exit from SELECT mode and go back to display view, if save_changes == 1 use the current SELECT view info +// to modify the current selected units and reset the views properly (usually if the ORIGIN unit has been +// changed, reset everything; otherwise just trigger the convert function with a new DESTINATION) +// +// currently this function DON'T CHECK invalid unit relations (the navigation and display functions will +// prevent weird behaviours, so for now we're trusting the selected_unit_orig/dest_type values) +// +// returns an enum code MultiConverterDisplayTrigger based on doing nothing (cancel), triggering the display +// convert method or reseting the whole display mode (when fully changing the units) +// +// notice the MODE CHANGE itself is not done here but in the main loop (outside the call) via the ModeTrigger enum element +// +MultiConverterModeTrigger multi_converter_mode_select_exit(uint8_t save_changes, MultiConverterState* const multi_converter_state); + +// +// switch between selecting the ORIGIN or the DESTINATION unit on DISPLAY mode (since there're only +// two options, both left/right arrow keys acts as toggles, no "direction" required) +// +void multi_converter_mode_select_switch(MultiConverterState* const multi_converter_state); + +// +// change the selected unit on SELECTED mode, using the select_orig flag to check if we're switching the +// ORIGIN or the DESTINATION unit; the DIRECTION (up or down to travel the array) is set as a param +// +// when switching the ORIGIN one, reset the DESTINATION to the first valid unit (if the current one is not +// valid anymore); when switching the DESTINATION one, an allowed_function() check is performed in order to +// properly set a valid destination unit. +// +// (notice the draw step also perform which units are valid to display, so no worries about that here) +// +void multi_converter_mode_select_change_unit(int8_t direction, MultiConverterState* const multi_converter_state); diff --git a/applications/multi_converter/multi_converter_units.c b/applications/multi_converter/multi_converter_units.c new file mode 100644 index 0000000000..2812849231 --- /dev/null +++ b/applications/multi_converter/multi_converter_units.c @@ -0,0 +1,230 @@ +#include "multi_converter_units.h" + +#define MULTI_CONVERTER_CHAR_OVERFLOW '#' +#define MULTI_CONVERTER_MAX_SUPORTED_INT 999999999 + +#define multi_converter_unit_set_overflow(b) for (int _i = 0; _i < MULTI_CONVERTER_NUMBER_DIGITS; _i++) b[_i] = MULTI_CONVERTER_CHAR_OVERFLOW; + +// +// DEC / HEX / BIN conversion +// +void multi_converter_unit_dec_hex_bin_convert(MultiConverterState* const multi_converter_state) { + + char dest[MULTI_CONVERTER_NUMBER_DIGITS]; + + int i = 0; + uint8_t overflow = 0; + + int a = 0; + int r = 0; + uint8_t f = 1; + + switch(multi_converter_state->unit_type_orig) { + default: + break; + case UnitTypeDec: { + a = atoi(multi_converter_state->buffer_orig); + f = (multi_converter_state->unit_type_dest == UnitTypeHex ? 16 : 2); + + break; + } + case UnitTypeHex: + a = strtol(multi_converter_state->buffer_orig, NULL, 16); + f = (multi_converter_state->unit_type_dest == UnitTypeDec ? 10 : 2); + + break; + case UnitTypeBin: + a = strtol(multi_converter_state->buffer_orig, NULL, 2); + f = (multi_converter_state->unit_type_dest == UnitTypeDec ? 10 : 16); + + break; + } + + while (a > 0) { + r = a % f; + dest[i] = r + (r < 10 ? '0' : ('A' - 10) ); + a /= f; + if (i++ >= MULTI_CONVERTER_NUMBER_DIGITS) { + overflow = 1; + break; + } + } + + if (overflow) { + multi_converter_unit_set_overflow(multi_converter_state->buffer_dest); + } else { + // copy DEST (reversed) to destination and append empty chars at the end + for (int j = 0; j < MULTI_CONVERTER_NUMBER_DIGITS; j++) { + if (i >= 1) multi_converter_state->buffer_dest[j] = dest[--i]; + else multi_converter_state->buffer_dest[j] = ' '; + } + } + +} + +uint8_t multi_converter_unit_dec_hex_bin_allowed(MultiConverterUnitType unit_type) { + return (unit_type == UnitTypeDec || unit_type == UnitTypeHex || unit_type == UnitTypeBin); +} + +// +// CEL / FAR / KEL +// +void multi_converter_unit_temperature_convert(MultiConverterState* const multi_converter_state) { + + double a = strtof(multi_converter_state->buffer_orig, NULL); + uint8_t overflow = 0; + + switch(multi_converter_state->unit_type_orig) { + default: + break; + case UnitTypeCelsius: + if (multi_converter_state->unit_type_dest == UnitTypeFahernheit) { + // celsius to fahrenheit + a = (a * ((double) 1.8)) + 32; + } else { // UnitTypeKelvin + a += ((double) 273.15); + } + + break; + case UnitTypeFahernheit: + // fahrenheit to celsius, always + a = (a - 32) / ((double) 1.8); + if (multi_converter_state->unit_type_dest == UnitTypeKelvin) { + // if kelvin, add + a += ((double) 273.15); + } + + break; + case UnitTypeKelvin: + // kelvin to celsius, always + a -= ((double) 273.15); + if (multi_converter_state->unit_type_dest == UnitTypeFahernheit) { + // if fahernheit, convert + a = (a * ((double) 1.8)) + 32; + } + + break; + } + + if (overflow) { + multi_converter_unit_set_overflow(multi_converter_state->buffer_dest); + } else { + + int ret = snprintf(multi_converter_state->buffer_dest, MULTI_CONVERTER_NUMBER_DIGITS + 1, "%.3lf", a); + + if (ret < 0) multi_converter_unit_set_overflow(multi_converter_state->buffer_dest); + } + +} + +uint8_t multi_converter_unit_temperature_allowed(MultiConverterUnitType unit_type) { + return (unit_type == UnitTypeCelsius || unit_type == UnitTypeFahernheit || unit_type == UnitTypeKelvin); +} + +// +// KM / M / CM / MILES / FEET / INCHES +// + +void multi_converter_unit_distance_convert(MultiConverterState* const multi_converter_state) { + double a = strtof(multi_converter_state->buffer_orig, NULL); + uint8_t overflow = 0; + + switch(multi_converter_state->unit_type_orig) { + default: + break; + case UnitTypeKilometers: + if (multi_converter_state->unit_type_dest == UnitTypeMeters) a *= ((double) 1000); + else if (multi_converter_state->unit_type_dest == UnitTypeCentimeters) a *= ((double) 100000); + else if (multi_converter_state->unit_type_dest == UnitTypeMiles) a *= ((double) 0.6213711); + else if (multi_converter_state->unit_type_dest == UnitTypeFeet) a *= ((double) 3280.839895013); + else if (multi_converter_state->unit_type_dest == UnitTypeInches) a *= ((double) 39370.078740157); + break; + case UnitTypeMeters: + if (multi_converter_state->unit_type_dest == UnitTypeKilometers) a /= ((double) 1000); + else if (multi_converter_state->unit_type_dest == UnitTypeCentimeters) a *= ((double) 100); + else if (multi_converter_state->unit_type_dest == UnitTypeMiles) a *= ((double) 0.0006213711); + else if (multi_converter_state->unit_type_dest == UnitTypeFeet) a *= ((double) 3.280839895013); + else if (multi_converter_state->unit_type_dest == UnitTypeInches) a *= ((double) 39.370078740157); + break; + case UnitTypeCentimeters: + if (multi_converter_state->unit_type_dest == UnitTypeKilometers) a /= ((double) 100000); + else if (multi_converter_state->unit_type_dest == UnitTypeMeters) a /= ((double) 100); + else if (multi_converter_state->unit_type_dest == UnitTypeMiles) a *= ((double) 0.000006213711); + else if (multi_converter_state->unit_type_dest == UnitTypeFeet) a *= ((double) 0.03280839895013); + else if (multi_converter_state->unit_type_dest == UnitTypeInches) a *= ((double) 0.39370078740157); + break; + + case UnitTypeMiles: + if (multi_converter_state->unit_type_dest == UnitTypeKilometers) a *= ((double) 1.609344); + else if (multi_converter_state->unit_type_dest == UnitTypeMeters) a *= ((double) 1609.344); + else if (multi_converter_state->unit_type_dest == UnitTypeCentimeters) a *= ((double) 160934.4); + else if (multi_converter_state->unit_type_dest == UnitTypeFeet) a *= ((double) 5280); + else if (multi_converter_state->unit_type_dest == UnitTypeInches) a *= ((double) 63360); + break; + case UnitTypeFeet: + if (multi_converter_state->unit_type_dest == UnitTypeKilometers) a *= ((double) 0.0003048); + else if (multi_converter_state->unit_type_dest == UnitTypeMeters) a *= ((double) 0.3048); + else if (multi_converter_state->unit_type_dest == UnitTypeCentimeters) a *= ((double) 30.48); + else if (multi_converter_state->unit_type_dest == UnitTypeMiles) a *= ((double) 0.000189393939394); + else if (multi_converter_state->unit_type_dest == UnitTypeInches) a *= ((double) 12); + break; + case UnitTypeInches: + if (multi_converter_state->unit_type_dest == UnitTypeKilometers) a *= ((double) 0.0000254); + else if (multi_converter_state->unit_type_dest == UnitTypeMeters) a *= ((double) 0.0254); + else if (multi_converter_state->unit_type_dest == UnitTypeCentimeters) a *= ((double) 2.54); + else if (multi_converter_state->unit_type_dest == UnitTypeMiles) a *= ((double) 0.0000157828282828); + else if (multi_converter_state->unit_type_dest == UnitTypeFeet) a *= ((double) 0.0833333333333); + break; + + } + + if (overflow) { + multi_converter_unit_set_overflow(multi_converter_state->buffer_dest); + } else { + + int ret = snprintf(multi_converter_state->buffer_dest, MULTI_CONVERTER_NUMBER_DIGITS + 1, "%lf", a); + + if (ret < 0) multi_converter_unit_set_overflow(multi_converter_state->buffer_dest); + } +} + +uint8_t multi_converter_unit_distance_allowed(MultiConverterUnitType unit_type) { + return ( + unit_type == UnitTypeKilometers || unit_type == UnitTypeMeters || unit_type == UnitTypeCentimeters || + unit_type == UnitTypeMiles || unit_type == UnitTypeFeet || unit_type == UnitTypeInches + ); +} + +// +// DEG / RAD +// + +void multi_converter_unit_angle_convert(MultiConverterState* const multi_converter_state) { + double a = strtof(multi_converter_state->buffer_orig, NULL); + uint8_t overflow = 0; + + switch(multi_converter_state->unit_type_orig) { + default: + break; + case UnitTypeDegree: + if (multi_converter_state->unit_type_dest == UnitTypeRadian) a *= ((double) 0.0174532925199); + break; + + case UnitTypeRadian: + if (multi_converter_state->unit_type_dest == UnitTypeDegree) a *= ((double) 57.2957795131); + break; + } + + if (overflow) { + multi_converter_unit_set_overflow(multi_converter_state->buffer_dest); + } else { + + int ret = snprintf(multi_converter_state->buffer_dest, MULTI_CONVERTER_NUMBER_DIGITS + 1, "%lf", a); + + if (ret < 0) multi_converter_unit_set_overflow(multi_converter_state->buffer_dest); + } +} + +uint8_t multi_converter_unit_angle_allowed(MultiConverterUnitType unit_type) { + return (unit_type == UnitTypeDegree || unit_type == UnitTypeRadian); +} \ No newline at end of file diff --git a/applications/multi_converter/multi_converter_units.h b/applications/multi_converter/multi_converter_units.h new file mode 100644 index 0000000000..da281627eb --- /dev/null +++ b/applications/multi_converter/multi_converter_units.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include + +#include "multi_converter_definitions.h" + +#define MULTI_CONVERTER_AVAILABLE_UNITS 14 + +#define multi_converter_get_unit(unit_type) multi_converter_available_units[unit_type] +#define multi_converter_get_unit_type_offset(unit_type, offset) (((unit_type + offset) % MULTI_CONVERTER_AVAILABLE_UNITS + MULTI_CONVERTER_AVAILABLE_UNITS) % MULTI_CONVERTER_AVAILABLE_UNITS) +// the modulo operation will fail with extremely large values on the units array + +// DEC / HEX / BIN +void multi_converter_unit_dec_hex_bin_convert(MultiConverterState* const multi_converter_state); +uint8_t multi_converter_unit_dec_hex_bin_allowed(MultiConverterUnitType); + +// CEL / FAR / KEL +void multi_converter_unit_temperature_convert(MultiConverterState* const multi_converter_state); +uint8_t multi_converter_unit_temperature_allowed(MultiConverterUnitType); + +// KM / M / CM / MILES / FEET / INCHES +void multi_converter_unit_distance_convert(MultiConverterState* const multi_converter_state); +uint8_t multi_converter_unit_distance_allowed(MultiConverterUnitType); + +// DEG / RAD +void multi_converter_unit_angle_convert(MultiConverterState* const multi_converter_state); +uint8_t multi_converter_unit_angle_allowed(MultiConverterUnitType unit_type); + +// +// each unit is made of comma? + negative? + keyboard_length + mini_name + name + convert function + allowed function +// (setting functions as NULL will cause convert / select options to be ignored) +// +static const MultiConverterUnit multi_converter_unit_dec = { 0, 0, 10, "DEC\0", "Decimal\0", multi_converter_unit_dec_hex_bin_convert, multi_converter_unit_dec_hex_bin_allowed }; +static const MultiConverterUnit multi_converter_unit_hex = { 0, 0, 16, "HEX\0", "Hexadecimal\0", multi_converter_unit_dec_hex_bin_convert, multi_converter_unit_dec_hex_bin_allowed }; +static const MultiConverterUnit multi_converter_unit_bin = { 0, 0, 2, "BIN\0", "Binary\0", multi_converter_unit_dec_hex_bin_convert, multi_converter_unit_dec_hex_bin_allowed }; + +static const MultiConverterUnit multi_converter_unit_cel = { 1, 1, 10, "CEL\0", "Celsius\0", multi_converter_unit_temperature_convert, multi_converter_unit_temperature_allowed }; +static const MultiConverterUnit multi_converter_unit_far = { 1, 1, 10, "FAR\0", "Fahernheit\0", multi_converter_unit_temperature_convert, multi_converter_unit_temperature_allowed }; +static const MultiConverterUnit multi_converter_unit_kel = { 1, 1, 10, "KEL\0", "Kelvin\0", multi_converter_unit_temperature_convert, multi_converter_unit_temperature_allowed }; + +static const MultiConverterUnit multi_converter_unit_km = { 1, 0, 10, "KM\0", "Kilometers\0", multi_converter_unit_distance_convert, multi_converter_unit_distance_allowed }; +static const MultiConverterUnit multi_converter_unit_m = { 1, 0, 10, "M\0", "Meters\0", multi_converter_unit_distance_convert, multi_converter_unit_distance_allowed }; +static const MultiConverterUnit multi_converter_unit_cm = { 1, 0, 10, "CM\0", "Centimeters\0", multi_converter_unit_distance_convert, multi_converter_unit_distance_allowed }; +static const MultiConverterUnit multi_converter_unit_mi = { 1, 0, 10, "MI\0", "Miles\0", multi_converter_unit_distance_convert, multi_converter_unit_distance_allowed }; +static const MultiConverterUnit multi_converter_unit_ft = { 1, 0, 10, "FT\0", "Feet\0", multi_converter_unit_distance_convert, multi_converter_unit_distance_allowed }; +static const MultiConverterUnit multi_converter_unit_in = { 1, 0, 10, " \"\0", "Inches\0", multi_converter_unit_distance_convert, multi_converter_unit_distance_allowed }; + +static const MultiConverterUnit multi_converter_unit_deg = { 1, 0, 10, "DEG\0", "Degree\0", multi_converter_unit_angle_convert, multi_converter_unit_angle_allowed }; +static const MultiConverterUnit multi_converter_unit_rad = { 1, 0, 10, "RAD\0", "Radian\0", multi_converter_unit_angle_convert, multi_converter_unit_angle_allowed }; + +// index order set by the MultiConverterUnitType enum element (multi_converter_definitions.h) +static const MultiConverterUnit multi_converter_available_units[MULTI_CONVERTER_AVAILABLE_UNITS] = { + [UnitTypeDec] = multi_converter_unit_dec, + [UnitTypeHex] = multi_converter_unit_hex, + [UnitTypeBin] = multi_converter_unit_bin, + + [UnitTypeCelsius] = multi_converter_unit_cel, + [UnitTypeFahernheit] = multi_converter_unit_far, + [UnitTypeKelvin] = multi_converter_unit_kel, + + [UnitTypeKilometers] = multi_converter_unit_km, + [UnitTypeMeters] = multi_converter_unit_m, + [UnitTypeCentimeters] = multi_converter_unit_cm, + [UnitTypeMiles] = multi_converter_unit_mi, + [UnitTypeFeet] = multi_converter_unit_ft, + [UnitTypeInches] = multi_converter_unit_in, + + [UnitTypeDegree] = multi_converter_unit_deg, + [UnitTypeRadian] = multi_converter_unit_rad, +}; \ No newline at end of file diff --git a/documentation/MultiConverter.md b/documentation/MultiConverter.md new file mode 100644 index 0000000000..820563622d --- /dev/null +++ b/documentation/MultiConverter.md @@ -0,0 +1,61 @@ +# MultiConverter + +## Author: [theisolinearchip](https://github.com/theisolinearchip/flipperzero_stuff/tree/main/applications/multi_converter) + +An expanded version of my previous __Dec/Hex Converter__, this time allowing more units and a _(probably poorly made from a design-point-of-view)_ selector mode +to swap between different unit groups. + +I wrote it with the idea of _expanding the unit list_ on mind, so adding new ones it's a matter of increasing an array of constants + defining the proper conversion functions. + +(Actually the whole project is more about "making the framework" rather than providing _ALL_ of the possible units : D) + +![Img 1](http://albertgonzalez.coffee/projects/flipperzero/multi_converter/img/1_small.png) ![Img 2](http://albertgonzalez.coffee/projects/flipperzero/multi_converter/img/2_small.png) + +## Current conversions + +- `Decimal / Hexadecimal / Binary` +- `Celsius / Fahernheit / Kelvin` +- `Kilometers / Meters / Centimeters / Miles / Feet / Inches` +- `Degree / Radian` + +## Usage + +Base keyboard allows numbers from `0` to `F`, being disabled (or not) according to the current selected unit. + +Long press on `0` toggles a __negative__ value; long press on `1` sets a __decimal point__ (only if allowed by the current selected unit). + +`<` removes the last character; `#` changes to __Unit Select Mode__. + +### Unit Select Mode + +`Left` and `Right` to swap between __origin unit__ and __destination unit__ (notice the _destination_ will change according to the current selected _origin_). + +`Ok` to save the changes and go back to the __Display Mode__; `Back` to go back without changing any unit. + +## Adding new units + +1. Add the new units in the `MultiConverterUnitType` enum on `multi_converter_definitions.h` (basic definitions header). Notice each enum element will be used as an array index later. + +2. Increase the `MULTI_CONVERTER_AVAILABLE_UNITS` constant on `multi_converter_units.h` (units main header file). + +3. Set a pair of functions for __converting__ units and to __check__ if a target unit is allowed to work with the destination unit (both on `multi_converter_units.h` +and `multi_converter_units.c`; follow the already built-in units for more info). + +4. Add the proper `MultiConverterUnit` structs for each new unit. + +5. Add each new struct to the main `multi_converter_available_units` array. + +And that's it! The system will fetch the new units and display it! + +## Known issues, TODO-list, etc. + +This is an initial release, so expect some bugs and issues (also I don't work with C that much, so there're probably lots of things that can be improved and/or changed!). + +- I've noticed some small decimal variations when "going deep" with some units (like converting __miles__ to __centimeters__ and things like that); probably due to the precision-level required. Need to check that. +- Pending: improve overflow checks. +- The way some long numbers are shown could probably be improved to look fancier. +- Both _origin_ and _destination buffers_ are the same. The destination one could probably be longer in order to avoid certain _overflow scenarios_. +- The GUI needs improvement too: there's a whole __widget/views system__ built in the Flipper that allows things like setting up keys, showing "Save/Back/Cancel" messages with +callbacks and stuff like that. Didn't know anything about them, so I moved on with something more basic (which is probably fince since it's not a "very big project"); but +a more "standard" way with the regular GUI stuff provided by the firmware will be interesting... +- More GUI stuff: the _long click buttons_ for adding a decimal point / negative number aren't very clear on the view itself (I tried to add a small dot / dash symbol, but I think those are small enough to be a little bit confusing) From b0daa601ad5b87427a45f9089c8b403a01f72c2a Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Tue, 23 Aug 2022 19:18:28 +0300 Subject: [PATCH 24/78] [FL-2727, FL-2749] New icon in BLE remote app #1644 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../power_service/views/power_unplug_usb.c | 2 +- .../icons/BLE/BLE_HID/Ble_connected_15x15.png | Bin 177 -> 3634 bytes .../BLE/BLE_HID/Ble_disconnected_15x15.png | Bin 178 -> 3632 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/power/power_service/views/power_unplug_usb.c b/applications/power/power_service/views/power_unplug_usb.c index 6d14be22c7..5632cd8b05 100644 --- a/applications/power/power_service/views/power_unplug_usb.c +++ b/applications/power/power_service/views/power_unplug_usb.c @@ -17,7 +17,7 @@ static void power_unplug_usb_draw_callback(Canvas* canvas, void* _model) { canvas_set_color(canvas, ColorWhite); canvas_set_font(canvas, FontPrimary); elements_multiline_text_aligned( - canvas, 64, 32, AlignCenter, AlignCenter, "It's now safe to unplug\nUSB cable"); + canvas, 64, 32, AlignCenter, AlignCenter, "It's now safe to unplug\nthe USB cable"); } PowerUnplugUsb* power_unplug_usb_alloc() { diff --git a/assets/icons/BLE/BLE_HID/Ble_connected_15x15.png b/assets/icons/BLE/BLE_HID/Ble_connected_15x15.png index 58776828ed48a1c3a497755800660b79ea3b8137..64dab9b5307410bb10fd7a6634cc35ed88af4671 100644 GIT binary patch literal 3634 zcmaJ@XH-+!7QPHfZz4rRoDdKYA%&ipP?FH3Ly#aALI@#Z3LzSbBA_&NKt!nqvCxYO ziXxyisR9C`bfk+6@P;Cc2)r;e&U-)Ry}Rx`Wv~5x``i2Mv(}Asa)gyir`390UNO7E~>RB=X1PyRqDR|dedGy-I3dS}z{FW`l zMNSyxg1Htho2ag(A|ib>R^?v5oOA7N3kw0I=B!x$`1tVaa?aY~S4I1TCROgoUw#mK zwRK}G^nw3}s#n;`x{ZyFXoSYG@prgqTH$sxbj+ z;W8hUz)e*?U_A_lIt;E6dIj(W^@s@rHTD@bu>CRHQeQA>C-}mz@YS#rjctX)WdXC0 zcuWppX2}=MO;vXVvIGFHHj?)Q;G_e1X7n-P(cap^a)mB5Az^)lz1AwJU zM(uk|Vg7Kx%VV9K?M2f~tE_`SxUbF40020JQ-k1J%S@Yu0RWd3q4n5YX{C0rc8%cv z+Fe7nV&AM+t6QJ?VrEU!aFkr>VB_Q%RvUeNbu%KA0Ve$h!xNl2aB3rRFn z>KjowvsSYzLPWs4S$GdoWgwQ%`zk>-URWV5YF(w)T0rKS8mJ{!)){P@XkZO@xrzt5 zSt~E0SwA6SPFTK7Jkkv4Mt+a3vVz}=D0N1^7k`GW$TQk^#qz$`J0CVYJwZMz;~nei zKJ<0Ndo%9}{iFsGOt4L`n$LTM^cv2>AdU5yC&t<$Nu;(X;3DzD#(j^E74cWbt&%#Q za0Fx`ENVmy1vnTG@qoEC!H(e2XPpPyucp6yK*UId|B7>+1~@6t_Nn^I-M=^N_11;Q z5UjOTKgcBPfl7zQVjGOqWa6;88WlHwvU&0l-!0Q^*-dv*oz>3I(6`>Fn$$Aj<6kO- zxTOs`+#EH@ovfeKn^c-qS@IO+dYc72Tz4JUbZI?vRB=jrN`Fd_oT_W?_8{G5IPV^Q zw?V>jO!2*Pmq*Sqd3*HFr6bxe%iGvy7vI0#v(Hb#Z;krsGyCQ4;oAosQr@|Dx6N98 zPWjBg!V#B&r?OXhRAIn@@G9vcyo=1oU6PH0$B5;}HqXI%SThjT@9U7hhidWfLtV5z{YOsC-;GEbu8y7I_RglHPG=!Sv#rmE>6{h0rP8 z*{3&AzNhU_1C{HV(PKqXpi~52UXHyMXB*iDNil(BC^Zf@S5F>guLhhP3+Z0vW|U>r z&F2k1S}P^O1o;Jf-}>?h}`E>p3)w_*OHMPZIu#|X-^8C56=n&@8q z@$vI)PQe;+QNiS^3G42J$pp%1M0dpF^jo8v=grUC9P1gGr=v!(msGcXwnMhNfZXtd zd=&n;2=fTfpElM*E~vbYH$@JTzn1pTn_thWFqbn=h%Anrsx4OWYyR~{vC7&^YDZ!R zRWiyc?DL0rLd0p}wfZn|ji{I?_h{32W-MV}7d*v)(=~(*9L0UZCF4diC~!x_Bb}oL zS|$aMGpGThm-;VF8zH_PZ+i(`g3Vdm{RoIwi6Q;$tI_ZC%Q55Jaj}U|g;Z$sNoMf9 zj=GhoT={&6j5ada%r4f!_}0J7rM2?puOD36!#Nl)8eFGbM*%~-47+0cuqU(*I4oIf z*@xWxHL=PdSnZ8ow)RxT6^;BGRdy0~!x_j-`SkN3nl2hy4ZnOd@kRiqK*c_(obrV- z?R&nhh#XbA^@e`!IrPA7p%(wL8%4W3bVSQBIiK;zH9u+zl~Ty=zOUQkS`o>GnTOlw z-hs$i-bPksVY> zk-OBVITSRd6vJqJoi=pqX?|ftg-@q%x9{xqh)$-bWO6~ubc!ThqJQA2#OSf7^Q&Ji z2B9hKnuC>>%dr&?UZY-Ak#k!*+K-sxAL3W=-|&VD-NVm_AJ^$!3re9?U-f_O9rUbP z+car;HR#6YX5Z`EOWv^AC|ffvi7S|0Pu`%NEOwv;%s26O^KS~NN|t}Dc;BnsjmEnq zd^kL3CE4`zt1a##M@Pa?!tIwkjpM3JT=3-Vn#kzd0SV;5`Rk!YV?sSYpI4?RL(gE+ zm(ndWT+=r^y**z#zBTFk@MR?AyVc;&Qg`%G9>GVK@h#MW*~p$G%2MZb?rrYHFv#yi zUW50`LuW`Gqi3WTi!Y_wW8D_p*Jh4X9qBl+^n$%qIykk*{e^q_Bjjn?7xov_R#J~+ zQ{|n?^pc7b{uK)$)z3nG*JhP6jXH)`s)K)%-~P~>i9iomFNZMJ-mI;T$`6OJG&Vch zD*HJa3&mBARi{_X=FR)D!!f<4o?AnGi$j;r)NrzvyN0aR1fwo@ZY8cJNMUy+q$RXP zOGM9Q8k-;x^jrm&65J!3O!Kjqu1UA9m4oPCr zAjBOXNDz(5LjwTHG>Azg`IFfoZ!(2SM}rqDUxPtZA2itAz#eAL#FG7})*&piYls7$ z6yi@p_<&7KK&T)jkAOyI6G1_=v-Ch@5E}dkFOs+3F+;(iKU~=UXz-t+2=-1OEQ3V` z8A0GWBp3_^GD1MeK15w_JzpY88>9=W8Df{r`8R(f;-hWV?|6 zqxT<)1M$I3GSr0}$T-I$@y^aybte=PiDi+AYz7O@V4VF?NGCrAn-S>8V1jh@AaIbT zJ&{DE?^q7~0kOA7+Ry{pL^_FVgF}OPBoHdq2Wbp5#~AYlILs0bhg;yx4UCM<4Y3%w z0TyRyY-#=ji(`<^(a3c653J9Bu$cde-DwCKlNT9BW>L?ReJoiF8t9L#k<@?CVri+5 z(>FGvJlsS56? zwa>bP2^Z^@FRGlr0u%{pVoGBfs_k&zaIF(!=}V`?lVl&v}>*&{01Rn(MF zwyYsUb_q!i-eZZA@Q(AI&ini0*ZW-0^W69Sy*{7Mce%g!b=~of_7-Bo2ZR9t5VNwx zJ99^g-A|C0`xg}?2Lphx85M_fw8G&)3?|)|dX@|T!Nb`u6oSi~EM|Rt6>Ae0am$A8 zEF%bV#$Jn%PEyrS5|XrzQ_35XajM^IX2z$`nj6QPkPvZQ#z|B3s_>w|w9?&#%lG20 zwr@^`-SZ!)S^w0z{q()jZ0SmNWw$_`plGV4wv%pzXc6|%-Vc{snwlr4AtsT+DhxnU zu+m2|pGU#20MF37&{6Jaw!j0~^5zX}}~j z0s8q;@Z=@|pnc>xJm6;t zly)DxY6cKtfV8ho6A~EI0$^5dzLvnFXFy$-q(}uICFihl>}eyR|XPyHPbXG&4OtXx)VMAho+)+@>^~u5;Tu z`)4@%`}*34mmgIk5ho)p_%=Q?yjiu)KiGX!=!)0qr$meI&qQ{INgs;`jKma&}SAh`PD~($O0RW#Hsqx5EVYPn0W*z^* z`aPrdBHumru3%M~8nBXBVV{VDOwS{wQCRhu&PR$Gp3rwDiaK>pelf`maY%#fb8!qq z;u}dYr(V4#Qi#vARd63kX*iC@>nc$>K~OFudPAw+l27WI3aBkk+6iovq-zOxzDfYO zS}HDMn7<%nPnf?*GHeA9QQu=~Ea0~yE1WRzM4#fS3iS_MF~2MF)`tbpOq9*dddqxr z0CQb0Z}x48pTuyY5v~PR_j$j7cGFoHq`49M*g#V#*}LO0xKy;H`M{%NrM%VgYu??D z*?dxwW_3b(d~7U;bjZ|_XiKyov@8T2RMFWxETk{Qd&Q|i4V+wP^F;N<-ani6dm-Sl zL`zNO0jb1&P|2`3T$8?vR6Gu$R(0bStH<{Vy;8mAy#db3bDBk2I+h2NliP-U{3`^I zw=_XVTcfA5ryHlWrxm7^mOX^Cy-Wh{Z@7F^cWyspEk7eUqcg)#PDhx!-ph0zE6gM8 z)lEE(Ez9FLKXi&M+^2Ic6WMuL*2*To>~2cm0Y5pvb?U>;vDn6vnt z_L+B;Eh-ixbGapsqAs7cUtm8)p1uEJy6pq`zH9O=1eiX2K7BSrB7^Qq)Zl1bkV$G6 zPO(l=O;ON*5{il+6pt5+xURT%5E6?{xm+wachz>8DiV5^TH;!q?KtnE;6f=fEQ~Ft z6w(RC_ru+{;`!YhZ5thM_nmSdpPs5|28npfR|ab;`HPjroQu?LQhnSxbm6>4b^4ZK z^)*a!Q63VfZLRHA>AZ5w*H~aGJ#gbT%U)8?9{EJi5 zQi&y&B~B$4^R;^A3kBH^YR#(MHzUPOTddVis98`FyY^(yx(vCD6$lr|+F?*@<&a|k ze1*JfJo{BZ!D4#O%Tp0Kw)BGWklNXA2QNam2wSvo1#1?fME*)q75)*?uKnoOx`A}G zBD7`X4=3EoMiX2(u5GQz}!mW?J(-Ren_^RU5l6c8i(L zc2y6KJTSC1v~B5p(|NaZAVW6`1AmX0&6>@6pEdE!^LX%aO->=_IoYaW`uGF)MNUmX z^l_wnKGF5~$x8FG?6SiH)n(NMdkd=UlkH1#1}Ke>{@}E6ik`_oni=FDDd*5Q7fBQ^ zIm)xw<&BHUwaFJ>T>NbdBOn$#BwnI;TroW82~!$%3^ktFb$ikH;_KDaIVgqLE!jP& zJ;mAAaiocw?UL1JL6M_W1zlc=yB2Q~)d5K}f@CQ)kG0lLTeH>zPfmvRu4QLcW;HAn zjyzn{Tcj?=j^25rbLU8oyLQmq##Y=1r{<4)Ek=QR`&kU zvwU{(I%!GH=&KR)&Xmye%-UyXB`fW^qkYt6SzytJ3c$1J3T-_#9kw1&x2?P45}7>`DW6MKy0y+T{4IAh4RVw zd`Brcx?=lvz_n-4Ln#7n{*^aM_qb~bbFdFS6OOCD*AS?nkllP=b;h?NQ%iD=b}qcB zY#+Iye|zc9&Vp2f)Z|T0evFNqmLl;}ZRr_g1v)TfM0iSO&(WA;{H5sUS2-HAeut6; zx3u!`TGdcH|HxDI?NRkldHm-^T!m+%FV2s?UpVPNgt|{WC4Gy@Rxpx@zgjLmB9|s} zX;6JMct#h+Jte*02=pF>Oa z?dr_(suTWIi=nko!+h806ms;t##U=X{*c`n=+8l7#%fnW>Fcl8*Cu4g!kKDYT^-d! zY_-L*8i$(Gt0oJkL%6Zneq)dA(ZQwBOK0lXxhp-R7VG@cm%F!<))FOfdlEAeJ7UCQ z=5q{;kjRh5%&oca1-NdXZq*#Q?Yr9@<#Mvn@QwcY_gy{dJ$Y%%Y00l>7xK5h)XmF3 z9BFQ7KJ>CJSQ~z7_1NY@J$sa`xO8tq!eROX=#u)5-=B}yT;3LJCd(%$@9^=auY6z9 zy%oj1SIV=@h%6VnFN;lLk^xg6x)&K_MI%wj&Sa8LNMIWo4FJ6AR05Gjw6jHd(`gXW zE(Q`zV{q93fHn?hki7lLERYwOLJh!xm#SZZK~x_M*iF|CX2-yh{iv3qOtMR;J;6KF z-y7)zHZ}sGgHc=o8kt1`1=G$31fha4;JWUAptB>uvS2j@(%?(ImnwyWw5C9 z0MM=?$%}rDg#mMe{ZAG&#y_$FL4Q|@TQg`di2;Q}V7poU0NUC8ZzzrS4?2kDO#W}Y z|F3WmA%sDOI+KIw=a}Byz4KMxb;Us8m}C-*&Lq(3XMYsZ(T~oe2l>$%AcQsq4pO%x zc~b*+El2*M*x8}10)kki0B^Dt9s}lzK&Vt7lmW~XYhVB~gTu_>aJU)XR9D}?R1b%R z>*DZw2Ii(exOlqvIT|^D^@Hp4U#|I2xw{QPV{kp=$xP~bvX42FP6PdwHH!N4Sa3hp z`4;>HBMME_y7#@1dVYmnK*?Wfd%qJP&ba;T%ADYqq8{>*rHE(~k8}&d P00000NkvXXu0mjf##lkG From 3a985eff4d0387e96ab3151ac2770827168b2c23 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 23 Aug 2022 19:32:09 +0300 Subject: [PATCH 25/78] rename unirf / update readme --- ReadMe.md | 1 - applications/unirfremix/application.fam | 2 +- documentation/HowToBuild.md | 25 ------------------------- 3 files changed, 1 insertion(+), 27 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index 1f29878ba3..222572381b 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -65,7 +65,6 @@ See changelog in releases for latest updates! - GPIO: Sentry Safe plugin [(by H4ckd4ddy)](https://github.com/H4ckd4ddy/flipperzero-sentry-safe-plugin) - ESP32: WiFi Marauder companion plugin [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion) - NRF24: Sniffer & MouseJacker (with changes) [(by mothball187)](https://github.com/mothball187/flipperzero-nrf24/tree/main/mousejacker) -- HID Analyzer [(by Ownasaurus)](https://github.com/Ownasaurus/flipperzero-firmware/tree/hid-analyzer/applications/hid_analyzer) - Simple Clock (fixed) !! New version WIP, wait for updates !! [(Original by CompaqDisc)](https://gist.github.com/CompaqDisc/4e329c501bd03c1e801849b81f48ea61) - UniversalRF Remix (with changes)(only RAW subghz files) [(by ESurge)(Original UniversalRF by jimilinuxguy)](https://github.com/ESurge/flipperzero-firmware-unirfremix) - Tetris (with fixes) [(by jeffplang)](https://github.com/jeffplang/flipperzero-firmware/tree/tetris_game/applications/tetris_game) diff --git a/applications/unirfremix/application.fam b/applications/unirfremix/application.fam index d8eaaab896..dd3a85fe25 100644 --- a/applications/unirfremix/application.fam +++ b/applications/unirfremix/application.fam @@ -1,6 +1,6 @@ App( appid="unirfremix", - name="UniRF Remix", + name="Sub-GHz Remote", apptype=FlipperAppType.APP, entry_point="unirfremix_app", cdefines=["APP_UNIRFREMIX"], diff --git a/documentation/HowToBuild.md b/documentation/HowToBuild.md index 4a23e97cd6..be3d877630 100644 --- a/documentation/HowToBuild.md +++ b/documentation/HowToBuild.md @@ -58,31 +58,6 @@ Check `dist/` for build outputs. Use **`flipper-z-{target}-full-{suffix}.dfu`** to flash your device. -## Build with Docker -### Prerequisites - -1. Install [Docker Engine and Docker Compose](https://www.docker.com/get-started) -2. Prepare the container: - - ```sh - docker-compose up -d - ``` - -### Compile everything for development - -```sh -docker-compose exec dev ./fbt -``` - -### Compile everything for release + get updater package to update from microSD card - -```sh -docker-compose exec dev ./fbt COMPACT=1 DEBUG=0 updater_package -``` - -Check `dist/` for build outputs. - -Use **`flipper-z-{target}-full-{suffix}.dfu`** to flash your device. If compilation fails, make sure all submodules are all initialized. Either clone with `--recursive` or use `git submodule update --init --recursive`. From 7c54fcf60ae9e555482113a3dcece885e1fa1590 Mon Sep 17 00:00:00 2001 From: Max Andreev Date: Tue, 23 Aug 2022 20:57:59 +0300 Subject: [PATCH 26/78] fix fbtenv.sh under zsh (#1645) * fix fbtenv under ZSH, some improovements, add amap workflow timeout * fix copy .map file in build.yml --- .github/workflows/amap_analyse.yml | 1 + .github/workflows/build.yml | 2 +- scripts/toolchain/fbtenv.sh | 58 +++++++++++++++++++++++++----- 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/.github/workflows/amap_analyse.yml b/.github/workflows/amap_analyse.yml index dd903e2e83..3443771dd4 100644 --- a/.github/workflows/amap_analyse.yml +++ b/.github/workflows/amap_analyse.yml @@ -15,6 +15,7 @@ env: jobs: amap_analyse: runs-on: [self-hosted,FlipperZeroMacShell] + timeout-minutes: 15 steps: - name: 'Wait Build workflow' uses: fountainhead/action-wait-for-check@v1.0.0 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b677a293f6..7eeb5c22b4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -110,7 +110,7 @@ jobs: - name: 'Copy .map file' run: | - cp build/f7-firmware-D/firmware.elf.map artifacts/flipper-z-f7-firmware-${{steps.names.outputs.suffix}}.elf.map + cp build/f7-firmware-*/firmware.elf.map artifacts/flipper-z-f7-firmware-${{steps.names.outputs.suffix}}.elf.map - name: 'Upload artifacts to update server' if: ${{ !github.event.pull_request.head.repo.fork }} diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index b06c582aeb..6f3e8c661a 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -8,20 +8,61 @@ SCRIPT_PATH="${SCRIPT_PATH:-$DEFAULT_SCRIPT_PATH}"; FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"8"}"; FBT_TOOLCHAIN_PATH="${FBT_TOOLCHAIN_PATH:-$SCRIPT_PATH}"; +fbtenv_show_usage() +{ + echo "Running this script manually is wrong, please source it"; + echo "Example:"; + printf "\tsource scripts/toolchain/fbtenv.sh\n"; +} + +fbtenv_curl() +{ + curl --progress-bar -SLo "$1" "$2"; +} + +fbtenv_wget() +{ + wget --show-progress --progress=bar:force -qO "$1" "$2"; +} + fbtenv_check_sourced() { case "${ZSH_EVAL_CONTEXT:-""}" in *:file:*) return 0;; esac + if [ ${0##*/} = "fbtenv.sh" ]; then # exluding script itself + fbtenv_show_usage; + return 1; + fi case ${0##*/} in dash|-dash|bash|-bash|ksh|-ksh|sh|-sh|*.sh|fbt) return 0;; esac - echo "Running this script manually is wrong, please source it"; - echo "Example:"; - printf "\tsource scripts/toolchain/fbtenv.sh\n"; + fbtenv_show_usage; return 1; } +fbtenv_chck_many_source() +{ + if ! echo "${PS1:-""}" | grep -q "[fbt]"; then + if ! echo "${PROMPT:-""}" | grep -q "[fbt]"; then + return 0; + fi + fi + echo "Warning! It script seen to be sourced more then once!"; + echo "It may signalise what you are making some mistakes, please open a new shell!"; + return 1; +} + +fbtenv_set_shell_prompt() +{ + if [ -n "${PS1:-""}" ]; then + PS1="[fbt]$PS1"; + elif [ -n "${PROMPT:-""}" ]; then + PROMPT="[fbt]$PROMPT"; + fi + return 0; # all other shells +} + fbtenv_check_script_path() { if [ ! -x "$SCRIPT_PATH/fbt" ]; then @@ -97,7 +138,7 @@ fbtenv_download_toolchain_tar() { echo "Downloading toolchain:"; mkdir -p "$FBT_TOOLCHAIN_PATH/toolchain" || return 1; - "$DOWNLOADER" $DOWNLOADER_ARGS "$FBT_TOOLCHAIN_PATH/toolchain/$TOOLCHAIN_TAR" "$TOOLCHAIN_URL" || return 1; + "$FBT_DOWNLOADER" "$FBT_TOOLCHAIN_PATH/toolchain/$TOOLCHAIN_TAR" "$TOOLCHAIN_URL" || return 1; echo "done"; return 0; } @@ -156,13 +197,11 @@ fbtenv_curl_wget_check() return 1; fi echo "yes" - DOWNLOADER="wget"; - DOWNLOADER_ARGS="--show-progress --progress=bar:force -qO"; + FBT_DOWNLOADER="fbtenv_wget"; return 0; fi echo "yes" - DOWNLOADER="curl"; - DOWNLOADER_ARGS="--progress-bar -SLo"; + FBT_DOWNLOADER="fbtenv_curl"; return 0; } @@ -196,10 +235,11 @@ fbtenv_download_toolchain() fbtenv_main() { fbtenv_check_sourced || return 1; + fbtenv_chck_many_source; # many source it's just a warning + fbtenv_set_shell_prompt; fbtenv_check_script_path || return 1; fbtenv_get_kernel_type || return 1; fbtenv_check_download_toolchain || return 1; - PS1="[FBT]${PS1-}"; PATH="$TOOLCHAIN_ARCH_DIR/python/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/protobuf/bin:$PATH"; From 803422c18ee90cd974185e649162ea5853424942 Mon Sep 17 00:00:00 2001 From: Daniel <71837281+darmiel@users.noreply.github.com> Date: Tue, 23 Aug 2022 20:47:54 +0200 Subject: [PATCH 27/78] fix[unirf]: fixed dynamic protocol, refactoring --- applications/unirfremix/unirfremix_app.c | 328 ++++++++++------------- 1 file changed, 146 insertions(+), 182 deletions(-) diff --git a/applications/unirfremix/unirfremix_app.c b/applications/unirfremix/unirfremix_app.c index 07cd65d830..08c0ee1459 100644 --- a/applications/unirfremix/unirfremix_app.c +++ b/applications/unirfremix/unirfremix_app.c @@ -33,6 +33,7 @@ typedef struct { SubGhzSetting* setting; SubGhzEnvironment* environment; + SubGhzReceiver* subghz_receiver; string_t up_file; string_t down_file; @@ -78,20 +79,26 @@ typedef struct { uint32_t frequency; string_t name; + string_t protocol; + uint32_t repeat; + uint8_t* data; size_t data_size; SubGhzProtocolDecoderBase* decoder; } UniRFPreset; -UniRFPreset* unirf_preset_alloc(void) { +UniRFPreset* unirfremix_preset_alloc(void) { UniRFPreset* preset = malloc(sizeof(UniRFPreset)); string_init(preset->name); + string_init(preset->protocol); + preset->repeat = 200; return preset; } -void unirf_preset_free(UniRFPreset* preset) { +void unirfremix_preset_free(UniRFPreset* preset) { string_clear(preset->name); + string_clear(preset->protocol); free(preset); } @@ -143,13 +150,13 @@ static char* extract_filename(const char* name, int len) { } /* -*check that map file exists -*assign variables to values within map file -*set missing filenames to N/A -*set filename as label if label definitions are missing -*set error flag if all buttons are N/A -*set error flag if missing map file -*/ + * check that map file exists + * assign variables to values within map file + * set missing filenames to N/A + * set filename as label if label definitions are missing + * set error flag if all buttons are N/A + * set error flag if missing map file + */ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { Storage* storage = furi_record_open(RECORD_STORAGE); @@ -168,90 +175,68 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { //check that map file exists if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) { - FURI_LOG_I(TAG, "Could not open MAP file %s", string_get_cstr(file_name)); + FURI_LOG_E(TAG, "Could not open MAP file %s", string_get_cstr(file_name)); } else { //Filename Assignment/Check Start //assign variables to values within map file //set missing filenames to N/A if(!flipper_format_read_string(fff_data_file, "UP", app->up_file)) { - FURI_LOG_I(TAG, "Could not read UP string"); - + FURI_LOG_W(TAG, "Could not read UP string"); //increment file_blank for processing later app->file_blank++; - //set label to "N/A" app->up_label = "N/A"; - //disable the ability to process the signal on button press app->up_enabled = 0; - - FURI_LOG_I(TAG, "Up_Enabled: %d", app->up_enabled); } else { //check name length for proper screen fit //then set filename as label. Might be replaced with defined label later on below. app->up_label = extract_filename(string_get_cstr(app->up_file), label_len); - FURI_LOG_I(TAG, "UP file: %s", string_get_cstr(app->up_file)); } //Repeat process for Down if(!flipper_format_read_string(fff_data_file, "DOWN", app->down_file)) { - FURI_LOG_I(TAG, "Could not read DOWN string"); - + FURI_LOG_W(TAG, "Could not read DOWN string"); app->file_blank++; app->down_label = "N/A"; app->down_enabled = 0; - - FURI_LOG_I(TAG, "Down_Enabled: %d", app->down_enabled); } else { app->down_label = extract_filename(string_get_cstr(app->down_file), label_len); - FURI_LOG_I(TAG, "DOWN file: %s", string_get_cstr(app->down_file)); } //Repeat process for Left if(!flipper_format_read_string(fff_data_file, "LEFT", app->left_file)) { - FURI_LOG_I(TAG, "Could not read LEFT string"); - + FURI_LOG_W(TAG, "Could not read LEFT string"); app->file_blank++; app->left_label = "N/A"; app->left_enabled = 0; - - FURI_LOG_I(TAG, "Left_Enabled: %d", app->left_enabled); } else { app->left_label = extract_filename(string_get_cstr(app->left_file), label_len); - FURI_LOG_I(TAG, "LEFT file: %s", string_get_cstr(app->left_file)); } //Repeat process for Right if(!flipper_format_read_string(fff_data_file, "RIGHT", app->right_file)) { - FURI_LOG_I(TAG, "Could not read RIGHT string"); - + FURI_LOG_W(TAG, "Could not read RIGHT string"); app->file_blank++; app->right_label = "N/A"; app->right_enabled = 0; - - FURI_LOG_I(TAG, "Right_Enabled: %d", app->right_enabled); } else { app->right_label = extract_filename(string_get_cstr(app->right_file), label_len); - FURI_LOG_I(TAG, "RIGHT file: %s", string_get_cstr(app->right_file)); } //Repeat process for Ok if(!flipper_format_read_string(fff_data_file, "OK", app->ok_file)) { - FURI_LOG_I(TAG, "Could not read OK string"); - + FURI_LOG_W(TAG, "Could not read OK string"); app->file_blank++; app->ok_label = "N/A"; app->ok_enabled = 0; - - FURI_LOG_I(TAG, "Ok_Enabled: %d", app->ok_enabled); } else { app->ok_label = extract_filename(string_get_cstr(app->ok_file), label_len); - FURI_LOG_I(TAG, "OK file: %s", string_get_cstr(app->ok_file)); } @@ -262,8 +247,7 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { //assign variables to values within map file if(!flipper_format_read_string(fff_data_file, "ULABEL", app->up_l)) { - FURI_LOG_I(TAG, "Could not read ULABEL string"); - + FURI_LOG_W(TAG, "Could not read ULABEL string"); //if Up button is disabled, set the label to "N/A"; if(app->up_enabled == 0) { app->up_label = "N/A"; @@ -276,13 +260,11 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { //set label from map to variable and shrink to fit screen app->up_label = char_to_str((char*)string_get_cstr(app->up_l), label_len); } - FURI_LOG_I(TAG, "UP label: %s", app->up_label); } if(!flipper_format_read_string(fff_data_file, "DLABEL", app->down_l)) { - FURI_LOG_I(TAG, "Could not read DLABEL string"); - + FURI_LOG_W(TAG, "Could not read DLABEL string"); if(app->down_enabled == 0) { app->down_label = "N/A"; } @@ -292,13 +274,11 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { } else { app->down_label = char_to_str((char*)string_get_cstr(app->down_l), label_len); } - FURI_LOG_I(TAG, "DOWN label: %s", app->down_label); } if(!flipper_format_read_string(fff_data_file, "LLABEL", app->left_l)) { - FURI_LOG_I(TAG, "Could not read LLABEL string"); - + FURI_LOG_W(TAG, "Could not read LLABEL string"); if(app->left_enabled == 0) { app->left_label = "N/A"; } @@ -308,13 +288,11 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { } else { app->left_label = char_to_str((char*)string_get_cstr(app->left_l), label_len); } - FURI_LOG_I(TAG, "LEFT label: %s", app->left_label); } if(!flipper_format_read_string(fff_data_file, "RLABEL", app->right_l)) { - FURI_LOG_I(TAG, "Could not read RLABEL string"); - + FURI_LOG_W(TAG, "Could not read RLABEL string"); if(app->right_enabled == 0) { app->right_label = "N/A"; } @@ -324,13 +302,11 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { } else { app->right_label = char_to_str((char*)string_get_cstr(app->right_l), label_len); } - FURI_LOG_I(TAG, "RIGHT label: %s", app->right_label); } if(!flipper_format_read_string(fff_data_file, "OKLABEL", app->ok_l)) { - FURI_LOG_I(TAG, "Could not read OKLABEL string"); - + FURI_LOG_W(TAG, "Could not read OKLABEL string"); if(app->ok_enabled == 0) { app->ok_label = "N/A"; } @@ -340,14 +316,15 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { } else { app->ok_label = char_to_str((char*)string_get_cstr(app->ok_l), label_len); } - FURI_LOG_I(TAG, "OK label: %s", app->ok_label); } app->file_result = 2; } + flipper_format_file_close(fff_data_file); flipper_format_free(fff_data_file); + furi_record_close(RECORD_STORAGE); //File Existence Check @@ -357,7 +334,7 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { //determine whether or not to continue to launch app with missing variables //if 5 files are missing, throw error - FURI_LOG_I(TAG, "app->file_blank: %d", app->file_blank); + FURI_LOG_D(TAG, "app->file_blank: %d", app->file_blank); if(app->file_blank == 5) { //trigger invalid file error screen @@ -374,7 +351,7 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { fff_data_file = flipper_format_file_alloc(storage); if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) { - FURI_LOG_I(TAG, "Could not open UP file %s", string_get_cstr(file_name)); + FURI_LOG_W(TAG, "Could not open UP file %s", string_get_cstr(file_name)); //disable button, and set label to "N/A" app->up_enabled = 0; @@ -383,6 +360,7 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { } //close the file + flipper_format_file_close(fff_data_file); flipper_format_free(fff_data_file); furi_record_close(RECORD_STORAGE); } @@ -393,13 +371,14 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { fff_data_file = flipper_format_file_alloc(storage); if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) { - FURI_LOG_I(TAG, "Could not open DOWN file %s", string_get_cstr(file_name)); + FURI_LOG_W(TAG, "Could not open DOWN file %s", string_get_cstr(file_name)); app->down_enabled = 0; app->down_label = "N/A"; app->file_blank++; } + flipper_format_file_close(fff_data_file); flipper_format_free(fff_data_file); furi_record_close(RECORD_STORAGE); } @@ -410,13 +389,14 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { fff_data_file = flipper_format_file_alloc(storage); if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) { - FURI_LOG_I(TAG, "Could not open LEFT file %s", string_get_cstr(file_name)); + FURI_LOG_W(TAG, "Could not open LEFT file %s", string_get_cstr(file_name)); app->left_enabled = 0; app->left_label = "N/A"; app->file_blank++; } + flipper_format_file_close(fff_data_file); flipper_format_free(fff_data_file); furi_record_close(RECORD_STORAGE); } @@ -427,13 +407,14 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { fff_data_file = flipper_format_file_alloc(storage); if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) { - FURI_LOG_I(TAG, "Could not open RIGHT file %s", string_get_cstr(file_name)); + FURI_LOG_W(TAG, "Could not open RIGHT file %s", string_get_cstr(file_name)); app->right_enabled = 0; app->right_label = "N/A"; app->file_blank++; } + flipper_format_file_close(fff_data_file); flipper_format_free(fff_data_file); furi_record_close(RECORD_STORAGE); } @@ -444,13 +425,14 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { fff_data_file = flipper_format_file_alloc(storage); if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) { - FURI_LOG_I(TAG, "Could not open OK file %s", string_get_cstr(file_name)); + FURI_LOG_W(TAG, "Could not open OK file %s", string_get_cstr(file_name)); app->ok_enabled = 0; app->ok_label = "N/A"; app->file_blank++; } + flipper_format_file_close(fff_data_file); flipper_format_free(fff_data_file); furi_record_close(RECORD_STORAGE); } @@ -467,7 +449,7 @@ static void unirfremix_end_send(UniRFRemix* app) { app->processing = 0; } -bool unirf_set_preset(UniRFPreset* p, const char* preset) { +bool unirfremix_set_preset(UniRFPreset* p, const char* preset) { if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { string_set(p->name, "AM270"); } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { @@ -485,7 +467,7 @@ bool unirf_set_preset(UniRFPreset* p, const char* preset) { return true; } -bool unirf_key_load( +bool unirfremix_key_load( UniRFPreset* preset, FlipperFormat* fff_file, FlipperFormat* fff_data, @@ -505,19 +487,17 @@ bool unirf_key_load( do { // load frequency from file - uint32_t frequency = 0; - if(!flipper_format_read_uint32(fff_file, "Frequency", &frequency, 1)) { + if(!flipper_format_read_uint32(fff_file, "Frequency", &preset->frequency, 1)) { FURI_LOG_W(TAG, "Cannot read frequency. Defaulting to 433.92 MHz"); - frequency = 433920000; + preset->frequency = 433920000; } - preset->frequency = frequency; // load preset from file if(!flipper_format_read_string(fff_file, "Preset", temp_str)) { FURI_LOG_W(TAG, "Could not read Preset. Defaulting to Ook650Async"); string_set(temp_str, "FuriHalSubGhzPresetOok650Async"); } - if(!unirf_set_preset(preset, string_get_cstr(temp_str))) { + if(!unirfremix_set_preset(preset, string_get_cstr(temp_str))) { FURI_LOG_E(TAG, "Could not set preset"); break; } @@ -530,19 +510,25 @@ bool unirf_key_load( preset->data_size = subghz_setting_get_preset_data_size(setting, preset_index); // load protocol from file - if(!flipper_format_read_string(fff_file, "Protocol", temp_str)) { - FURI_LOG_W(TAG, "Could not read Protocol."); + if(!flipper_format_read_string(fff_file, "Protocol", preset->protocol)) { + FURI_LOG_E(TAG, "Could not read Protocol."); break; } - if(!string_cmp_str(temp_str, "RAW")) { + if(!string_cmp_str(preset->protocol, "RAW")) { subghz_protocol_raw_gen_fff_data(fff_data, path); } else { stream_copy_full( flipper_format_get_raw_stream(fff_file), flipper_format_get_raw_stream(fff_data)); } - preset->decoder = - subghz_receiver_search_decoder_base_by_name(receiver, string_get_cstr(temp_str)); + // repeat + if(!flipper_format_insert_or_update_uint32(fff_file, "Repeat", &preset->repeat, 1)) { + FURI_LOG_E(TAG, "Unable to insert or update Repeat"); + break; + } + + preset->decoder = subghz_receiver_search_decoder_base_by_name( + receiver, string_get_cstr(preset->protocol)); if(preset->decoder) { if(!subghz_protocol_decoder_base_deserialize(preset->decoder, fff_data)) { break; @@ -560,7 +546,8 @@ bool unirf_key_load( } // method modified from subghz_i.c -bool unirf_save_protocol_to_file(FlipperFormat* fff_file, const char* dev_file_name) { +// https://github.com/flipperdevices/flipperzero-firmware/blob/b0daa601ad5b87427a45f9089c8b403a01f72c2a/applications/subghz/subghz_i.c#L417-L456 +bool unirfremix_save_protocol_to_file(FlipperFormat* fff_file, const char* dev_file_name) { furi_assert(fff_file); furi_assert(dev_file_name); @@ -590,7 +577,7 @@ bool unirf_save_protocol_to_file(FlipperFormat* fff_file, const char* dev_file_n stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); saved = true; - FURI_LOG_I(TAG, "(save) OK Save"); + FURI_LOG_D(TAG, "(save) OK Save"); } while(0); string_clear(file_dir); furi_record_close(RECORD_STORAGE); @@ -603,132 +590,112 @@ static bool unirfremix_send_sub( FlipperFormat* fff_data, const char* path) { // - if(!flipper_format_file_open_existing(fff_file, path)) { - FURI_LOG_E(TAG, "Could not open file %s", path); - return false; - } + UniRFPreset* preset = unirfremix_preset_alloc(); - SubGhzReceiver* subghz_receiver = subghz_receiver_alloc_init(app->environment); // no - UniRFPreset* preset = unirf_preset_alloc(); // no - if(!unirf_key_load(preset, fff_file, fff_data, app->setting, subghz_receiver, path)) { - FURI_LOG_E(TAG, "Could not load key"); - return false; - } - FURI_LOG_I(TAG, "Loaded preset."); + bool res = false; + do { + // load settings/stream from .sub file + bool open_ok = false; + do { + if(!flipper_format_file_open_existing(fff_file, path)) { + FURI_LOG_E(TAG, "Could not open file %s", path); + break; + } + if(!unirfremix_key_load( + preset, fff_file, fff_data, app->setting, app->subghz_receiver, path)) { + FURI_LOG_E(TAG, "Could not load key"); + break; + } + open_ok = true; + } while(0); + flipper_format_free(fff_file); + if(!open_ok) { + break; + } - // TODO: reimplement this later: - /* - if(!furi_hal_subghz_is_tx_allowed(frequency)) { + if(!furi_hal_subghz_is_tx_allowed(preset->frequency)) { printf( "In your settings, only reception on this frequency (%lu) is allowed,\r\n" "the actual operation of the unirf app is not possible\r\n ", - frequency); + preset->frequency); app->tx_not_allowed = true; unirfremix_end_send(app); - return false; + break; } else { app->tx_not_allowed = false; } - */ - - string_t temp_str; - string_init(temp_str); - string_t temp_protocol_str; - string_init(temp_protocol_str); - - bool res = false; - do { - if(!flipper_format_rewind(fff_file)) { - FURI_LOG_E(TAG, "Rewind error"); - break; - } - - if(!flipper_format_read_string(fff_file, "Protocol", temp_protocol_str)) { - FURI_LOG_E(TAG, "Could not read Protocol"); - break; - } - - uint32_t repeat = 200; - if(!flipper_format_insert_or_update_uint32(fff_file, "Repeat", &repeat, 1)) { - FURI_LOG_E(TAG, "Unable to insert or update Repeat"); + SubGhzTransmitter* transmitter = + subghz_transmitter_alloc_init(app->environment, string_get_cstr(preset->protocol)); + if(!transmitter) { break; } - SubGhzTransmitter* transmitter = - subghz_transmitter_alloc_init(app->environment, string_get_cstr(temp_protocol_str)); - FURI_LOG_I(TAG, "Got transmitter for %s", string_get_cstr(temp_protocol_str)); - - if(transmitter) { - subghz_transmitter_deserialize(transmitter, fff_data); - - furi_hal_subghz_reset(); - furi_hal_subghz_idle(); - furi_hal_subghz_load_custom_preset(preset->data); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); - - furi_hal_subghz_idle(); - furi_hal_subghz_set_frequency_and_path(preset->frequency); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - furi_hal_gpio_write(&gpio_cc1101_g0, true); + subghz_transmitter_deserialize(transmitter, fff_data); - furi_hal_power_suppress_charge_enter(); + furi_hal_subghz_reset(); + furi_hal_subghz_idle(); + furi_hal_subghz_load_custom_preset(preset->data); + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); - if(furi_hal_subghz_tx()) { - furi_hal_subghz_start_async_tx(subghz_transmitter_yield, transmitter); + furi_hal_subghz_idle(); + furi_hal_subghz_set_frequency_and_path(preset->frequency); + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_write(&gpio_cc1101_g0, true); - FURI_LOG_I(TAG, "Sending..."); - while(!furi_hal_subghz_is_async_tx_complete()) { - // fflush(stdout); - furi_delay_ms(33); - } - FURI_LOG_I(TAG, " Done!"); + furi_hal_power_suppress_charge_enter(); - furi_hal_subghz_stop_async_tx(); + if(!furi_hal_subghz_tx()) { + FURI_LOG_E(TAG, "Sending not allowed"); + } - subghz_transmitter_stop(transmitter); + FURI_LOG_I(TAG, "Sending..."); - flipper_format_file_close(fff_file); + furi_hal_subghz_start_async_tx(subghz_transmitter_yield, transmitter); + while(!furi_hal_subghz_is_async_tx_complete()) { + furi_delay_ms(33); + } + furi_hal_subghz_stop_async_tx(); - subghz_protocol_decoder_base_deserialize(preset->decoder, fff_data); - subghz_protocol_decoder_base_get_string(preset->decoder, temp_str); - FURI_LOG_I(TAG, "Decoded: %s", string_get_cstr(temp_str)); + FURI_LOG_I(TAG, " Done!"); - FURI_LOG_I(TAG, "Checking if protocol is dynamic"); - const SubGhzProtocol* registry_protocol = - subghz_protocol_registry_get_by_name(string_get_cstr(temp_protocol_str)); - FURI_LOG_I(TAG, "Protocol-TYPE %d", registry_protocol->type); - if(registry_protocol && registry_protocol->type == SubGhzProtocolTypeDynamic) { - FURI_LOG_I(TAG, " Protocol is dynamic. Updating Repeat"); - unirf_save_protocol_to_file(fff_data, path); - } - } else { - FURI_LOG_E(TAG, "Sending not allowed"); - } + subghz_transmitter_stop(transmitter); - subghz_transmitter_free(transmitter); - - FURI_LOG_I(TAG, "Cleaning up."); - furi_hal_subghz_idle(); - furi_hal_subghz_sleep(); - furi_hal_power_suppress_charge_exit(); + // display decoded data + { + string_t temp_str; + string_init(temp_str); + subghz_protocol_decoder_base_deserialize(preset->decoder, fff_data); + subghz_protocol_decoder_base_get_string(preset->decoder, temp_str); + FURI_LOG_D(TAG, "Decoded: %s", string_get_cstr(temp_str)); + string_clear(temp_str); } res = true; - } while(0); - unirf_preset_free(preset); + FURI_LOG_D(TAG, "Checking if protocol is dynamic"); + const SubGhzProtocol* registry = + subghz_protocol_registry_get_by_name(string_get_cstr(preset->protocol)); + FURI_LOG_D(TAG, "Protocol-TYPE %d", registry->type); + if(registry && registry->type == SubGhzProtocolTypeDynamic) { + FURI_LOG_D(TAG, " Protocol is dynamic. Updating Repeat"); + unirfremix_save_protocol_to_file(fff_data, path); + + keeloq_reset_mfname(); + keeloq_reset_kl_type(); + star_line_reset_mfname(); + star_line_reset_kl_type(); + } - string_clear(temp_str); - string_clear(temp_protocol_str); + subghz_transmitter_free(transmitter); - unirfremix_end_send(app); - - keeloq_reset_mfname(); - keeloq_reset_kl_type(); - star_line_reset_mfname(); - star_line_reset_kl_type(); + furi_hal_subghz_idle(); + furi_hal_subghz_sleep(); + furi_hal_power_suppress_charge_exit(); + } while(0); + unirfremix_preset_free(preset); + unirfremix_end_send(app); return res; } @@ -743,17 +710,11 @@ static void unirfremix_send_signal(UniRFRemix* app, Storage* storage, const char for(int x = 0; x < app->repeat; ++x) { FlipperFormat* fff_file = flipper_format_file_alloc(storage); - bool res = unirfremix_send_sub(app, fff_file, fff_data, path); - - if(!res) { // errored - flipper_format_free(fff_file); - break; - } + unirfremix_send_sub(app, fff_file, fff_data, path); } - string_clear(preset); string_clear(protocol); - + string_clear(preset); flipper_format_free(fff_data); unirfremix_end_send(app); @@ -872,7 +833,7 @@ static void input_callback(InputEvent* input_event, void* ctx) { furi_message_queue_put(app->input_queue, input_event, 0); } -UniRFRemix* unirfremix_alloc() { +UniRFRemix* unirfremix_alloc(void) { UniRFRemix* app = malloc(sizeof(UniRFRemix)); app->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal); @@ -901,6 +862,8 @@ UniRFRemix* unirfremix_alloc() { subghz_environment_set_nice_flor_s_rainbow_table_file_name( app->environment, EXT_PATH("subghz/assets/nice_flor_s")); + app->subghz_receiver = subghz_receiver_alloc_init(app->environment); + return app; } @@ -930,6 +893,7 @@ void unirfremix_free(UniRFRemix* app) { furi_mutex_free(app->model_mutex); subghz_setting_free(app->setting); + subghz_receiver_free(app->subghz_receiver); subghz_environment_free(app->environment); free(app); @@ -980,7 +944,7 @@ int32_t unirfremix_app(void* p) { bool exit_loop = false; if(app->file_result == 2) { - FURI_LOG_I( + FURI_LOG_D( TAG, "U: %s - D: %s - L: %s - R: %s - O: %s ", string_get_cstr(app->up_file), @@ -1005,7 +969,7 @@ int32_t unirfremix_app(void* p) { while(1) { furi_check( furi_message_queue_get(app->input_queue, &input, FuriWaitForever) == FuriStatusOk); - FURI_LOG_I( + FURI_LOG_D( TAG, "key: %s type: %s", input_get_key_name(input.key), @@ -1093,12 +1057,12 @@ int32_t unirfremix_app(void* p) { } if(app->processing == 0) { - FURI_LOG_I(TAG, "processing 0"); + FURI_LOG_D(TAG, "processing 0"); app->send_status = "Idle"; app->send_status_c = 0; app->button = 0; } else if(app->processing == 1) { - FURI_LOG_I(TAG, "processing 1"); + FURI_LOG_D(TAG, "processing 1"); app->send_status = "Send"; @@ -1141,7 +1105,7 @@ int32_t unirfremix_app(void* p) { while(1) { furi_check( furi_message_queue_get(app->input_queue, &input, FuriWaitForever) == FuriStatusOk); - FURI_LOG_I( + FURI_LOG_D( TAG, "key: %s type: %s", input_get_key_name(input.key), From 029f82dc822e6d3515b39b839a2f70500dc9bb86 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 23 Aug 2022 22:59:49 +0300 Subject: [PATCH 28/78] new universal projector remote and assets update assets by @Amec0e --- .drone.yml | 1 + .../infrared/scenes/infrared_scene_config.h | 1 + .../scenes/infrared_scene_universal.c | 11 + .../infrared_scene_universal_projector.c | 86 +++++ assets/resources/Manifest | 9 +- assets/resources/infrared/assets/ac.ir | 328 +++++++++++++++++- assets/resources/infrared/assets/audio.ir | 60 +++- .../resources/infrared/assets/projectors.ir | 326 +++++++++++++++++ assets/resources/infrared/assets/tv.ir | 10 +- 9 files changed, 818 insertions(+), 14 deletions(-) create mode 100644 applications/infrared/scenes/infrared_scene_universal_projector.c create mode 100644 assets/resources/infrared/assets/projectors.ir diff --git a/.drone.yml b/.drone.yml index 7499ccbee2..15c5dfce15 100644 --- a/.drone.yml +++ b/.drone.yml @@ -44,6 +44,7 @@ steps: - cp assets/resources/nfc/assets/mf_classic_dict.nfc sd-card/nfc/assets/mf_classic_dict.nfc - cp assets/resources/infrared/assets/tv.ir sd-card/infrared/assets/tv.ir - cp assets/resources/infrared/assets/ac.ir sd-card/infrared/assets/ac.ir + - cp assets/resources/infrared/assets/projectors.ir sd-card/infrared/assets/projectors.ir - cp assets/resources/infrared/assets/audio.ir sd-card/infrared/assets/audio.ir - cp assets/resources/unirf/unirf_map_example.txt sd-card/unirf/unirf_map_example.txt - cp assets/resources/Manifest sd-card/Manifest diff --git a/applications/infrared/scenes/infrared_scene_config.h b/applications/infrared/scenes/infrared_scene_config.h index 111fd2d31b..27eabe225f 100644 --- a/applications/infrared/scenes/infrared_scene_config.h +++ b/applications/infrared/scenes/infrared_scene_config.h @@ -17,6 +17,7 @@ ADD_SCENE(infrared, universal, Universal) ADD_SCENE(infrared, universal_tv, UniversalTV) ADD_SCENE(infrared, universal_ac, UniversalAC) ADD_SCENE(infrared, universal_audio, UniversalAudio) +ADD_SCENE(infrared, universal_projector, UniversalProjector) ADD_SCENE(infrared, debug, Debug) ADD_SCENE(infrared, error_databases, ErrorDatabases) ADD_SCENE(infrared, rpc, Rpc) diff --git a/applications/infrared/scenes/infrared_scene_universal.c b/applications/infrared/scenes/infrared_scene_universal.c index 8c6fe22b23..36c7d86e1d 100644 --- a/applications/infrared/scenes/infrared_scene_universal.c +++ b/applications/infrared/scenes/infrared_scene_universal.c @@ -3,6 +3,7 @@ typedef enum { SubmenuIndexUniversalTV, SubmenuIndexUniversalAudio, + SubmenuIndexUniversalProjector, SubmenuIndexUniversalAirConditioner, } SubmenuIndex; @@ -30,6 +31,13 @@ void infrared_scene_universal_on_enter(void* context) { infrared_scene_universal_submenu_callback, context); + submenu_add_item( + submenu, + "Projectors", + SubmenuIndexUniversalProjector, + infrared_scene_universal_submenu_callback, + context); + submenu_add_item( submenu, "ACs", @@ -52,6 +60,9 @@ bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubmenuIndexUniversalAudio) { scene_manager_next_scene(scene_manager, InfraredSceneUniversalAudio); consumed = true; + } else if(event.event == SubmenuIndexUniversalProjector) { + scene_manager_next_scene(scene_manager, InfraredSceneUniversalProjector); + consumed = true; } else if(event.event == SubmenuIndexUniversalAirConditioner) { scene_manager_next_scene(scene_manager, InfraredSceneUniversalAC); consumed = true; diff --git a/applications/infrared/scenes/infrared_scene_universal_projector.c b/applications/infrared/scenes/infrared_scene_universal_projector.c new file mode 100644 index 0000000000..11a0077f5e --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_universal_projector.c @@ -0,0 +1,86 @@ +#include "../infrared_i.h" + +#include "common/infrared_scene_universal_common.h" + +void infrared_scene_universal_projector_on_enter(void* context) { + infrared_scene_universal_common_on_enter(context); + + Infrared* infrared = context; + ButtonPanel* button_panel = infrared->button_panel; + InfraredBruteForce* brute_force = infrared->brute_force; + + infrared_brute_force_set_db_filename(brute_force, EXT_PATH("infrared/assets/projectors.ir")); + //TODO Improve Projectors universal remote + button_panel_reserve(button_panel, 2, 2); + uint32_t i = 0; + button_panel_add_item( + button_panel, + i, + 0, + 0, + 3, + 19, + &I_Power_25x27, + &I_Power_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "POWER"); + button_panel_add_item( + button_panel, + i, + 1, + 0, + 36, + 19, + &I_Mute_25x27, + &I_Mute_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "MUTE"); + button_panel_add_item( + button_panel, + i, + 0, + 1, + 3, + 64, + &I_Vol_up_25x27, + &I_Vol_up_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "VOL+"); + button_panel_add_item( + button_panel, + i, + 1, + 1, + 36, + 64, + &I_Vol_down_25x27, + &I_Vol_down_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "VOL-"); + + button_panel_add_label(button_panel, 10, 11, FontPrimary, "Projector"); + button_panel_add_label(button_panel, 17, 60, FontSecondary, "Volume"); + + view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); + + infrared_show_loading_popup(infrared, true); + bool success = infrared_brute_force_calculate_messages(brute_force); + infrared_show_loading_popup(infrared, false); + + if(!success) { + scene_manager_next_scene(infrared->scene_manager, InfraredSceneErrorDatabases); + } +} + +bool infrared_scene_universal_projector_on_event(void* context, SceneManagerEvent event) { + return infrared_scene_universal_common_on_event(context, event); +} + +void infrared_scene_universal_projector_on_exit(void* context) { + infrared_scene_universal_common_on_exit(context); +} diff --git a/assets/resources/Manifest b/assets/resources/Manifest index adac70b34c..35898f60e8 100644 --- a/assets/resources/Manifest +++ b/assets/resources/Manifest @@ -1,5 +1,5 @@ V:0 -T:1660773536 +T:1661280310 D:badusb D:dolphin D:infrared @@ -241,9 +241,10 @@ F:33b8fde22f34ef556b64b77164bc19b0:578:dolphin/L3_Lab_research_128x54/frame_8.bm F:f267f0654781049ca323b11bb4375519:581:dolphin/L3_Lab_research_128x54/frame_9.bm F:41106c0cbc5144f151b2b2d3daaa0527:727:dolphin/L3_Lab_research_128x54/meta.txt D:infrared/assets -F:cedef6d481ec8a10072168bfe82b9ec4:60995:infrared/assets/ac.ir -F:92f0d9326b08834472e04b4748eb19b3:47287:infrared/assets/audio.ir -F:005cd139f858369893c0008f7abbad43:127677:infrared/assets/tv.ir +F:ed61e6f4adc7972bde0e7b5028effac3:101928:infrared/assets/ac.ir +F:229a87b90c1890c5ec6d9e3b0f4695fb:48062:infrared/assets/audio.ir +F:63ca357ca0b85a6ad900539e7b6a0fed:5086:infrared/assets/projectors.ir +F:0370c1333f1e0d8d690b5afbfc623a60:127656:infrared/assets/tv.ir F:a157a80f5a668700403d870c23b9567d:470:music_player/Marble_Machine.fmf D:nfc/assets F:81dc04c7b181f94b644079a71476dff4:4742:nfc/assets/aid.nfc diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index fece63b334..28c8c03e43 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -4,7 +4,7 @@ Version: 1 # Universal AC IR codes - Brute force updated by jaroslavmraz # Fixes and tweaks provided by MX (MasterX) # -# BETA version - Aug 14, 2022 +# BETA version - Aug 23, 2022 # # Old SAMSUNG AC # @@ -579,7 +579,333 @@ type: parsed protocol: NECext address: 01 08 00 00 command: 3F 00 00 00 +# +#########################NEW LIST######################## +# +# file: Flipper-IRDB/ACs/Admiral/Admiral_AC.ir +# +name: POWER +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 02 00 00 00 +# +name: MODE +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 09 00 00 00 +# +name: TEMP+ +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 0A 00 00 00 +# +name: TEMP- +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 11 00 00 00 +# +# file: Flipper-IRDB/ACs/Airmet/Airmet_ac.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8917 4491 587 565 534 1665 594 559 540 1659 589 1688 540 534 585 1666 562 1664 564 1661 587 564 535 591 538 1661 567 585 534 1665 563 588 541 559 560 1665 563 563 566 559 540 586 533 1692 536 564 565 534 585 567 532 1667 592 534 565 587 542 531 588 564 535 591 538 561 568 558 540 585 534 565 564 1687 541 1658 560 1667 592 1660 558 1667 561 1664 584 567 542 558 561 564 565 561 538 588 541 558 561 1690 538 1661 567 1659 589 1662 566 1659 559 1667 591 559 540 587 532 541 588 564 535 591 538 561 558 567 542 584 535 565 564 1687 541 532 587 1664 564 1662 566 585 534 1691 537 589 540 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8971 4489 568 584 535 564 565 561 537 588 541 558 561 565 534 592 537 562 567 1659 559 566 563 563 536 1664 584 567 542 584 535 1664 564 587 542 558 561 564 535 591 538 562 567 558 541 585 534 566 563 562 537 589 540 559 560 566 533 593 536 563 566 560 539 587 532 567 562 564 535 591 538 1661 567 1658 590 1662 566 1659 559 1667 592 1660 558 567 562 563 536 590 539 561 558 567 542 584 535 1664 564 1662 586 1665 563 1662 566 1659 589 1663 565 560 559 566 533 593 536 564 565 560 538 587 542 557 562 564 535 591 538 1661 567 585 534 1666 562 1663 585 566 533 1667 592 560 538 +# +# file: Flipper-IRDB/ACs/Amcor/Amcor_AC.ir +# +name: POWER +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 9B 00 00 00 +# +# file: Flipper-IRDB/ACs/Ariston/Ariston_AC_A-MW09-IGX.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4481 4414 595 1596 594 527 562 1602 588 1604 586 535 565 530 570 1594 596 526 563 532 568 1596 594 528 561 534 566 1598 592 1600 590 531 569 1596 594 527 562 1603 587 1604 586 1605 648 1543 594 527 562 1603 587 1604 586 1605 595 525 564 531 569 526 563 532 568 1596 594 528 561 534 566 1598 592 1600 590 1601 589 532 568 527 562 533 567 528 561 534 566 529 560 535 565 530 570 1594 596 1596 594 1597 593 1598 592 1599 591 5252 4503 4418 590 1601 589 532 568 1597 593 1598 592 529 560 535 565 1600 590 531 569 526 563 1602 588 533 567 529 560 1604 596 1595 595 526 563 1602 588 533 567 1598 592 1599 591 1600 590 1601 589 532 568 1598 592 1599 591 1600 590 531 569 527 562 532 568 528 561 1603 587 534 566 530 559 1605 595 1596 594 1597 593 528 561 534 566 529 560 535 565 530 570 525 564 531 569 527 562 1602 588 1603 587 1604 596 1595 595 1596 594 +# +# file: Flipper-IRDB/ACs/Bonaire/Bonaire_DurangoAC.ir +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1303 438 1287 429 418 1254 1308 434 1281 434 423 1250 444 1255 439 1259 1303 439 418 1254 440 1258 446 8172 1313 428 1276 411 446 1252 1310 404 1311 403 444 1255 439 1259 445 1253 1309 405 442 1257 447 1250 444 8173 1302 412 1303 410 447 1251 1300 439 1276 410 447 1251 443 1255 439 1259 1303 437 420 1250 496 1202 439 8177 1308 434 1281 433 414 1256 1306 435 1280 434 413 1284 420 1251 443 1255 1307 433 414 1283 421 1250 444 8173 1302 438 1277 436 421 1276 1275 438 1277 436 421 1275 419 1252 442 1256 1306 434 413 1284 420 1250 444 8173 1302 438 1277 436 421 1276 1275 437 1278 435 412 1285 419 1278 416 1281 1281 432 415 1282 412 1285 419 +# +# file: Flipper-IRDB/ACs/Botti/Botti_BL-168DLR.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9577 4536 622 576 621 577 620 577 620 578 619 578 619 578 619 579 618 1667 625 1660 622 1664 618 1668 624 1662 620 1666 616 1670 622 1664 618 580 617 581 616 1669 623 575 622 575 622 1664 618 580 617 580 617 581 616 1669 623 575 622 1664 618 1668 624 573 624 1662 620 1666 616 1670 622 39798 9556 2250 626 96841 9564 2245 620 96843 9560 2253 622 96836 9569 2244 621 96844 9571 2244 621 96843 9573 2247 619 96844 9572 2248 617 96847 9570 2248 617 96848 9568 2250 626 96833 9564 2251 625 96834 9564 2252 624 96843 9595 2223 653 96809 9597 2221 644 96822 9604 2215 650 96814 9591 2226 650 96813 9591 2225 650 96811 9600 2218 647 96816 9597 2221 654 96812 9601 2219 646 96815 9598 2220 645 96813 9601 2216 649 96815 9599 2219 657 96809 9565 2252 624 96842 9564 2254 622 96841 9565 2254 622 96838 9568 2249 616 96844 9571 2247 619 96842 9574 2245 620 96840 9566 2251 625 96838 9567 2251 625 96835 9570 2250 615 96848 9566 2254 621 96843 9572 2247 618 96847 9567 2253 623 96842 9572 2249 616 96843 9572 2247 618 96843 9572 2249 616 96849 9576 2245 621 96842 9574 2246 619 96842 9575 2246 619 96843 9573 2248 617 96843 9572 2249 616 96847 9571 2249 617 96839 9569 2251 625 96837 9569 2251 624 96837 9568 2250 626 96835 9572 2248 618 96844 9572 2246 619 96843 9564 2253 623 96834 9572 2245 620 96835 9569 2246 619 +# +# file: Flipper-IRDB/ACs/Corlitec/Cortlitec_portable_ac.ir +# +name: POWER +type: parsed +protocol: NECext +address: 10 E7 00 00 +command: 05 FA 00 00 +# +# file: Flipper-IRDB/ACs/Daikin/Daikin_AC_industrial_TB.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 5055 2191 335 1799 360 752 338 714 365 716 364 1800 359 723 367 715 365 718 361 720 359 1805 365 747 332 1802 357 1806 364 719 360 1803 367 1798 361 1803 367 1797 362 1802 368 744 335 1799 360 721 369 714 365 716 363 719 360 721 369 713 366 1798 361 1802 368 715 364 717 362 720 359 723 367 715 364 1799 360 722 368 714 365 717 363 719 361 722 368 714 365 716 363 719 360 721 369 713 366 716 363 718 361 721 359 723 367 1797 362 1802 368 1796 363 1801 358 754 336 716 363 719 361 29583 5057 2160 366 1798 361 750 329 723 367 715 364 1800 359 753 337 715 364 717 363 720 359 1804 366 747 332 1801 358 1806 364 718 361 1803 356 1798 1802 368 1797 362 1802 368 714 365 1799 360 722 368 714 365 717 362 719 360 722 368 714 365 1798 361 1803 367 715 364 718 362 721 359 723 367 715 364 718 361 720 359 723 367 715 364 717 362 720 360 1804 366 1799 360 721 369 714 365 1798 361 1803 367 1798 361 720 359 723 367 715 364 718 361 720 360 723 367 715 364 717 362 720 359 722 368 714 365 717 362 719 360 722 368 1796 363 719 360 721 369 714 365 716 363 719 361 721 369 713 366 716 363 718 361 721 358 723 367 716 363 718 362 720 359 723 367 715 364 718 361 720 359 723 367 715 364 1799 360 1804 366 1799 360 721 369 714 365 716 363 1801 358 754 336 1798 361 720 360 1805 365 748 331 720 359 723 367 715 364 717 363 720 360 722 368 714 365 717 362 720 359 722 368 714 365 717 363 719 361 722 368 714 365 1798 361 751 339 713 366 716 363 1801 359 1805 365 1800 359 1805 365 1800 359 1805 365 1799 360 +# +# file: Flipper-IRDB/ACs/DeLonghi/Delonghi_portable_Pinguino-Air-to-Air-PAC-N81_ac.ir +# +name: POWER +type: parsed +protocol: NECext +address: 48 12 00 00 +command: 88 08 00 00 +# +# file: Flipper-IRDB/ACs/Friedrich/Friedrich.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 5624 5582 567 553 568 550 571 550 561 557 564 584 537 554 567 1672 571 1671 562 554 567 553 568 1696 537 1676 567 1673 570 1668 565 554 567 556 565 1671 562 557 564 1676 567 1671 562 584 537 555 566 1673 570 552 569 1666 567 1671 562 1676 567 1671 572 548 563 556 565 1672 571 554 567 547 564 556 565 1674 569 549 562 558 563 1676 567 551 570 554 568 548 563 557 564 555 566 554 567 1672 571 1667 566 1674 569 1673 570 545 566 554 567 1671 572 1667 566 554 567 1672 561 557 564 1677 566 # +# file: Flipper-IRDB/ACs/Frigidaire/Frigidaire_AC.ir +# +name: POWER +type: parsed +protocol: NECext +address: 01 FF 00 00 +command: 0A F5 00 00 +# +# file: Flipper-IRDB/ACs/Fujitsu/Fujitsu_AC.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3302 1618 435 393 436 391 438 1207 431 396 433 1213 435 392 437 391 438 388 441 1206 432 1214 434 392 437 389 440 388 431 1215 433 1213 435 392 437 390 439 388 431 396 433 395 434 392 437 390 439 388 431 396 433 394 435 392 437 390 439 388 441 1205 433 395 434 392 437 389 440 388 431 396 433 394 435 392 437 1209 439 388 431 397 432 394 435 393 436 1210 438 387 432 396 433 394 435 392 437 390 439 388 431 1215 433 394 435 1211 437 1208 440 1205 433 1213 435 1211 437 1209 439 +# +# file: Flipper-IRDB/ACs/Hisense/Hisense_window_AC.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8961 4409 563 541 570 533 568 535 566 537 564 539 562 1649 564 1648 565 539 562 541 570 533 568 536 565 1645 568 1644 569 1643 570 534 567 536 565 1646 567 1645 568 536 565 565 536 1648 565 540 572 558 543 560 541 562 539 564 537 566 546 558 543 560 541 563 538 565 536 567 544 559 542 562 539 564 537 566 546 558 543 561 540 563 538 565 536 568 544 560 541 562 539 564 537 566 546 558 543 561 540 563 538 565 536 568 544 560 541 562 539 564 537 567 545 559 542 561 540 563 538 566 545 558 543 561 540 563 538 565 536 568 544 560 541 562 539 565 536 567 544 559 542 561 540 564 537 566 545 558 543 561 540 563 538 565 536 568 543 560 541 562 539 564 537 566 545 532 569 534 567 537 564 539 562 541 571 560 541 536 565 538 563 540 572 532 569 535 566 537 564 539 573 531 570 534 567 536 565 539 562 541 571 533 568 535 566 538 563 540 572 532 569 535 566 537 564 540 572 532 569 534 567 537 564 539 573 532 569 534 567 536 565 539 562 541 571 533 568 536 565 538 563 541 571 533 568 535 566 538 563 540 572 532 569 535 566 537 564 540 572 532 569 534 567 537 564 539 562 542 570 534 567 536 565 539 562 541 570 534 567 536 565 539 562 542 570 534 567 536 565 539 562 542 570 534 567 536 565 539 562 542 570 534 567 536 565 539 562 542 570 1641 572 1640 563 543 569 535 566 538 563 540 561 543 569 535 566 538 563 540 561 543 569 535 566 538 563 541 571 533 568 536 565 539 562 541 571 534 567 537 564 539 562 542 570 534 567 537 564 1646 567 1646 567 539 562 542 570 534 567 537 564 540 561 542 590 +# +# file: Flipper-IRDB/ACs/Kenmore/Kenmore_AC.ir +# +name: TEMP- +type: parsed +protocol: NECext +address: 08 F5 00 00 +command: 0D F2 00 00 +# +# file: Flipper-IRDB/ACs/LG/LG_AC_2.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8455 4196 542 1566 541 539 519 535 513 541 517 1565 541 538 520 534 514 540 518 1563 544 1565 542 538 520 533 515 539 519 535 513 541 517 536 522 532 516 538 520 533 515 539 519 535 513 1569 538 542 516 1566 541 539 519 534 514 540 518 1564 542 +# +# file: Flipper-IRDB/ACs/LG/LG_AC_LP1417GSR.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8912 4459 593 1636 593 1640 599 525 600 528 597 533 602 532 593 544 601 1637 592 523 591 1639 600 1636 593 535 600 529 596 538 597 541 594 534 601 1629 600 1634 595 531 1719 1649 532 593 541 594 543 602 526 599 519 595 1640 599 525 600 529 596 1649 601 534 601 537 598 529 596 522 603 519 595 529 596 533 602 528 597 538 597 540 595 532 593 523 602 518 596 527 598 528 597 535 600 533 592 545 601 509 595 7882 598 519 595 524 601 521 593 535 600 530 595 538 597 1650 600 1637 602 514 600 517 597 526 599 527 598 532 593 541 594 544 601 525 600 515 599 519 595 527 598 529 596 534 601 532 593 545 600 526 599 519 595 551 574 524 601 526 599 533 602 532 593 545 600 526 599 517 597 523 602 522 603 525 600 532 593 541 594 543 602 525 600 516 598 522 592 530 595 533 602 529 596 539 596 541 594 532 593 524 601 518 596 527 598 528 597 533 602 531 594 543 592 533 602 1625 593 526 599 523 602 1636 603 1639 600 533 592 1657 593 1628 601 7882 597 521 593 527 598 526 599 529 596 535 600 535 600 538 597 531 594 1634 595 1641 598 527 598 531 594 535 600 532 593 542 593 535 600 518 596 524 601 521 593 533 602 528 597 537 598 539 596 528 597 520 594 525 600 521 593 533 602 528 597 536 599 537 598 527 598 517 597 522 603 521 593 1644 595 1646 593 1651 599 537 598 526 599 516 598 520 594 527 598 528 597 532 593 539 596 540 595 531 594 1638 601 1633 596 528 597 1645 594 1652 598 1649 601 535 600 509 595 +# +# file: Flipper-IRDB/ACs/LG/LP1015WNR.ir +# +name: POWER +type: parsed +protocol: NECext +address: 10 E7 00 00 +command: 06 F9 00 00 +# +# file: Flipper-IRDB/ACs/Midea/Midea_AC_MAW05R1WBL.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4454 4377 594 1560 591 486 589 1565 597 480 595 482 593 484 591 485 590 1564 598 1557 594 1560 591 1563 588 489 597 480 595 482 593 483 592 485 590 487 588 1565 597 1558 593 1562 589 487 588 489 597 1558 593 1561 590 1564 598 1557 594 1560 591 1563 588 1567 595 1560 591 1563 588 1566 596 1559 592 1562 589 1565 597 1558 593 1562 589 1565 597 1557 594 1561 590 486 590 488 598 479 596 1558 593 484 591 1563 588 489 597 1557 594 5161 4459 4371 601 476 589 1565 597 481 594 1560 592 1562 589 1565 597 1558 593 484 591 485 590 487 589 488 598 1556 595 1559 592 1563 588 1566 596 1559 592 1562 589 488 587 489 597 480 595 1559 592 1562 589 488 598 479 596 480 595 482 593 484 591 485 601 476 589 488 598 480 595 481 594 483 592 484 591 486 590 487 588 489 597 480 595 481 594 483 592 1562 589 1565 597 1558 593 483 592 1562 589 488 587 1567 595 482 593 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3439 1755 439 1262 435 1286 432 438 441 423 456 418 441 1282 436 433 436 431 438 1285 433 1314 435 408 461 1293 435 408 440 426 433 1289 460 1296 412 455 414 1312 406 1319 409 429 440 429 461 1267 441 426 464 406 442 1281 437 430 439 427 432 436 464 405 433 432 437 458 411 456 434 422 437 428 462 412 436 428 441 422 457 411 437 456 413 454 405 436 433 434 435 427 432 435 465 404 434 435 434 431 459 413 435 429 440 422 437 433 457 1270 438 1288 461 410 438 426 464 404 434 1293 435 1315 413 423 436 1287 462 407 431 434 435 435 434 433 467 415 433 1318 410 1286 463 409 439 1284 455 1301 438 410 438 426 464 1262 456 1269 439 429 461 410 469 407 462 1268 440 1285 433 461 408 456 413 1284 465 1261 457 414 455 1271 468 1277 431 1321 438 405 433 460 409 430 439 426 464 407 462 407 441 450 409 434 435 430 439 452 438 431 438 405 464 405 464 405 464 409 460 409 439 430 439 427 442 423 436 460 430 415 433 431 438 425 434 444 435 456 413 432 437 427 442 425 434 436 464 429 430 439 430 417 442 428 441 428 462 411 437 452 438 405 433 434 435 456 413 427 442 425 434 455 414 427 432 435 434 433 436 427 463 406 432 437 442 449 430 1268 460 1265 463 1262 466 405 464 406 442 422 437 1289 439 428 441 17052 3577 1746 407 1321 407 1294 434 460 409 431 459 439 409 1288 440 429 440 431 438 1309 430 1272 456 415 464 1289 408 433 457 412 436 1289 439 1284 465 404 434 1292 436 1289 439 428 441 450 409 1315 413 427 442 451 408 1294 434 432 437 430 439 428 462 406 432 432 458 414 455 414 434 430 439 428 441 426 433 436 433 432 437 454 405 438 441 428 431 434 456 418 441 448 431 411 437 429 440 425 434 433 436 458 411 425 434 433 436 457 412 1287 462 1263 455 419 461 408 440 430 439 1310 429 1272 435 460 409 1288 440 429 461 408 441 425 465 405 464 407 441 1286 432 1291 437 432 437 1315 413 1314 414 450 440 406 442 1283 456 1270 458 413 456 413 456 413 435 1297 431 1294 465 404 434 433 436 1314 414 1285 433 433 436 1288 440 1285 464 1264 433 433 436 453 416 425 434 460 409 434 435 432 437 454 415 423 436 431 459 424 435 430 460 413 435 430 439 423 456 413 435 431 438 455 414 427 432 435 434 455 414 426 464 406 432 437 442 422 457 414 434 431 438 424 435 435 455 414 455 416 432 433 436 457 412 426 464 410 438 453 437 412 436 437 463 409 439 425 434 455 414 426 433 437 432 433 436 433 436 457 433 412 436 453 437 406 432 435 465 1266 462 1263 434 1318 410 426 464 410 438 426 433 1293 435 434 435 +# +# file: Flipper-IRDB/ACs/Mitsubishi/Mitsubishi_SRK35ZS-W.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3199 1594 380 414 380 1208 379 415 389 405 389 1201 386 407 386 1202 385 409 384 408 385 1203 384 1203 384 1204 383 410 383 1206 381 412 382 1208 379 1207 380 1209 389 404 390 406 387 405 389 406 387 1201 386 1202 385 408 385 1204 383 409 384 1204 383 1205 382 412 382 411 382 413 380 1206 382 414 380 1208 379 414 379 416 388 1201 386 1201 386 1201 386 408 385 1202 385 1204 383 1204 383 1206 381 1205 382 1207 380 1207 380 1208 390 405 388 405 389 406 387 406 387 406 387 407 386 408 385 1202 385 1204 383 1203 384 411 382 1205 382 1205 382 1207 380 1207 381 414 390 404 379 414 380 1210 388 406 387 408 385 406 387 408 385 1202 385 1203 384 409 384 1205 382 1205 382 1206 381 1206 381 1208 379 415 389 404 389 1199 388 407 386 406 387 407 386 408 385 409 384 1202 385 1204 383 1204 383 1204 383 1205 382 412 381 1208 379 1208 379 415 389 404 390 406 387 406 387 407 386 1200 387 409 384 408 385 1202 385 1205 383 410 383 1205 382 1205 382 412 381 1207 380 1207 380 415 389 404 379 1209 389 406 387 405 388 1200 387 408 385 408 385 1202 385 1204 383 1204 383 1204 383 1208 379 1207 380 1207 380 1208 379 416 388 405 388 407 386 407 386 407 386 407 386 407 386 408 385 408 385 1204 383 1204 383 1205 382 1205 382 1207 380 1208 379 414 379 1210 388 406 387 406 387 406 387 407 386 407 386 409 384 1203 384 +# +name: TEMP+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3198 1595 389 404 379 1209 389 405 388 406 387 1200 387 407 386 1202 385 409 384 410 383 1203 384 1204 383 1179 408 413 380 1207 380 414 379 1209 389 1172 415 1200 387 406 387 409 384 408 385 409 384 1204 383 1205 382 410 383 1206 381 412 381 1206 381 1183 415 404 389 405 388 406 387 1200 387 406 387 1202 385 408 385 409 384 1204 383 1204 383 1205 382 412 381 1206 381 1181 406 414 390 1199 388 1173 414 1175 412 1175 412 1177 410 409 384 409 384 1205 382 410 383 411 382 412 381 412 382 412 381 1207 380 1209 389 405 389 1199 388 1174 413 1175 412 1175 412 1177 410 410 383 409 384 1205 382 412 381 412 381 413 380 413 380 1208 379 1207 380 414 379 1209 389 1173 414 1176 411 1177 410 1178 409 409 384 410 383 1206 381 411 382 412 381 412 382 413 381 413 380 1208 379 1208 379 1183 415 1173 414 1175 412 407 386 1203 384 1177 410 410 383 412 381 412 381 412 381 412 381 1207 380 414 379 414 379 1208 390 1199 388 405 388 1199 388 1200 387 409 384 1202 385 1177 410 410 383 412 381 1206 381 411 382 413 380 1207 380 413 380 414 380 1208 390 1199 388 1175 412 1175 412 1176 411 1179 408 1178 409 1179 408 412 381 413 380 414 379 414 379 415 389 404 379 414 379 416 388 405 389 1201 386 1200 387 1201 386 1177 410 1177 410 1179 408 411 382 1208 379 413 380 413 381 413 380 415 389 404 389 405 389 1199 388 +# +name: TEMP- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3200 1592 382 412 381 1206 381 414 379 414 379 1208 379 416 388 1200 387 406 387 407 386 1202 385 1176 411 1178 409 410 383 1179 408 411 382 1182 416 1172 415 1172 415 404 389 406 387 407 386 408 385 1201 386 1177 410 409 384 1179 408 412 381 1179 408 1181 406 413 380 413 380 414 379 1209 389 405 388 1199 388 406 387 408 385 1202 385 1179 408 1178 409 412 381 1180 407 1182 405 414 379 1182 416 1174 413 1174 413 1176 411 1176 411 410 383 410 383 1204 383 412 381 412 381 412 381 413 380 1209 389 1172 415 1174 413 406 387 1174 413 1177 410 1177 410 1179 408 410 383 412 381 413 380 1206 381 413 380 414 379 414 379 415 389 1199 388 1175 412 407 386 1177 410 1178 409 1178 409 1179 408 1180 407 413 380 414 379 1208 379 415 389 405 388 407 386 406 387 407 386 1201 386 1177 410 1178 409 1179 408 1180 407 412 381 1180 407 1182 405 416 388 405 388 406 387 407 386 407 386 1201 386 409 384 409 384 1204 383 1179 408 411 382 1180 407 1182 405 416 388 1172 415 1173 414 406 387 407 386 1201 386 409 384 410 383 1203 384 410 383 412 381 1206 381 1183 415 1173 414 1173 414 1174 413 1175 412 1178 409 1178 409 410 383 411 382 411 382 412 381 412 381 413 380 413 380 416 388 403 380 1208 379 1184 414 1175 412 1175 412 1176 411 1177 410 411 382 1178 409 411 382 412 381 413 380 413 380 413 380 413 380 1208 379 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3197 1595 390 404 379 1210 388 406 388 406 388 1201 386 407 386 1202 386 408 385 409 384 1205 383 1204 383 1206 382 412 381 1206 381 413 381 1207 381 1208 380 1209 389 405 389 406 387 405 389 407 387 1200 388 1201 386 408 385 1203 384 412 382 1205 383 1204 384 412 382 412 382 412 382 1207 381 413 381 1208 380 414 380 414 380 1209 389 1199 389 1201 386 1200 387 1202 385 408 385 409 384 1204 384 1205 383 1205 382 1205 383 412 382 413 380 1207 381 1209 389 406 388 405 389 405 389 405 389 1200 387 1203 384 1201 386 409 384 1203 384 1205 382 1205 383 1205 383 411 383 412 382 412 382 1207 380 414 380 415 389 404 379 417 387 1199 389 1199 389 1201 386 1204 384 1203 384 1203 384 1203 384 1204 384 411 382 412 382 412 382 412 382 413 380 413 381 414 380 414 380 1209 389 1199 389 1199 389 1200 387 1201 386 408 385 1203 385 1203 384 409 384 412 381 410 383 413 381 411 383 1206 382 413 381 413 380 1207 381 1209 389 404 379 1209 389 1199 389 407 386 1201 386 1202 385 408 385 410 384 1203 384 410 383 411 383 1204 384 412 382 412 382 1206 381 1207 380 1208 379 1211 387 1199 389 1201 386 1201 386 1202 385 408 385 410 383 409 385 409 385 410 384 410 384 410 383 411 383 412 382 1207 381 1206 382 1209 389 1197 380 1210 388 1199 389 406 387 1200 387 408 385 407 386 408 385 409 384 408 385 409 384 1204 384 +# +# file: Flipper-IRDB/ACs/Panasonic/Panasonic_CWA75C4179.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3472 1744 416 457 415 1306 418 463 419 466 416 473 419 474 418 478 414 457 415 458 414 463 419 462 420 465 417 472 420 1316 418 479 413 458 414 459 413 464 418 463 419 466 416 473 419 1318 416 1324 420 1295 418 454 418 459 413 1312 422 463 419 470 422 471 421 475 417 454 418 455 417 460 422 459 413 472 420 469 413 480 412 485 417 453 419 454 418 459 413 468 414 471 421 468 414 479 413 484 418 452 420 453 419 458 414 468 414 471 421 467 415 478 414 483 419 451 421 453 419 1301 412 1312 422 463 419 470 422 471 421 476 416 433 418 10535 3469 1746 414 459 413 1308 415 465 417 468 414 475 417 476 416 481 421 449 413 461 421 455 417 465 417 467 415 474 418 1319 415 482 420 450 422 451 421 457 415 466 416 469 413 476 416 1320 414 1327 417 1297 416 457 415 462 420 1305 419 466 416 473 419 474 418 478 414 457 415 458 414 463 419 462 420 465 417 472 420 473 419 477 415 456 416 1301 412 464 418 463 419 1310 413 1319 415 1321 413 485 417 453 419 454 418 459 413 1312 422 1307 416 472 420 1317 416 480 412 459 413 460 412 465 417 464 418 467 415 474 418 475 417 479 413 1302 422 1295 418 1302 421 1303 421 1308 415 473 419 1318 416 481 421 1293 420 1296 417 460 412 1313 421 1307 416 473 419 473 419 478 414 457 415 458 414 463 419 462 420 465 417 472 420 473 419 477 415 456 416 457 415 1306 418 1307 416 1312 422 467 415 478 414 483 419 451 421 452 420 457 415 467 415 469 413 476 416 1321 413 1328 416 1298 415 458 414 463 419 462 420 465 417 472 420 472 420 477 415 456 416 457 415 462 420 461 421 464 418 470 422 471 421 476 416 454 418 1299 414 463 419 461 421 464 418 471 421 472 420 477 415 1299 414 459 413 464 418 463 419 466 416 473 419 473 419 478 414 457 415 458 414 463 419 462 420 465 417 472 420 473 419 477 415 456 416 457 415 1306 417 1307 416 468 414 1319 415 478 414 483 419 430 421 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3473 1716 444 455 417 1304 420 461 421 464 418 471 421 471 421 476 416 455 417 456 416 461 421 460 412 473 419 469 413 1324 420 477 415 455 417 457 415 462 420 461 421 463 419 470 422 1315 419 1321 413 1302 422 451 421 456 416 1309 414 470 422 467 415 478 414 482 420 451 421 452 420 457 415 466 416 469 413 476 416 477 415 481 421 450 412 461 421 456 416 465 417 468 414 474 418 475 417 480 412 458 414 459 413 464 418 463 419 466 416 473 419 474 418 478 414 457 415 458 414 1307 417 1308 416 469 413 476 416 477 415 481 421 428 413 10540 3465 1751 419 454 418 1302 422 459 413 472 420 469 413 480 412 485 417 453 419 454 418 459 413 468 414 471 421 468 414 1322 422 475 417 454 418 455 417 460 412 469 413 472 420 468 414 1323 421 1320 414 1300 413 460 412 465 417 1307 417 468 414 475 417 476 416 481 421 449 413 460 422 455 417 464 418 467 415 474 418 474 418 479 413 458 414 459 413 464 418 463 419 1309 415 1318 416 1321 413 484 418 452 420 453 419 458 414 1311 413 1316 418 471 421 1315 419 478 414 457 415 458 414 463 419 462 420 465 417 472 420 472 420 477 415 1299 414 1302 422 1299 414 1310 414 1315 419 470 422 1315 419 478 414 1300 413 1303 421 456 416 1309 415 1314 420 469 413 480 412 485 417 453 419 454 418 459 413 468 414 471 421 468 414 479 413 484 418 452 420 453 419 1302 422 1303 421 1307 417 473 419 473 419 478 414 457 415 458 414 463 419 462 420 465 417 471 421 1316 418 1322 422 1293 420 452 420 457 415 466 416 469 413 476 416 477 415 482 420 450 422 451 421 456 416 465 417 468 414 475 417 476 416 480 412 459 413 1304 420 457 415 466 416 469 413 476 416 477 415 481 421 1293 420 453 419 458 414 467 415 470 412 477 415 477 415 482 420 450 422 451 421 456 416 465 417 468 414 475 417 476 416 481 421 449 413 1304 420 457 415 1310 414 471 421 1311 413 481 421 475 417 432 419 +# +name: TEMP+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3466 1750 420 453 419 1302 422 459 413 472 420 469 413 480 412 485 417 453 419 455 417 460 412 469 413 472 420 469 413 1324 420 476 416 455 417 456 416 461 421 460 422 463 419 470 422 1315 419 1322 412 1302 422 452 420 457 415 1310 414 471 421 468 414 479 413 484 418 452 420 453 419 458 414 468 414 471 421 467 415 478 414 483 419 452 420 453 419 458 414 467 415 470 412 477 415 478 414 483 419 451 421 452 420 457 415 466 416 469 413 476 416 477 415 482 420 450 422 451 421 1300 413 1312 412 473 419 470 412 481 421 475 417 432 419 10572 3473 1743 417 456 416 1305 419 462 420 465 417 472 420 473 419 477 415 456 416 457 415 463 419 461 421 464 418 471 421 1316 418 479 413 457 415 459 413 464 418 463 419 466 416 473 419 1317 417 1324 420 1294 419 454 418 459 413 1312 422 463 419 470 422 471 421 476 416 454 418 455 417 461 421 460 412 473 419 469 413 480 422 475 417 453 419 1298 415 462 420 461 421 1308 415 1317 417 1320 414 483 419 451 421 452 420 1301 412 1312 422 1307 417 473 419 1317 417 480 422 449 412 1304 419 1301 412 1312 422 1307 416 1316 418 1319 415 1326 418 453 419 1298 415 462 420 461 421 464 418 1314 420 1317 417 480 422 449 412 460 422 1299 414 467 415 1313 421 468 414 480 412 484 418 453 419 454 418 459 413 468 414 471 421 468 414 479 413 484 418 452 420 453 419 1302 422 1303 421 1308 415 474 418 474 418 479 413 458 414 459 413 464 418 463 419 466 416 473 419 1318 416 1324 420 1295 418 454 418 459 413 468 414 471 421 468 414 479 413 484 418 452 420 454 418 459 413 468 414 471 421 467 415 478 414 483 419 452 420 1297 416 460 422 459 413 472 420 469 413 480 412 484 418 1297 416 456 416 461 421 460 422 463 419 470 422 471 421 476 416 454 418 455 417 460 422 459 413 472 420 469 413 480 412 485 417 453 419 454 418 1303 421 1304 420 466 416 1316 418 476 416 480 422 1271 412 +# +name: TEMP- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3474 1742 417 456 416 1305 418 462 420 465 417 472 420 473 419 478 414 456 416 458 414 463 419 462 420 465 417 472 420 1316 418 479 413 458 414 459 413 464 418 463 419 466 416 474 418 1318 416 1325 419 1296 417 455 417 460 422 1303 421 464 418 471 421 472 420 477 415 456 416 457 415 462 420 461 421 464 418 471 421 472 420 477 415 455 417 456 416 462 420 461 421 464 418 471 421 471 421 476 416 455 417 456 416 461 421 460 422 463 419 470 422 471 421 476 416 454 418 456 416 1305 419 1306 417 467 415 474 418 475 417 480 412 437 414 10576 3468 1747 413 461 421 1299 414 467 415 470 422 467 415 478 414 483 419 451 421 452 420 458 414 467 415 470 412 477 415 1321 413 485 417 453 419 454 418 459 413 469 413 472 420 469 413 1323 421 1320 414 1301 412 460 422 456 416 1309 414 470 422 467 415 478 414 483 419 451 421 452 420 457 415 467 415 470 412 477 415 478 414 482 420 451 421 1296 417 459 413 468 414 1315 419 1314 420 1317 417 480 422 449 412 460 422 455 417 1308 415 1313 421 469 413 1323 421 476 416 455 417 1300 413 1308 415 1309 414 1314 420 1313 421 1316 418 1323 421 450 422 1295 418 458 414 468 414 471 421 1311 413 1324 420 477 415 456 415 457 415 1306 417 464 418 1311 412 476 416 477 415 482 420 450 422 451 421 456 416 466 416 469 413 476 416 477 415 481 421 450 422 451 421 1300 413 1311 412 1316 418 472 420 473 419 477 415 456 416 457 415 463 419 462 420 465 417 472 420 1316 418 1323 421 1294 419 453 419 458 414 468 414 471 421 467 415 478 414 483 419 452 420 453 419 458 414 467 415 471 421 467 415 478 414 483 419 452 420 1297 416 460 422 459 413 472 420 469 413 480 412 485 417 1297 416 457 415 462 420 461 421 464 418 471 421 472 420 477 415 455 417 457 415 462 420 461 421 464 418 471 421 471 421 476 416 455 417 456 416 461 421 1304 419 465 417 1316 418 476 416 480 422 1271 422 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3467 1749 420 452 420 1301 412 468 414 472 420 468 414 479 413 484 418 453 419 454 418 459 413 469 413 472 420 469 413 1323 421 476 416 455 417 457 415 462 420 461 421 464 418 471 421 1315 419 1322 422 1293 420 452 420 458 414 1311 412 472 420 469 413 480 412 485 417 453 419 455 417 460 422 459 413 472 420 469 413 480 412 485 417 453 419 455 417 460 412 469 413 472 420 469 413 480 412 485 417 453 419 455 417 460 422 459 413 472 420 469 413 480 412 485 417 453 419 455 417 1304 419 1305 418 466 416 473 419 474 418 479 413 436 415 10538 3465 1751 419 454 418 1303 420 461 421 464 418 471 421 472 420 477 415 455 417 457 415 462 420 461 421 464 418 471 421 1315 418 479 413 457 415 459 412 464 418 463 419 466 416 473 419 1318 415 1325 419 1295 418 455 416 461 421 1303 420 465 417 472 420 473 419 478 414 456 416 458 414 463 419 462 420 465 417 472 420 473 419 478 414 456 416 1301 412 465 417 464 418 1311 412 476 416 477 415 482 420 451 421 452 420 457 415 1310 413 471 421 468 414 1323 421 476 416 455 417 456 416 462 420 461 421 464 418 471 421 471 421 476 416 1299 414 1302 421 1299 414 1311 412 1316 417 471 421 1316 417 479 413 1302 421 1295 418 459 412 1312 421 1307 416 472 420 473 419 478 414 457 415 458 414 464 418 463 419 466 416 473 419 473 419 478 414 457 415 458 414 1307 416 1309 414 1314 419 469 413 480 422 475 417 454 418 455 417 460 422 459 413 473 419 469 413 1324 420 1321 412 1302 421 452 420 457 415 466 416 469 413 476 416 477 415 482 420 451 421 452 420 457 414 467 415 470 412 477 415 478 414 483 419 451 421 1296 417 460 412 469 413 472 420 469 413 480 412 485 417 1297 416 457 415 462 420 461 421 464 418 471 421 472 420 477 415 456 416 457 414 462 420 461 421 464 418 471 421 472 420 477 415 456 416 457 414 1306 417 1307 416 1312 421 1311 412 481 421 1319 414 1279 414 +# +# file: Flipper-IRDB/ACs/Remko/Remko_RKL.ir +# +name: POWER +type: parsed +protocol: NECext +address: 86 6B 00 00 +command: 12 ED 00 00 +# +name: TEMP+ +type: parsed +protocol: NECext +address: 86 6B 00 00 +command: 1A E5 00 00 +# +name: TEMP- +type: parsed +protocol: NECext +address: 86 6B 00 00 +command: 1E E1 00 00 +# +name: MODE +type: parsed +protocol: NECext +address: 86 6B 00 00 +command: 02 FD 00 00 +# +# file: Flipper-IRDB/ACs/Rinnai/Rinnai_AC.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9026 4519 590 1654 616 1657 623 574 561 582 563 582 563 583 562 1688 592 1656 675 1627 593 1650 620 1654 677 521 563 1660 620 1656 614 1664 616 581 564 578 567 575 560 582 563 581 564 579 566 1684 596 1655 615 1661 619 577 568 574 561 581 564 580 565 579 566 580 565 582 563 581 564 577 568 574 561 582 563 580 565 579 566 1657 613 1664 616 582 563 578 567 575 560 583 562 581 564 580 565 582 563 584 561 582 563 578 567 575 560 583 562 581 564 580 565 1659 621 579 566 578 567 574 561 581 564 579 566 577 568 576 569 577 568 579 566 578 567 574 561 580 565 578 567 576 569 575 560 587 568 579 566 577 568 573 562 580 565 578 567 576 569 575 560 586 569 552 593 577 568 573 562 580 565 577 568 576 559 585 560 586 569 552 593 576 569 1703 567 575 560 1713 567 577 568 576 569 577 568 553 592 578 567 1704 566 1707 563 1656 614 1662 618 1659 621 577 568 553 592 1706 564 +# +# file: Flipper-IRDB/ACs/Samsung/Samsung_AC_AR12K.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 270 18152 3021 8955 523 499 495 1497 492 504 500 468 526 496 498 498 496 499 495 501 493 502 492 1499 500 496 498 524 470 1521 498 497 497 499 495 1496 492 1499 500 1491 497 1494 494 1497 502 494 500 495 499 497 497 498 496 500 494 528 466 530 464 531 473 522 493 503 491 504 500 495 499 497 497 498 496 500 494 501 493 503 491 504 500 495 499 496 498 498 496 499 495 501 493 529 465 531 473 522 472 523 492 504 490 505 499 496 498 498 496 499 495 1496 492 1499 500 1492 496 1494 525 2947 2999 8953 525 1519 469 499 516 507 497 498 496 500 494 501 493 503 491 504 500 495 499 1492 496 499 495 501 493 1498 501 495 499 1492 496 1522 466 1524 496 1496 492 1499 500 1492 496 499 495 500 494 502 492 504 500 495 499 496 498 498 496 499 495 500 494 502 492 530 474 521 473 523 523 472 522 474 489 506 498 497 497 499 495 500 494 502 492 503 501 494 500 496 498 497 497 499 495 500 494 502 492 503 501 521 473 523 471 524 522 474 520 475 498 497 497 499 495 500 494 2978 2999 8952 525 1492 496 499 495 501 493 503 491 504 500 495 499 497 497 525 469 526 468 1524 516 479 494 501 493 503 491 504 500 495 499 497 497 1494 494 1497 492 1500 499 1492 496 499 495 1497 491 531 473 1518 522 1469 499 496 498 498 496 500 494 1497 491 1500 499 1492 496 499 495 501 493 502 492 504 500 495 499 523 471 525 469 526 520 1472 516 1475 493 502 492 504 500 495 499 1492 496 499 495 501 493 502 492 504 500 495 499 496 498 498 496 1522 466 1525 525 1466 491 1500 499 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 552 17959 3004 8946 521 530 474 1490 519 477 517 505 499 497 497 498 496 500 494 501 493 503 501 1464 524 497 497 499 495 1470 518 504 500 495 499 1493 495 1496 492 1499 520 1472 516 1475 524 498 496 500 494 501 493 503 501 494 500 496 498 497 497 499 495 501 493 502 492 531 473 522 472 524 470 525 490 506 498 497 497 499 495 501 493 502 492 504 500 495 499 497 497 498 496 500 494 501 493 503 501 494 500 496 498 524 470 526 468 527 467 529 496 1469 519 1472 527 1465 523 1468 520 2979 2997 8954 523 1469 519 502 492 504 500 495 499 524 470 525 469 527 467 528 497 499 495 1470 518 503 501 495 499 1466 522 500 494 1471 528 1464 524 497 497 1468 520 1446 604 1440 496 525 469 1496 523 499 495 1470 518 1473 526 497 497 498 496 500 494 1471 528 1464 524 1467 521 501 493 529 465 531 473 522 472 524 491 1474 525 497 497 1469 519 502 492 1474 525 1466 522 500 494 1471 528 494 500 496 498 1494 494 528 466 529 475 521 494 502 492 503 491 1474 525 1467 521 1470 518 1474 525 +# +name: TEMP+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 451 18082 2995 8958 519 529 465 1527 472 524 491 504 490 506 498 497 497 499 495 501 493 502 492 1500 499 497 497 498 496 1496 492 503 501 494 500 1492 496 1522 466 1525 494 1497 491 1500 498 498 496 499 495 501 493 503 501 494 500 495 499 497 497 499 495 500 494 502 492 503 501 495 499 523 471 525 469 526 468 528 497 498 496 500 494 502 492 503 501 495 499 496 498 498 496 499 495 501 493 502 492 504 500 495 499 497 497 499 495 527 467 529 465 1500 519 1499 489 1502 497 1495 493 2979 2997 8955 522 1469 519 503 501 494 500 496 498 497 497 499 495 501 493 529 465 531 473 1518 491 505 489 506 498 498 496 1495 493 1498 501 1491 497 499 495 1496 492 1500 499 1492 496 527 467 1525 494 501 493 1498 490 1502 497 499 495 500 494 502 492 1499 500 1492 496 1496 492 503 501 494 500 496 498 524 470 526 468 527 519 1446 522 1497 491 1500 499 1493 495 501 493 502 492 504 500 495 499 497 497 1494 494 501 493 503 501 521 473 523 471 524 522 1470 498 1494 494 1497 502 1490 498 +# +name: TEMP- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 701 17814 3056 8923 554 441 522 1496 492 504 490 505 499 497 497 498 496 500 494 502 492 503 501 1491 497 498 496 500 494 1497 502 494 500 523 471 1520 468 1523 496 1496 492 1499 500 1492 496 499 495 501 493 503 501 494 500 496 498 497 497 499 495 501 493 502 492 531 473 522 472 524 470 525 490 506 498 498 496 499 495 501 493 503 491 504 500 495 499 497 497 499 495 500 494 502 492 504 500 495 499 497 497 525 469 527 467 528 466 530 495 501 493 1498 501 1491 497 1494 494 1498 500 2972 3004 8948 518 1500 499 470 524 498 496 500 494 529 465 531 473 522 493 530 464 505 489 1502 497 499 495 501 493 1498 501 1491 497 1494 494 1498 501 495 499 1492 496 1522 497 1495 493 502 492 1500 499 497 497 1494 494 1497 502 495 499 496 498 498 496 1496 492 1499 500 1518 470 526 468 527 498 498 496 500 494 501 493 503 491 505 499 1492 496 1495 493 1498 501 495 499 497 497 499 495 500 494 502 492 1527 472 523 523 473 490 506 498 497 497 499 495 1497 491 1500 499 1492 496 1496 492 +# +# file: Flipper-IRDB/ACs/Samsung/Samsung_Wind-Free.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 606 17832 2994 8936 520 501 496 1491 494 501 496 498 489 532 465 529 488 505 492 502 495 499 488 1499 496 499 498 495 492 1496 499 1463 522 499 498 1463 522 1467 517 1469 526 1491 493 1495 520 500 487 507 490 504 493 500 497 497 490 504 493 501 496 498 489 505 492 501 496 498 499 495 492 502 495 499 498 522 465 529 468 526 492 502 495 499 488 506 491 503 494 499 498 496 491 503 494 500 497 497 490 504 493 500 497 497 490 504 493 500 497 497 490 531 466 528 469 1518 487 1475 520 2947 3018 8939 517 1471 524 496 491 503 494 500 497 497 490 504 493 500 497 497 490 504 493 1521 464 530 467 527 491 1471 514 507 490 1471 524 1465 519 1468 517 1472 523 1465 520 1468 517 477 520 501 496 497 490 531 466 528 469 525 493 501 496 498 489 505 492 502 495 498 499 495 492 502 495 499 498 495 492 502 495 499 498 496 491 502 495 499 498 496 491 529 468 526 471 523 495 499 488 506 491 503 494 499 498 496 491 503 494 500 497 496 491 503 494 500 497 497 490 503 494 2973 2992 8939 517 1469 526 522 465 529 488 506 491 503 494 499 488 506 491 503 494 500 497 1490 495 499 498 496 491 1497 498 1464 520 1468 517 1470 525 524 463 1498 517 1471 524 1465 520 1468 517 1471 524 1465 520 1468 517 1472 523 497 490 504 493 501 496 1491 494 1496 519 1469 516 504 493 501 496 498 489 505 492 501 496 498 499 495 492 502 495 1492 493 1469 526 495 492 529 468 1492 513 1476 519 502 495 498 489 505 492 502 495 499 498 496 491 503 494 499 498 496 491 1497 498 1464 541 +# +# file: Flipper-IRDB/ACs/Toshiba/Toshiba_RAS13SKV2E.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4387 4349 553 1609 553 1607 555 1605 546 1613 549 531 550 530 551 1610 552 527 554 526 555 526 555 525 556 524 557 1602 549 1611 551 529 552 1608 554 526 555 525 556 525 556 524 546 533 548 532 549 1611 551 1608 554 1606 556 1604 558 1603 548 1611 551 1609 553 1607 555 525 556 525 556 524 557 523 547 533 548 533 548 532 549 531 550 530 551 1607 555 526 555 1605 557 1603 548 531 550 531 550 530 551 529 552 528 553 527 554 526 555 526 555 525 556 524 546 1612 550 1610 552 1608 554 527 554 526 555 526 555 525 556 524 557 523 547 533 548 532 549 531 550 1609 553 1607 555 525 556 525 556 1603 548 1612 550 530 551 7454 4385 4352 549 1611 551 1609 553 1608 554 1606 556 525 556 524 557 1602 549 531 550 531 550 530 551 530 551 529 552 1633 529 1604 558 523 558 1601 550 531 550 530 551 530 551 529 552 528 553 527 554 1604 558 1603 548 1611 551 1609 553 1608 554 1606 556 1604 558 1602 549 532 549 531 550 530 551 530 551 529 552 528 553 527 554 526 555 525 556 1603 548 532 549 1610 552 1608 554 527 554 527 554 526 555 525 556 524 557 523 547 533 548 532 549 531 550 530 551 1608 554 1606 556 1604 558 523 547 533 548 532 549 531 550 530 551 529 552 528 553 527 554 526 555 1605 557 1602 549 531 550 531 550 1609 553 1607 555 526 555 +# +# file: Flipper-IRDB/ACs/Toshiba/Toshiba_RG57H4.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4413 4375 541 1579 568 504 569 1576 571 501 562 510 563 534 539 507 566 1578 569 1577 570 1575 572 500 563 509 564 508 565 506 567 1578 569 502 571 501 562 1583 564 1581 566 1579 568 504 569 503 570 1574 563 510 563 1607 540 506 567 505 568 503 570 502 571 1573 564 508 565 1580 567 1578 569 503 570 502 571 500 563 535 538 507 566 1579 568 1577 570 502 571 500 563 536 537 1581 566 506 567 504 569 503 570 1574 563 5170 4409 4379 537 509 564 1581 566 506 567 1577 570 1575 572 1573 564 1582 565 507 566 505 568 504 569 1575 572 1573 564 1582 565 1580 567 505 568 1576 571 1574 563 509 564 508 565 532 541 1577 570 1575 572 500 563 1582 565 507 566 1578 569 1576 571 1574 562 1583 564 508 565 1579 568 504 569 502 571 1574 563 1582 565 1580 567 1578 569 1576 571 501 562 510 563 1581 566 1579 568 1577 570 501 572 1573 564 1581 566 1579 568 504 569 +# +# file: Flipper-IRDB/ACs/Whynter/Whynter_AC.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 781 710 2930 2876 775 716 781 735 752 2175 779 711 776 2177 746 745 773 2232 753 2173 749 768 750 2177 745 745 773 743 754 737 750 741 746 744 754 737 771 746 751 739 748 2178 776 742 755 2172 771 719 778 2227 747 744 754 2200 754 737 750 2203 751 741 746 2181 773 744 753 737 750 741 746 +# # Old SAMSUNG AC # name: POWER diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index 3d46218717..12088838ee 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -9,7 +9,7 @@ Version: 1 # HUGE thank you to Amec0e for continued maintenance! ##################################################### # -# Updated 15th August 2022 +# Updated 23th August 2022 # # | SPEAKERS | # @@ -562,6 +562,26 @@ type: parsed protocol: NECext address: 0A 1D 00 00 command: 01 FE 00 00 +# +# CREATIVE +# +name: VOL+ +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 06 00 00 00 +# +name: VOL- +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 07 00 00 00 +# +name: MUTE +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 1E 00 00 00 # # KLIPSCH # @@ -952,6 +972,24 @@ protocol: NEC address: 00 00 00 00 command: 40 00 00 00 # +name: VOL+ +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 41 00 00 00 +# +name: VOL- +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 45 00 00 00 +# +name: MUTE +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 48 00 00 00 +# # XIAOMI # name: VOL+ @@ -1114,6 +1152,26 @@ protocol: NECext address: D2 03 00 00 command: 05 FA 00 00 # +# PHILLIPS +# +name: POWER +type: parsed +protocol: RC5 +address: 14 00 00 00 +command: 0C 00 00 00 +# +name: VOL- +type: parsed +protocol: RC5 +address: 14 00 00 00 +command: 11 00 00 00 +# +name: VOL+ +type: parsed +protocol: RC5 +address: 14 00 00 00 +command: 10 00 00 00 +# # REGA # name: MUTE diff --git a/assets/resources/infrared/assets/projectors.ir b/assets/resources/infrared/assets/projectors.ir new file mode 100644 index 0000000000..413fdd5e71 --- /dev/null +++ b/assets/resources/infrared/assets/projectors.ir @@ -0,0 +1,326 @@ +Filetype: IR signals file +Version: 1 +# +# file: Flipper-IRDB/Projectors/Anker/NebulaMarsLite.ir +# +name: POWER +type: parsed +protocol: NECext +address: 80 19 00 00 +command: 10 EF 00 00 +# +name: VOL+ +type: parsed +protocol: NECext +address: 80 19 00 00 +command: 1C E3 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: 80 19 00 00 +command: 46 B9 00 00 +# +# file: Flipper-IRDB/Projectors/Anker/Nebula_Capsule_Mini_Projector.ir +# +name: POWER +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 51 00 00 00 +# +# file: Flipper-IRDB/Projectors/BenQ/BenQ.ir +# +name: POWER +type: parsed +protocol: NECext +address: 40 40 00 00 +command: 0A F5 00 00 +# +# file: Flipper-IRDB/Projectors/BenQ/BenQ_W1050.ir +# +name: POWER +type: parsed +protocol: NECext +address: 00 30 00 00 +command: 4E B1 00 00 +# +name: VOL+ +type: parsed +protocol: NECext +address: 00 30 00 00 +command: 0E F1 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: 00 30 00 00 +command: 0D F2 00 00 +# +# file: Flipper-IRDB/Projectors/BenQ/BenQ_W1070.ir +# +name: POWER +type: parsed +protocol: NECext +address: 00 30 00 00 +command: 4F B0 00 00 +# +name: MUTE +type: parsed +protocol: NECext +address: 00 30 00 00 +command: 14 EB 00 00 +# +# file: Flipper-IRDB/Projectors/BrandUnknown/LED_Smart_Home_Theater_Projector.ir +# +name: POWER +type: parsed +protocol: NECext +address: 08 16 00 00 +command: 87 78 00 00 +# +name: MUTE +type: parsed +protocol: NECext +address: 08 16 00 00 +command: C8 37 00 00 +# +# file: Flipper-IRDB/Projectors/Byintek/Byintek_P10.ir +# +name: POWER +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 01 00 00 00 +# +name: MUTE +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 02 00 00 00 +# +name: VOL+ +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 28 00 00 00 +# +name: VOL- +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 29 00 00 00 +# +# file: Flipper-IRDB/Projectors/Casio/Casio_YT-130.ir +# +name: POWER +type: parsed +protocol: NECext +address: 84 F4 00 00 +command: 0B F4 00 00 +# +# file: Flipper-IRDB/Projectors/Eiki/Eiki_Projector.ir +# +name: POWER +type: parsed +protocol: NECext +address: 33 00 00 00 +command: 00 FF 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: 33 00 00 00 +command: 1E E1 00 00 +# +name: VOL+ +type: parsed +protocol: NECext +address: 33 00 00 00 +command: 1D E2 00 00 +# +name: MUTE +type: parsed +protocol: NECext +address: 33 00 00 00 +command: 0B F4 00 00 +# +# file: Flipper-IRDB/Projectors/Epson/Epson.ir +# +name: POWER +type: parsed +protocol: NECext +address: 83 55 00 00 +command: 90 6F 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: 83 55 00 00 +command: 99 66 00 00 +# +name: VOL+ +type: parsed +protocol: NECext +address: 83 55 00 00 +command: 98 67 00 00 +# +# file: Flipper-IRDB/Projectors/Minolta/Minolta_MN674.ir +# +name: POWER +type: parsed +protocol: NECext +address: 00 DF 00 00 +command: 1C E3 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: 00 DF 00 00 +command: 4F B0 00 00 +# +name: VOL+ +type: parsed +protocol: NECext +address: 00 DF 00 00 +command: 4B B4 00 00 +# +# file: Flipper-IRDB/Projectors/Optoma/Optoma_Profomo_L-27-5KEY.ir +# +name: POWER +type: parsed +protocol: NEC +address: 32 00 00 00 +command: 02 00 00 00 +# +name: POWER +type: parsed +protocol: NEC +address: 32 00 00 00 +command: 2E 00 00 00 +# +name: MUTE +type: parsed +protocol: NEC +address: 32 00 00 00 +command: 52 00 00 00 +# +# file: Flipper-IRDB/Projectors/Philips/Philips_NeoPix_Prime_Projector.ir +# +name: POWER +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 41 00 00 00 +# +name: VOL+ +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 51 00 00 00 +# +name: VOL- +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 56 00 00 00 +# +name: MUTE +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 5A 00 00 00 +# +# file: Flipper-IRDB/Projectors/Sony/Sony_RM_PJ24.ir +# +name: POWER +type: parsed +protocol: SIRC15 +address: 54 00 00 00 +command: 15 00 00 00 +# +# file: Flipper-IRDB/Projectors/ViewSonic/ViewSonic_Projector_PA503W-2.ir +# +name: VOL+ +type: parsed +protocol: NECext +address: 83 F4 00 00 +command: 82 7D 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: 83 F4 00 00 +command: 83 7C 00 00 +# +name: MUTE +type: parsed +protocol: NECext +address: 83 F4 00 00 +command: 14 EB 00 00 +# +# file: Flipper-IRDB/Projectors/Vivitek/Vivitek.ir +# +name: POWER +type: parsed +protocol: NEC +address: 31 00 00 00 +command: 91 00 00 00 +# +name: POWER +type: parsed +protocol: NEC +address: 31 00 00 00 +command: 90 00 00 00 +# +name: VOL+ +type: parsed +protocol: NEC +address: 31 00 00 00 +command: D0 00 00 00 +# +name: MUTE +type: parsed +protocol: NEC +address: 31 00 00 00 +command: 89 00 00 00 +# +# 3M +# +name: POWER +type: parsed +protocol: NECext +address: 86 00 00 00 +command: 00 00 00 00 +# +name: VOL+ +type: parsed +protocol: NECext +address: 86 00 00 00 +command: 30 00 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: 86 00 00 00 +command: 31 00 00 00 +# +name: MUTE +type: parsed +protocol: NECext +address: 86 00 00 00 +command: 32 00 00 00 +# +# Boxlight +# +name: POWER +type: parsed +protocol: NECext +address: 30 00 00 00 +command: 00 00 00 00 +# +name: POWER +type: parsed +protocol: NECext +address: 87 4E 00 00 +command: 0D 00 00 00 diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir index e2d8197827..8f3d990205 100755 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -11,7 +11,7 @@ Version: 1 # Also a HUGE thank you to Amec0e for continued maintenance! ############################################################ # -# Updated on 17th August 2022 +# Updated on 21th August 2022 # name: POWER type: parsed @@ -117,8 +117,6 @@ protocol: Samsung32 address: 0e 00 00 00 command: 14 00 00 00 # -# -# name: VOL- type: parsed protocol: Samsung32 @@ -1765,8 +1763,6 @@ protocol: NECext address: 02 7D 00 00 command: 15 EA 00 00 # -# -# name: POWER type: parsed protocol: NECext @@ -2369,6 +2365,7 @@ type: parsed protocol: NEC address: 01 00 00 00 command: 17 00 00 00 +# # BRANDT # name: POWER @@ -2830,8 +2827,6 @@ type: parsed protocol: NEC address: A0 00 00 00 command: 1F 00 00 00 -# -# ROKU # # SAMSUNG # @@ -3051,7 +3046,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 3994 3986 512 1989 515 1986 518 1982 512 1989 515 985 517 983 519 2008 486 988 514 1987 517 1983 521 979 513 987 515 986 516 984 518 982 520 980 512 1988 516 1985 519 981 521 1980 514 986 516 984 518 2009 485 1990 514 9041 3994 3986 511 1989 515 1985 519 1982 512 1989 515 984 518 982 520 1981 513 987 515 1986 518 1982 512 988 514 986 516 984 518 983 519 981 521 979 513 1987 517 1984 520 980 512 1989 515 984 518 982 520 2007 487 1988 516 9038 4028 3952 514 1986 518 1982 512 1989 515 1985 519 980 512 989 513 2013 491 983 519 1982 512 1989 515 984 519 982 520 980 522 979 513 987 515 985 517 1983 521 1980 514 986 516 1985 519 980 512 989 513 2013 491 1984 520 # -# # WBOX # name: POWER From 94f440d286001c1d7b1096f01658a6605c87abb4 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 24 Aug 2022 03:55:13 +0300 Subject: [PATCH 29/78] update readme/changelog & some fixes --- CHANGELOG.md | 20 ++++++++++++------ ReadMe.md | 5 ++++- .../desktop/views/desktop_view_slideshow.c | 4 ++-- applications/picopass/picopass_worker.c | 2 +- applications/unirfremix/application.fam | 2 +- assets/slideshow/update_default/frame_00.png | Bin 2211 -> 2958 bytes .../{UniRFRemix.md => SubGHzRemotePlugin.md} | 0 7 files changed, 22 insertions(+), 11 deletions(-) rename documentation/{UniRFRemix.md => SubGHzRemotePlugin.md} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f48929acb..64ed851a2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,18 @@ ### New changes -* Wifi Marauder app update (by @0xchocolate) -* Updated Universal remote assets (by @Amec0e) -* Fixed music player -* Fixed typos in subghz encoders -* OFW: New NFC info screens -* OFW: U2F fixes +* New universal remote for projectors +* OFW: New LF-RFID subsystem (New protocols, Animal tags support) +* Updated universal remote assets (by @Amec0e) +* Renamed UniRF Remix -> Sub-GHz Remote +* Replaced Hex/Dec converter with Multi Converter plugin [(by theisolinearchip)](https://github.com/theisolinearchip/flipperzero_stuff) +* New update screen, readme pictures (by @Svaarich) +* Fixed crash if Center button is pressed on the "update success" screen via screensharing +* Temporary disabled one log call in picopass plugin to fix crash/freeze on Read screen +* OFW: Picopass load/info/delete +* OFW: SubGhz: add protocol Magellen +* OFW: Fix mifare ultralight/ntag unlock +* OFW: Dolphin level thresholds update +* OFW: Add MFC 1/4K 4/7bUID to "Add Manually" +* OFW: Other fixes and changes **Note: Prefer installing using web updater or by self update package, all needed assets will be installed** diff --git a/ReadMe.md b/ReadMe.md index 222572381b..b9cc9e257d 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -32,6 +32,9 @@ Our Discord Community: * Picopass/iClass plugin included in releases * Recompiled IR TV Universal Remote for ALL buttons * Universal A/C and Audio(soundbars, etc.) remote +* Universal remote for Projectors +* BadUSB keyboard layouts +* Customizable Flipper name * Other small fixes and changes throughout See changelog in releases for latest updates! @@ -88,7 +91,7 @@ See changelog in releases for latest updates! ### **Plugins** -## [- Configure UniversalRF Remix App](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/UniRFRemix.md) +## [- Configure Sub-GHz Remote App](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/SubGHzRemotePlugin.md) ## [- Barcode Generator](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/BarcodeGenerator.md) diff --git a/applications/desktop/views/desktop_view_slideshow.c b/applications/desktop/views/desktop_view_slideshow.c index 58a8f6d0c1..3462d2f085 100644 --- a/applications/desktop/views/desktop_view_slideshow.c +++ b/applications/desktop/views/desktop_view_slideshow.c @@ -61,9 +61,9 @@ static bool desktop_view_slideshow_input(InputEvent* event, void* context) { furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_SHORT); } else if(event->type == InputTypeRelease) { furi_timer_stop(instance->timer); - if(!slideshow_is_one_page(model->slideshow)) { + /*if(!slideshow_is_one_page(model->slideshow)) { furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_LONG); - } + }*/ } } view_commit_model(instance->view, update_view); diff --git a/applications/picopass/picopass_worker.c b/applications/picopass/picopass_worker.c index 88df8d45b8..560548a188 100644 --- a/applications/picopass/picopass_worker.c +++ b/applications/picopass/picopass_worker.c @@ -105,7 +105,7 @@ ReturnCode picopass_detect_card(int timeout) { err = rfalPicoPassPollerCheckPresence(); if(err != ERR_RF_COLLISION) { - FURI_LOG_E(TAG, "rfalPicoPassPollerCheckPresence error %d", err); + //FURI_LOG_E(TAG, "rfalPicoPassPollerCheckPresence error %d", err); return err; } diff --git a/applications/unirfremix/application.fam b/applications/unirfremix/application.fam index dd3a85fe25..fd35539472 100644 --- a/applications/unirfremix/application.fam +++ b/applications/unirfremix/application.fam @@ -9,6 +9,6 @@ App( "dialogs", ], icon="A_UniRFRemix_14", - stack_size=2 * 1024, + stack_size=4 * 1024, order=11, ) diff --git a/assets/slideshow/update_default/frame_00.png b/assets/slideshow/update_default/frame_00.png index 385fbbe061539ecd682922a07996d5b5ad23bfd9..bf70b363eb9c4d45dcac884925197841f3fb102f 100644 GIT binary patch literal 2958 zcmcIm4R93I9e=q4lIT$fNE5LPEE{H!F?+XPx3_!cNOB)Bfm{+}Y61*4d%JHhYwm83 z-Ai&w!CnP}V8=SrQIHVhsMBCZidMlIh6W2w9V}?tAqq%R1xIT$YDnrN9iZ>>aWWW? zai%x(Zg=1Q-tYhQ`@enLE6VPjd)r;N0RZNf6niVtHGxJ!h6(*|c>S}x(Iqolyw(7~ znwuPH@t5)&0mulcRW-31f2mW_!d6k%0?--{M-du;mHF|gDAmIl7JxxD;=;e|{u7R= zvJ0=a`$>P)1MAe{79HN-QdT9k)JuYl=dZ$6#+`^D3}Ye|4~HU#Gw#ACc%A4zIc>wS z2}rEog%>6bVm1B>%%kZL-(qW@Wf~K7$=d?4})DK72 zbXjp$dW)uPp(ht!7mG!mHd|9uleLMlYI@K{34&lFX&X%w2tgRlk(d}KB1Y~sgBKc- zu0~_37QvE?VnAz%xp3s^WC-DCiZ)_Qr3od>78j#7%1S0fng;s)H;0D9DYOyuH6klh z{?15jR5eGTtr8kqgDyc|BaFmyr;W){YHhSZ4^2cWOEwsSVFWXfV^qpiv`&j@MxAzp zI8v`u(L|jd9f~ncuhO*8bfGGySumQmlGxqVYDCtWj1@_brWQc27=tbxRgES{o}ig3 znsKtIYScX><0Q#Rs2}M-7GvUdV73Zj82);&CaX&Gtw8;LXGz3}i4h5wcwIPh%Brfe zlVf-ZQcxjy-fky&2TK#YAj*VdryP`nX6-B~Pxyt_do`&cnZD%uN!iMpgg8C=|;QfdC~Fe1HuEpuq4Pn_?^1Rn$3R=vvmKS2AK0?F^^z4v`=wq)7-_ z2O-duLf8e)u80i7aEyRsvgA}WJuD)fs9`Y(ZP7>&$G-K(qlGlxugNIq%(e3+9#4g? zDQXD4Fe>kLV3+Cz>Mo>W6Y6w|QnD#rxRg`_ zM1f6Ct23ne)&iPb-&6+?=}lBJ2{SY$)+Fk%Fo;U>y(+Zb$azC-yt(UwViyEE$q`5! z6rsp0DyJlngdowJgOVL23zg~6|1YjjrB$jEBSDCESR4MsgSj=i&sc}=HsBAb!_2|h zk{j!!!fe-z?^``jcS<4Z;iNQ;shYaQV5+*SW^PP|6G;jR0>LpX`dE-GL+~;y5rU$~ zG9}BXNy(KHUWC-|$|czuR^&yBU}d|E zx}8-Bfsr|a*XL#_WVeW?D4$30xxGFg$Jhn8k9HT%5YhC? z07*&7y^64Ne1M>Yq+J^FgoAVNBuP3LhrnE8cOo;BX|~W=i_m%gLUH!Vc`}EksvqQ~Y!v{uBJ?p9et)=_R zrN8nQn82yyJC$|Rp7reJ(8W(cV)N09@;#TcbNuB`T((#~m^D4M0x%B)-zbgTH+1#Vza8f&1{tq4u$-NH)8mKf$bi^UR+9 zO%K1_x2pQlf`v>iox@r#ZByrbdNFIwf;O1=F}}Yx930;ScCXlT;s`Z%@814t!j_B=Jwsd!bls{ripw z^LMA$?&`wk6`3+N{-gBFmfw{B$J{fp@kKLeUVKIGZ#!}2uJ>jqN?t8Bb=D6Qp4_+9 z2lkc4zp?CEkb8K=5;Jxp{YlXRxTRSSfY5ts>tDchZZL5{1PA|>SiR{F3){PPJ<+|m zbL%^CDL?V=k^3I3Joe1(>%Q5xZ~splI-hQv|HmcKMFk%YSLc0r`jqL(-U}oXkrghb7(7*O7r?V?XzwL{=c5Ex;$l z_5c6>KxXKn%XL7Cv%n*=n1O*?7=#%aX3dcRsxq2r<+HL=Ua)LhR{H`&0zK*8Kn zFEu66D9JcYN5ROz$WY%9h)i@1jjW6ftW1m)pg_rvmrG&dcPCaLrJyj`lCh3CC^c~(h}2*bj^~D%yd(dO;U6%Owy8cEmDn>%nXu}(u@<6Cp$8WXaL=#my(%c zW$NN)Zs26*Vrpz*ZfNN0Z0X`=>|*3&&{0Mw3}tv=zYN z0t^}(pas6ZRxYVUnPsUdZbkXI3dJR$pvq?vt%sWDh|5wXh+32H}tQN!tpaGi*FKXBavgy?u z>lrF&glFcZ0h(F9u^A{L|yt3LFt0G|h_uSmVGcTko%#FXB7oXqx{7!fMa??8j z%NKTi&&)_RG2PC%^y>bMMLTaj{Jiy$ZAHzrt0&ISefs*()rYDNgloQ9@87g(=6&m1 z55t?5yK(3q3SXyg!DhyByT^G0NB;gb>FfEnB|K91e0Q(?px3=ei3fAtAGFET=4}Z` zT*Ws*SVG{`oorj?p6MWbJXjrwtpsSN{ALALh3qAi0No^AQI&dCA2UI*zwUhrXI+XjoNpXVS^jif_W;*!tH~zWxBydTB z0neo;b)5BaqGt`>a7;10#j~Y;)frD=t`&XG_Q883aug1Rsxy9J2@_=Ak@&)M&8pA6 z9A|FoF33BZBIBcMr{6gJCX37(!L(vdkq?@G-50E}I3{geUYQ+dPEtr7+K7avHr1+8WL+CH^PfyF2PnAN*3#ST5$UHp#j<$nYj{xi Date: Wed, 24 Aug 2022 14:28:27 +0200 Subject: [PATCH 30/78] feat[unirf]: blinking on send * fixed a HardFault when trying to `subghz_protocol_decoder_base_get_string` * don't enter `power_suppress_charge` for each sending individually --- applications/unirfremix/unirfremix_app.c | 33 +++++++++++++----------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/applications/unirfremix/unirfremix_app.c b/applications/unirfremix/unirfremix_app.c index 08c0ee1459..81c5fd380e 100644 --- a/applications/unirfremix/unirfremix_app.c +++ b/applications/unirfremix/unirfremix_app.c @@ -4,6 +4,8 @@ #include #include #include + +#include #include #include @@ -34,6 +36,7 @@ typedef struct { SubGhzSetting* setting; SubGhzEnvironment* environment; SubGhzReceiver* subghz_receiver; + NotificationApp* notification; string_t up_file; string_t down_file; @@ -477,7 +480,7 @@ bool unirfremix_key_load( // if(!flipper_format_rewind(fff_file)) { FURI_LOG_E(TAG, "Rewind error"); - return NULL; + return false; } string_t temp_str; @@ -572,7 +575,7 @@ bool unirfremix_save_protocol_to_file(FlipperFormat* fff_file, const char* dev_f FURI_LOG_E(TAG, "(save) Cannot remove"); break; } - //ToDo check Write + stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); @@ -643,13 +646,13 @@ static bool unirfremix_send_sub( furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); furi_hal_gpio_write(&gpio_cc1101_g0, true); - furi_hal_power_suppress_charge_enter(); - if(!furi_hal_subghz_tx()) { FURI_LOG_E(TAG, "Sending not allowed"); + break; } FURI_LOG_I(TAG, "Sending..."); + notification_message(app->notification, &sequence_blink_start_green); furi_hal_subghz_start_async_tx(subghz_transmitter_yield, transmitter); while(!furi_hal_subghz_is_async_tx_complete()) { @@ -658,27 +661,20 @@ static bool unirfremix_send_sub( furi_hal_subghz_stop_async_tx(); FURI_LOG_I(TAG, " Done!"); + notification_message(app->notification, &sequence_blink_stop); subghz_transmitter_stop(transmitter); - // display decoded data - { - string_t temp_str; - string_init(temp_str); - subghz_protocol_decoder_base_deserialize(preset->decoder, fff_data); - subghz_protocol_decoder_base_get_string(preset->decoder, temp_str); - FURI_LOG_D(TAG, "Decoded: %s", string_get_cstr(temp_str)); - string_clear(temp_str); - } - res = true; FURI_LOG_D(TAG, "Checking if protocol is dynamic"); const SubGhzProtocol* registry = subghz_protocol_registry_get_by_name(string_get_cstr(preset->protocol)); FURI_LOG_D(TAG, "Protocol-TYPE %d", registry->type); + FURI_LOG_I(TAG, "3"); if(registry && registry->type == SubGhzProtocolTypeDynamic) { FURI_LOG_D(TAG, " Protocol is dynamic. Updating Repeat"); + FURI_LOG_I(TAG, "4"); unirfremix_save_protocol_to_file(fff_data, path); keeloq_reset_mfname(); @@ -691,7 +687,6 @@ static bool unirfremix_send_sub( furi_hal_subghz_idle(); furi_hal_subghz_sleep(); - furi_hal_power_suppress_charge_exit(); } while(0); unirfremix_preset_free(preset); @@ -864,6 +859,8 @@ UniRFRemix* unirfremix_alloc(void) { app->subghz_receiver = subghz_receiver_alloc_init(app->environment); + app->notification = furi_record_open(RECORD_NOTIFICATION); + return app; } @@ -896,6 +893,8 @@ void unirfremix_free(UniRFRemix* app) { subghz_receiver_free(app->subghz_receiver); subghz_environment_free(app->environment); + furi_record_close(RECORD_NOTIFICATION); + free(app); } @@ -964,6 +963,8 @@ int32_t unirfremix_app(void* p) { furi_mutex_release(app->model_mutex); view_port_update(app->view_port); + furi_hal_power_suppress_charge_enter(); + //input detect loop start InputEvent input; while(1) { @@ -1144,5 +1145,7 @@ int32_t unirfremix_app(void* p) { // remove & free all stuff created by app unirfremix_free(app); + furi_hal_power_suppress_charge_exit(); + return 0; } \ No newline at end of file From 9ec0835012282423c6b2aea03cfad15336575cc0 Mon Sep 17 00:00:00 2001 From: Daniel <71837281+darmiel@users.noreply.github.com> Date: Wed, 24 Aug 2022 14:36:50 +0200 Subject: [PATCH 31/78] fix[unirf]: removed leftover debug messages --- applications/unirfremix/unirfremix_app.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/applications/unirfremix/unirfremix_app.c b/applications/unirfremix/unirfremix_app.c index 81c5fd380e..459049b0c6 100644 --- a/applications/unirfremix/unirfremix_app.c +++ b/applications/unirfremix/unirfremix_app.c @@ -671,10 +671,8 @@ static bool unirfremix_send_sub( const SubGhzProtocol* registry = subghz_protocol_registry_get_by_name(string_get_cstr(preset->protocol)); FURI_LOG_D(TAG, "Protocol-TYPE %d", registry->type); - FURI_LOG_I(TAG, "3"); if(registry && registry->type == SubGhzProtocolTypeDynamic) { FURI_LOG_D(TAG, " Protocol is dynamic. Updating Repeat"); - FURI_LOG_I(TAG, "4"); unirfremix_save_protocol_to_file(fff_data, path); keeloq_reset_mfname(); From 7e20df7e93379190298b3e7573e009c2ac94cafe Mon Sep 17 00:00:00 2001 From: SG Date: Thu, 25 Aug 2022 00:41:59 +1000 Subject: [PATCH 32/78] LFRFID RC fixes (#1652) * lfrid: fix write validation * lfrid app: restore key data after write --- applications/lfrfid/scene/lfrfid_app_scene_write.cpp | 9 +++++++++ lib/lfrfid/lfrfid_worker_modes.c | 12 ++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/applications/lfrfid/scene/lfrfid_app_scene_write.cpp b/applications/lfrfid/scene/lfrfid_app_scene_write.cpp index 8e04d8e8de..39e0630e7d 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_write.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_write.cpp @@ -35,6 +35,11 @@ void LfRfidAppSceneWrite::on_enter(LfRfidApp* app, bool /* need_restore */) { popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61); app->view_controller.switch_to(); + + size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); + app->old_key_data = (uint8_t*)malloc(size); + protocol_dict_get_data(app->dict, app->protocol_id, app->old_key_data, size); + lfrfid_worker_start_thread(app->lfworker); lfrfid_worker_write_start( app->lfworker, (LFRFIDProtocol)app->protocol_id, lfrfid_write_callback, app); @@ -76,4 +81,8 @@ void LfRfidAppSceneWrite::on_exit(LfRfidApp* app) { app->view_controller.get()->clean(); lfrfid_worker_stop(app->lfworker); lfrfid_worker_stop_thread(app->lfworker); + + size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); + protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size); + free(app->old_key_data); } diff --git a/lib/lfrfid/lfrfid_worker_modes.c b/lib/lfrfid/lfrfid_worker_modes.c index f41a7194a1..33683589c5 100644 --- a/lib/lfrfid/lfrfid_worker_modes.c +++ b/lib/lfrfid/lfrfid_worker_modes.c @@ -522,9 +522,17 @@ static void lfrfid_worker_mode_write_process(LFRFIDWorker* worker) { &read_result); if(state == LFRFIDWorkerReadOK) { - protocol_dict_get_data(worker->protocols, protocol, read_data, data_size); + bool read_success = false; - if(memcmp(read_data, verify_data, data_size) == 0) { + if(read_result == protocol) { + protocol_dict_get_data(worker->protocols, protocol, read_data, data_size); + + if(memcmp(read_data, verify_data, data_size) == 0) { + read_success = true; + } + } + + if(read_success) { if(worker->write_cb) { worker->write_cb(LFRFIDWorkerWriteOK, worker->cb_ctx); } From ce7b943793926ba7cffa914942f91c8791396595 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Wed, 24 Aug 2022 19:14:27 +0400 Subject: [PATCH 33/78] [FL-2764] SubGhz: fix CAME, Chamberlain potocol (#1650) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: fix guard time CAME potocol * SubGhz: fix file upload Chamberlain * Github: fix spelling Co-authored-by: あく --- .github/workflows/amap_analyse.yml | 2 +- .github/workflows/build.yml | 2 +- lib/subghz/protocols/came.c | 11 +++++++---- lib/subghz/protocols/chamberlain_code.c | 4 ++-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/amap_analyse.yml b/.github/workflows/amap_analyse.yml index 3443771dd4..a87857e74b 100644 --- a/.github/workflows/amap_analyse.yml +++ b/.github/workflows/amap_analyse.yml @@ -86,7 +86,7 @@ jobs: ${{ secrets.RSYNC_DEPLOY_USER }}@${{ secrets.RSYNC_DEPLOY_HOST }}:"${{ secrets.RSYNC_DEPLOY_BASE_PATH }}${{steps.names.outputs.branch-name}}/" artifacts/; rm ./deploy_key; - - name: 'Make .map file analyse' + - name: 'Make .map file analyze' run: | cd artifacts/ /Applications/amap/Contents/MacOS/amap -f flipper-z-f7-firmware-${{steps.names.outputs.suffix}}.elf.map diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7eeb5c22b4..3fe733caa7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -93,7 +93,7 @@ jobs: rm -rf artifacts/${BUNDLE_NAME} done - - name: "Check for uncommited changes" + - name: "Check for uncommitted changes" run: | git diff --exit-code diff --git a/lib/subghz/protocols/came.c b/lib/subghz/protocols/came.c index 37048017e3..726461d4d1 100644 --- a/lib/subghz/protocols/came.c +++ b/lib/subghz/protocols/came.c @@ -112,8 +112,11 @@ static bool subghz_protocol_encoder_came_get_upload(SubGhzProtocolEncoderCame* i instance->encoder.size_upload = size_upload; } //Send header - instance->encoder.upload[index++] = - level_duration_make(false, (uint32_t)subghz_protocol_came_const.te_short * 36); + instance->encoder.upload[index++] = level_duration_make( + false, + ((instance->generic.data_count_bit == subghz_protocol_came_const.min_count_bit_for_found) ? + (uint32_t)subghz_protocol_came_const.te_short * 39 : + (uint32_t)subghz_protocol_came_const.te_short * 76)); //Send start bit instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)subghz_protocol_came_const.te_short); @@ -213,8 +216,8 @@ void subghz_protocol_decoder_came_feed(void* context, bool level, uint32_t durat SubGhzProtocolDecoderCame* instance = context; switch(instance->decoder.parser_step) { case CameDecoderStepReset: - if((!level) && (DURATION_DIFF(duration, subghz_protocol_came_const.te_short * 51) < - subghz_protocol_came_const.te_delta * 51)) { //Need protocol 36 te_short + if((!level) && (DURATION_DIFF(duration, subghz_protocol_came_const.te_short * 56) < + subghz_protocol_came_const.te_delta * 47)) { //Found header CAME instance->decoder.parser_step = CameDecoderStepFoundStartBit; } diff --git a/lib/subghz/protocols/chamberlain_code.c b/lib/subghz/protocols/chamberlain_code.c index 6c99d84519..51f2bcd323 100644 --- a/lib/subghz/protocols/chamberlain_code.c +++ b/lib/subghz/protocols/chamberlain_code.c @@ -215,7 +215,7 @@ bool subghz_protocol_encoder_chamb_code_deserialize(void* context, FlipperFormat FURI_LOG_E(TAG, "Deserialize error"); break; } - if(instance->generic.data_count_bit < + if(instance->generic.data_count_bit > subghz_protocol_chamb_code_const.min_count_bit_for_found) { FURI_LOG_E(TAG, "Wrong number of bits in key"); break; @@ -441,7 +441,7 @@ bool subghz_protocol_decoder_chamb_code_deserialize(void* context, FlipperFormat if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { break; } - if(instance->generic.data_count_bit < + if(instance->generic.data_count_bit > subghz_protocol_chamb_code_const.min_count_bit_for_found) { FURI_LOG_E(TAG, "Wrong number of bits in key"); break; From 273871013efe0e0f5273c463e082171e7aa61f0b Mon Sep 17 00:00:00 2001 From: "Gana (@G4N4P4T1)" Date: Wed, 24 Aug 2022 18:14:03 +0200 Subject: [PATCH 34/78] Add flipfrid application --- applications/flipfrid/LICENSE.md | 8 + applications/flipfrid/README.md | 4 + applications/flipfrid/application.fam | 11 + applications/flipfrid/flipfrid.c | 317 ++++++++++++++++++++++++++ applications/flipfrid/flipfrid.h | 7 + applications/flipfrid/raw_em4100.c | 106 +++++++++ applications/flipfrid/raw_em4100.h | 11 + applications/meta/application.fam | 1 + 8 files changed, 465 insertions(+) create mode 100644 applications/flipfrid/LICENSE.md create mode 100644 applications/flipfrid/README.md create mode 100644 applications/flipfrid/application.fam create mode 100644 applications/flipfrid/flipfrid.c create mode 100644 applications/flipfrid/flipfrid.h create mode 100644 applications/flipfrid/raw_em4100.c create mode 100644 applications/flipfrid/raw_em4100.h diff --git a/applications/flipfrid/LICENSE.md b/applications/flipfrid/LICENSE.md new file mode 100644 index 0000000000..a856581c9f --- /dev/null +++ b/applications/flipfrid/LICENSE.md @@ -0,0 +1,8 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * @G4N4P4T1 wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. + * ---------------------------------------------------------------------------- + */ \ No newline at end of file diff --git a/applications/flipfrid/README.md b/applications/flipfrid/README.md new file mode 100644 index 0000000000..d5f79bf5d2 --- /dev/null +++ b/applications/flipfrid/README.md @@ -0,0 +1,4 @@ +# FlipFrid + +A simple implementation of ZigFrid on Flipper zero (+bonus) +(https://z4ziggy.wordpress.com/2017/07/21/zigfrid-a-passive-rfid-fuzzer/) \ No newline at end of file diff --git a/applications/flipfrid/application.fam b/applications/flipfrid/application.fam new file mode 100644 index 0000000000..87b38b6d29 --- /dev/null +++ b/applications/flipfrid/application.fam @@ -0,0 +1,11 @@ +App( + appid="flipfrid", + name="Rfid fuzzer", + apptype=FlipperAppType.PLUGIN, + entry_point="flipfrid_start", + cdefines=["APP_FLIP_FRID"], + requires=["gui"], + stack_size=1 * 1024, + icon="A_125khz_14", + order=185, +) diff --git a/applications/flipfrid/flipfrid.c b/applications/flipfrid/flipfrid.c new file mode 100644 index 0000000000..5f38ff4585 --- /dev/null +++ b/applications/flipfrid/flipfrid.c @@ -0,0 +1,317 @@ +#include +#include +#include +#include + +#include +#include "raw_em4100.h" +#include + +#include "flipfrid.h" + +#define NUMBER_OF_ATTACKS 4 +#define TIME_BETWEEN_CARDS \ + 5 // Emulate 2 cards per second : (5 * (configTICK_RATE_HZ_RAW/10)) == (5*(1000/10)) == (5*100) == (500)ms +#define TAG "FLIPFRID" + +uint8_t id_list[16][5] = { + {0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // Only FF + {0x11, 0x11, 0x11, 0x11, 0x11}, // Only 11 + {0x22, 0x22, 0x22, 0x22, 0x22}, // Only 22 + {0x33, 0x33, 0x33, 0x33, 0x33}, // Only 33 + {0x44, 0x44, 0x44, 0x44, 0x44}, // Only 44 + {0x55, 0x55, 0x55, 0x55, 0x55}, // Only 55 + {0x66, 0x66, 0x66, 0x66, 0x66}, // Only 66 + {0x77, 0x77, 0x77, 0x77, 0x77}, // Only 77 + {0x88, 0x88, 0x88, 0x88, 0x88}, // Only 88 + {0x99, 0x99, 0x99, 0x99, 0x99}, // Only 99 + {0x12, 0x34, 0x56, 0x78, 0x9A}, // Incremental UID + {0x04, 0xd0, 0x9b, 0x0d, 0x6a}, // From arha + {0x34, 0x00, 0x29, 0x3d, 0x9e}, // From arha + {0x04, 0xdf, 0x00, 0x00, 0x01}, // From arha + {0xCA, 0xCA, 0xCA, 0xCA, 0xCA}, // From arha +}; + +typedef enum { + DefaultKeys, + BruteForceCustomerId, + BadCrc, +} AttackType; + +typedef enum { + EventTypeTick, + EventTypeKey, +} EventType; + +typedef struct { + EventType evt_type; + InputKey key; + InputType input_type; +} FlipFridEvent; + +// STRUCTS +typedef struct { + bool emitting; + AttackType current_attack_type; + uint8_t* current_uid; + uint8_t meta_data; + NotificationApp* notify; +} FlipFridState; + +static void flipfrid_draw_callback(Canvas* const canvas, void* ctx) { + const FlipFridState* flipfrid_state = (FlipFridState*)acquire_mutex((ValueMutex*)ctx, 100); + + if(flipfrid_state == NULL) { + return; + } + + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + + // Frame + canvas_draw_frame(canvas, 0, 0, 128, 64); + + // Title + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 64, 8, AlignCenter, AlignTop, "Flip/Frid"); + + // Badge Type + char uid[16]; + char badge_type[21]; + switch(flipfrid_state->current_attack_type) { + case DefaultKeys: + strcpy(badge_type, " Default Values >"); + break; + case BruteForceCustomerId: + strcpy(badge_type, "< BF Customer ID >"); + break; + case BadCrc: + strcpy(badge_type, "< Bad CRC "); + break; + default: + break; + } + + if(flipfrid_state->current_attack_type == BruteForceCustomerId) { + snprintf(uid, sizeof(uid), " ID : %2X ", flipfrid_state->current_uid[0]); + } else if (flipfrid_state->current_attack_type == BadCrc) { + snprintf(uid, sizeof(uid), "Sending packets"); + } else { + snprintf( + uid, + sizeof(uid), + "%2X:%2X:%2X:%2X:%2X", + flipfrid_state->current_uid[0], + flipfrid_state->current_uid[1], + flipfrid_state->current_uid[2], + flipfrid_state->current_uid[3], + flipfrid_state->current_uid[4]); + } + + // Badge infos + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 64, 28, AlignCenter, AlignCenter, badge_type); + + if(flipfrid_state->emitting) { + canvas_draw_str_aligned(canvas, 64, 42, AlignCenter, AlignCenter, uid); + } else { + canvas_draw_str_aligned( + canvas, 64, 42, AlignCenter, AlignCenter, "Press OK to start/stop"); + } + + release_mutex((ValueMutex*)ctx, flipfrid_state); +} + +void flipfrid_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { + furi_assert(event_queue); + + FlipFridEvent event = { + .evt_type = EventTypeKey, .key = input_event->key, .input_type = input_event->type}; + furi_message_queue_put(event_queue, &event, 25); +} + +static void flipfrid_timer_callback(FuriMessageQueue* event_queue) { + furi_assert(event_queue); + + FlipFridEvent event = { + .evt_type = EventTypeTick, .key = InputKeyUp, .input_type = InputTypeRelease}; + furi_message_queue_put(event_queue, &event, 25); +} + +// ENTRYPOINT +int32_t flipfrid_start(void* p) { + UNUSED(p); + + // Input + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(FlipFridEvent)); + FlipFridState* flipfrid_state = (FlipFridState*)malloc(sizeof(FlipFridState)); + ValueMutex flipfrid_state_mutex; + + // Mutex + if(!init_mutex(&flipfrid_state_mutex, flipfrid_state, sizeof(FlipFridState))) { + furi_message_queue_free(event_queue); + free(flipfrid_state); + } + + // Configure view port + ViewPort* view_port = view_port_alloc(); + view_port_draw_callback_set(view_port, flipfrid_draw_callback, &flipfrid_state_mutex); + view_port_input_callback_set(view_port, flipfrid_input_callback, event_queue); + + // Configure timer + FuriTimer* timer = + furi_timer_alloc(flipfrid_timer_callback, FuriTimerTypePeriodic, event_queue); + furi_timer_start(timer, furi_kernel_get_tick_frequency() / 10); // configTICK_RATE_HZ_RAW 1000 + + // Register view port in GUI + Gui* gui = (Gui*)furi_record_open(RECORD_GUI); + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + + // Init values + FlipFridEvent event; + flipfrid_state->emitting = false; + flipfrid_state->current_uid = id_list[0]; + flipfrid_state->current_attack_type = DefaultKeys; + flipfrid_state->meta_data = 0; + flipfrid_state->notify = furi_record_open(RECORD_NOTIFICATION); + + // RFID Configuration + size_t data_size = 5; // Default EM4100 data size is 5 (1 customer id + 4 uid) + LFRFIDWorker* worker; + const ProtocolBase* lfrfid_protocol[] = {&protocol_raw_em4100, &protocol_raw_wrong_crc_em4100}; + ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocol, 2); + worker = lfrfid_worker_alloc(dict); + uint8_t selectedProtocol = CLEAN; + + // Application state + int menu_selected_item_index = 0; // Menu current item index + uint8_t counter = 0; // Used to count the step and wqaiting time between each test + uint8_t attack_state = 0; // Used to store the current attack state + uint8_t candidate[5]; // uid candidate + bool running = true; // Used to stop the application + + // Main loop + while(running) { + // Get next event + FuriStatus event_status = furi_message_queue_get(event_queue, &event, 25); + if(event_status == FuriStatusOk) { + if(event.evt_type == EventTypeKey) { + if(event.input_type == InputTypeShort) { + counter = 0; + switch(event.key) { + case InputKeyUp: + case InputKeyDown: + // OSEF + break; + case InputKeyRight: + // Next badge type + flipfrid_state->emitting = false; + if(menu_selected_item_index < (NUMBER_OF_ATTACKS - 1)) { + menu_selected_item_index++; + flipfrid_state->current_attack_type = + (AttackType)menu_selected_item_index; + } + break; + case InputKeyLeft: + // Previous badge type + flipfrid_state->emitting = false; + if(menu_selected_item_index > 0) { + menu_selected_item_index--; + flipfrid_state->current_attack_type = + (AttackType)menu_selected_item_index; + } + break; + case InputKeyOk: + if(flipfrid_state->emitting) { + flipfrid_state->emitting = false; + attack_state = 0; + // TODO FIX BLINK + notification_message(flipfrid_state->notify, &sequence_blink_stop); + } else { + flipfrid_state->emitting = true; + attack_state = 0; + // TODO FIX BLINK + notification_message(flipfrid_state->notify, &sequence_blink_start_magenta); + } + break; + case InputKeyBack: + flipfrid_state->emitting = false; + running = false; + break; + } + } + } else if(event.evt_type == EventTypeTick) { + // Emulate card + if(flipfrid_state->emitting) { + if(1 == counter) { + protocol_dict_set_data( + dict, (LFRFIDProtocol)0, flipfrid_state->current_uid, data_size); + worker = lfrfid_worker_alloc(dict); + lfrfid_worker_start_thread(worker); + lfrfid_worker_emulate_start(worker, (LFRFIDProtocol)selectedProtocol); + } else if(0 == counter) { + lfrfid_worker_stop(worker); + lfrfid_worker_stop_thread(worker); + // set next value + switch(flipfrid_state->current_attack_type) { + case DefaultKeys: { + selectedProtocol = CLEAN; + data_size = 5; + flipfrid_state->current_uid = id_list[attack_state]; + attack_state = attack_state + 1; + if(attack_state >= sizeof(id_list) / sizeof(id_list[0])) { + attack_state = 0; + } + break; + } + case BruteForceCustomerId: { + data_size = 5; + selectedProtocol = CLEAN; + candidate[0] = attack_state; + flipfrid_state->current_uid = candidate; + attack_state = attack_state + 1; + if((attack_state + 1) == 256) { + attack_state = 0; + } + break; + } + case BadCrc: { + selectedProtocol = BAD_CRC; + data_size = 5; + candidate[0] = 0xFF; + candidate[1] = 0xDE; + candidate[2] = 0xAD; + candidate[3] = 0xBE; + candidate[4] = 0xEF; + flipfrid_state->current_uid = candidate; + break; + } + } + } + if(counter > TIME_BETWEEN_CARDS) { + counter = 0; + } else { + counter++; + } + } + view_port_update(view_port); + } + } + } + + // Cleanup + notification_message(flipfrid_state->notify, &sequence_blink_stop); + lfrfid_worker_stop(worker); + lfrfid_worker_stop_thread(worker); + lfrfid_worker_free(worker); + protocol_dict_free(dict); + furi_timer_stop(timer); + furi_timer_free(timer); + free(flipfrid_state); + gui_remove_view_port(gui, view_port); + view_port_free(view_port); + furi_message_queue_free(event_queue); + furi_record_close(RECORD_GUI); + return 0; +} \ No newline at end of file diff --git a/applications/flipfrid/flipfrid.h b/applications/flipfrid/flipfrid.h new file mode 100644 index 0000000000..1b2369a4ca --- /dev/null +++ b/applications/flipfrid/flipfrid.h @@ -0,0 +1,7 @@ +#pragma once +#include +#include +#include +#include "raw_em4100.h" + +int32_t flipfrid_start(void* p); \ No newline at end of file diff --git a/applications/flipfrid/raw_em4100.c b/applications/flipfrid/raw_em4100.c new file mode 100644 index 0000000000..4cc477ee78 --- /dev/null +++ b/applications/flipfrid/raw_em4100.c @@ -0,0 +1,106 @@ +#include "raw_em4100.h" +#include + +bool protocol_em4100_raw_encoder_start(ProtocolEM4100* proto) { + FURI_LOG_D("RAW_EM4100", "encoder_start : CLEAN"); + // header + proto->encoded_data = 0b111111111; + + // data + for(uint8_t i = 0; i < EM4100_DECODED_DATA_SIZE; i++) { + em4100_write_nibble(false, proto->data[i], &proto->encoded_data); + em4100_write_nibble(true, proto->data[i], &proto->encoded_data); + } + + // column parity and stop bit + uint8_t parity_sum; + + for(uint8_t c = 0; c < EM_COLUMN_COUNT; c++) { + parity_sum = 0; + for(uint8_t i = 1; i <= EM_ROW_COUNT; i++) { + uint8_t parity_bit = (proto->encoded_data >> (i * EM_BITS_PER_ROW_COUNT - 1)) & 1; + parity_sum += parity_bit; + } + proto->encoded_data = (proto->encoded_data << 1) | ((parity_sum % 2) & 1); + } + + // stop bit + proto->encoded_data = (proto->encoded_data << 1) | 0; + + proto->encoded_data_index = 0; + proto->encoded_polarity = true; + + return true; +}; + +bool protocol_em4100_wrong_crc_encoder_start(ProtocolEM4100* proto) { + FURI_LOG_D("RAW_EM4100", "encoder_start : WRONG CRC"); + // header + proto->encoded_data = 0b111111111; + + // data + for(uint8_t i = 0; i < EM4100_DECODED_DATA_SIZE; i++) { + em4100_write_nibble(false, proto->data[i], &proto->encoded_data); + em4100_write_nibble(true, proto->data[i], &proto->encoded_data); + } + + for(uint8_t c = 0; c < EM_COLUMN_COUNT; c++) { + proto->encoded_data = (proto->encoded_data << 1) | ((0 % 2) & 1); + } + + // stop bit + proto->encoded_data = (proto->encoded_data << 1) | 1; + + proto->encoded_data_index = 0; + proto->encoded_polarity = true; + + return true; +}; + +const ProtocolBase protocol_raw_em4100 = { + .name = "RawEM4100", + .manufacturer = "EM-Micro", + .data_size = EM4100_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK | LFRFIDFeaturePSK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_em4100_alloc, + .free = (ProtocolFree)protocol_em4100_free, + .get_data = (ProtocolGetData)protocol_em4100_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_em4100_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_em4100_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_em4100_raw_encoder_start, + .yield = (ProtocolEncoderYield)protocol_em4100_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_em4100_render_data, + .render_brief_data = (ProtocolRenderData)protocol_em4100_render_data, + .write_data = (ProtocolWriteData)protocol_em4100_write_data, +}; + +const ProtocolBase protocol_raw_wrong_crc_em4100 = { + .name = "RawEM4100", + .manufacturer = "EM-Micro", + .data_size = EM4100_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK | LFRFIDFeaturePSK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_em4100_alloc, + .free = (ProtocolFree)protocol_em4100_free, + .get_data = (ProtocolGetData)protocol_em4100_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_em4100_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_em4100_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_em4100_wrong_crc_encoder_start, + .yield = (ProtocolEncoderYield)protocol_em4100_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_em4100_render_data, + .render_brief_data = (ProtocolRenderData)protocol_em4100_render_data, + .write_data = (ProtocolWriteData)protocol_em4100_write_data, +}; \ No newline at end of file diff --git a/applications/flipfrid/raw_em4100.h b/applications/flipfrid/raw_em4100.h new file mode 100644 index 0000000000..faa2ccd9e3 --- /dev/null +++ b/applications/flipfrid/raw_em4100.h @@ -0,0 +1,11 @@ +#pragma once +#include + + +enum FlipFridProtocol { + CLEAN, + BAD_CRC, +}; + +extern const ProtocolBase protocol_raw_em4100; +extern const ProtocolBase protocol_raw_wrong_crc_em4100; \ No newline at end of file diff --git a/applications/meta/application.fam b/applications/meta/application.fam index 2859d144d9..0d654eb9c9 100644 --- a/applications/meta/application.fam +++ b/applications/meta/application.fam @@ -36,6 +36,7 @@ App( provides=[ "music_player", "bt_hid", + "flipfrid", ], ) From 7abc49ea219a8cf3924858730b56913eae853286 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 24 Aug 2022 23:14:33 +0300 Subject: [PATCH 35/78] Implement TX while button is hold, other small changes Repeat functionality removed since all buttons adds event in queue to be executed after tx is finished --- applications/unirfremix/unirfremix_app.c | 297 ++++++++++++----------- 1 file changed, 155 insertions(+), 142 deletions(-) diff --git a/applications/unirfremix/unirfremix_app.c b/applications/unirfremix/unirfremix_app.c index 459049b0c6..f89d197862 100644 --- a/applications/unirfremix/unirfremix_app.c +++ b/applications/unirfremix/unirfremix_app.c @@ -25,6 +25,19 @@ #define TAG "UniRF Remix" +typedef struct { + uint32_t frequency; + string_t name; + + string_t protocol; + uint32_t repeat; + + uint8_t* data; + size_t data_size; + + SubGhzProtocolDecoderBase* decoder; +} UniRFPreset; + typedef struct { FuriMutex* model_mutex; @@ -37,6 +50,7 @@ typedef struct { SubGhzEnvironment* environment; SubGhzReceiver* subghz_receiver; NotificationApp* notification; + UniRFPreset* txpreset; string_t up_file; string_t down_file; @@ -68,7 +82,11 @@ typedef struct { char* send_status; int send_status_c; int processing; - int repeat; + + SubGhzTransmitter* tx_transmitter; + FlipperFormat* tx_fff_data; + const char* tx_file_path; + //int repeat; int button; int file_result; @@ -78,19 +96,6 @@ typedef struct { string_t signal; } UniRFRemix; -typedef struct { - uint32_t frequency; - string_t name; - - string_t protocol; - uint32_t repeat; - - uint8_t* data; - size_t data_size; - - SubGhzProtocolDecoderBase* decoder; -} UniRFPreset; - UniRFPreset* unirfremix_preset_alloc(void) { UniRFPreset* preset = malloc(sizeof(UniRFPreset)); string_init(preset->name); @@ -113,7 +118,7 @@ static char* char_to_str(char* str, int i) { return converted; } - +/* static const char* int_to_char(int number) { switch(number) { case 0: @@ -140,7 +145,7 @@ static const char* int_to_char(int number) { return "0"; } } - +*/ //get filename without path static char* extract_filename(const char* name, int len) { string_t tmp; @@ -328,8 +333,6 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { flipper_format_file_close(fff_data_file); flipper_format_free(fff_data_file); - furi_record_close(RECORD_STORAGE); - //File Existence Check //Check each file definition if not already set to "N/A" @@ -350,7 +353,6 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { //if button is still enabled, check that file exists if(app->up_enabled == 1) { string_set(file_name, app->up_file); - storage = furi_record_open(RECORD_STORAGE); fff_data_file = flipper_format_file_alloc(storage); if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) { @@ -365,12 +367,10 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { //close the file flipper_format_file_close(fff_data_file); flipper_format_free(fff_data_file); - furi_record_close(RECORD_STORAGE); } if(app->down_enabled == 1) { string_set(file_name, app->down_file); - storage = furi_record_open(RECORD_STORAGE); fff_data_file = flipper_format_file_alloc(storage); if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) { @@ -383,12 +383,10 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { flipper_format_file_close(fff_data_file); flipper_format_free(fff_data_file); - furi_record_close(RECORD_STORAGE); } if(app->left_enabled == 1) { string_set(file_name, app->left_file); - storage = furi_record_open(RECORD_STORAGE); fff_data_file = flipper_format_file_alloc(storage); if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) { @@ -401,12 +399,10 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { flipper_format_file_close(fff_data_file); flipper_format_free(fff_data_file); - furi_record_close(RECORD_STORAGE); } if(app->right_enabled == 1) { string_set(file_name, app->right_file); - storage = furi_record_open(RECORD_STORAGE); fff_data_file = flipper_format_file_alloc(storage); if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) { @@ -419,12 +415,10 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { flipper_format_file_close(fff_data_file); flipper_format_free(fff_data_file); - furi_record_close(RECORD_STORAGE); } if(app->ok_enabled == 1) { string_set(file_name, app->ok_file); - storage = furi_record_open(RECORD_STORAGE); fff_data_file = flipper_format_file_alloc(storage); if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) { @@ -437,9 +431,10 @@ void unirfremix_cfg_set_check(UniRFRemix* app, string_t file_name) { flipper_format_file_close(fff_data_file); flipper_format_free(fff_data_file); - furi_record_close(RECORD_STORAGE); } + furi_record_close(RECORD_STORAGE); + if(app->file_blank == 5) { app->file_result = 1; } else { @@ -587,40 +582,50 @@ bool unirfremix_save_protocol_to_file(FlipperFormat* fff_file, const char* dev_f return saved; } -static bool unirfremix_send_sub( - UniRFRemix* app, - FlipperFormat* fff_file, - FlipperFormat* fff_data, - const char* path) { - // - UniRFPreset* preset = unirfremix_preset_alloc(); +void unirfremix_tx_stop(UniRFRemix* app) { + if(!string_cmp_str(app->txpreset->protocol, "RAW")) { + while(!furi_hal_subghz_is_async_tx_complete()) { + furi_delay_ms(60); + } + } + //Stop TX + furi_hal_subghz_stop_async_tx(); + FURI_LOG_I(TAG, "TX Done!"); + subghz_transmitter_stop(app->tx_transmitter); + + FURI_LOG_D(TAG, "Checking if protocol is dynamic"); + const SubGhzProtocol* registry = + subghz_protocol_registry_get_by_name(string_get_cstr(app->txpreset->protocol)); + FURI_LOG_D(TAG, "Protocol-TYPE %d", registry->type); + if(registry && registry->type == SubGhzProtocolTypeDynamic) { + FURI_LOG_D(TAG, "Protocol is dynamic. Saving key"); + unirfremix_save_protocol_to_file(app->tx_fff_data, app->tx_file_path); + + keeloq_reset_mfname(); + keeloq_reset_kl_type(); + star_line_reset_mfname(); + star_line_reset_kl_type(); + } + + subghz_transmitter_free(app->tx_transmitter); + furi_hal_subghz_idle(); + + notification_message(app->notification, &sequence_blink_stop); + + unirfremix_preset_free(app->txpreset); + flipper_format_free(app->tx_fff_data); + unirfremix_end_send(app); +} +static bool unirfremix_send_sub(UniRFRemix* app, FlipperFormat* fff_data) { + // bool res = false; do { - // load settings/stream from .sub file - bool open_ok = false; - do { - if(!flipper_format_file_open_existing(fff_file, path)) { - FURI_LOG_E(TAG, "Could not open file %s", path); - break; - } - if(!unirfremix_key_load( - preset, fff_file, fff_data, app->setting, app->subghz_receiver, path)) { - FURI_LOG_E(TAG, "Could not load key"); - break; - } - open_ok = true; - } while(0); - flipper_format_free(fff_file); - if(!open_ok) { - break; - } - - if(!furi_hal_subghz_is_tx_allowed(preset->frequency)) { + if(!furi_hal_subghz_is_tx_allowed(app->txpreset->frequency)) { printf( "In your settings, only reception on this frequency (%lu) is allowed,\r\n" "the actual operation of the unirf app is not possible\r\n ", - preset->frequency); + app->txpreset->frequency); app->tx_not_allowed = true; unirfremix_end_send(app); break; @@ -628,21 +633,21 @@ static bool unirfremix_send_sub( app->tx_not_allowed = false; } - SubGhzTransmitter* transmitter = - subghz_transmitter_alloc_init(app->environment, string_get_cstr(preset->protocol)); - if(!transmitter) { + app->tx_transmitter = subghz_transmitter_alloc_init( + app->environment, string_get_cstr(app->txpreset->protocol)); + if(!app->tx_transmitter) { break; } - subghz_transmitter_deserialize(transmitter, fff_data); + subghz_transmitter_deserialize(app->tx_transmitter, fff_data); furi_hal_subghz_reset(); furi_hal_subghz_idle(); - furi_hal_subghz_load_custom_preset(preset->data); + furi_hal_subghz_load_custom_preset(app->txpreset->data); furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); furi_hal_subghz_idle(); - furi_hal_subghz_set_frequency_and_path(preset->frequency); + furi_hal_subghz_set_frequency_and_path(app->txpreset->frequency); furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); furi_hal_gpio_write(&gpio_cc1101_g0, true); @@ -652,65 +657,52 @@ static bool unirfremix_send_sub( } FURI_LOG_I(TAG, "Sending..."); - notification_message(app->notification, &sequence_blink_start_green); - - furi_hal_subghz_start_async_tx(subghz_transmitter_yield, transmitter); - while(!furi_hal_subghz_is_async_tx_complete()) { - furi_delay_ms(33); - } - furi_hal_subghz_stop_async_tx(); - - FURI_LOG_I(TAG, " Done!"); - notification_message(app->notification, &sequence_blink_stop); + notification_message(app->notification, &sequence_blink_start_magenta); - subghz_transmitter_stop(transmitter); + furi_hal_subghz_start_async_tx(subghz_transmitter_yield, app->tx_transmitter); res = true; - - FURI_LOG_D(TAG, "Checking if protocol is dynamic"); - const SubGhzProtocol* registry = - subghz_protocol_registry_get_by_name(string_get_cstr(preset->protocol)); - FURI_LOG_D(TAG, "Protocol-TYPE %d", registry->type); - if(registry && registry->type == SubGhzProtocolTypeDynamic) { - FURI_LOG_D(TAG, " Protocol is dynamic. Updating Repeat"); - unirfremix_save_protocol_to_file(fff_data, path); - - keeloq_reset_mfname(); - keeloq_reset_kl_type(); - star_line_reset_mfname(); - star_line_reset_kl_type(); - } - - subghz_transmitter_free(transmitter); - - furi_hal_subghz_idle(); - furi_hal_subghz_sleep(); } while(0); - unirfremix_preset_free(preset); - unirfremix_end_send(app); return res; } static void unirfremix_send_signal(UniRFRemix* app, Storage* storage, const char* path) { FURI_LOG_I(TAG, "Sending: %s", path); - FlipperFormat* fff_data = flipper_format_string_alloc(); + app->tx_file_path = path; - string_t preset, protocol; - string_init(preset); - string_init(protocol); + app->tx_fff_data = flipper_format_string_alloc(); - for(int x = 0; x < app->repeat; ++x) { - FlipperFormat* fff_file = flipper_format_file_alloc(storage); - unirfremix_send_sub(app, fff_file, fff_data, path); - } + app->txpreset = unirfremix_preset_alloc(); - string_clear(protocol); - string_clear(preset); - flipper_format_free(fff_data); + // load settings/stream from .sub file + FlipperFormat* fff_file = flipper_format_file_alloc(storage); + bool open_ok = false; + do { + if(!flipper_format_file_open_existing(fff_file, path)) { + FURI_LOG_E(TAG, "Could not open file %s", path); + break; + } + if(!unirfremix_key_load( + app->txpreset, + fff_file, + app->tx_fff_data, + app->setting, + app->subghz_receiver, + path)) { + FURI_LOG_E(TAG, "Could not load key"); + break; + } + open_ok = true; + } while(0); + flipper_format_free(fff_file); + if(!open_ok) { + FURI_LOG_E(TAG, "Could not load file!"); + return; + } - unirfremix_end_send(app); + unirfremix_send_sub(app, app->tx_fff_data); } static void unirfremix_process_signal(UniRFRemix* app, string_t signal) { @@ -739,7 +731,7 @@ static void render_callback(Canvas* canvas, void* ctx) { canvas_draw_str_aligned(canvas, 62, 5, AlignCenter, AlignTop, "Config is incorrect."); canvas_set_font(canvas, FontSecondary); canvas_draw_str_aligned(canvas, 62, 30, AlignCenter, AlignTop, "Please configure map."); - canvas_draw_str_aligned(canvas, 62, 60, AlignCenter, AlignBottom, "Hold Back to Exit."); + canvas_draw_str_aligned(canvas, 62, 60, AlignCenter, AlignBottom, "Press Back to Exit."); } else if(app->tx_not_allowed) { canvas_clear(canvas); canvas_set_font(canvas, FontPrimary); @@ -748,7 +740,7 @@ static void render_callback(Canvas* canvas, void* ctx) { canvas_draw_str_aligned(canvas, 62, 15, AlignCenter, AlignTop, "Frequency is outside of"); canvas_draw_str_aligned(canvas, 62, 25, AlignCenter, AlignTop, "default range."); canvas_draw_str_aligned(canvas, 62, 35, AlignCenter, AlignTop, "Check docs."); - canvas_draw_str_aligned(canvas, 62, 60, AlignCenter, AlignBottom, "Hold Back to Exit."); + canvas_draw_str_aligned(canvas, 62, 60, AlignCenter, AlignBottom, "Press Back to Exit."); } else { //map found, draw all the things canvas_clear(canvas); @@ -779,8 +771,7 @@ static void render_callback(Canvas* canvas, void* ctx) { canvas_draw_str(canvas, 10, 40, app->right_label); canvas_draw_str(canvas, 10, 50, app->ok_label); - canvas_draw_str_aligned( - canvas, 11, 62, AlignLeft, AlignBottom, "Hold=Exit. Tap for Repeat:"); + canvas_draw_str_aligned(canvas, 11, 62, AlignLeft, AlignBottom, "Press=Exit."); //Status text and indicator canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, app->send_status); @@ -814,8 +805,7 @@ static void render_callback(Canvas* canvas, void* ctx) { //Repeat indicator //canvas_draw_str_aligned(canvas, 125, 40, AlignRight, AlignBottom, "Repeat:"); //canvas_draw_icon(canvas, 115, 39, &I_UniRFRemix_Repeat_12x14); - canvas_draw_str_aligned( - canvas, 125, 62, AlignRight, AlignBottom, int_to_char(app->repeat)); + //canvas_draw_str_aligned(canvas, 125, 62, AlignRight, AlignBottom, int_to_char(app->repeat)); } furi_mutex_release(app->model_mutex); @@ -826,21 +816,7 @@ static void input_callback(InputEvent* input_event, void* ctx) { furi_message_queue_put(app->input_queue, input_event, 0); } -UniRFRemix* unirfremix_alloc(void) { - UniRFRemix* app = malloc(sizeof(UniRFRemix)); - - app->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - - app->input_queue = furi_message_queue_alloc(32, sizeof(InputEvent)); - - app->view_port = view_port_alloc(); - view_port_draw_callback_set(app->view_port, render_callback, app); - view_port_input_callback_set(app->view_port, input_callback, app); - - // Open GUI and register view_port - app->gui = furi_record_open(RECORD_GUI); - gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen); - +void unirfremix_subghz_alloc(UniRFRemix* app) { // load subghz presets app->setting = subghz_setting_alloc(); subghz_setting_load(app->setting, EXT_PATH("subghz/assets/setting_user")); @@ -856,6 +832,22 @@ UniRFRemix* unirfremix_alloc(void) { app->environment, EXT_PATH("subghz/assets/nice_flor_s")); app->subghz_receiver = subghz_receiver_alloc_init(app->environment); +} + +UniRFRemix* unirfremix_alloc(void) { + UniRFRemix* app = malloc(sizeof(UniRFRemix)); + + app->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal); + + app->input_queue = furi_message_queue_alloc(32, sizeof(InputEvent)); + + app->view_port = view_port_alloc(); + view_port_draw_callback_set(app->view_port, render_callback, app); + view_port_input_callback_set(app->view_port, input_callback, app); + + // Open GUI and register view_port + app->gui = furi_record_open(RECORD_GUI); + gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen); app->notification = furi_record_open(RECORD_NOTIFICATION); @@ -887,6 +879,7 @@ void unirfremix_free(UniRFRemix* app) { furi_mutex_free(app->model_mutex); + furi_hal_subghz_sleep(); subghz_setting_free(app->setting); subghz_receiver_free(app->subghz_receiver); subghz_environment_free(app->environment); @@ -938,6 +931,9 @@ int32_t unirfremix_app(void* p) { unirfremix_cfg_set_check(app, app->file_path); } + // init subghz stuff + unirfremix_subghz_alloc(app); + bool exit_loop = false; if(app->file_result == 2) { @@ -954,7 +950,7 @@ int32_t unirfremix_app(void* p) { app->send_status = "Idle"; app->send_status_c = 0; app->processing = 0; - app->repeat = 1; + //app->repeat = 1; app->button = 0; //refresh screen to update variables before processing main screen or error screens @@ -976,7 +972,7 @@ int32_t unirfremix_app(void* p) { switch(input.key) { case InputKeyUp: - if(input.type == InputTypeShort) { + if(input.type == InputTypePress) { if(app->up_enabled) { if(app->processing == 0) { *app->signal = *app->empty; @@ -986,10 +982,15 @@ int32_t unirfremix_app(void* p) { } } } + if(input.type == InputTypeRelease) { + if(app->up_enabled) { + unirfremix_tx_stop(app); + } + } break; case InputKeyDown: - if(input.type == InputTypeShort) { + if(input.type == InputTypePress) { if(app->down_enabled) { if(app->processing == 0) { *app->signal = *app->empty; @@ -999,10 +1000,15 @@ int32_t unirfremix_app(void* p) { } } } + if(input.type == InputTypeRelease) { + if(app->down_enabled) { + unirfremix_tx_stop(app); + } + } break; case InputKeyRight: - if(input.type == InputTypeShort) { + if(input.type == InputTypePress) { if(app->right_enabled) { if(app->processing == 0) { *app->signal = *app->empty; @@ -1012,10 +1018,15 @@ int32_t unirfremix_app(void* p) { } } } + if(input.type == InputTypeRelease) { + if(app->right_enabled) { + unirfremix_tx_stop(app); + } + } break; case InputKeyLeft: - if(input.type == InputTypeShort) { + if(input.type == InputTypePress) { if(app->left_enabled) { if(app->processing == 0) { *app->signal = *app->empty; @@ -1025,10 +1036,15 @@ int32_t unirfremix_app(void* p) { } } } + if(input.type == InputTypeRelease) { + if(app->left_enabled) { + unirfremix_tx_stop(app); + } + } break; case InputKeyOk: - if(input.type == InputTypeShort) { + if(input.type == InputTypePress) { if(app->ok_enabled) { if(app->processing == 0) { *app->signal = *app->empty; @@ -1038,18 +1054,15 @@ int32_t unirfremix_app(void* p) { } } } + if(input.type == InputTypeRelease) { + if(app->ok_enabled) { + unirfremix_tx_stop(app); + } + } break; case InputKeyBack: if(input.type == InputTypeShort) { - if(app->processing == 0) { - if(app->repeat < 5) { - app->repeat++; - } else { - app->repeat = 1; - } - } - } else if(input.type == InputTypeLong) { exit_loop = true; } break; @@ -1122,7 +1135,7 @@ int32_t unirfremix_app(void* p) { case InputKeyOk: break; case InputKeyBack: - if(input.type == InputTypeLong) { + if(input.type == InputTypeShort) { exit_loop = true; } break; From 33176220f6a13bab49ccf1a993914e9500b49367 Mon Sep 17 00:00:00 2001 From: Daniel <71837281+darmiel@users.noreply.github.com> Date: Thu, 25 Aug 2022 01:24:11 +0200 Subject: [PATCH 36/78] feat[freq-analzer]: added feedback levels 0, 1, 2 0 - no feedback 1 - vibro only 2 - vibro and beep switch the modes with the "UP" key --- .../subghz/views/subghz_frequency_analyzer.c | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/applications/subghz/views/subghz_frequency_analyzer.c b/applications/subghz/views/subghz_frequency_analyzer.c index 14942fc753..510d6ac6d0 100644 --- a/applications/subghz/views/subghz_frequency_analyzer.c +++ b/applications/subghz/views/subghz_frequency_analyzer.c @@ -40,6 +40,7 @@ struct SubGhzFrequencyAnalyzer { SubGhzFrequencyAnalyzerCallback callback; void* context; bool locked; + uint8_t feedback_level; // 0 - no feedback, 1 - vibro only, 2 - vibro and sound float rssi_last; uint32_t frequency_last; uint32_t frequency_last_vis; @@ -174,9 +175,19 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { need_redraw = true; } + if(event->type == InputTypePress && event->key == InputKeyUp) { + if(instance->feedback_level == 0) { + instance->feedback_level = 2; + } else { + instance->feedback_level--; + } + FURI_LOG_D(TAG, "feedback_level = %d", instance->feedback_level); + need_redraw = true; + } + if(need_redraw) { SubGhzFrequencyAnalyzer* instance = context; - with_view_model( + instance->view with_view_model( instance->view, (SubGhzFrequencyAnalyzerModel * model) { model->rssi_last = instance->rssi_last; model->frequency_last = instance->frequency_last; @@ -218,7 +229,18 @@ void subghz_frequency_analyzer_pair_callback(void* context, uint32_t frequency, // Triggered! instance->rssi_last = rssi; notification_message(instance->notifications, &sequence_hw_blink_stop); - notification_message(instance->notifications, &sequence_success); + + switch(instance->feedback_level) { + case 1: // 1 - only vibro + notification_message(instance->notifications, &sequence_single_vibro); + break; + case 2: // 2 - vibro and beep + notification_message(instance->notifications, &sequence_success); + break; + default: // 0 - no feedback + break; + } + FURI_LOG_D(TAG, "triggered"); } // Update values @@ -294,6 +316,8 @@ SubGhzFrequencyAnalyzer* subghz_frequency_analyzer_alloc() { SubGhzFrequencyAnalyzer* instance = malloc(sizeof(SubGhzFrequencyAnalyzer)); furi_assert(instance); + instance->feedback_level = 2; + // View allocation and configuration instance->view = view_alloc(); view_allocate_model( From f9d3d6bf5c20ecac4f0dc7896a5a43b62401b727 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 25 Aug 2022 03:21:44 +0300 Subject: [PATCH 37/78] fix unirf crash, fix keeloq seed display, fix flipfrid and add new unirf icon(animated) by Svarich --- applications/flipfrid/application.fam | 5 +- applications/flipfrid/flipfrid.c | 74 ++++++++++-------- applications/meta/application.fam | 2 +- applications/unirfremix/unirfremix_app.c | 23 +++--- .../icons/MainMenu/UniRFRemix_14/frame_0.png | Bin 170 -> 1623 bytes .../icons/MainMenu/UniRFRemix_14/frame_1.png | Bin 165 -> 1622 bytes .../icons/MainMenu/UniRFRemix_14/frame_2.png | Bin 171 -> 1593 bytes .../icons/MainMenu/UniRFRemix_14/frame_3.png | Bin 168 -> 1610 bytes .../icons/MainMenu/UniRFRemix_14/frame_4.png | Bin 169 -> 1609 bytes .../icons/MainMenu/UniRFRemix_14/frame_5.png | Bin 166 -> 1610 bytes .../icons/MainMenu/UniRFRemix_14/frame_6.png | Bin 0 -> 1593 bytes .../icons/MainMenu/UniRFRemix_14/frame_7.png | Bin 0 -> 1622 bytes .../icons/MainMenu/UniRFRemix_14/frame_rate | 2 +- lib/subghz/protocols/keeloq.c | 53 +++++++++---- 14 files changed, 94 insertions(+), 65 deletions(-) create mode 100644 assets/icons/MainMenu/UniRFRemix_14/frame_6.png create mode 100644 assets/icons/MainMenu/UniRFRemix_14/frame_7.png diff --git a/applications/flipfrid/application.fam b/applications/flipfrid/application.fam index 87b38b6d29..0eee3cc1bd 100644 --- a/applications/flipfrid/application.fam +++ b/applications/flipfrid/application.fam @@ -1,11 +1,10 @@ App( appid="flipfrid", - name="Rfid fuzzer", + name="RFID Fuzzer", apptype=FlipperAppType.PLUGIN, entry_point="flipfrid_start", cdefines=["APP_FLIP_FRID"], requires=["gui"], stack_size=1 * 1024, - icon="A_125khz_14", - order=185, + order=29, ) diff --git a/applications/flipfrid/flipfrid.c b/applications/flipfrid/flipfrid.c index 5f38ff4585..cc8898dff6 100644 --- a/applications/flipfrid/flipfrid.c +++ b/applications/flipfrid/flipfrid.c @@ -9,7 +9,7 @@ #include "flipfrid.h" -#define NUMBER_OF_ATTACKS 4 +#define NUMBER_OF_ATTACKS 3 #define TIME_BETWEEN_CARDS \ 5 // Emulate 2 cards per second : (5 * (configTICK_RATE_HZ_RAW/10)) == (5*(1000/10)) == (5*100) == (500)ms #define TAG "FLIPFRID" @@ -95,7 +95,7 @@ static void flipfrid_draw_callback(Canvas* const canvas, void* ctx) { if(flipfrid_state->current_attack_type == BruteForceCustomerId) { snprintf(uid, sizeof(uid), " ID : %2X ", flipfrid_state->current_uid[0]); - } else if (flipfrid_state->current_attack_type == BadCrc) { + } else if(flipfrid_state->current_attack_type == BadCrc) { snprintf(uid, sizeof(uid), "Sending packets"); } else { snprintf( @@ -142,7 +142,7 @@ static void flipfrid_timer_callback(FuriMessageQueue* event_queue) { // ENTRYPOINT int32_t flipfrid_start(void* p) { UNUSED(p); - + // Input FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(FlipFridEvent)); FlipFridState* flipfrid_state = (FlipFridState*)malloc(sizeof(FlipFridState)); @@ -207,6 +207,8 @@ int32_t flipfrid_start(void* p) { case InputKeyRight: // Next badge type flipfrid_state->emitting = false; + attack_state = 0; + notification_message(flipfrid_state->notify, &sequence_blink_stop); if(menu_selected_item_index < (NUMBER_OF_ATTACKS - 1)) { menu_selected_item_index++; flipfrid_state->current_attack_type = @@ -216,6 +218,8 @@ int32_t flipfrid_start(void* p) { case InputKeyLeft: // Previous badge type flipfrid_state->emitting = false; + attack_state = 0; + notification_message(flipfrid_state->notify, &sequence_blink_stop); if(menu_selected_item_index > 0) { menu_selected_item_index--; flipfrid_state->current_attack_type = @@ -232,10 +236,12 @@ int32_t flipfrid_start(void* p) { flipfrid_state->emitting = true; attack_state = 0; // TODO FIX BLINK - notification_message(flipfrid_state->notify, &sequence_blink_start_magenta); + notification_message( + flipfrid_state->notify, &sequence_blink_start_blue); } break; case InputKeyBack: + notification_message(flipfrid_state->notify, &sequence_blink_stop); flipfrid_state->emitting = false; running = false; break; @@ -255,38 +261,38 @@ int32_t flipfrid_start(void* p) { lfrfid_worker_stop_thread(worker); // set next value switch(flipfrid_state->current_attack_type) { - case DefaultKeys: { - selectedProtocol = CLEAN; - data_size = 5; - flipfrid_state->current_uid = id_list[attack_state]; - attack_state = attack_state + 1; - if(attack_state >= sizeof(id_list) / sizeof(id_list[0])) { - attack_state = 0; - } - break; - } - case BruteForceCustomerId: { - data_size = 5; - selectedProtocol = CLEAN; - candidate[0] = attack_state; - flipfrid_state->current_uid = candidate; - attack_state = attack_state + 1; - if((attack_state + 1) == 256) { - attack_state = 0; - } - break; + case DefaultKeys: { + selectedProtocol = CLEAN; + data_size = 5; + flipfrid_state->current_uid = id_list[attack_state]; + attack_state = attack_state + 1; + if(attack_state >= sizeof(id_list) / sizeof(id_list[0])) { + attack_state = 0; } - case BadCrc: { - selectedProtocol = BAD_CRC; - data_size = 5; - candidate[0] = 0xFF; - candidate[1] = 0xDE; - candidate[2] = 0xAD; - candidate[3] = 0xBE; - candidate[4] = 0xEF; - flipfrid_state->current_uid = candidate; - break; + break; + } + case BruteForceCustomerId: { + data_size = 5; + selectedProtocol = CLEAN; + candidate[0] = attack_state; + flipfrid_state->current_uid = candidate; + attack_state = attack_state + 1; + if((attack_state + 1) == 256) { + attack_state = 0; } + break; + } + case BadCrc: { + selectedProtocol = BAD_CRC; + data_size = 5; + candidate[0] = 0xFF; + candidate[1] = 0xDE; + candidate[2] = 0xAD; + candidate[3] = 0xBE; + candidate[4] = 0xEF; + flipfrid_state->current_uid = candidate; + break; + } } } if(counter > TIME_BETWEEN_CARDS) { diff --git a/applications/meta/application.fam b/applications/meta/application.fam index 0d654eb9c9..65a9f1dc46 100644 --- a/applications/meta/application.fam +++ b/applications/meta/application.fam @@ -36,7 +36,6 @@ App( provides=[ "music_player", "bt_hid", - "flipfrid", ], ) @@ -78,5 +77,6 @@ App( "wifi_scanner", "wav_player", "multi_converter", + "flipfrid", ], ) \ No newline at end of file diff --git a/applications/unirfremix/unirfremix_app.c b/applications/unirfremix/unirfremix_app.c index f89d197862..064f839a42 100644 --- a/applications/unirfremix/unirfremix_app.c +++ b/applications/unirfremix/unirfremix_app.c @@ -86,7 +86,6 @@ typedef struct { SubGhzTransmitter* tx_transmitter; FlipperFormat* tx_fff_data; const char* tx_file_path; - //int repeat; int button; int file_result; @@ -457,7 +456,9 @@ bool unirfremix_set_preset(UniRFPreset* p, const char* preset) { } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { string_set(p->name, "FM476"); } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) { - string_set(p->name, "CUSTOM"); + FURI_LOG_E(TAG, "Custom preset unsupported now"); + return false; + // string_set(p->name, "CUSTOM"); } else { FURI_LOG_E(TAG, "Unsupported preset"); return false; @@ -501,6 +502,8 @@ bool unirfremix_key_load( } if(!strcmp(string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) { // TODO: check if preset is custom + FURI_LOG_E(TAG, "Could not use custom preset"); + break; } size_t preset_index = subghz_setting_get_inx_preset_by_name(setting, string_get_cstr(preset->name)); @@ -583,11 +586,16 @@ bool unirfremix_save_protocol_to_file(FlipperFormat* fff_file, const char* dev_f } void unirfremix_tx_stop(UniRFRemix* app) { + if(app->processing == 0) { + return; + } + if(!string_cmp_str(app->txpreset->protocol, "RAW")) { while(!furi_hal_subghz_is_async_tx_complete()) { - furi_delay_ms(60); + furi_delay_ms(15); } } + //Stop TX furi_hal_subghz_stop_async_tx(); FURI_LOG_I(TAG, "TX Done!"); @@ -1062,9 +1070,8 @@ int32_t unirfremix_app(void* p) { break; case InputKeyBack: - if(input.type == InputTypeShort) { - exit_loop = true; - } + unirfremix_tx_stop(app); + exit_loop = true; break; } @@ -1135,9 +1142,7 @@ int32_t unirfremix_app(void* p) { case InputKeyOk: break; case InputKeyBack: - if(input.type == InputTypeShort) { - exit_loop = true; - } + exit_loop = true; break; } diff --git a/assets/icons/MainMenu/UniRFRemix_14/frame_0.png b/assets/icons/MainMenu/UniRFRemix_14/frame_0.png index 8d135853f5ec8f6905074e662b76e8d2bdd4535b..166d2229b4c8f2e6c023173424d6e155e955afd6 100644 GIT binary patch literal 1623 zcmcIk&x_BY3d7Qt1xUNyVgQ zx@Rtmh_HL|;J>hf2R(~|dJ#nMz8CS}LGa>LJo&0S9T(Xjb1{&ll6>{O@4ffs-PzxJ z^YWz^FKL=~d9d3*fcv^SpScLvPhR=@W4NtVyKgs|W^AbQ!u;OmiKadMV?I2Thsn)| ziNc_%7;$4>RDjmB>znh6vLi0hh>!C!#(#eE9Y%Q?|R>O9e!S$v)Z^HAkL7bVi7c{LrvG z*A0T#kWFl265q6lZrc&@qMn1=14Fbr&7y<;8*MCjit$9sDl*O4Y-Y?HL)2r_3d7JO zwrSfsAoS+6lyt6_&BltM&l^_fmCQwn6eAspV;N&mx=f*{I@+>n%LD~8=d>~{gQ%2N zz$AG*v?w}sBX>?9N~`yw#Le)u;^qNw#Bt5|&IvE&#wu9Ky1mtLJzZp)GLuhv0k8&y zSzV}VBBW?0;t_dtpSx_TXuIZAih3x-bk(T+6$`R$gP^Oo^D-5)=9*H}Zs2_?d5ocJ zwoU@wc88W9xlZKtUL{UM$P$`>4^k@W`M@I0v(xiHlO!6Hjie>xgMN%bl#%CY`AgfZ9DpfS}{0sz9MtZt!xm>3~mg*VdPUZm% z?fDp`EXqV(Q1D4!&@nfwa*WZxYPQ8x)QL!;=8keRutOHRc>}FGZU2v3{JnNH&C$Yi z5oOBjF=ndCJjLzn{9)BQm(C^aY{G%`G0k7X8j;Bvt@+j%D*Z%rnU50R(32-fKUd@b zN9k=@*@Tv34ujLgDj8Fam}OJU|MqL~?SXN$g2Rkc%Wk;BLpPpz3Dh+V-@9V%Zy4OY zL4Rv_^#%6Vb5A`RXg4mr^UM1$X~qv9e7^oO`Rby)cmIpehS%2CzyHno>C^Q;o<~Cf*(6m=>pl}gPD1fmkM91v-#?Prg_sfj|Il96zTl0glXD)ssK&Wx3@pRt`8 zCqe=t1Y!kSegLcxD^{?8>|lX}_#@r28`RW!>m9Oss( z6P>8URy88)x<@R}?1}9mVYDJ1di%khHWohl(zvQ}PgQ5LnKJ7sycnsP>$)n@Rb7`6 zA(tmvMQb@L*Om+cl&nbdD&d*fFw%%0SH6Tw7b&E9N1K&xnXq7LO>4IV z)3igE)%Fylw0fUNTnu5nP(a^6(*1(tVCg27b+j~ zikD;llsvl6T{gM5RRFDcG2nc%Y}DS8MbveLi0gNgEatQFMx&_R00FJQm#}NPOdMG^ z2Ab^|hG*DslAcG%0vh5R#I&Lp1M@f;o?HYPhF(7_E1EIr2fl=&lq88g+ljQua5UM8 zbX&GG!;&Mz#CZbKa%|eOnbDi;!u_}$2H5&T=Ai^XULGcK=a*vY3+M7ZlfP; z4%S~}|9t)2%X?>^41W9cht>P5AAG)Y@WLC{!z+JIZ{B$QY^DDA&bNP`y?W`j;Fk8s aW#KLVr+Z(nKm4n4{{HrE@Z&oVKKmD_yz`s@ delta 148 zcmV;F0Bir&45a~(8Gi-<0019IEztk~00DDSM?wIu&K&6g003V}L_t(2k+o7m4!|%7 z0@MG0nVq^Ar`0qWCu6}9l#+x5Bmn@$GwdXabt{};WzEW7D~$HCLCX^*f#ip{d!A<* z@q|6#Ivn#BCU|XU2QUsN;@5SQ;Yd3ETw3jp`~l0cJ{Avf`3-^q0000NLOmOF`k*-wX*gYdy?Jc z$e~iz16(+Ati*{w01hC*fin_+2RGCs-|Tu#h1!q{mTZshH}8Aj55FfzhacU(_4X~t zac++ehR1M!)1I%t2G_6O{oyg(-lz^fYaGYhvgeKEvz>Ftx%pc@J~1ch$4uzL<5FkJ zTNV|d9p}N$vf|=Y88=hYyiCxaKmLT=TqfvIKP73kr)K%VWvw1w9*)K3sfZ=odEb4o zWI#|T!`)>uFB`T@(2AGA+P?OYyMmb01nt^@?n!#&?&(^&kw>r~gt~*+3!*UG-hR)e zgc6?&{D5Fe8HrfG=e7reXtkWM)#$TYsQq(QnypPRDZ0JYSv_B6Duu7+ssLC6!h$YTHPc2n zGyRG@y3buU72B&7H@Y5cJ>N9yXv5-C>Jj(eqr8-Q(Y#|7wHwrs8)0BQIq|V{b;qw<+ttttOVUNVoq#xlpP(7>y;K@ipaS(EqsZffHQshd(Cb}*- z%t>DGsq(9GirjzH?CH6#Q!Sz9Jv+_74p|)J4Ycl}{XZV6FWS{ScUMElxUjRHAYq%V zBx+yhFR9-3bgpR^GXHi!q|5f4}etxy|>oxv=l-`zA%y>Cf zV4Oa($@tb{)=lyM-LKWR7wl*Q2amJM&RpT4vu9NTbq(g*`^J0=#{Jf4xI4agM?C-P n#@(Ntr_aCp{nKZ^-oNS0$A8`Z#0l&B delta 154 zcmV;L0A>HV466Z<8Gi-<0019IEztk~00DDSM?wIu&K&6g003o4L_t(2k)4uB4!|G` z18vm*e|dVMLXlHw=NOy?Ck9Z!wj`-}*65M|0Z)O-6{AbXj+oeuw@s|wQlV=V&OcS* zjIFwnggb0!S5FvkmUjShI)GzyQpFv=*U_3YPwrF4y0gR$z7rEc6&nF$_5c6?07*qo IM6N<$f@D!Vxc~qF diff --git a/assets/icons/MainMenu/UniRFRemix_14/frame_3.png b/assets/icons/MainMenu/UniRFRemix_14/frame_3.png index efd7181f0a36490d555a6e16df3bf2c457d592f2..c6d314d86ffecc88f52cecc87fc9f6caf6a8452c 100644 GIT binary patch literal 1610 zcmcIkJ#XYh7bhdH6UkmfAeo*6&y^FHr~-%kz?UcGVs z`RkTt-RSLgkKny-?x&xC=jXS+{TN=?%DuO0%W^l&y*9hQb!J&l{halW^>MmSxyoH8 z)Ihqkyacpm-QJp&jGstt59BB-66g2tesJteB+k87iqmpOjqTX0BbY;z}tkjt*Y{SR~>QpBVC|!h*mkn)EFVh4G^Jc8{d>5OLR=_m9 z9Gd41y4JgA;AN@zp~Q9nyp-ONtkr47zhW=(m-~ZmWcyZBM5g8 z3HyFT!#2g_1sqU}7tj>?Krqd&238^)o?iu;rnFboniX93x`_j#+$<9`h;cmZ1RTXf z93k$95n?PNNRT+6OLEvHw-Gqb90Km4KWFrkfX0>}55S?tJ-w+?DSxSCh=1Hyvf%^m^iO zQ)CIzFOIW^WbbM^7xvS!1ky{2zkt6vg{*z2@H@7)L8O%s8`bhAV8E@hl6Vu3-3n`O@E?!rcNxX*^?mt0WV%X`ldS_7ug->VjxK+dFpwe_ao0&M~83Sxc=gG zP19}+4*JJ%f3`WFegdvvzw-STaJyC^9S4Kn)cMs>F}gJiQfsi%1kCy zBF%YL09w1##mls)Qx$R$$8{O-gHE9A6I2 zvJPF<`{xj))%!@|YPcvQK9-d_E4kc1mwCOp4kmcFw>T@O%S;8waw;=`RUpjjLKPEL zt7@VilSlWt%ccnTO37+f4wag&8+Ej1L6n*V-MX9RLd~k%jiPpg?6X=%I&_U1#5brj zw7k%PuDP!gJ0xTUjbRQ1tJ&4SN~EL3RiJSk4)UsIIhTWeq=P6kO+`pOS5nXR4Tt;8 zV8Zc?M7X|T*}ONh0&ZEBz0?K!`--16Z^5{44*EO8 zTQBgxo_q2cU)$Zd_xmR=Y35I#-hcVKKi+%r`R?s&&%Z6o4ebs3%hs>&FMeyxez1So K|7Q2Y&;ABlOYj%~ delta 152 zcmX@fvyyRwWIY=L1B1MW?nNNQSRCZ;#IWw1%u66A+0(@_L}TLCNtS#Jh8)bkQ~uZA zj22Wpt&uZPbEhGT=OF<>hK6IkS5+snoD6ojc`eGS?8cG2J=u%Oid)Ng&&)M3$TiKo zTNb#fA++?+ERI0SbhdH6UkmfAeo*6&y^FHr~-%kz?UcGVs z`RkTt-RSLgkKny-?x&xC=jXS+{TN=?%DuO0%W^l&y*9hQb!J&l{halW^>MmSxyoH8 z)Ihqkyacpm-QJp&jGstt59BB-66g2tesJteB+k87iqmpOjqTX0BbY;z}tkjt*Y{SR~>QpBVC|!h*mkn)EFVh4G^Jc8{d>5OLR=_m9 z9Gd41y4JgA;AN@zp~Q9nyp-ONtkr47zhW=(m-~ZmWcyZBM5g8 z3HyFT!#2g_1sqU}7tj>?Krqd&238^)o?iu;rnFboniX93x`_j#+$<9`h;cmZ1RTXf z93k$95n?PNNRT+6OLEvHw-Gqb90Km4KWFrkfX0>}55S?tJ-w+?DSxSCh=1Hyvf%^m^iO zQ)CIzFOIW^WbbM^7xvS!1ky{2zkt6vg{*z2@H@7)L8O%s8`bhAV8E@hl6Vu3-3n`O@E?!rXOssI3?j7}tyAo&g0@z~!*F~Jg(y(@87bAwuqYIYXa zn%=D-rchuu)d~6(xq}>*JAg?zKdmFFo|L22+mXK;jyNU!zz(~f00000NkvXXu0mjf DF!ei$ diff --git a/assets/icons/MainMenu/UniRFRemix_14/frame_6.png b/assets/icons/MainMenu/UniRFRemix_14/frame_6.png new file mode 100644 index 0000000000000000000000000000000000000000..10727049d33e55e592d1330b94bcf1ae5e785788 GIT binary patch literal 1593 zcmcIk&u`pB7NLOmOF`k*-wX*gYdy?Jc z$e~iz16(+Ati*{w01hC*fin_+2RGCs-|Tu#h1!q{mTZshH}8Aj55FfzhacU(_4X~t zac++ehR1M!)1I%t2G_6O{oyg(-lz^fYaGYhvgeKEvz>Ftx%pc@J~1ch$4uzL<5FkJ zTNV|d9p}N$vf|=Y88=hYyiCxaKmLT=TqfvIKP73kr)K%VWvw1w9*)K3sfZ=odEb4o zWI#|T!`)>uFB`T@(2AGA+P?OYyMmb01nt^@?n!#&?&(^&kw>r~gt~*+3!*UG-hR)e zgc6?&{D5Fe8HrfG=e7reXtkWM)#$TYsQq(QnypPRDZ0JYSv_B6Duu7+ssLC6!h$YTHPc2n zGyRG@y3buU72B&7H@Y5cJ>N9yXv5-C>Jj(eqr8-Q(Y#|7wHwrs8)0BQIq|V{b;qw<+ttttOVUNVoq#xlpP(7>y;K@ipaS(EqsZffHQshd(Cb}*- z%t>DGsq(9GirjzH?CH6#Q!Sz9Jv+_74p|)J4Ycl}{XZV6FWS{ScUMElxUjRHAYq%V zBx+yhFR9-3bgpR^GXHi!q|5f4}etxy|>oxv=l-`zA%y>Cf zV4Oa($@tb{)=lyM-LKWR7wl*Q2amJM&RpT4vu9NTbq(g*`^J0=#{Jf4xI4agM?C-P n#@(Ntr_aCp{nKZ^-oNS0$A8`Z#0l&B literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/UniRFRemix_14/frame_7.png b/assets/icons/MainMenu/UniRFRemix_14/frame_7.png new file mode 100644 index 0000000000000000000000000000000000000000..8bd337c697cf824fa2670e36db8b116f40b5d35d GIT binary patch literal 1622 zcmcIkO>f*(6m=>pl}gPD1fmkM91v-#?Prg_sfj|Il96zTl0glXD)ssK&Wx3@pRt`8 zCqe=t1Y!kSegLcxD^{?8>|lX}_#@r28`RW!>m9Oss( z6P>8URy88)x<@R}?1}9mVYDJ1di%khHWohl(zvQ}PgQ5LnKJ7sycnsP>$)n@Rb7`6 zA(tmvMQb@L*Om+cl&nbdD&d*fFw%%0SH6Tw7b&E9N1K&xnXq7LO>4IV z)3igE)%Fylw0fUNTnu5nP(a^6(*1(tVCg27b+j~ zikD;llsvl6T{gM5RRFDcG2nc%Y}DS8MbveLi0gNgEatQFMx&_R00FJQm#}NPOdMG^ z2Ab^|hG*DslAcG%0vh5R#I&Lp1M@f;o?HYPhF(7_E1EIr2fl=&lq88g+ljQua5UM8 zbX&GG!;&Mz#CZbKa%|eOnbDi;!u_}$2H5&T=Ai^XULGcK=a*vY3+M7ZlfP; z4%S~}|9t)2%X?>^41W9cht>P5AAG)Y@WLC{!z+JIZ{B$QY^DDA&bNP`y?W`j;Fk8s aW#KLVr+Z(nKm4n4{{HrE@Z&oVKKmD_yz`s@ literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/UniRFRemix_14/frame_rate b/assets/icons/MainMenu/UniRFRemix_14/frame_rate index 00750edc07..b8626c4cff 100644 --- a/assets/icons/MainMenu/UniRFRemix_14/frame_rate +++ b/assets/icons/MainMenu/UniRFRemix_14/frame_rate @@ -1 +1 @@ -3 +4 diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 32582faf93..12c5dfa8f6 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -944,21 +944,40 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, string_t output) { uint32_t code_found_reverse_hi = code_found_reverse >> 32; uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; - string_cat_printf( - output, - "%s %dbit\r\n" - "Key:%08lX%08lX\r\n" - "Fix:0x%08lX Cnt:%04X\r\n" - "Hop:0x%08lX Btn:%01lX\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, - code_found_reverse_lo, - instance->generic.btn, - instance->manufacture_name, - instance->generic.seed); + if(strcmp(instance->manufacture_name, "BFT") == 0) { + string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%08lX%08lX\r\n" + "Fix:0x%08lX Cnt:%04X\r\n" + "Hop:0x%08lX Btn:%01lX\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, + code_found_reverse_lo, + instance->generic.btn, + instance->manufacture_name, + instance->generic.seed); + } else { + string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%08lX%08lX\r\n" + "Fix:0x%08lX Cnt:%04X\r\n" + "Hop:0x%08lX Btn:%01lX\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); + } } From f6d38939c2e8894a15a4ad829ad0cab35a188787 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 25 Aug 2022 05:13:08 +0300 Subject: [PATCH 38/78] hide txt extension in unirf browser --- applications/unirfremix/unirfremix_app.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/unirfremix/unirfremix_app.c b/applications/unirfremix/unirfremix_app.c index 064f839a42..4e0dab2e7d 100644 --- a/applications/unirfremix/unirfremix_app.c +++ b/applications/unirfremix/unirfremix_app.c @@ -929,7 +929,7 @@ int32_t unirfremix_app(void* p) { DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); bool res = dialog_file_browser_show( - dialogs, app->file_path, app->file_path, UNIRFMAP_EXTENSION, true, &I_sub1_10px, false); + dialogs, app->file_path, app->file_path, UNIRFMAP_EXTENSION, true, &I_sub1_10px, true); furi_record_close(RECORD_DIALOGS); if(!res) { From 6c2cf6807712823b8431b0f247183c8b88e1886b Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 25 Aug 2022 05:31:47 +0300 Subject: [PATCH 39/78] update tv asset by @Amec0e --- assets/resources/Manifest | 4 +-- assets/resources/infrared/assets/tv.ir | 40 +++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/assets/resources/Manifest b/assets/resources/Manifest index 35898f60e8..484831bbfa 100644 --- a/assets/resources/Manifest +++ b/assets/resources/Manifest @@ -1,5 +1,5 @@ V:0 -T:1661280310 +T:1661394663 D:badusb D:dolphin D:infrared @@ -244,7 +244,7 @@ D:infrared/assets F:ed61e6f4adc7972bde0e7b5028effac3:101928:infrared/assets/ac.ir F:229a87b90c1890c5ec6d9e3b0f4695fb:48062:infrared/assets/audio.ir F:63ca357ca0b85a6ad900539e7b6a0fed:5086:infrared/assets/projectors.ir -F:0370c1333f1e0d8d690b5afbfc623a60:127656:infrared/assets/tv.ir +F:8920a0548ec658a546a8c6476298e0db:128166:infrared/assets/tv.ir F:a157a80f5a668700403d870c23b9567d:470:music_player/Marble_Machine.fmf D:nfc/assets F:81dc04c7b181f94b644079a71476dff4:4742:nfc/assets/aid.nfc diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir index 8f3d990205..fb7f2123e2 100755 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -11,7 +11,7 @@ Version: 1 # Also a HUGE thank you to Amec0e for continued maintenance! ############################################################ # -# Updated on 21th August 2022 +# Updated on 25th August 2022 # name: POWER type: parsed @@ -2502,6 +2502,44 @@ protocol: NECext address: 64 46 00 00 command: DB 24 00 00 # +# FURRION +# +name: POWER +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 52 00 00 00 +# +name: MUTE +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 53 00 00 00 +# +name: CH+ +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 02 00 00 00 +# +name: CH- +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 09 00 00 00 +# +name: VOL+ +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 03 00 00 00 +# +name: VOL- +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 41 00 00 00 +# # HISENSE # name: POWER From e828d15fe3fd13b98400990de337f8bc195e776a Mon Sep 17 00:00:00 2001 From: Daniel <71837281+darmiel@users.noreply.github.com> Date: Thu, 25 Aug 2022 08:57:31 +0200 Subject: [PATCH 40/78] feat[freq-analzer]: added ui for feedbacl level --- .../subghz/views/subghz_frequency_analyzer.c | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/applications/subghz/views/subghz_frequency_analyzer.c b/applications/subghz/views/subghz_frequency_analyzer.c index 510d6ac6d0..5be00888fe 100644 --- a/applications/subghz/views/subghz_frequency_analyzer.c +++ b/applications/subghz/views/subghz_frequency_analyzer.c @@ -53,6 +53,7 @@ typedef struct { float rssi; float rssi_last; float trigger; + uint8_t feedback_level; } SubGhzFrequencyAnalyzerModel; void subghz_frequency_analyzer_set_callback( @@ -142,6 +143,21 @@ void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel } canvas_draw_str(canvas, 9, 42, buffer); + switch(model->feedback_level) { + case 2: + canvas_draw_icon(canvas, 128 - 8 - 1, 1, &I_Volup_8x6); + break; + case 1: + canvas_draw_icon(canvas, 128 - 8 - 1, 1, &I_Voldwn_6x6); + break; + case 0: + canvas_draw_icon(canvas, 128 - 8 - 1, 1, &I_Voldwn_6x6); + canvas_set_color(canvas, ColorWhite); + canvas_draw_box(canvas, 128 - 2 - 1 - 2, 1, 2, 6); + canvas_set_color(canvas, ColorBlack); + break; + } + // Buttons hint elements_button_left(canvas, "T-"); elements_button_right(canvas, "T+"); @@ -175,7 +191,7 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { need_redraw = true; } - if(event->type == InputTypePress && event->key == InputKeyUp) { + if(event->type == InputTypePress && event->key == InputKeyDown) { if(instance->feedback_level == 0) { instance->feedback_level = 2; } else { @@ -187,12 +203,13 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { if(need_redraw) { SubGhzFrequencyAnalyzer* instance = context; - instance->view with_view_model( + with_view_model( instance->view, (SubGhzFrequencyAnalyzerModel * model) { model->rssi_last = instance->rssi_last; model->frequency_last = instance->frequency_last; model->trigger = subghz_frequency_analyzer_worker_get_trigger_level(instance->worker); + model->feedback_level = instance->feedback_level; return true; }); } @@ -258,6 +275,7 @@ void subghz_frequency_analyzer_pair_callback(void* context, uint32_t frequency, model->frequency = frequency; model->frequency_last = instance->frequency_last_vis; model->trigger = subghz_frequency_analyzer_worker_get_trigger_level(instance->worker); + model->feedback_level = instance->feedback_level; return true; }); } From a0819df87410c4c48501a0b3d310bc4bf4d65d85 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 25 Aug 2022 14:36:51 +0300 Subject: [PATCH 41/78] update changelog --- CHANGELOG.md | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64ed851a2b..872bf8654c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,18 +1,12 @@ ### New changes -* New universal remote for projectors -* OFW: New LF-RFID subsystem (New protocols, Animal tags support) +* UniRF (Sub-GHz Remote) - All protocols support, long button press support (by @darmiel & @xMasterX) (PR #47) +* Frequency Analyzer feedback modes (by @darmiel) (PR #49) +* RFID EM4100 Fuzzer plugin (by @Ganapati & some fixes by @xMasterX) (PR #48) * Updated universal remote assets (by @Amec0e) -* Renamed UniRF Remix -> Sub-GHz Remote -* Replaced Hex/Dec converter with Multi Converter plugin [(by theisolinearchip)](https://github.com/theisolinearchip/flipperzero_stuff) -* New update screen, readme pictures (by @Svaarich) -* Fixed crash if Center button is pressed on the "update success" screen via screensharing -* Temporary disabled one log call in picopass plugin to fix crash/freeze on Read screen -* OFW: Picopass load/info/delete -* OFW: SubGhz: add protocol Magellen -* OFW: Fix mifare ultralight/ntag unlock -* OFW: Dolphin level thresholds update -* OFW: Add MFC 1/4K 4/7bUID to "Add Manually" -* OFW: Other fixes and changes +* New UniRF Animated icon (by @Svaarich) +* Fixed Keeloq seed display +* OFW: SubGhz: fix CAME, Chamberlain protocol +* OFW: LFRFID RC fixes **Note: Prefer installing using web updater or by self update package, all needed assets will be installed** From 64edddeabffbf1f2cb8087bf961a5bd9083649fd Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 25 Aug 2022 17:39:55 +0300 Subject: [PATCH 42/78] new spectrum analyzer icon by @Svaarich --- .../MainMenu/SpectrumAnalyzer_14/frame_0.png | Bin 173 -> 1863 bytes .../MainMenu/SpectrumAnalyzer_14/frame_1.png | Bin 168 -> 1868 bytes .../MainMenu/SpectrumAnalyzer_14/frame_2.png | Bin 157 -> 1876 bytes .../MainMenu/SpectrumAnalyzer_14/frame_3.png | Bin 114 -> 1878 bytes .../MainMenu/SpectrumAnalyzer_14/frame_4.png | Bin 121 -> 1876 bytes .../MainMenu/SpectrumAnalyzer_14/frame_5.png | Bin 150 -> 1868 bytes .../MainMenu/SpectrumAnalyzer_14/frame_rate | 2 +- assets/icons/MainMenu/UniRFRemix_14/frame_rate | 2 +- 8 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_0.png b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_0.png index 4fd68002e264f17319e9ffcebbc942760c3ee111..f2fc132ed5087f825214f25d85249998f021aa67 100644 GIT binary patch literal 1863 zcmcIlO>f*p7J^tPu)vVIp&}@Z6l&)wvmD!o`u9daNv7PKD z+&Ca{gMR=AkN^qpMS=qt{sR9Y5*)de*ZW~YN!zFrD|tPhdFFYa_ha7qYVN$7i;fZz>JPk#M0r<^lkL+&-ap+L@Y4g{7JBC$ zbbCgDAe9wEvviV`bQbD!UJB!S+SJh;QXPc)W^EAdN4u!23W99NdnU%*tRM0spp{OPX}v-i0NMM-K8z~3iWYS<1aJ1{N5y3Bsow0x^pwA>(jtdgM)S+g-| zVcQ*80d*bfcyAMj60(3sPzQol>*9H4~iXYYCtM@O;Rwxb}O@t`-JmLD> z!9z=OOl;T1ERZp7Gj78Y47t5xd%sBF@SS#(=f`AZ`bkapGayawTT1Sm2mQ zC-%LeWL}^n!D+0DltG;&DH};M&qg}>M@?5vR1qlwF?Y_-_q*NQLdD4h7RtT5cTj(; z>sxK#$F^bBWe+mI-R-1=9G@%?(tUZj98D55uTIK%eJDbm*VP~)OpEE{f-qmsp~e2` zSOV!Ys$>BxRa{M3AvZ^mlIK>T`84q*JARII%W-%h8FqX~2&A+HIc-_caU5uCF|phL za{50?Uvl#?%SIA9tf{}aGnXs(3!VAz0eq1>Tu(9zX89yrzA3)>+fO;=gU&xbnuqP5kTi o-*4n=;_%kJFZyTqzCFWQ_nX0^!;gRbvcBs2TRXiU?tJvg-=>;FzW@LL delta 156 zcmV;N0Av5h4y^%@8Gi-<0019IEztk~00DDSM?wIu&K&6g003u6L_t(2k-d^Z5`Z8K z1G|j>|8l%os6Yihm=gotQbLdMRfd0000< KMNUMnLSTZKxjpUx diff --git a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_1.png b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_1.png index f09e6eee588832a55864feceaa7b1a1ddce01976..7bb4f38955dfb2afd1b5e17b95ac91358658a5f2 100644 GIT binary patch literal 1868 zcmcIlO^f727>=_b?!pQSet@Tt0ohe6sZ_p;ZJXKdcBjRR!)(Kj;DVJ(r8_&FR7^6{ zJ#!KT!JC2?j|yHqEO-(W)Po?1Cr=*4Um$oBFS5SrFUQ^4-Ca7p9 zx2~Q)_uM%}QO@@_yF2iHvbmpFgXf1YeEmMW&K8?*REnanH}_-H&)Wxz^7yyuV7J~4 zU!z=RI*Vl_^l4TAT2U^yrv>ACqE;g@O!JoZ=QrPJY8tn+>rRNnq9aD>=20oG9c>Nx z(H;+Ct^Klkc}jsG6E#z(**LH0w582>DU6$GLsMsvdatEzGzQh(a9i!jQmC$u5yzOQ zUZ9(a7K@DRvndlQsm*vnf zgCH<4F$h6`K-FPhvnk4}^(8}BRJ=@!I+eNFFtSMQ*DVc{&Rxig6>VNE!UO>`rmQeb z9XBp5fnj)mXqK(eRoy!PD+|3R5?6!6LKr)ulKUkWy#tZg>q}!XU#%_n%kj+9m>Xg& zGJsVe%v_l&MzWUGNZ!Mb)$f%z1?`lA)v_E&IbJ4ed&!~_qGR>q^)!#=q`K57S}YJ< zR*RMfStAJhh}Z+uqqapY=S6H$jOWl0>L6w{y94YDOqXJxV(Wik8K=qNX`o?9`*~Hf zoQr<9rGY3tO=FrwF7~3xMs8p;6gjqyg21y8@q;L~1YwvsGhML0EBSsCzGnTrY-7oR zV-+Dv>nA1d-8G|}WGd2`Pkq?BD^?P0Qk*V90VIAp|-PVxDh8 z$FZQTCD^n*vUL5CNMD4Nk61nw&|wYj;hi~Mxu2MayEov&9E6ljF_-6l( zHDO5PYzjJiGh7`h@Uc3SL=JH(;mG;*x84~zuIzqyV{q|l{`c+M?K2mYFaBs>P(FR{ zuUEgk`TUJbXW!ZV>KF3nM>p1<-FW85&z}0^hg%>2^!u7((yi}*zB&1)Iq&+tt?sQW HZ@v33$kjz( delta 151 zcmV;I0BHZr4yXZ;8Gi-<0019IEztk~00DDSM?wIu&K&6g003f1L_t(2k-d_^4!|G? zLtC@||K;v72tyIG!+J8p1Jaa|1OO!QJWIu%VV{yf@(6O!fC`R~)yK)U?WwD#-LMku zbXA4UVK*l?u1<|!xH;8;3{2*90m#n30?=s+z!&`w-t1{T9T4PSp5*`l002ovPDHLk FV1l`lKf?e3 diff --git a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_2.png b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_2.png index 1192ed0afda50a9e32d639c36f52d5db55d6e028..3a27b10b25ccbc32eda1a9fab331203ba2d9c484 100644 GIT binary patch literal 1876 zcmcIlO^@3|7&eq5s8pm%<-*B$FD)?kc>EQQ8lv4Kbc5<;*^Sgi0*T3ZoS2P0#`bQq zD}`#N#LQnu|1ge8B?JoCKI`!Vl)vAJ>e z{JEFTDT;Ewx8B);_Y2ki+|%&<`jsC)hu8Dj`a6Z9=quIz)bwU+Us0a@Demu-JHa)| zWumiC4un2UGC(WJmDV(4d{>m}Kn&xwsolH%v!=#jQ@id2ILO*!6t5rVV*7BT&kuLG zA8M`F)hkm91c@k_I!(rDL8nb^#!KP58a6a_1}S%&+G=G`-3d0;w#KJj1iR$^f z>DqRq@tR67!3OpW6C*+>cBx~j^`(KeJdEg8=Z)GH{57>vS!UEQCXXa4b%61 z0~3P~1PD|dq$Qi8v{+d%bVR}PI4fhBsud#}$i1?ufzr7PNw%a-i#kjYFk{Lx!_;x* z(gGL+kB2775?z$teXvsNJ(0NRA7sMV5{2B$x#;eTv|L#j3;A+wwwI4*o`&2IW03%? z0Ac3RR5p^OEJpGXek`Y#-ek0$3s%a!FXecVsLch7N{EitOV{Hxl#}9erKnyYI;<2; z4YEcMZXja!O^@0ZwVYS6MKPX31E_Gm;8;8nLSAS)sNs9?aK*rK9MiYl!Auvd??}E^g|AvaFWXRZ;8;e8 znwG_ElM&=QK0_9y5>>y&= z0AJiLZTYOl5jbn9Ios{uvQ#3VRRf7n%dN@8Q z%%^f_PCFS1Abm`g%wdI$$_dNG>JU=$#40o%CB9($Pmm5t<(`0ax{we8od+?mVM52T zpshvNv^}zL{eO{Ohn0_5Iuy`h4edWTbE2%on>*Ho zA(68o=%eRl2U zj)J0bf6~4D?VYpA@1MSX=hi*<&+6Rk MbvHV<*51GI0M@=pBme*a delta 140 zcmV;70CWG;4xIsz8Gi-<0019IEztk~00DDSM?wIu&K&6g0037>L_t(2k-d^p4uCKS zL;HyLzjFQ2#Km=+#@H_cywCvHwj=>M!l-Lcok`mQmY@b4!96#1>snL6X21*9=N<^8ho&2Y90Y!5zw@D;=Q6cC7#a002ovP6b4+LSTaa13A+G diff --git a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_3.png b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_3.png index 8db45a90100ca4c66ed2e237c5c0da49a0a1c55f..72e9b7f83ad90a8af15ebd4679b90db312f0e5eb 100644 GIT binary patch literal 1878 zcmcIlJ&fE$7&SS8AWD#~00|Jt@-+!C_W0i(WwW~5J#q{9a=NT^myX$)@ve1ikFkBX zdsk8*AsUd7prxRpNRX+KzBe=P zZEapTfA;yailUtFY_zxG{dE02c?SMJc=?NW;q_F$alKR&eWiXL8-Lb3P?RUWO1it% zZuBN$GSw-UJ)w`&9MFn#sX5Lm+Y^=A6a6G>Xn%b9wWcP#q3yU4j`EfmBpXMCxOTMJ zWk-7~wyU~`~l7&z`9V3RZ zrTU?6dX5tWuc{Wduz`KU#K^J;_K0h%v!4d56+9-}?bl{&!B;~YR8>w4V>BA+BU_h6 z-!Q{4G_Yk@76Jq+53`DnQC6lC=>j$vPOz(-rW%n=_#S;=xB?-R#jco9ubT7{sMEV@z-=Y`suv#6G(WA(yLl5sgIFV>1? z6GWRJlXr_cy|z-dMA0lQt(BRC+o|1YrQNql%3XcUo7 zR#r4)qSJ0@AWBaXPM90SA@vv-h?+=*4n-mMI0^zrT|bCzpP3U~FuyI?ex1I0{?xWy zGT>Nbh`3-(&v6B^z0gA}aBS4GEgNwf_%`FdEo^_zcC|=g=g{GC)>;(@MxTbBABR4o z47Na};A?$DZ30piNUbBe5(}3O-3v+80Ki^)>Y$H7z-mMI<@o+&BO!jiiJcAI>(?HSzYWHB8irI|*g=rf6uac7x#B ztUEa&&8G`!N;?_|Abo&Krm#}R)rb~iwGSnEs0)qzi7)BFL!_Iw&3r-Yn)+Z`CqUE> zOfZZM$6Aa{$G7I8|1Z*KX=MYN^#z=;hW6;eoX+ki*5SV!@KNe;axg}HuudIj+-ttc z*s((x3OVV5lf7;(t`zuKTuLH?JQZ-|kXwJf2-nr+PJ6X`;TF4n_il4(S^50;=CbnX zQuNVJumAGBcKxEY^#0WkfBWH?!Yno4JVvwdUjt#|$gL@G-G delta 95 zcmcb{S2RH~l8u3ZLEc06B9LM%4sv&5Sa(k5C6J@z>EaloF){hi|NsB%*^C&3EoZUK ubOQo5AbxfGM3Z+@K*HtwD;GmeGHzielF{r5}E+jpdoJn diff --git a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_4.png b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_4.png index fbd1b47aaf405826bd7a1c5096fec614087d2611..3a27b10b25ccbc32eda1a9fab331203ba2d9c484 100644 GIT binary patch literal 1876 zcmcIlO^@3|7&eq5s8pm%<-*B$FD)?kc>EQQ8lv4Kbc5<;*^Sgi0*T3ZoS2P0#`bQq zD}`#N#LQnu|1ge8B?JoCKI`!Vl)vAJ>e z{JEFTDT;Ewx8B);_Y2ki+|%&<`jsC)hu8Dj`a6Z9=quIz)bwU+Us0a@Demu-JHa)| zWumiC4un2UGC(WJmDV(4d{>m}Kn&xwsolH%v!=#jQ@id2ILO*!6t5rVV*7BT&kuLG zA8M`F)hkm91c@k_I!(rDL8nb^#!KP58a6a_1}S%&+G=G`-3d0;w#KJj1iR$^f z>DqRq@tR67!3OpW6C*+>cBx~j^`(KeJdEg8=Z)GH{57>vS!UEQCXXa4b%61 z0~3P~1PD|dq$Qi8v{+d%bVR}PI4fhBsud#}$i1?ufzr7PNw%a-i#kjYFk{Lx!_;x* z(gGL+kB2775?z$teXvsNJ(0NRA7sMV5{2B$x#;eTv|L#j3;A+wwwI4*o`&2IW03%? z0Ac3RR5p^OEJpGXek`Y#-ek0$3s%a!FXecVsLch7N{EitOV{Hxl#}9erKnyYI;<2; z4YEcMZXja!O^@0ZwVYS6MKPX31E_Gm;8;8nLSAS)sNs9?aK*rK9MiYl!Auvd??}E^g|AvaFWXRZ;8;e8 znwG_ElM&=QK0_9y5>>y&= z0AJiLZTYOl5jbn9Ios{uvQ#3VRRf7n%dN@8Q z%%^f_PCFS1Abm`g%wdI$$_dNG>JU=$#40o%CB9($Pmm5t<(`0ax{we8od+?mVM52T zpshvNv^}zL{eO{Ohn0_5Iuy`h4edWTbE2%on>*Ho zA(68o=%eRl2U zj)J0bf6~4D?VYpA@1MSX=hi*<&+6Rk MbvHV<*51GI0M@=pBme*a delta 102 zcmcb@S2;m4fsKKILEc06B9LM%4sv&5Sa(k5C6Ht6>EaloF){hi|NsB%*^C&3EoZTL zC<8$lr<=_b?!pQSet@Tt0ohe6sZ_p;ZJXKdcBjRR!)(Kj;DVJ(r8_&FR7^6{ zJ#!KT!JC2?j|yHqEO-(W)Po?1Cr=*4Um$oBFS5SrFUQ^4-Ca7p9 zx2~Q)_uM%}QO@@_yF2iHvbmpFgXf1YeEmMW&K8?*REnanH}_-H&)Wxz^7yyuV7J~4 zU!z=RI*Vl_^l4TAT2U^yrv>ACqE;g@O!JoZ=QrPJY8tn+>rRNnq9aD>=20oG9c>Nx z(H;+Ct^Klkc}jsG6E#z(**LH0w582>DU6$GLsMsvdatEzGzQh(a9i!jQmC$u5yzOQ zUZ9(a7K@DRvndlQsm*vnf zgCH<4F$h6`K-FPhvnk4}^(8}BRJ=@!I+eNFFtSMQ*DVc{&Rxig6>VNE!UO>`rmQeb z9XBp5fnj)mXqK(eRoy!PD+|3R5?6!6LKr)ulKUkWy#tZg>q}!XU#%_n%kj+9m>Xg& zGJsVe%v_l&MzWUGNZ!Mb)$f%z1?`lA)v_E&IbJ4ed&!~_qGR>q^)!#=q`K57S}YJ< zR*RMfStAJhh}Z+uqqapY=S6H$jOWl0>L6w{y94YDOqXJxV(Wik8K=qNX`o?9`*~Hf zoQr<9rGY3tO=FrwF7~3xMs8p;6gjqyg21y8@q;L~1YwvsGhML0EBSsCzGnTrY-7oR zV-+Dv>nA1d-8G|}WGd2`Pkq?BD^?P0Qk*V90VIAp|-PVxDh8 z$FZQTCD^n*vUL5CNMD4Nk61nw&|wYj;hi~Mxu2MayEov&9E6ljF_-6l( zHDO5PYzjJiGh7`h@Uc3SL=JH(;mG;*x84~zuIzqyV{q|l{`c+M?K2mYFaBs>P(FR{ zuUEgk`TUJbXW!ZV>KF3nM>p1<-FW85&z}0^hg%>2^!u7((yi}*zB&1)Iq&+tt?sQW HZ@v33$kjz( delta 132 zcmX@ZH;r+EWGx#51B1MW?nNNQSRCZ;#IWw1%u66Az|+MsL}TL9366XR3^)!aZTVks zX+72V>I{MF&t#O7a-y4$uy_e%Ft3)Ll(L(ZIqLKxriM=v2KOsMgZ`)7u6y$4==$*c kdO?2Xn#+B2EE)GO-f@>#KD6}DMxfaYp00i_>zopr04td?KL7v# diff --git a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_rate b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_rate index e440e5c842..bf0d87ab1b 100644 --- a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_rate +++ b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_rate @@ -1 +1 @@ -3 \ No newline at end of file +4 \ No newline at end of file diff --git a/assets/icons/MainMenu/UniRFRemix_14/frame_rate b/assets/icons/MainMenu/UniRFRemix_14/frame_rate index b8626c4cff..bf0d87ab1b 100644 --- a/assets/icons/MainMenu/UniRFRemix_14/frame_rate +++ b/assets/icons/MainMenu/UniRFRemix_14/frame_rate @@ -1 +1 @@ -4 +4 \ No newline at end of file From ab4bb55d0fc7cbc1b117104c0190cac2d21ab8b3 Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Thu, 25 Aug 2022 10:07:54 -0600 Subject: [PATCH 43/78] nfc: Change furi_assert to furi_crash for default switch cases (#1662) * nfc: Change furi_assert to furi_crash for default switch cases * Nfc: change MiFare Ultralight crash message Co-authored-by: Aleksandr Kutuzov --- applications/nfc/helpers/nfc_generators.c | 2 +- lib/nfc/protocols/mifare_ultralight.c | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/applications/nfc/helpers/nfc_generators.c b/applications/nfc/helpers/nfc_generators.c index b94adbd7b0..11083b9f0a 100644 --- a/applications/nfc/helpers/nfc_generators.c +++ b/applications/nfc/helpers/nfc_generators.c @@ -254,7 +254,7 @@ static void session_register_page = 234; break; default: - furi_assert(false); + furi_crash("Unknown MFUL"); break; } diff --git a/lib/nfc/protocols/mifare_ultralight.c b/lib/nfc/protocols/mifare_ultralight.c index f637d378a7..b3d80deb3c 100644 --- a/lib/nfc/protocols/mifare_ultralight.c +++ b/lib/nfc/protocols/mifare_ultralight.c @@ -940,7 +940,7 @@ static bool mf_ul_check_lock(MfUltralightEmulator* emulator, int16_t write_page) if(write_page >= 512) return true; break; default: - furi_assert(false); + furi_crash("Unknown MFUL"); return true; } @@ -967,8 +967,7 @@ static bool mf_ul_check_lock(MfUltralightEmulator* emulator, int16_t write_page) else if(write_page == 41) shift = 12; else { - furi_assert(false); - shift = 0; + furi_crash("Unknown MFUL"); } break; @@ -999,8 +998,7 @@ static bool mf_ul_check_lock(MfUltralightEmulator* emulator, int16_t write_page) shift = (write_page - 16) / 32; break; default: - furi_assert(false); - shift = 0; + furi_crash("Unknown MFUL"); break; } @@ -1177,8 +1175,7 @@ static void mf_ul_emulate_write( block_lock_count = 8; break; default: - furi_assert(false); - block_lock_count = 0; + furi_crash("Unknown MFUL"); break; } From 04f522487eefcf6126432f10199cb5fa7d84fccc Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 26 Aug 2022 20:02:25 +0300 Subject: [PATCH 44/78] Universal remote for fans, new buttons for AC updated assets by @Amec0e --- .drone.yml | 5 +- .../infrared/scenes/infrared_scene_config.h | 1 + .../scenes/infrared_scene_universal.c | 11 + .../scenes/infrared_scene_universal_ac.c | 32 +- .../scenes/infrared_scene_universal_fan.c | 113 +++ assets/icons/Infrared/Rotate_25x27.png | Bin 0 -> 1685 bytes assets/icons/Infrared/Rotate_hvr_25x27.png | Bin 0 -> 1664 bytes assets/icons/Infrared/Swing_25x27.png | Bin 0 -> 1706 bytes assets/icons/Infrared/Swing_hvr_25x27.png | Bin 0 -> 1686 bytes assets/icons/Infrared/Timer_25x27.png | Bin 0 -> 1936 bytes assets/icons/Infrared/Timer_hvr_25x27.png | Bin 0 -> 1916 bytes assets/resources/Manifest | 9 +- assets/resources/infrared/assets/ac.ir | 430 ++++---- assets/resources/infrared/assets/audio.ir | 31 +- assets/resources/infrared/assets/fans.ir | 927 ++++++++++++++++++ assets/resources/infrared/assets/tv.ir | 7 +- 16 files changed, 1381 insertions(+), 185 deletions(-) create mode 100644 applications/infrared/scenes/infrared_scene_universal_fan.c create mode 100644 assets/icons/Infrared/Rotate_25x27.png create mode 100644 assets/icons/Infrared/Rotate_hvr_25x27.png create mode 100644 assets/icons/Infrared/Swing_25x27.png create mode 100644 assets/icons/Infrared/Swing_hvr_25x27.png create mode 100644 assets/icons/Infrared/Timer_25x27.png create mode 100644 assets/icons/Infrared/Timer_hvr_25x27.png create mode 100644 assets/resources/infrared/assets/fans.ir diff --git a/.drone.yml b/.drone.yml index 15c5dfce15..7a9577fa59 100644 --- a/.drone.yml +++ b/.drone.yml @@ -44,6 +44,7 @@ steps: - cp assets/resources/nfc/assets/mf_classic_dict.nfc sd-card/nfc/assets/mf_classic_dict.nfc - cp assets/resources/infrared/assets/tv.ir sd-card/infrared/assets/tv.ir - cp assets/resources/infrared/assets/ac.ir sd-card/infrared/assets/ac.ir + - cp assets/resources/infrared/assets/fans.ir sd-card/infrared/assets/fans.ir - cp assets/resources/infrared/assets/projectors.ir sd-card/infrared/assets/projectors.ir - cp assets/resources/infrared/assets/audio.ir sd-card/infrared/assets/audio.ir - cp assets/resources/unirf/unirf_map_example.txt sd-card/unirf/unirf_map_example.txt @@ -115,9 +116,7 @@ steps: [-Install via Web Updater-](https://my.flipp.dev/?url=https://unleashedflip.com/builds/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=dev-cfw&version=${DRONE_TAG})" document: - - artifacts-default/flipper-z-f7-full-${DRONE_TAG}.dfu - - artifacts-default/flipper-z-f7-update-${DRONE_TAG}.zip - - artifacts-default/sd-card-${DRONE_TAG}.zip + - artifacts-default/flipper-z-f7-update-${DRONE_TAG}.tgz - name: "Send discord notification" image: appleboy/drone-discord diff --git a/applications/infrared/scenes/infrared_scene_config.h b/applications/infrared/scenes/infrared_scene_config.h index 27eabe225f..5514852955 100644 --- a/applications/infrared/scenes/infrared_scene_config.h +++ b/applications/infrared/scenes/infrared_scene_config.h @@ -16,6 +16,7 @@ ADD_SCENE(infrared, remote_list, RemoteList) ADD_SCENE(infrared, universal, Universal) ADD_SCENE(infrared, universal_tv, UniversalTV) ADD_SCENE(infrared, universal_ac, UniversalAC) +ADD_SCENE(infrared, universal_fan, UniversalFan) ADD_SCENE(infrared, universal_audio, UniversalAudio) ADD_SCENE(infrared, universal_projector, UniversalProjector) ADD_SCENE(infrared, debug, Debug) diff --git a/applications/infrared/scenes/infrared_scene_universal.c b/applications/infrared/scenes/infrared_scene_universal.c index 36c7d86e1d..b70ffbd5c9 100644 --- a/applications/infrared/scenes/infrared_scene_universal.c +++ b/applications/infrared/scenes/infrared_scene_universal.c @@ -4,6 +4,7 @@ typedef enum { SubmenuIndexUniversalTV, SubmenuIndexUniversalAudio, SubmenuIndexUniversalProjector, + SubmenuIndexUniversalFan, SubmenuIndexUniversalAirConditioner, } SubmenuIndex; @@ -38,6 +39,13 @@ void infrared_scene_universal_on_enter(void* context) { infrared_scene_universal_submenu_callback, context); + submenu_add_item( + submenu, + "Fans", + SubmenuIndexUniversalFan, + infrared_scene_universal_submenu_callback, + context); + submenu_add_item( submenu, "ACs", @@ -63,6 +71,9 @@ bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubmenuIndexUniversalProjector) { scene_manager_next_scene(scene_manager, InfraredSceneUniversalProjector); consumed = true; + } else if(event.event == SubmenuIndexUniversalFan) { + scene_manager_next_scene(scene_manager, InfraredSceneUniversalFan); + consumed = true; } else if(event.event == SubmenuIndexUniversalAirConditioner) { scene_manager_next_scene(scene_manager, InfraredSceneUniversalAC); consumed = true; diff --git a/applications/infrared/scenes/infrared_scene_universal_ac.c b/applications/infrared/scenes/infrared_scene_universal_ac.c index 9e98a671ec..68a6ea9426 100644 --- a/applications/infrared/scenes/infrared_scene_universal_ac.c +++ b/applications/infrared/scenes/infrared_scene_universal_ac.c @@ -12,7 +12,7 @@ void infrared_scene_universal_ac_on_enter(void* context) { infrared_brute_force_set_db_filename(brute_force, EXT_PATH("infrared/assets/ac.ir")); //TODO Improve A/C universal remote - button_panel_reserve(button_panel, 2, 2); + button_panel_reserve(button_panel, 2, 3); uint32_t i = 0; button_panel_add_item( button_panel, @@ -44,7 +44,7 @@ void infrared_scene_universal_ac_on_enter(void* context) { 0, 1, 3, - 69, + 66, &I_Vol_up_25x27, &I_Vol_up_hvr_25x27, infrared_scene_universal_common_item_callback, @@ -56,15 +56,39 @@ void infrared_scene_universal_ac_on_enter(void* context) { 1, 1, 36, - 69, + 66, &I_Vol_down_25x27, &I_Vol_down_hvr_25x27, infrared_scene_universal_common_item_callback, context); infrared_brute_force_add_record(brute_force, i++, "TEMP-"); + button_panel_add_item( + button_panel, + i, + 0, + 2, + 3, + 98, + &I_Swing_25x27, + &I_Swing_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "SWING"); + button_panel_add_item( + button_panel, + i, + 1, + 2, + 36, + 98, + &I_Timer_25x27, + &I_Timer_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "TIMER"); button_panel_add_label(button_panel, 6, 11, FontPrimary, "AC remote"); - button_panel_add_label(button_panel, 20, 66, FontSecondary, "Temp"); + button_panel_add_label(button_panel, 20, 63, FontSecondary, "Temp"); button_panel_add_label(button_panel, 8, 23, FontSecondary, "Pwr"); button_panel_add_label(button_panel, 40, 23, FontSecondary, "Mod"); diff --git a/applications/infrared/scenes/infrared_scene_universal_fan.c b/applications/infrared/scenes/infrared_scene_universal_fan.c new file mode 100644 index 0000000000..37657ac3c7 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_universal_fan.c @@ -0,0 +1,113 @@ +#include "../infrared_i.h" + +#include "common/infrared_scene_universal_common.h" + +void infrared_scene_universal_fan_on_enter(void* context) { + infrared_scene_universal_common_on_enter(context); + + Infrared* infrared = context; + ButtonPanel* button_panel = infrared->button_panel; + InfraredBruteForce* brute_force = infrared->brute_force; + + infrared_brute_force_set_db_filename(brute_force, EXT_PATH("infrared/assets/fans.ir")); + + //TODO Improve Fan universal remote + button_panel_reserve(button_panel, 2, 3); + uint32_t i = 0; + button_panel_add_item( + button_panel, + i, + 0, + 0, + 3, + 24, + &I_Power_25x27, + &I_Power_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "POWER"); + button_panel_add_item( + button_panel, + i, + 1, + 0, + 36, + 24, + &I_Mode_25x27, + &I_Mode_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "MODE"); + button_panel_add_item( + button_panel, + i, + 0, + 1, + 3, + 66, + &I_Vol_up_25x27, + &I_Vol_up_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "SPEED+"); + button_panel_add_item( + button_panel, + i, + 1, + 1, + 36, + 66, + &I_Vol_down_25x27, + &I_Vol_down_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "SPEED-"); + button_panel_add_item( + button_panel, + i, + 0, + 2, + 3, + 98, + &I_Rotate_25x27, + &I_Rotate_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "ROTATE"); + button_panel_add_item( + button_panel, + i, + 1, + 2, + 36, + 98, + &I_Timer_25x27, + &I_Timer_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "TIMER"); + + button_panel_add_label(button_panel, 5, 11, FontPrimary, "Fan remote"); + button_panel_add_label(button_panel, 20, 63, FontSecondary, "Speed"); + button_panel_add_label(button_panel, 8, 23, FontSecondary, "Pwr"); + button_panel_add_label(button_panel, 40, 23, FontSecondary, "Mod"); + + view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); + + infrared_show_loading_popup(infrared, true); + bool success = infrared_brute_force_calculate_messages(brute_force); + infrared_show_loading_popup(infrared, false); + + if(!success) { + scene_manager_next_scene(infrared->scene_manager, InfraredSceneErrorDatabases); + } +} + +bool infrared_scene_universal_fan_on_event(void* context, SceneManagerEvent event) { + return infrared_scene_universal_common_on_event(context, event); +} + +void infrared_scene_universal_fan_on_exit(void* context) { + infrared_scene_universal_common_on_exit(context); +} diff --git a/assets/icons/Infrared/Rotate_25x27.png b/assets/icons/Infrared/Rotate_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..0c62e9dc10bcccf575253199f68f724e72401f38 GIT binary patch literal 1685 zcmcIlU5MON6rM`eZLvQ1P_T-`yY&yf$<57VG6|h7>&)tm+ichEU{}QIoqKO);!bk2 zNp>f@P>|9WA4HM*^DYIS1W_M~5BjDRK@s}kf}$W+QB;)nK@h!}pID?__r-xsZj$eQ z=R4;+IeBhz;o*II59}?KO8Z*P#*#eWDv#Tyu9N>a)Zd&fV z-`tG(vCV}x-CUtI12cz}LzyE90-h2j3;JQ=WHm74b>up~tpQ~SNmpuMHV>#QyNgO) z#9XPU2vUTwV%e%*DVM9&2NaAj(vYR;2x9D@ienne_y=UPn0d}psfh z8w>{Oz)(fp)pXmoHH0;cp+vxBBTPvK!(@8G(BKJ;{V4TCsN{^KBi7OykV;1>1W`d7 zCgU>6f@v9vG+jk`N)w>#ZVwHD0-dCD>oUq%?^TJD_D00DC7y`2nDV)G9;VZiV2l=f zqqVp{%#=}$_jw>;i4>+6p`xBhMbZ=3$fI~%WD_~{n3Gh*Z6W#-qZTJD3dSl@?mg~@ zObn9yaz*0}yg^c41JX4NQ59mdEnPE_V_Nqk!$D{Sb!8tgl9HW)1@pa)oj_gJX@yBj zLdsi>8jzw?-)9chZ9*urAt`$uNLbl`wpV4)u#ja|P3l!EWT;E-ZwR`UmoMKxYFj3# z*`j(?XNEz6!l>hkI3Ti5{D5@17KL4){G+BW`XY7(lQlQ;ZkFsa zi>9AQ>o&&k$1%P-UiE!t*mMq|d9T+1%}wSEjBoo_sou_Xj%WuxE=jjBe*{Z}mkvnG zXS=e}|JhvHwZtc6eS7IUGyZ>+J}xWmk+93<;M72#jFyj>kty20{Te>IVjNB2a>nJ$ zVz|nSVm$LuQpa-m{cNwz zKYyp!{owie?-!HTFM`uQ-yXklrg!6yKYV-Xu_O4NC&3f!==uG>pZNH|#ccoiJ(vF2 zx@GIPr(XH>h4!iL+{sU)?>-@Cp!dy7Uq0%cn0ooo*BW2EJAe7|uCMO6`_8Z5dgjIa P!_k^sXuSF0)2IFhxL_T= literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Rotate_hvr_25x27.png b/assets/icons/Infrared/Rotate_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..d2ab0f3fc5d73fff2744fc5d95bfa59ea0c2429a GIT binary patch literal 1664 zcmcIlPl()97*D0uI?{s&59%dk4qdS?dGnIVB%yKKo!PnrW?i-;yHXI}y!Un{>?AKH z*_qk(U=g9{LG<2}P!JRq1&gd=y{I69AVM!f5%D66^desT^JV^7q+R!7AjwPK@B4kf z?@zwGvbOrfsnSCwMNv+*R+{T@e-O@xPu>OByBi6dT8J+4u?k39G&IM1Mo7{dt2hHy_*PQU1V}6Wny_C;=DX_#@XC9*-883 zNI5e^Uqk@QKv-q&D(T5wW<7a_IOf~)XcDiH3YyEbEoFaJsI?i3N{Eitg^e)ga+p0* zD4H6GCe4MfLDdMt4kFbyRIN%pv-T)9J&Y&N0Q!K_oE{A6EtPAX$lI;}fE9@t2%OwMjd4@cW ziCLwzgRtFU$f;Twxt%ITwT`fu;|Ry8)Mji?r6GJdw0|pWp^5{e%UxSw+eRH>f*{v2 z5oLrS+v3=AD8@GCn#!5CCDVvPpM(+Z3L}ZTn);8LhV08UkQ{Pu7TpZ&5XDNELFsm< z-^Y3J{B+e1)p65#loh@1Ypf`;06&x0;cc>aG@TRsVNU?*A;q7-GP#uxX(|@Gkm>(y zF5^z(Gdeh2`q2viKT4mbmGx-c6)-prtq8^_M$Dur#=q+|-n(TS&EPQOisgK`!oz$# zix{X=7``8U`)3OV_p`0$VteJwgYPet6!qlsYoGpg<=}1d<_AwNyyaiJao@{7T?`($ z{QA!~E|o6b^WA$(?dvD5mddZ9PnLh%Kl8b`d09Mu`kf#4KmOuJV?e%n|CiG*+*~T( kUw`Aph2QJv{x~@P+UC`bi(i+H75|9V@@n(lrRQGy8<+49YXATM literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Swing_25x27.png b/assets/icons/Infrared/Swing_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..38a6c9040e9764c004f2dfd8c105df01ef9e91b7 GIT binary patch literal 1706 zcmcIlPl()97@w|Mx0R}(Ag)+qmKKX9c}Zq6N$9w)JL}G9v##60-Qq#ty!SE_c9IwK zvOBYjC#9gJo}`qD;6cQTY!&T6O07M0r3!+eh^Vl)_F@knY(40g`Dc-K-HU;jyqEWT zzwh_`$(J|hW@q;79^0ME<@Qu7<#~8M2;-sA5xDQ1`g8&wyW+|bk;|#$+1SzfU}7bg zyJI7$EvAd!A(!w_#gx~X+6iMo=W+)pIx!|oES2i45kw{Vx3lMEDWD~Jq2M7eo?^|Q zvX-#JYqK@7wnQ8%Pdp(V?6^P>vJ^|5uoVfnQK9 zt=(>`ZByk*L(?6{(U74Th5`shtVSvBD3KT+FqD}fNf4(2kEDzd*ZFcOI7EwddIhZX_1=_N)K+7r%`?H56T+rfSd@+rj8QT? z8!soVuBVh}ti?ir2@s|aO~p-~a?#|s@ME|=^d@$v5{6Tr)HrVq5;Zqqkqkpc(xVGO zM0r~r$Q1Pturf|rNrtQ$3bGZ$s_8}7D7t3xF=V<3^`IWq0mUia9+=a>U)>JW^W17A zQXCOhEtg~vr3L|YO;ks9r$7|nAyjb+d7|LFZY!2g9cCkwn5fXz1?S70EN9`%&iBfe zasnK~2)Q;xe%;Db1sAai4g#BRHy-pdyi0XdbmL*DDpC=)PItfDDU|JkCWa%F@Q@q6!k5h=bnN>5e zgBO)RKYkz%sx%wizYjk7p@wbd0 zM|N&La_q{!L-)=U$bntgH=DOz``q~WDBFMbhm+@>`2K~BKW0vib&ehR>f8$thVFb?1QJ^ef$1q?b3qx@U#A%7oNHJ k@;|7F&7|ti3!k7sXB9oBWwcLgRLvSvw2Ox@<>wdlBE{y_pF+$xD;$ z&g@U(@Z2SA^OusElydGrl|xyvK&NA z4AMt)MUxG@K{M{k&^1jVmZDW!<*K8X9b!F3bcc{J)B_(dn$g{X1q(VGyMcP1GascH zjeI`eaAgps1_5()Q*U#l4c@B2$c%-+SWC*GS&tA8^T}9%a`vT+m;C* zIEo5^|5(*FiLEf((iF38=n7>OL$SDK+SJ!ArkkTIf$gazfG>ykZ)eR_F<>;9VQU@E z6uVk66`O%7TGhB>6U#IV(>BVS%82<+Ma6TDLLzK2GpclT|-JBhxw5&%N%-e%@rx+3#;$`}6JonVUDzp0A(5SAYMgQTp!muOGgu z_O8Ew{^lQFUM+3UT)0x(ntSEr_tfRf$1in+a literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Timer_25x27.png b/assets/icons/Infrared/Timer_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..5ce468198d2d83d7a20845f491fc2495fd8b6d46 GIT binary patch literal 1936 zcmcIlTWB0r7+x)EEk?BVr7hwxc`>vzbLO%;7rG7EOS@~`G^PuQK6&PxGrL1}=1gWL z*-fY*)fUnR#RqMRC<+buP%NYr3`J@|TTo~PFQxRs`k)UMsZWKxsAu+;C~3@#3$t_k z&i8-k`@cD7VQlo^z_wl6QmNEHxl|Zu=bh}>z4c-C|7iZgFgraSlwOWfDRD449%?NP z&$3q^xz)*dvht#Zs3$^9Z6db3fT2^VeZ#E)qA3z{HmSLOmcMuDGS9g<%TJ^$pc3Rs z-7U?BdF6V~rOMbZfD@EMJe~ zz>=h9vne)Jk%l!%Hce9kilit4LkQ8FAH$a5M}s|v0*O%Q2C++hE@6Z=or$wNQ`(t= z7xZcUsB055OlrYEl0}eAsRyi7Himj$A05TTSyrX1cU|JBIu{UWoJ4dcM5H)N{CKce zEU43%Ms@lCZT;8(P>4~#U@#Ll+V)^1kp}S?cf_!ATVG)1Ljq$ORw-@t8a39d$SH~l zxaTKaAJb+ulql*BAO#qcEYG^82*41OOjXt`Rk!5K9-vwPbf6WM0}NxhIWWbpGq)LN zrDB!+D26^F8HXU0)j)nz8WjTPRW&@x)HiAxD7aL!oXeMzY z8Q+O5rigL$-Lx`}4NM(5ERGo>IEH2lFr9V;fDKhqk*=FW>9HLSUH0X`##+`y6=sYi ztpP_xX+hUjQ^1a<2vAYef}#Q>Lro<*LOi!xH%}WhtWeC{Re260%b}qMS$Y;%{pPE8#KQI zi>MPfVMs=5%<2COm-Ha<5uDvv`sNz{KT7Y~it5m>5w>tjd@>m+SzlsDUypgtjgK4FW+`HA66EjR+Xq4pw!bn|7w7qT#M`^@6E^ zT+U3(xx87_Wx1F$jlxLrfC7qoTFDm;W6j9+Oge(3jg_~NYnIub4Q%aBF8iAXyXkK` z#AlX;Y*RUPXZjnqA-z{Fj8se4K7aSn_SeDI{PJImcfbDg#G9vQ@#2o3QdhSBelhT# zvOZb<@$$fvxuLV4-PyTt?&+0hrmlJ)(!FP25qaC(a%Jg*w|;%>`%7QGf8wOPeCW)L zW5-|k?yKYW?(;7>*WW(5tNinCN8g#=bNl?#j-k8Z(P!!Po4+g{TsigHANLk+G(Rrg sdgJz)M^=WP_;%^J!;M=PC+^?havJ=A$hj|WCVOVNI9m8L_v*2~0cQewH~;_u literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Timer_hvr_25x27.png b/assets/icons/Infrared/Timer_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..f6959c24476f22bde7e1992727ca7e62802d23e2 GIT binary patch literal 1916 zcmcIlTWB0r7~Xg(u~0!mDXj>@2EBYWJ63^@{QPP+f7iQfFV=_-OS2)O*4!q1qCWlg1RI_pePp1TRBze|3n@wBCfSqneNBpPX)1=B%viq z?RGocRNU~{~5>zBb0UQD1jUYiC5X9pHh6;^w)(L80ac5d}rbLgDn1 z7ZBEt&!md_6KDk`v>@`TDF7Nk$=7AwQVmO0&qCFLum`ny9}twF!+{y`+>OIPZQGg+ z;sgbl&Q=N{7nSuqVmYR)sU|dmi>Lu)r0KxHE(KI}WF_aQhNC-OU3`9p;kDF>bbhaG z3B#OY=%$s+5zSE4JU}W|0f8C;rU5Z5zeU7oMIw3 z4=}|ppjdN&K@kO7-bKhXRoQ@=DD1{9vlfeNM!37GC=hJ9Ebnja@8>Q%koZ;Dx()c1|vhy!p}xH|m9tpZ)C4*YeIA+b{n)^27A#@ryIU QSb9FrR_7|)r3+hs122+kE&u=k literal 0 HcmV?d00001 diff --git a/assets/resources/Manifest b/assets/resources/Manifest index 484831bbfa..186624c83d 100644 --- a/assets/resources/Manifest +++ b/assets/resources/Manifest @@ -1,5 +1,5 @@ V:0 -T:1661394663 +T:1661527982 D:badusb D:dolphin D:infrared @@ -241,10 +241,11 @@ F:33b8fde22f34ef556b64b77164bc19b0:578:dolphin/L3_Lab_research_128x54/frame_8.bm F:f267f0654781049ca323b11bb4375519:581:dolphin/L3_Lab_research_128x54/frame_9.bm F:41106c0cbc5144f151b2b2d3daaa0527:727:dolphin/L3_Lab_research_128x54/meta.txt D:infrared/assets -F:ed61e6f4adc7972bde0e7b5028effac3:101928:infrared/assets/ac.ir -F:229a87b90c1890c5ec6d9e3b0f4695fb:48062:infrared/assets/audio.ir +F:379d21e5faf46466e6cad85eddb074a3:108241:infrared/assets/ac.ir +F:5bdb39269623772d93c2dd6f5e946bd5:48419:infrared/assets/audio.ir +F:9ce3babecb5fab4cca66422c5542bb38:81486:infrared/assets/fans.ir F:63ca357ca0b85a6ad900539e7b6a0fed:5086:infrared/assets/projectors.ir -F:8920a0548ec658a546a8c6476298e0db:128166:infrared/assets/tv.ir +F:fa586695d245aecdd0b3669e75defdcf:127999:infrared/assets/tv.ir F:a157a80f5a668700403d870c23b9567d:470:music_player/Marble_Machine.fmf D:nfc/assets F:81dc04c7b181f94b644079a71476dff4:4742:nfc/assets/aid.nfc diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index 28c8c03e43..1c1e7b8e13 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -3,19 +3,28 @@ Version: 1 # # Universal AC IR codes - Brute force updated by jaroslavmraz # Fixes and tweaks provided by MX (MasterX) -# -# BETA version - Aug 23, 2022 -# +# Updates and Maintenance by amec0e +# +# BETA version - Aug 26, 2022 +# # Old SAMSUNG AC -# +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 3027 9039 538 1530 514 558 490 557 491 582 486 560 488 559 488 584 464 583 464 582 486 1554 490 583 485 562 486 1554 490 584 484 1556 488 1554 510 562 485 1555 509 1531 533 1535 509 1558 569 1473 591 1475 517 1550 566 1475 517 556 492 581 487 559 488 558 490 557 491 582 486 560 487 559 488 558 489 583 464 582 486 560 508 565 482 1584 460 1556 508 1558 517 1524 572 1495 518 1551 513 1527 517 555 493 581 487 559 488 558 510 562 485 561 486 560 487 1579 485 1557 518 1523 541 1526 466 # +# file: Flipper-IRDB/ACs\Insigna\Insigna_AC_NSRC2AC9.ir +# +name: SWING +type: parsed +protocol: NECext +address: 10 E7 00 00 +command: 06 F9 00 00 +# # Airmet AC by JEREMYNO -# +# name: POWER type: raw frequency: 38000 @@ -56,7 +65,7 @@ command: 95 00 00 00 # # Ariston AC A-MW09-IGX # On and Off buttons set to 26 C° cool -# +# name: POWER type: raw frequency: 38000 @@ -64,21 +73,21 @@ duty_cycle: 0.330000 data: 4482 4413 596 1596 594 527 562 1602 588 1603 587 535 565 530 570 1595 595 526 563 532 568 1597 593 528 561 534 566 1599 591 1599 591 531 569 1596 594 1597 593 528 561 1603 587 1604 596 1595 595 1596 594 1597 593 1598 592 529 560 1604 596 525 564 531 569 526 563 532 568 527 562 533 567 1598 592 1599 591 530 570 1595 595 526 563 532 568 527 562 506 594 528 561 507 593 1598 592 529 571 1595 595 1596 594 1597 593 1598 592 5251 4505 4417 592 1599 591 530 570 1595 595 1596 594 527 562 533 567 1598 592 529 561 535 565 1600 590 531 569 526 563 1602 588 1603 587 534 566 1599 591 1600 590 531 569 1596 594 1597 593 1598 592 1599 591 1600 590 1601 589 532 568 1597 593 529 561 534 566 503 597 499 590 504 596 500 589 1601 589 1602 588 533 567 1599 591 530 570 499 591 504 596 526 563 505 595 501 589 1602 588 533 567 1598 592 1599 591 1600 590 1601 589 # # Bonaire DurangoAC -# +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 1305 435 1280 432 415 1255 1307 432 1272 439 418 1252 442 1255 1307 431 416 1255 439 1258 447 1251 443 8174 1302 437 1278 433 414 1255 1307 432 1273 438 419 1250 444 1254 1298 440 417 1253 441 1256 438 1259 445 8170 1306 433 1271 439 418 1251 1301 438 1277 434 413 1256 449 1249 1303 435 412 1258 446 1251 443 1254 440 8176 1300 438 1277 434 413 1283 1279 433 1271 440 417 1278 416 1255 1307 431 416 1253 441 1257 447 1250 444 8171 1305 433 1272 439 418 1278 1274 438 1277 433 414 1282 412 1259 1303 434 413 1256 448 1249 445 1252 442 8173 1303 435 1270 440 417 1279 1273 438 1277 433 414 1282 412 1258 1304 433 414 1282 412 1258 446 1250 444 8171 1305 433 1272 438 419 1276 1276 435 1270 441 416 1252 442 1255 1297 440 417 1279 415 1255 439 1257 447 8168 1297 439 1276 434 413 1256 1306 431 1273 436 411 1258 446 1250 1302 409 438 1284 421 1249 445 1252 442 -# +# # Boulanger AC -# +# name: POWER type: parsed protocol: NEC address: 81 00 00 00 command: 6B 00 00 00 -# +# name: TEMP+ type: parsed protocol: NEC @@ -90,23 +99,23 @@ type: parsed protocol: NEC address: 81 00 00 00 command: 68 00 00 00 -# +# name: MODE type: parsed protocol: NEC address: 81 00 00 00 command: 66 00 00 00 -# +# # Ciatronic AC -# +# name: TEMP- type: raw frequency: 38000 duty_cycle: 0.330000 data: 9013 4502 575 560 574 562 572 1671 565 569 565 570 543 592 542 540 594 567 546 1697 571 1672 575 560 574 1695 541 1702 545 1671 597 1673 574 563 1670 1703 575 560 542 592 542 540 593 568 545 590 544 564 569 565 548 587 547 1670 566 1702 566 1677 570 1674 573 1670 598 1698 538 1704 543 39972 9017 2251 568 96272 9021 2249 570 96268 9013 2256 574 96264 9015 2254 56 -# +# # Daikin TB industrial AC -# +# name: POWER type: raw frequency: 38000 @@ -136,7 +145,7 @@ address: 48 44 00 00 command: 88 08 00 00 # # Friedrich AC -# +# name: POWER type: raw frequency: 38000 @@ -156,7 +165,7 @@ duty_cycle: 0.330000 data: 5626 5579 569 549 562 582 539 581 540 578 543 577 544 575 536 1702 541 1703 540 549 562 557 564 1700 543 1670 563 1677 566 1698 545 547 564 586 535 1674 569 550 571 1668 565 1674 569 578 543 550 571 1670 563 587 545 1665 568 1671 562 1677 566 1700 543 577 544 548 563 1704 539 557 564 1698 545 574 537 1677 566 552 569 577 544 1668 565 554 567 583 538 1670 563 1702 541 1671 572 547 564 583 538 553 568 552 569 1700 543 545 566 582 539 1698 535 558 563 557 564 554 567 1671 562 585 536 # # Fujitsu AC -# +# name: POWER type: raw frequency: 38000 @@ -164,7 +173,7 @@ duty_cycle: 0.330000 data: 3302 1644 408 419 410 416 413 1233 405 423 406 1239 409 419 410 417 412 415 414 1232 406 1241 407 419 410 417 412 416 413 1233 405 1241 407 394 435 419 410 417 412 416 413 387 432 422 407 420 409 418 411 416 413 415 404 423 406 421 408 420 409 1237 411 416 413 413 406 422 407 420 409 418 411 417 412 415 414 1232 406 421 408 420 409 418 411 416 413 1232 406 1240 408 1238 410 1236 412 1234 414 1232 406 1240 408 1238 410 417 412 416 413 1233 405 422 407 421 408 419 410 417 412 414 404 397 432 421 408 420 409 1237 411 1234 414 387 432 422 407 1239 409 418 411 416 413 414 405 423 406 1240 408 1237 411 417 412 415 414 414 405 422 407 421 408 418 411 416 413 414 405 423 406 421 408 419 410 417 412 416 413 414 405 422 407 421 408 419 410 416 413 414 405 423 406 421 408 419 410 417 412 416 413 414 404 423 406 421 408 419 410 417 412 414 405 423 406 421 408 419 410 417 412 416 413 414 404 423 406 421 408 419 410 417 412 416 413 413 406 422 407 420 409 418 411 416 413 1233 405 422 407 421 408 1237 411 1235 413 1206 432 1240 408 420 409 418 411 1235 413 415 414 # # GE Air Conditioner -# +# name: POWER type: raw frequency: 38000 @@ -190,7 +199,7 @@ duty_cycle: 0.330000 data: 8523 4266 544 1595 516 1597 545 1594 538 544 516 1597 545 564 486 1601 541 1599 543 4213 545 1594 538 1576 545 563 518 565 516 540 521 563 518 565 516 540 624 19269 8522 4265 545 1595 537 1576 546 1594 538 571 489 1623 519 564 517 1595 516 1597 545 4209 539 1600 542 1597 514 568 513 569 512 571 490 567 514 568 513 570 594 19272 8519 4266 544 1595 516 1597 545 1593 539 543 518 1621 521 562 488 1598 544 1595 537 4217 541 1598 544 1569 542 566 515 568 513 543 518 565 516 567 514 542 622 # # GE Window AC -# +# name: POWER type: parsed protocol: NECext @@ -216,7 +225,7 @@ address: 98 6F 00 00 command: 08 F7 00 00 # # Hisense Window AC -# +# name: POWER type: raw frequency: 38000 @@ -242,7 +251,7 @@ duty_cycle: 0.330000 data: 8954 4428 565 539 562 542 559 544 567 537 564 540 561 1650 563 1650 563 540 561 543 558 546 566 538 563 1649 564 1649 564 1648 565 539 562 542 559 1653 560 1652 561 543 558 546 565 1647 566 537 564 540 561 543 558 545 566 537 564 540 561 542 559 545 567 537 564 539 562 542 559 544 568 537 564 539 562 542 559 544 567 537 564 539 562 542 559 544 568 537 564 539 562 542 559 544 568 536 565 539 562 542 559 544 568 537 564 539 562 542 559 544 568 537 564 539 562 542 559 545 567 537 564 540 561 542 559 545 567 537 564 540 561 543 558 546 565 538 563 541 560 544 568 536 565 539 562 542 559 544 568 537 564 540 561 542 559 545 567 538 563 540 561 543 558 546 566 538 563 541 560 544 568 536 565 539 562 542 559 545 567 537 564 540 561 543 558 546 566 538 563 541 560 544 567 537 564 539 562 542 559 545 566 538 563 541 560 543 558 546 566 565 536 542 559 544 568 537 564 540 561 543 558 545 567 538 563 541 560 544 568 537 564 539 562 542 559 545 567 538 563 541 560 544 568 536 565 539 562 542 559 545 566 538 563 541 560 544 568 536 565 539 562 542 559 545 567 538 563 541 560 544 568 537 564 540 561 543 558 545 567 538 563 541 560 544 568 536 565 539 562 542 559 545 566 538 563 541 560 544 568 537 564 540 561 543 558 545 566 538 563 541 560 1653 560 543 558 547 565 539 562 542 559 545 567 537 564 540 561 543 569 536 565 539 562 542 559 544 568 537 564 540 561 543 558 546 566 538 563 541 560 544 568 537 564 540 561 543 558 546 566 1647 566 538 563 541 560 544 568 537 564 540 561 542 590 # # Inventum AC -# +# name: POWER type: raw frequency: 38000 @@ -262,7 +271,7 @@ duty_cycle: 0.330000 data: 4424 4381 559 1621 565 529 564 1647 539 1615 561 533 560 534 559 1648 538 532 561 535 1627 559 560 533 535 568 1639 537 1617 559 535 568 1618 568 554 539 556 537 531 562 1618 558 1649 537 1617 559 1621 565 1644 532 1628 558 1622 564 1616 560 534 559 562 541 552 541 527 566 557 536 560 533 1625 561 559 534 1625 561 1619 567 553 540 528 565 532 561 1621 565 529 564 1647 539 528 565 556 537 1617 559 1621 565 1616 560 5229 4425 4363 567 1613 563 557 536 1622 564 1617 559 561 532 562 541 1613 563 559 534 562 541 1617 559 535 568 552 541 1613 563 1617 559 562 541 1618 568 528 565 529 564 556 537 1618 558 1622 564 1616 560 1646 540 1642 534 1627 559 1647 539 1615 561 533 560 561 532 562 541 527 566 556 537 559 534 1624 562 558 535 1623 563 1643 533 561 542 526 567 555 538 1619 567 527 566 1618 558 536 567 527 566 1641 535 1619 567 1617 559 # # Kenmore Window AC -# +# name: POWER type: parsed protocol: NECext @@ -316,7 +325,7 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 9007 4379 601 1628 591 1643 597 526 599 529 596 537 598 535 600 538 597 1641 599 517 597 1632 597 1639 590 535 600 529 596 537 598 536 599 526 599 1630 599 521 593 533 592 535 600 531 594 541 594 543 592 534 591 525 600 1630 599 525 600 530 595 1647 593 540 595 543 592 533 592 524 590 528 597 526 599 528 597 533 592 540 595 543 592 535 600 517 597 522 592 530 595 532 593 535 590 542 593 543 592 516 598 7876 594 523 591 528 597 528 597 531 594 538 597 537 598 1651 599 1639 590 525 600 520 594 529 596 531 594 535 590 543 592 544 591 534 591 524 590 529 596 526 599 527 598 531 594 539 596 540 595 529 596 520 594 525 600 522 592 533 592 538 597 536 599 538 597 529 596 519 595 525 600 523 591 535 600 531 594 539 596 541 594 533 592 524 590 528 597 524 590 536 599 531 594 538 597 540 595 531 594 523 591 530 595 529 596 530 595 536 599 534 591 547 599 528 597 1632 597 1637 592 532 593 536 599 1641 599 535 600 1651 599 1623 596 7879 591 526 599 520 594 527 598 528 597 532 593 538 597 538 597 528 597 519 595 1636 593 529 596 533 592 538 597 537 598 541 594 534 591 527 598 523 591 532 593 533 592 540 595 538 597 540 595 532 593 524 601 519 595 528 597 529 596 534 591 544 591 547 599 529 596 520 594 526 599 524 590 1645 595 1646 594 1653 597 541 594 534 591 525 600 519 595 528 597 529 596 535 600 533 592 546 600 528 597 520 594 1637 592 532 593 1647 593 1649 591 1656 594 543 592 518 596 -# +# # LG AC # name: POWER @@ -338,7 +347,7 @@ address: 81 66 00 00 command: 85 7A 00 00 # # LG Portable AC LP1015WNR -# +# name: POWER type: parsed protocol: NECext @@ -358,7 +367,7 @@ address: 10 E7 00 00 command: 0D F2 00 00 # # Midea_AC_MAW05R1WBL -# +# name: POWER type: raw frequency: 38000 @@ -384,25 +393,25 @@ duty_cycle: 0.330000 data: 4408 4423 570 1585 567 537 539 1590 561 542 544 533 542 535 541 537 539 1589 563 1593 569 534 541 1588 563 539 537 541 545 532 543 534 541 536 539 537 539 1590 562 1593 569 1586 566 538 538 539 537 1592 570 1585 567 1587 565 1590 561 1594 568 1586 565 1590 561 1593 569 1586 566 1589 562 1592 570 1584 568 1587 564 1590 561 1594 568 1586 565 1590 572 1583 568 534 541 1588 564 540 536 1593 569 534 541 1587 564 539 537 1592 570 5186 4455 4374 567 537 539 1590 561 542 544 1584 567 1588 563 1591 560 1594 568 535 541 537 539 1590 561 541 545 1584 568 1587 564 1590 561 1593 569 1586 565 1589 562 540 536 542 544 533 542 1586 566 1588 563 540 536 542 544 533 542 535 540 537 539 538 538 539 537 541 535 542 544 534 541 535 540 537 539 538 537 540 536 541 545 532 543 534 541 536 539 1589 562 540 536 1593 569 534 541 1588 563 540 535 1593 569 534 541 # # Mitsubishi AC MSG-GE10VA -# +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 3472 1691 441 1285 464 1265 443 451 408 459 410 456 434 1266 462 404 434 431 459 1271 437 1317 432 410 459 1293 435 407 431 436 433 1321 428 1273 435 432 458 1270 438 1314 414 426 433 432 458 1296 412 427 463 408 441 1312 406 432 437 432 437 456 434 411 438 425 465 404 434 433 457 414 455 414 455 414 434 430 460 410 439 423 436 432 458 411 438 425 434 459 410 430 439 428 462 405 433 1317 411 427 463 430 408 432 468 439 441 406 432 1318 431 1268 440 425 454 416 463 404 434 1291 437 1284 455 443 437 1265 432 434 456 413 435 436 433 432 437 456 434 1296 432 1266 462 409 460 1265 463 1309 409 429 461 410 439 1287 441 1284 434 433 436 429 440 424 435 1317 411 1312 406 459 431 414 435 1286 463 1265 463 408 441 1280 459 1269 439 1311 407 434 435 460 430 413 435 434 435 427 463 411 438 427 442 423 436 431 438 428 441 450 409 434 435 456 434 413 456 411 437 428 431 460 409 433 436 431 438 429 440 427 442 422 437 426 433 445 435 457 412 432 437 428 441 452 407 436 464 403 456 413 466 407 441 428 441 428 462 411 437 426 464 405 433 434 435 429 440 427 442 425 434 429 440 426 433 434 435 432 437 434 456 416 432 432 458 409 440 1288 440 1283 435 1288 441 429 440 453 406 1295 433 1290 439 426 443 17056 3607 1696 457 1271 437 1291 438 429 461 411 469 407 462 1292 405 461 408 433 436 1287 462 1265 432 435 434 1289 460 411 458 409 439 1286 463 1267 441 426 433 1319 409 1314 414 455 414 453 406 1295 433 431 459 435 434 1269 460 410 459 410 439 452 438 405 433 430 439 427 463 407 441 421 438 429 440 426 433 435 455 412 436 428 462 409 460 409 440 425 434 460 409 457 412 431 438 427 432 1293 435 429 440 425 434 429 440 426 433 430 439 1284 434 1315 413 425 465 405 433 434 435 1286 463 1264 464 407 462 1266 442 425 465 405 464 409 440 425 434 458 432 1271 457 1270 438 429 461 1298 410 1318 410 454 436 410 438 1282 457 1271 437 430 439 430 439 430 460 1270 438 1288 440 426 433 463 437 1266 442 1282 457 415 433 1290 439 1282 436 1290 438 452 407 430 439 428 441 421 438 429 440 427 463 406 442 421 459 410 459 408 461 408 440 426 433 456 413 430 470 408 440 450 430 422 457 414 434 431 438 428 441 424 455 413 435 432 437 430 439 425 465 407 441 449 410 431 459 408 461 417 463 409 439 425 434 433 436 431 438 427 463 406 463 410 439 431 438 424 435 432 437 452 438 405 433 460 409 454 436 409 439 427 442 449 431 417 442 429 440 1281 437 1286 432 1291 458 413 435 432 468 1277 431 1295 464 402 457 -# +# name: TEMP+ type: raw frequency: 38000 duty_cycle: 0.330000 data: 3469 1701 462 1263 434 1289 439 428 441 426 464 407 441 1311 428 441 407 431 438 1287 462 1290 407 457 433 1267 441 424 455 414 455 1274 465 1290 407 435 455 1297 431 1299 429 416 463 432 406 1317 411 429 461 406 442 1281 437 430 460 409 460 407 441 450 429 417 462 405 464 407 441 426 433 432 437 427 442 425 434 460 409 431 438 427 432 437 463 404 465 402 436 431 438 427 442 425 465 1306 433 437 411 455 435 406 442 425 434 435 455 1275 443 1307 442 405 433 461 429 422 457 412 457 410 438 1313 436 1268 440 438 462 436 412 425 465 403 435 458 442 1294 434 1268 440 451 439 1269 459 1292 436 431 407 438 462 1270 438 1288 461 432 437 430 408 443 457 1295 433 1293 435 431 438 1287 431 1295 433 1297 431 411 458 1270 438 1317 411 1312 437 405 433 436 433 458 432 409 440 428 441 423 436 429 440 436 464 403 435 434 456 437 411 427 432 438 462 407 431 438 462 409 439 430 439 432 458 413 435 430 460 433 415 425 434 431 438 455 414 427 442 423 436 429 461 408 440 451 408 439 461 410 438 426 433 435 434 432 437 428 462 407 462 409 460 407 462 405 433 434 435 434 435 434 456 411 437 454 415 423 456 413 435 429 440 429 440 425 434 1318 431 438 410 432 458 1273 434 443 457 1268 460 1266 462 406 463 17223 3603 1724 408 1318 410 1287 441 449 410 455 414 425 434 1316 412 426 464 429 409 1290 438 1285 433 432 437 1313 436 407 441 423 436 1316 412 1314 414 428 441 1285 464 1263 465 428 410 431 459 1269 439 452 407 434 466 1273 455 413 456 416 463 403 435 456 434 407 462 412 457 412 436 432 437 432 437 432 437 428 441 452 407 434 435 432 458 411 437 454 436 409 439 428 462 414 455 411 458 1268 440 427 442 451 408 433 457 410 459 412 457 1295 413 1311 407 462 438 405 433 434 456 411 437 429 440 1314 435 1265 432 458 442 436 412 455 435 417 462 433 436 1265 463 1291 437 403 435 1315 434 1300 408 433 457 410 438 1314 414 1283 435 458 411 432 437 430 460 1294 414 1310 439 403 435 1289 439 1310 439 1267 461 419 440 1310 408 1289 439 1286 442 427 463 408 461 410 438 427 463 404 434 433 436 429 461 406 432 435 434 430 439 426 464 405 433 432 437 436 464 408 440 450 409 432 437 430 470 410 459 412 457 410 438 428 431 441 438 428 441 428 441 426 433 432 437 428 441 425 465 403 435 434 435 432 458 411 437 427 442 449 410 433 457 413 456 413 435 432 437 429 440 451 408 437 442 425 465 409 439 436 464 405 433 432 437 427 442 425 434 1316 412 433 457 410 459 1269 459 407 462 1292 415 1284 434 433 436 -# +# name: TEMP- type: raw frequency: 38000 duty_cycle: 0.330000 data: 3467 1703 460 1266 441 1281 437 430 439 455 435 410 438 1287 462 407 441 450 409 1290 459 1266 442 450 430 1269 439 453 406 437 463 1267 461 1266 442 454 436 1266 441 1310 429 412 457 436 433 1295 433 409 439 428 431 1321 428 414 465 402 436 436 433 445 455 416 432 432 437 430 439 428 462 418 461 410 459 434 414 426 433 439 440 453 406 437 432 435 434 430 439 426 433 434 456 437 411 1290 438 453 437 404 434 435 434 435 434 435 465 1262 456 1296 411 453 406 438 441 423 436 1316 433 1293 435 409 439 1289 439 428 462 409 439 454 415 426 433 434 435 1290 438 1287 441 424 435 1288 440 1283 435 468 432 408 440 1283 456 1272 436 458 432 418 461 408 440 1308 431 1269 459 407 462 1303 415 1285 433 1292 436 429 440 1283 435 1293 456 1270 438 455 414 425 434 457 412 431 438 429 440 429 440 425 434 431 438 428 462 445 434 406 463 409 439 425 434 431 459 408 440 427 432 437 442 425 434 431 438 426 433 461 429 412 436 432 437 430 460 409 439 452 407 432 437 432 458 411 458 411 437 429 440 427 442 423 436 435 434 433 457 417 431 444 456 414 434 430 439 452 407 434 435 458 411 429 440 454 405 438 431 438 441 423 456 411 437 429 461 413 435 434 435 434 435 1287 462 432 406 1293 456 1271 457 412 436 17062 3577 1724 460 1266 442 1308 410 457 433 408 440 425 434 1293 456 416 432 459 431 1268 440 1284 455 412 436 1289 439 430 439 430 439 1310 408 1289 439 428 462 1268 440 1286 442 422 457 412 457 1297 411 428 441 426 433 1293 456 411 437 430 439 428 462 409 439 428 441 423 436 429 461 409 439 429 440 429 440 451 408 435 455 415 433 433 436 431 459 408 440 425 454 414 465 406 463 404 465 1260 437 430 439 428 441 426 464 403 466 406 432 1292 457 1269 459 408 440 451 408 435 455 1272 456 1278 461 407 462 1265 442 451 408 459 410 431 438 431 438 429 440 1309 409 1288 440 425 454 1271 457 1268 460 411 437 430 439 1295 454 1271 437 431 438 429 440 427 442 1283 455 1272 436 434 456 1296 412 1285 464 1262 435 431 459 1267 461 1264 433 1291 458 413 435 429 461 409 439 430 439 452 407 434 435 456 413 454 415 423 456 411 458 408 440 429 461 406 442 449 410 457 433 415 433 436 433 436 433 436 433 436 433 458 411 429 440 427 432 435 465 404 434 431 459 412 436 431 469 407 462 405 464 402 436 431 438 431 438 458 432 408 440 425 434 457 433 410 438 453 406 437 432 433 436 455 414 426 433 432 458 409 439 454 436 407 462 407 441 428 431 436 433 434 435 458 432 1269 439 431 438 1287 462 1266 442 425 434 -# +# name: MODE type: raw frequency: 38000 @@ -416,7 +425,7 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 9026 4518 591 1706 564 1709 561 581 564 579 566 579 566 580 565 1686 595 1708 562 1709 561 1711 569 1705 565 578 567 1683 587 1690 591 1687 593 577 568 573 562 579 566 577 568 575 560 584 561 1689 591 1686 594 1682 588 579 566 576 569 574 561 582 563 581 564 582 563 558 587 583 562 579 566 575 560 583 562 581 564 580 565 1686 594 1683 587 583 562 579 566 576 569 574 561 582 563 581 564 582 563 558 587 582 563 578 567 575 560 582 563 580 565 579 566 1684 586 561 594 575 560 581 564 578 567 576 559 584 561 583 562 558 587 560 585 584 561 580 565 577 568 574 561 582 563 581 564 556 589 558 587 582 563 578 567 575 560 582 563 580 565 579 566 1684 586 561 594 576 559 582 563 578 567 576 559 584 561 583 562 558 587 560 595 574 561 1711 559 582 563 1711 559 584 561 583 562 557 588 559 586 584 561 1711 559 1713 567 1705 565 1710 560 1689 591 1686 594 552 593 1706 564 -# +# name: TEMP+ type: raw frequency: 38000 @@ -442,15 +451,15 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 603 17909 2988 8942 524 496 491 1523 472 496 491 530 467 526 471 496 521 499 488 506 491 503 494 1467 518 503 494 500 497 1463 522 500 497 497 490 1498 497 1491 493 1494 490 1498 497 1491 514 507 490 504 493 501 496 498 499 494 493 501 496 498 489 505 492 502 495 498 499 495 492 502 495 499 498 495 492 529 468 526 471 523 494 499 488 506 491 503 494 499 498 496 491 503 494 500 497 496 491 503 494 500 497 497 490 504 493 500 497 497 490 504 493 1495 489 1498 517 1471 514 1475 520 2947 3018 8939 517 1471 524 497 490 504 493 500 497 497 490 504 493 501 496 498 489 505 492 1495 489 531 486 508 489 505 492 1469 515 1472 523 1466 518 502 495 1466 518 1470 525 1463 522 1467 517 1497 498 1491 514 1474 521 1467 517 503 494 499 498 496 491 1470 525 1463 522 1468 517 503 494 500 497 497 490 504 493 528 469 524 463 531 486 508 489 1471 524 1465 519 501 496 498 499 495 492 502 495 498 499 495 492 1496 499 495 492 502 495 499 498 523 464 1496 519 1470 515 1474 521 1467 517 -# +# # Suntec Wellness AC 14246 TRANSFORM 14.000 Eco R290 -# +# name: POWER type: parsed protocol: NEC address: 80 00 00 00 command: 9C 00 00 00 -# +# name: MODE type: parsed protocol: NEC @@ -523,7 +532,7 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 4406 4356 571 1574 563 509 564 1581 566 506 567 504 569 529 544 501 562 1582 565 1580 567 505 568 503 570 1575 562 510 563 508 565 1580 567 1604 543 529 544 1574 563 1582 565 507 566 1579 568 1577 570 1575 572 500 563 1582 565 1579 568 1577 570 1575 572 1573 564 1581 566 1579 568 1577 570 1575 572 1573 564 1581 566 1579 568 1577 570 1575 572 1573 564 1582 565 506 567 1578 569 1576 571 1574 563 1582 565 1580 567 505 568 503 570 5162 4408 4354 562 535 538 1581 566 505 568 1577 570 1575 572 1573 564 1581 566 506 567 505 568 1576 571 1573 564 509 564 1580 567 1578 569 503 570 501 562 1583 564 507 566 506 567 1577 570 502 571 500 563 509 564 1580 567 505 568 503 570 501 572 499 564 508 565 506 567 531 542 503 570 501 562 536 537 534 539 506 567 504 569 529 544 527 536 510 564 1580 567 505 568 503 570 501 572 526 537 508 565 1579 568 1577 570 -# +# # Vornado AC # name: POWER @@ -531,7 +540,7 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 1347 405 1322 422 410 1332 1300 448 1289 480 383 1303 445 1298 439 1331 417 1299 438 1332 416 1302 1320 6834 1292 456 1292 450 413 1304 1328 445 1292 452 411 1302 446 1297 440 1303 445 1298 439 1303 445 1301 1321 6806 1320 453 1295 422 441 1301 1321 454 1294 422 441 1301 436 1305 443 1300 448 1295 442 1301 447 1298 1324 6802 1324 451 1297 420 443 1299 1323 424 1324 419 444 1298 439 1304 444 1298 439 1304 444 1299 438 1306 1326 6815 1321 453 1295 421 442 1302 1320 426 1322 421 442 1301 436 1306 442 1301 447 1296 441 1301 447 1299 1323 6802 1324 424 1324 418 445 1300 1322 424 1324 419 444 1298 439 1304 444 1299 438 1304 444 1299 438 1306 1326 6809 1328 420 1317 424 439 1306 1326 419 1318 424 439 1304 444 1299 438 1305 443 1299 438 1305 443 1302 1320 -# +# # Whynter_AC.ir # name: POWER @@ -551,7 +560,7 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 746 745 2927 2882 748 2180 774 2207 778 2202 752 740 747 2181 752 2229 725 2203 751 2204 729 736 772 747 751 741 746 745 753 739 748 743 776 742 756 736 751 740 747 745 805 2202 752 740 747 2181 773 746 752 2176 778 715 772 2182 772 720 777 2177 746 746 772 2182 751 2178 776 742 756 736 803 -# +# # Zenith_AC # name: MODE @@ -561,345 +570,428 @@ address: 81 66 00 00 command: 9B 64 00 00 # # SAMSUNG AC 1,8 -# +# name: TEMP- type: parsed protocol: NECext address: 01 08 00 00 command: 31 00 00 00 -# +# name: TEMP+ type: parsed protocol: NECext address: 01 08 00 00 command: 32 00 00 00 -# +# name: POWER type: parsed protocol: NECext address: 01 08 00 00 command: 3F 00 00 00 # -#########################NEW LIST######################## -# -# file: Flipper-IRDB/ACs/Admiral/Admiral_AC.ir -# +# file: Flipper-IRDB/ACs\Admiral\Admiral_AC.ir +# name: POWER type: parsed protocol: NEC address: 20 00 00 00 command: 02 00 00 00 -# -name: MODE -type: parsed -protocol: NEC -address: 20 00 00 00 -command: 09 00 00 00 -# +# name: TEMP+ type: parsed protocol: NEC address: 20 00 00 00 command: 0A 00 00 00 -# +# name: TEMP- type: parsed protocol: NEC address: 20 00 00 00 command: 11 00 00 00 -# -# file: Flipper-IRDB/ACs/Airmet/Airmet_ac.ir +# +name: TIMER +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 19 00 00 00 +# +# file: Flipper-IRDB/ACs\Airmet\Airmet_ac.ir +# +# +name: SWING +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8918 4489 568 584 535 1664 564 588 541 1658 560 1666 593 558 540 1659 589 562 537 1663 585 566 533 593 536 1664 564 1661 587 564 535 591 538 1661 567 1658 590 1662 566 1659 559 1667 592 559 539 586 533 567 562 563 536 1664 584 567 542 584 535 564 565 560 539 587 542 558 561 564 535 591 538 561 568 1658 560 1666 562 1663 586 1666 562 1663 565 1660 588 563 536 590 539 560 559 567 542 584 535 564 565 1660 568 1658 560 1665 594 1658 560 1666 562 1663 585 566 533 593 536 563 566 559 540 586 533 567 562 563 536 590 539 560 559 1667 561 564 565 1661 567 1658 560 591 538 1662 566 585 534 # name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 8917 4491 587 565 534 1665 594 559 540 1659 589 1688 540 534 585 1666 562 1664 564 1661 587 564 535 591 538 1661 567 585 534 1665 563 588 541 559 560 1665 563 563 566 559 540 586 533 1692 536 564 565 534 585 567 532 1667 592 534 565 587 542 531 588 564 535 591 538 561 568 558 540 585 534 565 564 1687 541 1658 560 1667 592 1660 558 1667 561 1664 584 567 542 558 561 564 565 561 538 588 541 558 561 1690 538 1661 567 1659 589 1662 566 1659 559 1667 591 559 540 587 532 541 588 564 535 591 538 561 558 567 542 584 535 565 564 1687 541 532 587 1664 564 1662 566 585 534 1691 537 589 540 -# +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 8971 4489 568 584 535 564 565 561 537 588 541 558 561 565 534 592 537 562 567 1659 559 566 563 563 536 1664 584 567 542 584 535 1664 564 587 542 558 561 564 535 591 538 562 567 558 541 585 534 566 563 562 537 589 540 559 560 566 533 593 536 563 566 560 539 587 532 567 562 564 535 591 538 1661 567 1658 590 1662 566 1659 559 1667 592 1660 558 567 562 563 536 590 539 561 558 567 542 584 535 1664 564 1662 586 1665 563 1662 566 1659 589 1663 565 560 559 566 533 593 536 564 565 560 538 587 542 557 562 564 535 591 538 1661 567 585 534 1666 562 1663 585 566 533 1667 592 560 538 -# -# file: Flipper-IRDB/ACs/Amcor/Amcor_AC.ir -# +# +# file: Flipper-IRDB/ACs\Amcor\Amcor_AC.ir +# name: POWER type: parsed protocol: NEC address: 80 00 00 00 command: 9B 00 00 00 -# -# file: Flipper-IRDB/ACs/Ariston/Ariston_AC_A-MW09-IGX.ir -# +# +name: TIMER +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 9F 00 00 00 +# +# file: Flipper-IRDB/ACs\Ariston\Ariston_AC_A-MW09-IGX.ir +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 4481 4414 595 1596 594 527 562 1602 588 1604 586 535 565 530 570 1594 596 526 563 532 568 1596 594 528 561 534 566 1598 592 1600 590 531 569 1596 594 527 562 1603 587 1604 586 1605 648 1543 594 527 562 1603 587 1604 586 1605 595 525 564 531 569 526 563 532 568 1596 594 528 561 534 566 1598 592 1600 590 1601 589 532 568 527 562 533 567 528 561 534 566 529 560 535 565 530 570 1594 596 1596 594 1597 593 1598 592 1599 591 5252 4503 4418 590 1601 589 532 568 1597 593 1598 592 529 560 535 565 1600 590 531 569 526 563 1602 588 533 567 529 560 1604 596 1595 595 526 563 1602 588 533 567 1598 592 1599 591 1600 590 1601 589 532 568 1598 592 1599 591 1600 590 531 569 527 562 532 568 528 561 1603 587 534 566 530 559 1605 595 1596 594 1597 593 528 561 534 566 529 560 535 565 530 570 525 564 531 569 527 562 1602 588 1603 587 1604 596 1595 595 1596 594 -# -# file: Flipper-IRDB/ACs/Bonaire/Bonaire_DurangoAC.ir -# -name: MODE +# +# file: Flipper-IRDB/ACs\Bonaire\Bonaire_DurangoAC.ir +# +name: TIMER type: raw frequency: 38000 duty_cycle: 0.330000 -data: 1303 438 1287 429 418 1254 1308 434 1281 434 423 1250 444 1255 439 1259 1303 439 418 1254 440 1258 446 8172 1313 428 1276 411 446 1252 1310 404 1311 403 444 1255 439 1259 445 1253 1309 405 442 1257 447 1250 444 8173 1302 412 1303 410 447 1251 1300 439 1276 410 447 1251 443 1255 439 1259 1303 437 420 1250 496 1202 439 8177 1308 434 1281 433 414 1256 1306 435 1280 434 413 1284 420 1251 443 1255 1307 433 414 1283 421 1250 444 8173 1302 438 1277 436 421 1276 1275 438 1277 436 421 1275 419 1252 442 1256 1306 434 413 1284 420 1250 444 8173 1302 438 1277 436 421 1276 1275 437 1278 435 412 1285 419 1278 416 1281 1281 432 415 1282 412 1285 419 -# -# file: Flipper-IRDB/ACs/Botti/Botti_BL-168DLR.ir -# +data: 1307 407 1308 406 441 1257 1305 435 1279 408 439 1259 1303 410 447 1251 443 1255 449 1249 445 1253 441 8177 1308 405 1299 413 444 1254 1308 405 1299 413 444 1253 1309 404 443 1255 439 1259 445 1252 442 1256 448 8169 1306 406 1309 404 443 1254 1308 405 1299 413 444 1253 1298 413 444 1253 441 1257 447 1250 444 1254 440 8176 1299 413 1302 410 447 1250 1301 411 1304 408 439 1259 1303 409 448 1249 445 1252 442 1256 448 1249 445 8171 1304 408 1307 405 442 1256 1306 406 1298 413 444 1253 1299 413 444 1253 441 1257 447 1250 444 1253 441 8175 1300 412 1303 409 448 1249 1302 409 1306 406 441 1256 1306 406 441 1256 448 1249 445 1252 442 1255 439 +# +# file: Flipper-IRDB/ACs\Botti\Botti_BL-168DLR.ir +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 9577 4536 622 576 621 577 620 577 620 578 619 578 619 578 619 579 618 1667 625 1660 622 1664 618 1668 624 1662 620 1666 616 1670 622 1664 618 580 617 581 616 1669 623 575 622 575 622 1664 618 580 617 580 617 581 616 1669 623 575 622 1664 618 1668 624 573 624 1662 620 1666 616 1670 622 39798 9556 2250 626 96841 9564 2245 620 96843 9560 2253 622 96836 9569 2244 621 96844 9571 2244 621 96843 9573 2247 619 96844 9572 2248 617 96847 9570 2248 617 96848 9568 2250 626 96833 9564 2251 625 96834 9564 2252 624 96843 9595 2223 653 96809 9597 2221 644 96822 9604 2215 650 96814 9591 2226 650 96813 9591 2225 650 96811 9600 2218 647 96816 9597 2221 654 96812 9601 2219 646 96815 9598 2220 645 96813 9601 2216 649 96815 9599 2219 657 96809 9565 2252 624 96842 9564 2254 622 96841 9565 2254 622 96838 9568 2249 616 96844 9571 2247 619 96842 9574 2245 620 96840 9566 2251 625 96838 9567 2251 625 96835 9570 2250 615 96848 9566 2254 621 96843 9572 2247 618 96847 9567 2253 623 96842 9572 2249 616 96843 9572 2247 618 96843 9572 2249 616 96849 9576 2245 621 96842 9574 2246 619 96842 9575 2246 619 96843 9573 2248 617 96843 9572 2249 616 96847 9571 2249 617 96839 9569 2251 625 96837 9569 2251 624 96837 9568 2250 626 96835 9572 2248 618 96844 9572 2246 619 96843 9564 2253 623 96834 9572 2245 620 96835 9569 2246 619 -# -# file: Flipper-IRDB/ACs/Corlitec/Cortlitec_portable_ac.ir -# +# +name: SWING +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9542 4537 620 578 619 578 619 578 619 577 620 577 620 577 620 577 620 1666 616 1669 623 1662 620 1666 616 1670 622 1663 619 1667 615 1671 621 575 622 574 623 1663 619 1666 616 580 617 579 618 578 619 577 620 576 621 1665 617 579 618 577 620 1665 617 1668 614 1671 621 1664 618 1666 616 39847 9511 2253 622 96974 9541 2253 622 97001 9553 2256 619 96996 9567 2256 619 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9611 4510 657 544 653 548 649 552 655 544 653 547 650 550 657 544 653 1637 624 1664 618 1669 623 1663 618 1668 654 1635 647 1642 650 1640 652 550 647 1644 627 1663 619 1669 623 1665 617 1671 621 577 620 578 619 580 617 581 616 581 616 580 617 579 618 578 619 1668 624 1663 619 1669 623 39867 9578 2250 615 96998 9539 2257 618 96975 9513 2250 615 +# +# file: Flipper-IRDB/ACs\Boulanger\Boulanger_AC.ir +# +name: TIMER +type: parsed +protocol: NEC +address: 81 00 00 00 +command: 69 00 00 00 +# +# file: Flipper-IRDB/ACs\Corlitec\Cortlitec_portable_ac.ir +# name: POWER type: parsed protocol: NECext address: 10 E7 00 00 command: 05 FA 00 00 -# -# file: Flipper-IRDB/ACs/Daikin/Daikin_AC_industrial_TB.ir -# +# +name: TIMER +type: parsed +protocol: NECext +address: 10 E7 00 00 +command: 01 FE 00 00 +# +# file: Flipper-IRDB/ACs\Daikin\Daikin_AC_industrial_TB.ir +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 5055 2191 335 1799 360 752 338 714 365 716 364 1800 359 723 367 715 365 718 361 720 359 1805 365 747 332 1802 357 1806 364 719 360 1803 367 1798 361 1803 367 1797 362 1802 368 744 335 1799 360 721 369 714 365 716 363 719 360 721 369 713 366 1798 361 1802 368 715 364 717 362 720 359 723 367 715 364 1799 360 722 368 714 365 717 363 719 361 722 368 714 365 716 363 719 360 721 369 713 366 716 363 718 361 721 359 723 367 1797 362 1802 368 1796 363 1801 358 754 336 716 363 719 361 29583 5057 2160 366 1798 361 750 329 723 367 715 364 1800 359 753 337 715 364 717 363 720 359 1804 366 747 332 1801 358 1806 364 718 361 1803 356 1798 1802 368 1797 362 1802 368 714 365 1799 360 722 368 714 365 717 362 719 360 722 368 714 365 1798 361 1803 367 715 364 718 362 721 359 723 367 715 364 718 361 720 359 723 367 715 364 717 362 720 360 1804 366 1799 360 721 369 714 365 1798 361 1803 367 1798 361 720 359 723 367 715 364 718 361 720 360 723 367 715 364 717 362 720 359 722 368 714 365 717 362 719 360 722 368 1796 363 719 360 721 369 714 365 716 363 719 361 721 369 713 366 716 363 718 361 721 358 723 367 716 363 718 362 720 359 723 367 715 364 718 361 720 359 723 367 715 364 1799 360 1804 366 1799 360 721 369 714 365 716 363 1801 358 754 336 1798 361 720 360 1805 365 748 331 720 359 723 367 715 364 717 363 720 360 722 368 714 365 717 362 720 359 722 368 714 365 717 363 719 361 722 368 714 365 1798 361 751 339 713 366 716 363 1801 359 1805 365 1800 359 1805 365 1800 359 1805 365 1799 360 -# -# file: Flipper-IRDB/ACs/DeLonghi/Delonghi_portable_Pinguino-Air-to-Air-PAC-N81_ac.ir -# +# +# file: Flipper-IRDB/ACs\DeLonghi\Delonghi_portable_Pinguino-Air-to-Air-PAC-N81_ac.ir +# name: POWER type: parsed protocol: NECext address: 48 12 00 00 command: 88 08 00 00 -# -# file: Flipper-IRDB/ACs/Friedrich/Friedrich.ir -# +# +name: TIMER +type: parsed +protocol: NECext +address: 48 44 00 00 +command: C8 08 00 00 +# +# file: Flipper-IRDB/ACs\Friedrich\Friedrich.ir +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 5624 5582 567 553 568 550 571 550 561 557 564 584 537 554 567 1672 571 1671 562 554 567 553 568 1696 537 1676 567 1673 570 1668 565 554 567 556 565 1671 562 557 564 1676 567 1671 562 584 537 555 566 1673 570 552 569 1666 567 1671 562 1676 567 1671 572 548 563 556 565 1672 571 554 567 547 564 556 565 1674 569 549 562 558 563 1676 567 551 570 554 568 548 563 557 564 555 566 554 567 1672 571 1667 566 1674 569 1673 570 545 566 554 567 1671 572 1667 566 554 567 1672 561 557 564 1677 566 -# -# file: Flipper-IRDB/ACs/Frigidaire/Frigidaire_AC.ir -# +# +# file: Flipper-IRDB/ACs\Frigidaire\Frigidaire_AC.ir +# name: POWER type: parsed protocol: NECext address: 01 FF 00 00 command: 0A F5 00 00 -# -# file: Flipper-IRDB/ACs/Fujitsu/Fujitsu_AC.ir -# +# +name: TIMER +type: parsed +protocol: NECext +address: 01 FF 00 00 +command: 1B E4 00 00 +# +# file: Flipper-IRDB/ACs\Frigidaire\Frigidaire_RG15D_AC.ir +# +name: TEMP- +type: parsed +protocol: NECext +address: 08 F5 00 00 +command: 0D F2 00 00 +# +name: TIMER +type: parsed +protocol: NECext +address: 08 F5 00 00 +command: 06 F9 00 00 +# +name: POWER +type: parsed +protocol: NECext +address: 08 F5 00 00 +command: 00 FF 00 00 +# +# file: Flipper-IRDB/ACs\Fujitsu\Fujitsu_AC.ir +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 3302 1618 435 393 436 391 438 1207 431 396 433 1213 435 392 437 391 438 388 441 1206 432 1214 434 392 437 389 440 388 431 1215 433 1213 435 392 437 390 439 388 431 396 433 395 434 392 437 390 439 388 431 396 433 394 435 392 437 390 439 388 441 1205 433 395 434 392 437 389 440 388 431 396 433 394 435 392 437 1209 439 388 431 397 432 394 435 393 436 1210 438 387 432 396 433 394 435 392 437 390 439 388 431 1215 433 394 435 1211 437 1208 440 1205 433 1213 435 1211 437 1209 439 -# -# file: Flipper-IRDB/ACs/Hisense/Hisense_window_AC.ir -# +# +# file: Flipper-IRDB/ACs\Hisense\Hisense_window_AC.ir +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8956 4420 563 568 533 545 566 537 564 539 562 541 560 1650 563 1648 565 539 562 542 559 544 567 536 565 1671 542 1643 560 1652 561 543 558 545 566 1645 568 1643 560 544 568 536 565 1646 567 537 564 539 562 541 560 543 558 545 566 537 564 540 561 542 559 544 568 536 565 538 563 540 561 542 559 544 567 536 565 539 562 541 560 543 569 535 566 537 564 540 561 542 559 544 568 536 565 538 563 541 560 543 558 545 567 537 564 539 562 541 560 544 568 535 566 538 563 540 561 542 559 544 568 536 565 539 562 541 560 543 569 536 565 538 563 540 561 543 558 545 566 537 564 540 561 542 559 544 568 536 565 538 563 541 560 543 558 545 567 537 564 540 561 542 559 544 567 537 564 539 562 541 560 544 568 535 566 538 563 540 561 542 559 545 566 537 564 539 562 542 559 544 568 536 565 538 563 540 561 543 558 545 566 537 564 539 562 542 559 544 568 536 565 538 563 541 560 543 558 545 567 537 564 540 561 542 559 544 567 536 565 539 562 541 560 543 569 535 566 538 563 540 561 542 559 545 567 537 564 539 562 541 560 544 568 536 565 538 563 541 560 543 558 545 567 538 563 540 561 542 559 545 567 537 564 539 562 542 559 544 568 536 565 538 563 541 560 543 558 572 540 538 563 540 561 542 559 545 566 537 564 539 562 542 559 544 568 536 565 538 563 1649 564 540 561 1651 562 541 560 544 557 546 566 538 563 541 560 543 558 546 565 538 563 540 561 542 559 545 567 537 564 539 562 542 559 544 567 536 565 539 562 541 560 544 557 546 566 538 563 1649 564 539 583 1630 563 541 591 513 557 546 566 565 536 541 591 +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 8961 4409 563 541 570 533 568 535 566 537 564 539 562 1649 564 1648 565 539 562 541 570 533 568 536 565 1645 568 1644 569 1643 570 534 567 536 565 1646 567 1645 568 536 565 565 536 1648 565 540 572 558 543 560 541 562 539 564 537 566 546 558 543 560 541 563 538 565 536 567 544 559 542 562 539 564 537 566 546 558 543 561 540 563 538 565 536 568 544 560 541 562 539 564 537 566 546 558 543 561 540 563 538 565 536 568 544 560 541 562 539 564 537 567 545 559 542 561 540 563 538 566 545 558 543 561 540 563 538 565 536 568 544 560 541 562 539 565 536 567 544 559 542 561 540 564 537 566 545 558 543 561 540 563 538 565 536 568 543 560 541 562 539 564 537 566 545 532 569 534 567 537 564 539 562 541 571 560 541 536 565 538 563 540 572 532 569 535 566 537 564 539 573 531 570 534 567 536 565 539 562 541 571 533 568 535 566 538 563 540 572 532 569 535 566 537 564 540 572 532 569 534 567 537 564 539 573 532 569 534 567 536 565 539 562 541 571 533 568 536 565 538 563 541 571 533 568 535 566 538 563 540 572 532 569 535 566 537 564 540 572 532 569 534 567 537 564 539 562 542 570 534 567 536 565 539 562 541 570 534 567 536 565 539 562 542 570 534 567 536 565 539 562 542 570 534 567 536 565 539 562 542 570 534 567 536 565 539 562 542 570 1641 572 1640 563 543 569 535 566 538 563 540 561 543 569 535 566 538 563 540 561 543 569 535 566 538 563 541 571 533 568 536 565 539 562 541 571 534 567 537 564 539 562 542 570 534 567 537 564 1646 567 1646 567 539 562 542 570 534 567 537 564 540 561 542 590 -# -# file: Flipper-IRDB/ACs/Kenmore/Kenmore_AC.ir -# -name: TEMP- +# +# file: Flipper-IRDB/ACs\LG\LG_AC.ir +# +name: TIMER type: parsed protocol: NECext -address: 08 F5 00 00 -command: 0D F2 00 00 -# -# file: Flipper-IRDB/ACs/LG/LG_AC_2.ir -# +address: 81 66 00 00 +command: 9F 60 00 00 +# +# file: Flipper-IRDB/ACs\LG\LG_AC_2.ir +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 8455 4196 542 1566 541 539 519 535 513 541 517 1565 541 538 520 534 514 540 518 1563 544 1565 542 538 520 533 515 539 519 535 513 541 517 536 522 532 516 538 520 533 515 539 519 535 513 1569 538 542 516 1566 541 539 519 534 514 540 518 1564 542 -# -# file: Flipper-IRDB/ACs/LG/LG_AC_LP1417GSR.ir -# +# +# file: Flipper-IRDB/ACs\LG\LG_AC_LP1417GSR.ir +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8923 4452 599 1629 589 1643 596 527 597 530 594 538 597 536 599 536 599 1640 599 519 595 1641 598 1639 590 535 600 532 592 541 594 543 592 533 591 1638 591 1642 597 527 598 1645 594 538 597 541 594 542 593 532 592 1637 591 1642 597 526 599 530 594 536 599 534 590 546 599 527 598 519 595 525 600 525 600 528 597 533 591 542 593 545 600 528 597 520 594 526 599 526 599 528 597 534 590 544 591 547 598 511 593 7894 594 524 590 530 595 529 595 533 592 539 596 538 597 1655 594 1648 591 527 597 525 600 524 600 526 599 531 593 541 594 543 592 535 600 517 597 523 591 533 591 536 599 532 592 542 593 546 599 530 594 525 600 522 592 533 591 536 599 533 591 542 593 543 592 535 590 526 599 522 592 530 594 533 591 539 596 539 596 541 594 533 592 525 600 521 593 531 593 533 591 540 595 540 595 543 592 536 599 519 595 527 597 528 597 530 594 534 590 543 592 545 600 528 597 521 593 527 598 525 599 1638 591 540 595 540 595 1653 596 1626 592 7894 594 525 600 521 593 531 593 536 599 530 594 537 598 539 596 531 593 525 600 520 594 530 594 533 592 540 595 537 598 538 597 529 595 522 592 528 597 527 598 529 596 534 590 542 593 544 591 537 598 519 595 526 599 526 599 529 596 535 600 534 601 537 598 1646 593 525 600 522 592 532 592 1648 601 1646 593 1655 594 546 599 530 594 522 592 527 598 526 599 529 595 535 600 535 600 537 598 531 593 524 601 519 595 529 596 1641 598 1648 591 1655 594 545 600 1625 593 +# +name: SWING +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8929 4464 598 1633 595 1637 591 535 600 529 595 537 598 540 595 542 593 1643 596 521 593 1640 599 1637 591 538 597 535 600 536 599 540 595 532 592 1635 593 1636 592 531 593 1646 593 537 598 536 599 542 593 1649 600 1631 597 1635 593 531 593 533 602 530 594 539 596 542 593 535 600 517 597 523 591 532 592 532 592 538 597 535 600 536 599 527 597 517 597 523 591 531 593 532 592 536 599 535 600 538 597 513 601 7879 598 519 595 526 598 526 599 530 594 537 598 534 590 1658 591 1648 591 525 599 521 593 531 593 534 590 540 595 538 597 540 595 532 592 525 600 522 592 532 592 535 600 532 592 543 592 1655 594 533 591 527 597 525 600 525 599 529 595 536 599 536 599 539 596 530 594 521 593 526 598 525 600 528 597 535 600 534 590 547 598 530 594 524 601 521 593 531 593 534 601 530 594 540 595 542 593 534 590 526 598 522 592 530 594 532 592 539 596 539 596 541 594 533 591 524 590 529 595 529 596 1642 597 534 590 542 593 545 600 510 594 7889 599 519 595 524 590 533 591 534 590 538 597 536 599 537 598 529 595 1631 598 1635 593 1644 595 534 601 532 592 541 594 543 592 536 599 519 595 525 599 524 600 526 598 530 594 537 598 538 597 529 595 521 593 526 598 525 600 527 597 531 593 541 594 545 600 1641 598 521 593 527 597 526 598 1643 596 1646 593 1658 591 547 598 530 594 524 601 522 592 533 591 535 600 531 593 540 595 543 592 535 600 1628 601 1631 598 1641 598 1642 597 1647 592 1655 594 542 593 1626 592 +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 8912 4459 593 1636 593 1640 599 525 600 528 597 533 602 532 593 544 601 1637 592 523 591 1639 600 1636 593 535 600 529 596 538 597 541 594 534 601 1629 600 1634 595 531 1719 1649 532 593 541 594 543 602 526 599 519 595 1640 599 525 600 529 596 1649 601 534 601 537 598 529 596 522 603 519 595 529 596 533 602 528 597 538 597 540 595 532 593 523 602 518 596 527 598 528 597 535 600 533 592 545 601 509 595 7882 598 519 595 524 601 521 593 535 600 530 595 538 597 1650 600 1637 602 514 600 517 597 526 599 527 598 532 593 541 594 544 601 525 600 515 599 519 595 527 598 529 596 534 601 532 593 545 600 526 599 519 595 551 574 524 601 526 599 533 602 532 593 545 600 526 599 517 597 523 602 522 603 525 600 532 593 541 594 543 602 525 600 516 598 522 592 530 595 533 602 529 596 539 596 541 594 532 593 524 601 518 596 527 598 528 597 533 602 531 594 543 592 533 602 1625 593 526 599 523 602 1636 603 1639 600 533 592 1657 593 1628 601 7882 597 521 593 527 598 526 599 529 596 535 600 535 600 538 597 531 594 1634 595 1641 598 527 598 531 594 535 600 532 593 542 593 535 600 518 596 524 601 521 593 533 602 528 597 537 598 539 596 528 597 520 594 525 600 521 593 533 602 528 597 536 599 537 598 527 598 517 597 522 603 521 593 1644 595 1646 593 1651 599 537 598 526 599 516 598 520 594 527 598 528 597 532 593 539 596 540 595 531 594 1638 601 1633 596 528 597 1645 594 1652 598 1649 601 535 600 509 595 -# -# file: Flipper-IRDB/ACs/LG/LP1015WNR.ir -# -name: POWER -type: parsed -protocol: NECext -address: 10 E7 00 00 -command: 06 F9 00 00 -# -# file: Flipper-IRDB/ACs/Midea/Midea_AC_MAW05R1WBL.ir -# +# +# file: Flipper-IRDB/ACs\Midea\Midea_AC_MAW05R1WBL.ir +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 4454 4377 594 1560 591 486 589 1565 597 480 595 482 593 484 591 485 590 1564 598 1557 594 1560 591 1563 588 489 597 480 595 482 593 483 592 485 590 487 588 1565 597 1558 593 1562 589 487 588 489 597 1558 593 1561 590 1564 598 1557 594 1560 591 1563 588 1567 595 1560 591 1563 588 1566 596 1559 592 1562 589 1565 597 1558 593 1562 589 1565 597 1557 594 1561 590 486 590 488 598 479 596 1558 593 484 591 1563 588 489 597 1557 594 5161 4459 4371 601 476 589 1565 597 481 594 1560 592 1562 589 1565 597 1558 593 484 591 485 590 487 589 488 598 1556 595 1559 592 1563 588 1566 596 1559 592 1562 589 488 587 489 597 480 595 1559 592 1562 589 488 598 479 596 480 595 482 593 484 591 485 601 476 589 488 598 480 595 481 594 483 592 484 591 486 590 487 588 489 597 480 595 481 594 483 592 1562 589 1565 597 1558 593 483 592 1562 589 488 587 1567 595 482 593 -# +# +# file: Flipper-IRDB/ACs\Mitsubishi\mitsubishi-MSY-GE10VA.ir +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 3439 1755 439 1262 435 1286 432 438 441 423 456 418 441 1282 436 433 436 431 438 1285 433 1314 435 408 461 1293 435 408 440 426 433 1289 460 1296 412 455 414 1312 406 1319 409 429 440 429 461 1267 441 426 464 406 442 1281 437 430 439 427 432 436 464 405 433 432 437 458 411 456 434 422 437 428 462 412 436 428 441 422 457 411 437 456 413 454 405 436 433 434 435 427 432 435 465 404 434 435 434 431 459 413 435 429 440 422 437 433 457 1270 438 1288 461 410 438 426 464 404 434 1293 435 1315 413 423 436 1287 462 407 431 434 435 435 434 433 467 415 433 1318 410 1286 463 409 439 1284 455 1301 438 410 438 426 464 1262 456 1269 439 429 461 410 469 407 462 1268 440 1285 433 461 408 456 413 1284 465 1261 457 414 455 1271 468 1277 431 1321 438 405 433 460 409 430 439 426 464 407 462 407 441 450 409 434 435 430 439 452 438 431 438 405 464 405 464 405 464 409 460 409 439 430 439 427 442 423 436 460 430 415 433 431 438 425 434 444 435 456 413 432 437 427 442 425 434 436 464 429 430 439 430 417 442 428 441 428 462 411 437 452 438 405 433 434 435 456 413 427 442 425 434 455 414 427 432 435 434 433 436 427 463 406 432 437 442 449 430 1268 460 1265 463 1262 466 405 464 406 442 422 437 1289 439 428 441 17052 3577 1746 407 1321 407 1294 434 460 409 431 459 439 409 1288 440 429 440 431 438 1309 430 1272 456 415 464 1289 408 433 457 412 436 1289 439 1284 465 404 434 1292 436 1289 439 428 441 450 409 1315 413 427 442 451 408 1294 434 432 437 430 439 428 462 406 432 432 458 414 455 414 434 430 439 428 441 426 433 436 433 432 437 454 405 438 441 428 431 434 456 418 441 448 431 411 437 429 440 425 434 433 436 458 411 425 434 433 436 457 412 1287 462 1263 455 419 461 408 440 430 439 1310 429 1272 435 460 409 1288 440 429 461 408 441 425 465 405 464 407 441 1286 432 1291 437 432 437 1315 413 1314 414 450 440 406 442 1283 456 1270 458 413 456 413 456 413 435 1297 431 1294 465 404 434 433 436 1314 414 1285 433 433 436 1288 440 1285 464 1264 433 433 436 453 416 425 434 460 409 434 435 432 437 454 415 423 436 431 459 424 435 430 460 413 435 430 439 423 456 413 435 431 438 455 414 427 432 435 434 455 414 426 464 406 432 437 442 422 457 414 434 431 438 424 435 435 455 414 455 416 432 433 436 457 412 426 464 410 438 453 437 412 436 437 463 409 439 425 434 455 414 426 433 437 432 433 436 433 436 457 433 412 436 453 437 406 432 435 465 1266 462 1263 434 1318 410 426 464 410 438 426 433 1293 435 434 435 -# -# file: Flipper-IRDB/ACs/Mitsubishi/Mitsubishi_SRK35ZS-W.ir -# +# +# file: Flipper-IRDB/ACs\Mitsubishi\Mitsubishi_SRK35ZS-W.ir +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 3199 1594 380 414 380 1208 379 415 389 405 389 1201 386 407 386 1202 385 409 384 408 385 1203 384 1203 384 1204 383 410 383 1206 381 412 382 1208 379 1207 380 1209 389 404 390 406 387 405 389 406 387 1201 386 1202 385 408 385 1204 383 409 384 1204 383 1205 382 412 382 411 382 413 380 1206 382 414 380 1208 379 414 379 416 388 1201 386 1201 386 1201 386 408 385 1202 385 1204 383 1204 383 1206 381 1205 382 1207 380 1207 380 1208 390 405 388 405 389 406 387 406 387 406 387 407 386 408 385 1202 385 1204 383 1203 384 411 382 1205 382 1205 382 1207 380 1207 381 414 390 404 379 414 380 1210 388 406 387 408 385 406 387 408 385 1202 385 1203 384 409 384 1205 382 1205 382 1206 381 1206 381 1208 379 415 389 404 389 1199 388 407 386 406 387 407 386 408 385 409 384 1202 385 1204 383 1204 383 1204 383 1205 382 412 381 1208 379 1208 379 415 389 404 390 406 387 406 387 407 386 1200 387 409 384 408 385 1202 385 1205 383 410 383 1205 382 1205 382 412 381 1207 380 1207 380 415 389 404 379 1209 389 406 387 405 388 1200 387 408 385 408 385 1202 385 1204 383 1204 383 1204 383 1208 379 1207 380 1207 380 1208 379 416 388 405 388 407 386 407 386 407 386 407 386 407 386 408 385 408 385 1204 383 1204 383 1205 382 1205 382 1207 380 1208 379 414 379 1210 388 406 387 406 387 406 387 407 386 407 386 409 384 1203 384 -# +# name: TEMP+ type: raw frequency: 38000 duty_cycle: 0.330000 data: 3198 1595 389 404 379 1209 389 405 388 406 387 1200 387 407 386 1202 385 409 384 410 383 1203 384 1204 383 1179 408 413 380 1207 380 414 379 1209 389 1172 415 1200 387 406 387 409 384 408 385 409 384 1204 383 1205 382 410 383 1206 381 412 381 1206 381 1183 415 404 389 405 388 406 387 1200 387 406 387 1202 385 408 385 409 384 1204 383 1204 383 1205 382 412 381 1206 381 1181 406 414 390 1199 388 1173 414 1175 412 1175 412 1177 410 409 384 409 384 1205 382 410 383 411 382 412 381 412 382 412 381 1207 380 1209 389 405 389 1199 388 1174 413 1175 412 1175 412 1177 410 410 383 409 384 1205 382 412 381 412 381 413 380 413 380 1208 379 1207 380 414 379 1209 389 1173 414 1176 411 1177 410 1178 409 409 384 410 383 1206 381 411 382 412 381 412 382 413 381 413 380 1208 379 1208 379 1183 415 1173 414 1175 412 407 386 1203 384 1177 410 410 383 412 381 412 381 412 381 412 381 1207 380 414 379 414 379 1208 390 1199 388 405 388 1199 388 1200 387 409 384 1202 385 1177 410 410 383 412 381 1206 381 411 382 413 380 1207 380 413 380 414 380 1208 390 1199 388 1175 412 1175 412 1176 411 1179 408 1178 409 1179 408 412 381 413 380 414 379 414 379 415 389 404 379 414 379 416 388 405 389 1201 386 1200 387 1201 386 1177 410 1177 410 1179 408 411 382 1208 379 413 380 413 381 413 380 415 389 404 389 405 389 1199 388 -# +# name: TEMP- type: raw frequency: 38000 duty_cycle: 0.330000 data: 3200 1592 382 412 381 1206 381 414 379 414 379 1208 379 416 388 1200 387 406 387 407 386 1202 385 1176 411 1178 409 410 383 1179 408 411 382 1182 416 1172 415 1172 415 404 389 406 387 407 386 408 385 1201 386 1177 410 409 384 1179 408 412 381 1179 408 1181 406 413 380 413 380 414 379 1209 389 405 388 1199 388 406 387 408 385 1202 385 1179 408 1178 409 412 381 1180 407 1182 405 414 379 1182 416 1174 413 1174 413 1176 411 1176 411 410 383 410 383 1204 383 412 381 412 381 412 381 413 380 1209 389 1172 415 1174 413 406 387 1174 413 1177 410 1177 410 1179 408 410 383 412 381 413 380 1206 381 413 380 414 379 414 379 415 389 1199 388 1175 412 407 386 1177 410 1178 409 1178 409 1179 408 1180 407 413 380 414 379 1208 379 415 389 405 388 407 386 406 387 407 386 1201 386 1177 410 1178 409 1179 408 1180 407 412 381 1180 407 1182 405 416 388 405 388 406 387 407 386 407 386 1201 386 409 384 409 384 1204 383 1179 408 411 382 1180 407 1182 405 416 388 1172 415 1173 414 406 387 407 386 1201 386 409 384 410 383 1203 384 410 383 412 381 1206 381 1183 415 1173 414 1173 414 1174 413 1175 412 1178 409 1178 409 410 383 411 382 411 382 412 381 412 381 413 380 413 380 416 388 403 380 1208 379 1184 414 1175 412 1175 412 1176 411 1177 410 411 382 1178 409 411 382 412 381 413 380 413 380 413 380 413 380 1208 379 -# -name: MODE -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 3197 1595 390 404 379 1210 388 406 388 406 388 1201 386 407 386 1202 386 408 385 409 384 1205 383 1204 383 1206 382 412 381 1206 381 413 381 1207 381 1208 380 1209 389 405 389 406 387 405 389 407 387 1200 388 1201 386 408 385 1203 384 412 382 1205 383 1204 384 412 382 412 382 412 382 1207 381 413 381 1208 380 414 380 414 380 1209 389 1199 389 1201 386 1200 387 1202 385 408 385 409 384 1204 384 1205 383 1205 382 1205 383 412 382 413 380 1207 381 1209 389 406 388 405 389 405 389 405 389 1200 387 1203 384 1201 386 409 384 1203 384 1205 382 1205 383 1205 383 411 383 412 382 412 382 1207 380 414 380 415 389 404 379 417 387 1199 389 1199 389 1201 386 1204 384 1203 384 1203 384 1203 384 1204 384 411 382 412 382 412 382 412 382 413 380 413 381 414 380 414 380 1209 389 1199 389 1199 389 1200 387 1201 386 408 385 1203 385 1203 384 409 384 412 381 410 383 413 381 411 383 1206 382 413 381 413 380 1207 381 1209 389 404 379 1209 389 1199 389 407 386 1201 386 1202 385 408 385 410 384 1203 384 410 383 411 383 1204 384 412 382 412 382 1206 381 1207 380 1208 379 1211 387 1199 389 1201 386 1201 386 1202 385 408 385 410 383 409 385 409 385 410 384 410 384 410 383 411 383 412 382 1207 381 1206 382 1209 389 1197 380 1210 388 1199 389 406 387 1200 387 408 385 407 386 408 385 409 384 408 385 409 384 1204 384 -# -# file: Flipper-IRDB/ACs/Panasonic/Panasonic_CWA75C4179.ir -# +# +# file: Flipper-IRDB/ACs\Panasonic\Panasonic_CWA75C4179.ir +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 3472 1744 416 457 415 1306 418 463 419 466 416 473 419 474 418 478 414 457 415 458 414 463 419 462 420 465 417 472 420 1316 418 479 413 458 414 459 413 464 418 463 419 466 416 473 419 1318 416 1324 420 1295 418 454 418 459 413 1312 422 463 419 470 422 471 421 475 417 454 418 455 417 460 422 459 413 472 420 469 413 480 412 485 417 453 419 454 418 459 413 468 414 471 421 468 414 479 413 484 418 452 420 453 419 458 414 468 414 471 421 467 415 478 414 483 419 451 421 453 419 1301 412 1312 422 463 419 470 422 471 421 476 416 433 418 10535 3469 1746 414 459 413 1308 415 465 417 468 414 475 417 476 416 481 421 449 413 461 421 455 417 465 417 467 415 474 418 1319 415 482 420 450 422 451 421 457 415 466 416 469 413 476 416 1320 414 1327 417 1297 416 457 415 462 420 1305 419 466 416 473 419 474 418 478 414 457 415 458 414 463 419 462 420 465 417 472 420 473 419 477 415 456 416 1301 412 464 418 463 419 1310 413 1319 415 1321 413 485 417 453 419 454 418 459 413 1312 422 1307 416 472 420 1317 416 480 412 459 413 460 412 465 417 464 418 467 415 474 418 475 417 479 413 1302 422 1295 418 1302 421 1303 421 1308 415 473 419 1318 416 481 421 1293 420 1296 417 460 412 1313 421 1307 416 473 419 473 419 478 414 457 415 458 414 463 419 462 420 465 417 472 420 473 419 477 415 456 416 457 415 1306 418 1307 416 1312 422 467 415 478 414 483 419 451 421 452 420 457 415 467 415 469 413 476 416 1321 413 1328 416 1298 415 458 414 463 419 462 420 465 417 472 420 472 420 477 415 456 416 457 415 462 420 461 421 464 418 470 422 471 421 476 416 454 418 1299 414 463 419 461 421 464 418 471 421 472 420 477 415 1299 414 459 413 464 418 463 419 466 416 473 419 473 419 478 414 457 415 458 414 463 419 462 420 465 417 472 420 473 419 477 415 456 416 457 415 1306 417 1307 416 468 414 1319 415 478 414 483 419 430 421 -# +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 3473 1716 444 455 417 1304 420 461 421 464 418 471 421 471 421 476 416 455 417 456 416 461 421 460 412 473 419 469 413 1324 420 477 415 455 417 457 415 462 420 461 421 463 419 470 422 1315 419 1321 413 1302 422 451 421 456 416 1309 414 470 422 467 415 478 414 482 420 451 421 452 420 457 415 466 416 469 413 476 416 477 415 481 421 450 412 461 421 456 416 465 417 468 414 474 418 475 417 480 412 458 414 459 413 464 418 463 419 466 416 473 419 474 418 478 414 457 415 458 414 1307 417 1308 416 469 413 476 416 477 415 481 421 428 413 10540 3465 1751 419 454 418 1302 422 459 413 472 420 469 413 480 412 485 417 453 419 454 418 459 413 468 414 471 421 468 414 1322 422 475 417 454 418 455 417 460 412 469 413 472 420 468 414 1323 421 1320 414 1300 413 460 412 465 417 1307 417 468 414 475 417 476 416 481 421 449 413 460 422 455 417 464 418 467 415 474 418 474 418 479 413 458 414 459 413 464 418 463 419 1309 415 1318 416 1321 413 484 418 452 420 453 419 458 414 1311 413 1316 418 471 421 1315 419 478 414 457 415 458 414 463 419 462 420 465 417 472 420 472 420 477 415 1299 414 1302 422 1299 414 1310 414 1315 419 470 422 1315 419 478 414 1300 413 1303 421 456 416 1309 415 1314 420 469 413 480 412 485 417 453 419 454 418 459 413 468 414 471 421 468 414 479 413 484 418 452 420 453 419 1302 422 1303 421 1307 417 473 419 473 419 478 414 457 415 458 414 463 419 462 420 465 417 471 421 1316 418 1322 422 1293 420 452 420 457 415 466 416 469 413 476 416 477 415 482 420 450 422 451 421 456 416 465 417 468 414 475 417 476 416 480 412 459 413 1304 420 457 415 466 416 469 413 476 416 477 415 481 421 1293 420 453 419 458 414 467 415 470 412 477 415 477 415 482 420 450 422 451 421 456 416 465 417 468 414 475 417 476 416 481 421 449 413 1304 420 457 415 1310 414 471 421 1311 413 481 421 475 417 432 419 -# +# name: TEMP+ type: raw frequency: 38000 duty_cycle: 0.330000 data: 3466 1750 420 453 419 1302 422 459 413 472 420 469 413 480 412 485 417 453 419 455 417 460 412 469 413 472 420 469 413 1324 420 476 416 455 417 456 416 461 421 460 422 463 419 470 422 1315 419 1322 412 1302 422 452 420 457 415 1310 414 471 421 468 414 479 413 484 418 452 420 453 419 458 414 468 414 471 421 467 415 478 414 483 419 452 420 453 419 458 414 467 415 470 412 477 415 478 414 483 419 451 421 452 420 457 415 466 416 469 413 476 416 477 415 482 420 450 422 451 421 1300 413 1312 412 473 419 470 412 481 421 475 417 432 419 10572 3473 1743 417 456 416 1305 419 462 420 465 417 472 420 473 419 477 415 456 416 457 415 463 419 461 421 464 418 471 421 1316 418 479 413 457 415 459 413 464 418 463 419 466 416 473 419 1317 417 1324 420 1294 419 454 418 459 413 1312 422 463 419 470 422 471 421 476 416 454 418 455 417 461 421 460 412 473 419 469 413 480 422 475 417 453 419 1298 415 462 420 461 421 1308 415 1317 417 1320 414 483 419 451 421 452 420 1301 412 1312 422 1307 417 473 419 1317 417 480 422 449 412 1304 419 1301 412 1312 422 1307 416 1316 418 1319 415 1326 418 453 419 1298 415 462 420 461 421 464 418 1314 420 1317 417 480 422 449 412 460 422 1299 414 467 415 1313 421 468 414 480 412 484 418 453 419 454 418 459 413 468 414 471 421 468 414 479 413 484 418 452 420 453 419 1302 422 1303 421 1308 415 474 418 474 418 479 413 458 414 459 413 464 418 463 419 466 416 473 419 1318 416 1324 420 1295 418 454 418 459 413 468 414 471 421 468 414 479 413 484 418 452 420 454 418 459 413 468 414 471 421 467 415 478 414 483 419 452 420 1297 416 460 422 459 413 472 420 469 413 480 412 484 418 1297 416 456 416 461 421 460 422 463 419 470 422 471 421 476 416 454 418 455 417 460 422 459 413 472 420 469 413 480 412 485 417 453 419 454 418 1303 421 1304 420 466 416 1316 418 476 416 480 422 1271 412 -# +# name: TEMP- type: raw frequency: 38000 duty_cycle: 0.330000 data: 3474 1742 417 456 416 1305 418 462 420 465 417 472 420 473 419 478 414 456 416 458 414 463 419 462 420 465 417 472 420 1316 418 479 413 458 414 459 413 464 418 463 419 466 416 474 418 1318 416 1325 419 1296 417 455 417 460 422 1303 421 464 418 471 421 472 420 477 415 456 416 457 415 462 420 461 421 464 418 471 421 472 420 477 415 455 417 456 416 462 420 461 421 464 418 471 421 471 421 476 416 455 417 456 416 461 421 460 422 463 419 470 422 471 421 476 416 454 418 456 416 1305 419 1306 417 467 415 474 418 475 417 480 412 437 414 10576 3468 1747 413 461 421 1299 414 467 415 470 422 467 415 478 414 483 419 451 421 452 420 458 414 467 415 470 412 477 415 1321 413 485 417 453 419 454 418 459 413 469 413 472 420 469 413 1323 421 1320 414 1301 412 460 422 456 416 1309 414 470 422 467 415 478 414 483 419 451 421 452 420 457 415 467 415 470 412 477 415 478 414 482 420 451 421 1296 417 459 413 468 414 1315 419 1314 420 1317 417 480 422 449 412 460 422 455 417 1308 415 1313 421 469 413 1323 421 476 416 455 417 1300 413 1308 415 1309 414 1314 420 1313 421 1316 418 1323 421 450 422 1295 418 458 414 468 414 471 421 1311 413 1324 420 477 415 456 415 457 415 1306 417 464 418 1311 412 476 416 477 415 482 420 450 422 451 421 456 416 466 416 469 413 476 416 477 415 481 421 450 422 451 421 1300 413 1311 412 1316 418 472 420 473 419 477 415 456 416 457 415 463 419 462 420 465 417 472 420 1316 418 1323 421 1294 419 453 419 458 414 468 414 471 421 467 415 478 414 483 419 452 420 453 419 458 414 467 415 471 421 467 415 478 414 483 419 452 420 1297 416 460 422 459 413 472 420 469 413 480 412 485 417 1297 416 457 415 462 420 461 421 464 418 471 421 472 420 477 415 455 417 457 415 462 420 461 421 464 418 471 421 471 421 476 416 455 417 456 416 461 421 1304 419 465 417 1316 418 476 416 480 422 1271 422 -# -name: MODE -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 3467 1749 420 452 420 1301 412 468 414 472 420 468 414 479 413 484 418 453 419 454 418 459 413 469 413 472 420 469 413 1323 421 476 416 455 417 457 415 462 420 461 421 464 418 471 421 1315 419 1322 422 1293 420 452 420 458 414 1311 412 472 420 469 413 480 412 485 417 453 419 455 417 460 422 459 413 472 420 469 413 480 412 485 417 453 419 455 417 460 412 469 413 472 420 469 413 480 412 485 417 453 419 455 417 460 422 459 413 472 420 469 413 480 412 485 417 453 419 455 417 1304 419 1305 418 466 416 473 419 474 418 479 413 436 415 10538 3465 1751 419 454 418 1303 420 461 421 464 418 471 421 472 420 477 415 455 417 457 415 462 420 461 421 464 418 471 421 1315 418 479 413 457 415 459 412 464 418 463 419 466 416 473 419 1318 415 1325 419 1295 418 455 416 461 421 1303 420 465 417 472 420 473 419 478 414 456 416 458 414 463 419 462 420 465 417 472 420 473 419 478 414 456 416 1301 412 465 417 464 418 1311 412 476 416 477 415 482 420 451 421 452 420 457 415 1310 413 471 421 468 414 1323 421 476 416 455 417 456 416 462 420 461 421 464 418 471 421 471 421 476 416 1299 414 1302 421 1299 414 1311 412 1316 417 471 421 1316 417 479 413 1302 421 1295 418 459 412 1312 421 1307 416 472 420 473 419 478 414 457 415 458 414 464 418 463 419 466 416 473 419 473 419 478 414 457 415 458 414 1307 416 1309 414 1314 419 469 413 480 422 475 417 454 418 455 417 460 422 459 413 473 419 469 413 1324 420 1321 412 1302 421 452 420 457 415 466 416 469 413 476 416 477 415 482 420 451 421 452 420 457 414 467 415 470 412 477 415 478 414 483 419 451 421 1296 417 460 412 469 413 472 420 469 413 480 412 485 417 1297 416 457 415 462 420 461 421 464 418 471 421 472 420 477 415 456 416 457 414 462 420 461 421 464 418 471 421 472 420 477 415 456 416 457 414 1306 417 1307 416 1312 421 1311 412 481 421 1319 414 1279 414 -# -# file: Flipper-IRDB/ACs/Remko/Remko_RKL.ir -# +# +# file: Flipper-IRDB/ACs\Remko\Remko_RKL.ir +# name: POWER type: parsed protocol: NECext address: 86 6B 00 00 command: 12 ED 00 00 -# +# name: TEMP+ type: parsed protocol: NECext address: 86 6B 00 00 command: 1A E5 00 00 -# +# name: TEMP- type: parsed protocol: NECext address: 86 6B 00 00 command: 1E E1 00 00 -# -name: MODE +# +name: SWING type: parsed protocol: NECext address: 86 6B 00 00 -command: 02 FD 00 00 -# -# file: Flipper-IRDB/ACs/Rinnai/Rinnai_AC.ir -# +command: 00 FF 00 00 +# +# file: Flipper-IRDB/ACs\Rinnai\Rinnai_AC.ir +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 9026 4519 590 1654 616 1657 623 574 561 582 563 582 563 583 562 1688 592 1656 675 1627 593 1650 620 1654 677 521 563 1660 620 1656 614 1664 616 581 564 578 567 575 560 582 563 581 564 579 566 1684 596 1655 615 1661 619 577 568 574 561 581 564 580 565 579 566 580 565 582 563 581 564 577 568 574 561 582 563 580 565 579 566 1657 613 1664 616 582 563 578 567 575 560 583 562 581 564 580 565 582 563 584 561 582 563 578 567 575 560 583 562 581 564 580 565 1659 621 579 566 578 567 574 561 581 564 579 566 577 568 576 569 577 568 579 566 578 567 574 561 580 565 578 567 576 569 575 560 587 568 579 566 577 568 573 562 580 565 578 567 576 569 575 560 586 569 552 593 577 568 573 562 580 565 577 568 576 559 585 560 586 569 552 593 576 569 1703 567 575 560 1713 567 577 568 576 569 577 568 553 592 578 567 1704 566 1707 563 1656 614 1662 618 1659 621 577 568 553 592 1706 564 # -# file: Flipper-IRDB/ACs/Samsung/Samsung_AC_AR12K.ir -# +# file: Flipper-IRDB/ACs\Samsung\Samsung_AC_AR12K.ir +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 270 18152 3021 8955 523 499 495 1497 492 504 500 468 526 496 498 498 496 499 495 501 493 502 492 1499 500 496 498 524 470 1521 498 497 497 499 495 1496 492 1499 500 1491 497 1494 494 1497 502 494 500 495 499 497 497 498 496 500 494 528 466 530 464 531 473 522 493 503 491 504 500 495 499 497 497 498 496 500 494 501 493 503 491 504 500 495 499 496 498 498 496 499 495 501 493 529 465 531 473 522 472 523 492 504 490 505 499 496 498 498 496 499 495 1496 492 1499 500 1492 496 1494 525 2947 2999 8953 525 1519 469 499 516 507 497 498 496 500 494 501 493 503 491 504 500 495 499 1492 496 499 495 501 493 1498 501 495 499 1492 496 1522 466 1524 496 1496 492 1499 500 1492 496 499 495 500 494 502 492 504 500 495 499 496 498 498 496 499 495 500 494 502 492 530 474 521 473 523 523 472 522 474 489 506 498 497 497 499 495 500 494 502 492 503 501 494 500 496 498 497 497 499 495 500 494 502 492 503 501 521 473 523 471 524 522 474 520 475 498 497 497 499 495 500 494 2978 2999 8952 525 1492 496 499 495 501 493 503 491 504 500 495 499 497 497 525 469 526 468 1524 516 479 494 501 493 503 491 504 500 495 499 497 497 1494 494 1497 492 1500 499 1492 496 499 495 1497 491 531 473 1518 522 1469 499 496 498 498 496 500 494 1497 491 1500 499 1492 496 499 495 501 493 502 492 504 500 495 499 523 471 525 469 526 520 1472 516 1475 493 502 492 504 500 495 499 1492 496 499 495 501 493 502 492 504 500 495 499 496 498 498 496 1522 466 1525 525 1466 491 1500 499 -# -name: MODE -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 552 17959 3004 8946 521 530 474 1490 519 477 517 505 499 497 497 498 496 500 494 501 493 503 501 1464 524 497 497 499 495 1470 518 504 500 495 499 1493 495 1496 492 1499 520 1472 516 1475 524 498 496 500 494 501 493 503 501 494 500 496 498 497 497 499 495 501 493 502 492 531 473 522 472 524 470 525 490 506 498 497 497 499 495 501 493 502 492 504 500 495 499 497 497 498 496 500 494 501 493 503 501 494 500 496 498 524 470 526 468 527 467 529 496 1469 519 1472 527 1465 523 1468 520 2979 2997 8954 523 1469 519 502 492 504 500 495 499 524 470 525 469 527 467 528 497 499 495 1470 518 503 501 495 499 1466 522 500 494 1471 528 1464 524 497 497 1468 520 1446 604 1440 496 525 469 1496 523 499 495 1470 518 1473 526 497 497 498 496 500 494 1471 528 1464 524 1467 521 501 493 529 465 531 473 522 472 524 491 1474 525 497 497 1469 519 502 492 1474 525 1466 522 500 494 1471 528 494 500 496 498 1494 494 528 466 529 475 521 494 502 492 503 491 1474 525 1467 521 1470 518 1474 525 -# +# name: TEMP+ type: raw frequency: 38000 duty_cycle: 0.330000 data: 451 18082 2995 8958 519 529 465 1527 472 524 491 504 490 506 498 497 497 499 495 501 493 502 492 1500 499 497 497 498 496 1496 492 503 501 494 500 1492 496 1522 466 1525 494 1497 491 1500 498 498 496 499 495 501 493 503 501 494 500 495 499 497 497 499 495 500 494 502 492 503 501 495 499 523 471 525 469 526 468 528 497 498 496 500 494 502 492 503 501 495 499 496 498 498 496 499 495 501 493 502 492 504 500 495 499 497 497 499 495 527 467 529 465 1500 519 1499 489 1502 497 1495 493 2979 2997 8955 522 1469 519 503 501 494 500 496 498 497 497 499 495 501 493 529 465 531 473 1518 491 505 489 506 498 498 496 1495 493 1498 501 1491 497 499 495 1496 492 1500 499 1492 496 527 467 1525 494 501 493 1498 490 1502 497 499 495 500 494 502 492 1499 500 1492 496 1496 492 503 501 494 500 496 498 524 470 526 468 527 519 1446 522 1497 491 1500 499 1493 495 501 493 502 492 504 500 495 499 497 497 1494 494 501 493 503 501 521 473 523 471 524 522 1470 498 1494 494 1497 502 1490 498 -# +# name: TEMP- type: raw frequency: 38000 duty_cycle: 0.330000 data: 701 17814 3056 8923 554 441 522 1496 492 504 490 505 499 497 497 498 496 500 494 502 492 503 501 1491 497 498 496 500 494 1497 502 494 500 523 471 1520 468 1523 496 1496 492 1499 500 1492 496 499 495 501 493 503 501 494 500 496 498 497 497 499 495 501 493 502 492 531 473 522 472 524 470 525 490 506 498 498 496 499 495 501 493 503 491 504 500 495 499 497 497 499 495 500 494 502 492 504 500 495 499 497 497 525 469 527 467 528 466 530 495 501 493 1498 501 1491 497 1494 494 1498 500 2972 3004 8948 518 1500 499 470 524 498 496 500 494 529 465 531 473 522 493 530 464 505 489 1502 497 499 495 501 493 1498 501 1491 497 1494 494 1498 501 495 499 1492 496 1522 497 1495 493 502 492 1500 499 497 497 1494 494 1497 502 495 499 496 498 498 496 1496 492 1499 500 1518 470 526 468 527 498 498 496 500 494 501 493 503 491 505 499 1492 496 1495 493 1498 501 495 499 497 497 499 495 500 494 502 492 1527 472 523 523 473 490 506 498 497 497 499 495 1497 491 1500 499 1492 496 1496 492 -# -# file: Flipper-IRDB/ACs/Samsung/Samsung_Wind-Free.ir -# +# +# file: Flipper-IRDB/ACs\Samsung\Samsung_Wind-Free.ir +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 606 17832 2994 8936 520 501 496 1491 494 501 496 498 489 532 465 529 488 505 492 502 495 499 488 1499 496 499 498 495 492 1496 499 1463 522 499 498 1463 522 1467 517 1469 526 1491 493 1495 520 500 487 507 490 504 493 500 497 497 490 504 493 501 496 498 489 505 492 501 496 498 499 495 492 502 495 499 498 522 465 529 468 526 492 502 495 499 488 506 491 503 494 499 498 496 491 503 494 500 497 497 490 504 493 500 497 497 490 504 493 500 497 497 490 531 466 528 469 1518 487 1475 520 2947 3018 8939 517 1471 524 496 491 503 494 500 497 497 490 504 493 500 497 497 490 504 493 1521 464 530 467 527 491 1471 514 507 490 1471 524 1465 519 1468 517 1472 523 1465 520 1468 517 477 520 501 496 497 490 531 466 528 469 525 493 501 496 498 489 505 492 502 495 498 499 495 492 502 495 499 498 495 492 502 495 499 498 496 491 502 495 499 498 496 491 529 468 526 471 523 495 499 488 506 491 503 494 499 498 496 491 503 494 500 497 496 491 503 494 500 497 497 490 503 494 2973 2992 8939 517 1469 526 522 465 529 488 506 491 503 494 499 488 506 491 503 494 500 497 1490 495 499 498 496 491 1497 498 1464 520 1468 517 1470 525 524 463 1498 517 1471 524 1465 520 1468 517 1471 524 1465 520 1468 517 1472 523 497 490 504 493 501 496 1491 494 1496 519 1469 516 504 493 501 496 498 489 505 492 501 496 498 499 495 492 502 495 1492 493 1469 526 495 492 529 468 1492 513 1476 519 502 495 498 489 505 492 502 495 499 498 496 491 503 494 499 498 496 491 1497 498 1464 541 -# -# file: Flipper-IRDB/ACs/Toshiba/Toshiba_RAS13SKV2E.ir -# +# +# file: Flipper-IRDB/ACs\Toshiba\Toshiba_RAS13SKV2E.ir +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 4387 4349 553 1609 553 1607 555 1605 546 1613 549 531 550 530 551 1610 552 527 554 526 555 526 555 525 556 524 557 1602 549 1611 551 529 552 1608 554 526 555 525 556 525 556 524 546 533 548 532 549 1611 551 1608 554 1606 556 1604 558 1603 548 1611 551 1609 553 1607 555 525 556 525 556 524 557 523 547 533 548 533 548 532 549 531 550 530 551 1607 555 526 555 1605 557 1603 548 531 550 531 550 530 551 529 552 528 553 527 554 526 555 526 555 525 556 524 546 1612 550 1610 552 1608 554 527 554 526 555 526 555 525 556 524 557 523 547 533 548 532 549 531 550 1609 553 1607 555 525 556 525 556 1603 548 1612 550 530 551 7454 4385 4352 549 1611 551 1609 553 1608 554 1606 556 525 556 524 557 1602 549 531 550 531 550 530 551 530 551 529 552 1633 529 1604 558 523 558 1601 550 531 550 530 551 530 551 529 552 528 553 527 554 1604 558 1603 548 1611 551 1609 553 1608 554 1606 556 1604 558 1602 549 532 549 531 550 530 551 530 551 529 552 528 553 527 554 526 555 525 556 1603 548 532 549 1610 552 1608 554 527 554 527 554 526 555 525 556 524 557 523 547 533 548 532 549 531 550 530 551 1608 554 1606 556 1604 558 523 547 533 548 532 549 531 550 530 551 529 552 528 553 527 554 526 555 1605 557 1602 549 531 550 531 550 1609 553 1607 555 526 555 # -# file: Flipper-IRDB/ACs/Toshiba/Toshiba_RG57H4.ir -# +name: SWING +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4391 4345 555 1605 556 1604 547 1613 548 1611 550 530 550 529 551 1609 552 527 553 527 553 526 554 526 554 525 555 1604 547 1613 548 531 549 1611 550 529 551 529 551 529 551 528 552 527 553 526 554 1605 556 1603 548 1612 549 1611 550 1609 552 1608 553 1607 554 1605 556 524 556 524 556 523 547 533 547 533 547 532 548 531 549 530 550 529 551 1608 553 527 553 1606 555 1605 556 523 547 533 547 533 547 533 547 532 548 531 549 530 550 1609 552 527 553 527 553 527 553 526 554 1605 556 523 557 523 547 533 547 533 547 532 548 531 549 530 550 530 550 529 551 1608 553 526 554 526 554 526 554 525 555 524 556 523 547 7457 4390 4347 553 1608 553 1606 555 1605 556 1604 547 533 547 532 548 1612 549 530 550 530 550 529 551 529 552 528 552 1607 554 1605 556 524 556 1603 548 532 548 532 548 532 548 531 549 530 550 529 551 1608 553 1606 555 1605 556 1604 547 1613 548 1611 550 1610 551 1609 552 527 553 527 553 527 553 526 554 526 554 525 555 524 556 524 556 523 547 1612 549 531 549 1610 551 1609 552 527 553 527 553 527 553 526 554 526 554 525 555 524 556 1603 548 532 548 532 548 532 548 531 549 1610 551 528 552 528 552 528 552 527 553 526 554 525 555 525 555 524 556 523 547 1613 548 531 549 531 549 531 549 530 550 529 551 528 552 +# +# file: Flipper-IRDB/ACs\Toshiba\Toshiba_RG57H4.ir +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 4413 4375 541 1579 568 504 569 1576 571 501 562 510 563 534 539 507 566 1578 569 1577 570 1575 572 500 563 509 564 508 565 506 567 1578 569 502 571 501 562 1583 564 1581 566 1579 568 504 569 503 570 1574 563 510 563 1607 540 506 567 505 568 503 570 502 571 1573 564 508 565 1580 567 1578 569 503 570 502 571 500 563 535 538 507 566 1579 568 1577 570 502 571 500 563 536 537 1581 566 506 567 504 569 503 570 1574 563 5170 4409 4379 537 509 564 1581 566 506 567 1577 570 1575 572 1573 564 1582 565 507 566 505 568 504 569 1575 572 1573 564 1582 565 1580 567 505 568 1576 571 1574 563 509 564 508 565 532 541 1577 570 1575 572 500 563 1582 565 507 566 1578 569 1576 571 1574 562 1583 564 508 565 1579 568 504 569 502 571 1574 563 1582 565 1580 567 1578 569 1576 571 501 562 510 563 1581 566 1579 568 1577 570 501 572 1573 564 1581 566 1579 568 504 569 -# -# file: Flipper-IRDB/ACs/Whynter/Whynter_AC.ir -# +# +name: SWING +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4413 4349 566 1580 567 505 568 1577 570 502 571 501 572 526 537 1582 565 507 566 506 567 504 569 503 570 501 562 510 563 535 538 507 566 1579 568 1577 570 1575 572 1573 564 1582 565 1581 566 1579 568 1578 569 1576 571 1574 563 1583 564 1582 565 1580 567 1578 569 1577 570 1575 572 1573 564 1582 565 1581 566 1579 568 1578 569 1576 571 1574 563 1583 564 1581 566 506 567 1604 543 1576 571 1574 563 1583 564 1581 566 506 567 505 568 5164 4405 4357 569 502 571 1574 563 510 563 1582 565 1580 567 1578 569 503 570 1575 572 1573 564 1582 565 1580 567 1579 568 1577 570 1575 572 1573 564 509 564 508 565 506 567 505 568 503 570 502 571 526 537 509 564 508 565 506 567 505 568 503 570 501 572 500 563 509 564 507 566 506 567 504 569 503 570 501 572 499 564 508 565 507 566 505 568 504 569 1575 572 500 563 509 564 507 566 506 567 504 569 1576 571 1574 563 +# +# file: Flipper-IRDB/ACs\Vornado\Vornado.ir +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1296 454 1294 422 441 1304 1318 427 1321 422 441 1302 446 1297 440 1305 1317 426 437 1306 442 1301 436 7690 1321 424 1324 419 444 1301 1321 424 1324 420 443 1299 438 1304 444 1302 1320 423 440 1302 446 1297 440 7686 1325 420 1317 426 437 1308 1324 420 1317 426 437 1305 443 1300 437 1308 1324 419 444 1298 439 1304 444 7682 1318 427 1321 422 441 1304 1318 427 1321 423 471 1271 466 1277 471 1274 1317 427 467 1275 472 1270 467 7675 1325 420 1317 426 468 1277 1324 421 1316 427 436 1306 442 1301 467 1278 1323 420 443 1300 437 1305 474 7653 1316 429 1319 425 438 1306 1326 420 1317 425 438 1305 443 1300 437 1308 1324 419 444 1298 439 1304 443 7682 1318 427 1321 423 440 1305 1317 428 1320 423 471 1272 465 1277 439 1306 1316 427 467 1276 440 1302 446 7680 1320 426 1322 421 473 1272 1318 426 1322 422 472 1270 467 1276 472 1273 1317 426 468 1274 474 1269 468 7658 1321 424 1324 420 464 1281 1320 425 1354 389 464 1279 469 1274 474 1272 1318 424 470 1273 464 1279 468 7657 1322 423 1325 418 466 1280 1352 392 1345 400 463 1278 469 1273 464 1281 1351 394 469 1271 466 1277 470 7656 1323 422 1315 427 467 1278 1344 401 1347 399 464 1276 471 1272 465 1280 1321 422 472 1270 467 1276 472 7654 1325 421 1316 426 437 1308 1324 421 1316 427 436 1307 441 1302 445 1299 1323 421 442 1300 468 1274 474 +# +# file: Flipper-IRDB/ACs\Whynter\Whynter_AC.ir +# name: POWER type: raw frequency: 38000 @@ -907,7 +999,7 @@ duty_cycle: 0.330000 data: 781 710 2930 2876 775 716 781 735 752 2175 779 711 776 2177 746 745 773 2232 753 2173 749 768 750 2177 745 745 773 743 754 737 750 741 746 744 754 737 771 746 751 739 748 2178 776 742 755 2172 771 719 778 2227 747 744 754 2200 754 737 750 2203 751 741 746 2181 773 744 753 737 750 741 746 # # Old SAMSUNG AC -# +# name: POWER type: raw frequency: 38000 diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index 12088838ee..a07f8a7e90 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1,7 +1,7 @@ Filetype: IR signals file Version: 1 # -# This file has all the Speakers, SoundBars and Audio Receivers. POWER and MUTE buttons ONLY +# This file has all the Speakers, SoundBars and Audio Receivers. POWER,MUTE,VOL+/- buttons # from https://github.com/UberGuidoZ/Flipper-IRDB # Some Buttons was labeled PowerToggle,Pwr, Sleep or Off. These was assumed to be POWER functions. # While Care was taken to remove all possible duplicates, some may still be lurking. @@ -9,7 +9,7 @@ Version: 1 # HUGE thank you to Amec0e for continued maintenance! ##################################################### # -# Updated 23th August 2022 +# Updated 26th August 2022 # # | SPEAKERS | # @@ -964,6 +964,33 @@ protocol: NEC address: 80 00 00 00 command: 1E 00 00 00 # +# TEUFEL +# +# +name: POWER +type: parsed +protocol: NECext +address: EF 01 00 00 +command: 25 DA 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: EF 01 00 00 +command: 14 EB 00 00 +# +name: VOL+ +type: parsed +protocol: NECext +address: EF 01 00 00 +command: 13 EC 00 00 +# +name: MUTE +type: parsed +protocol: NECext +address: EF 01 00 00 +command: 28 D7 00 00 +# # VIZIO # name: POWER diff --git a/assets/resources/infrared/assets/fans.ir b/assets/resources/infrared/assets/fans.ir new file mode 100644 index 0000000000..cec82bf178 --- /dev/null +++ b/assets/resources/infrared/assets/fans.ir @@ -0,0 +1,927 @@ +Filetype: IR signals file +Version: 1 +# +# Created by amec0e with help from Edhel90 +# Special Thanks to Darmiel for the scrape script! +# +# Last Updated 26th Aug, 2022 +# +# Some Power functions was labelled Power,pwr,pwr_on/off,sleep,power_toggle,fan_power +# These was assumed to be POWER functions and added to the file. +# +# Some Rotate functions was labelled turn,tilt,horizontal_move,oscx,osc_hor these +# Was assumed to be ROTATE functions and added to the file. +# +# Some Speed functions was labelled speed,fan_speed,strength,slower,faster these +# Was assumed to be SPEED functions and added to the file. +# +# (Only added horizontal movement as it is the most common form of rotate for most fans) +# +# As such you may encounter some odd behaviour when using SOME power,rotate and speed +# functions. If you do, let me know and I will try my best to fix the issue! +# +# +# file: Flipper-IRDB/Fans\Big_Ass_Fans_Haiku.ir +# +name: POWER +type: parsed +protocol: NECext +address: BA F0 00 00 +command: 03 FC 00 00 +# +name: SPEED- +type: parsed +protocol: NECext +address: BA F0 00 00 +command: 41 BE 00 00 +# +name: SPEED- +type: parsed +protocol: NECext +address: 80 DE 00 00 +command: 10 EF 00 00 +# +name: SPEED+ +type: parsed +protocol: NECext +address: BA F0 00 00 +command: 50 AF 00 00 +# +name: TIMER +type: parsed +protocol: NECext +address: BA F0 00 00 +command: 40 BF 00 00 +# +name: POWER +type: parsed +protocol: NECext +address: BA F0 00 00 +command: 53 AC 00 00 +# +name: SPEED- +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 9F 00 00 00 +# +# file: Flipper-IRDB/Fans\Generic_Floor_Fan.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9069 4477 591 1695 622 528 625 525 618 505 617 532 621 527 626 497 625 525 618 532 621 1661 615 1640 595 1688 599 1684 613 1643 592 1691 626 1656 620 1636 620 1663 624 526 617 505 628 523 620 529 624 525 618 504 618 531 622 527 616 1643 623 1662 625 1658 618 1637 598 1685 622 1659 627 1655 570 1685 622 528 625 523 620 502 620 529 624 524 619 503 588 561 623 526 617 1667 619 1639 627 1654 622 1660 616 1638 617 1664 622 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9014 4522 597 1687 610 512 590 559 594 555 619 503 599 550 593 556 597 551 613 509 593 1688 588 1692 615 1639 596 1684 592 1689 587 1666 590 1691 595 1685 591 1689 566 1689 597 551 592 557 638 485 596 553 590 558 595 527 595 554 589 559 594 1686 611 1643 592 1688 588 1692 646 1607 597 1684 592 1688 619 1634 591 558 595 553 590 532 590 558 595 553 590 559 615 506 596 553 590 1693 594 1685 571 1683 593 1686 590 1690 565 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9066 4476 623 1662 625 525 618 504 587 561 623 526 617 531 622 501 621 528 625 524 619 1661 564 1692 625 1655 621 1660 565 1690 627 1654 622 1659 586 1668 618 1663 623 1657 619 1636 620 529 624 524 619 502 620 529 624 524 619 529 614 509 624 525 618 1663 613 1640 626 1655 621 1659 617 1637 619 1662 625 1656 620 1633 623 527 626 523 620 529 614 508 625 524 619 530 623 499 593 557 617 1663 623 1657 619 1635 621 1660 616 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9038 4530 589 1665 590 559 594 555 598 551 613 510 592 558 595 553 590 532 590 559 594 1686 590 1690 617 1637 598 1683 593 1687 620 1634 591 1691 595 1685 622 1632 593 557 596 1684 592 530 592 557 596 552 591 558 616 506 596 553 590 1690 596 526 596 1684 592 1688 588 1692 563 1690 596 1684 592 1687 620 503 589 1691 595 553 621 501 591 558 595 553 590 532 590 558 595 1689 597 551 623 1630 595 1686 590 1689 587 1666 589 +# +# file: Flipper-IRDB/Fans\Amazon\Amazon_Basics_Fan.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4609 4601 539 1515 545 1511 539 1518 542 1514 546 1510 540 1517 543 2559 541 1515 545 1511 539 2563 537 1519 541 2561 539 1516 544 1512 548 2554 546 1510 540 1515 4604 4605 545 1509 541 1515 545 1538 512 1518 542 1514 546 1511 539 2563 537 1519 541 1515 545 2557 543 1513 547 2555 545 1510 540 1516 544 2559 541 1514 546 13748 9234 2298 545 52033 9228 2304 539 52041 9230 2303 540 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4605 4603 547 1508 541 1515 545 1511 539 1518 542 1514 546 1511 539 2562 538 1518 542 1515 545 1511 538 2564 547 1509 541 1517 543 1513 547 2555 545 2556 544 1512 4607 4603 547 1508 542 1515 545 1511 539 1518 542 1514 546 1511 538 2564 546 1510 539 1517 543 1514 546 2557 543 1513 547 1510 540 1517 543 2559 541 2561 539 13755 9237 2297 546 52031 9229 2306 547 52033 9237 2297 546 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4608 4604 546 1509 541 1516 544 1513 547 1509 540 1516 544 1513 547 2555 545 1512 537 2565 545 1511 539 1518 542 2561 539 1516 544 1513 547 1510 539 2563 537 1517 4612 4599 541 1514 546 1511 539 1518 542 1514 546 1511 539 1518 542 2561 539 1518 542 2561 539 1517 543 1514 546 2557 543 1513 547 1510 540 1516 544 2559 541 13755 9237 2298 545 52044 9237 2298 545 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4606 4604 546 1509 541 1516 544 1512 548 1509 541 1516 544 1512 548 2554 546 1510 540 1517 543 2559 541 1515 545 2557 543 2558 542 1514 546 1511 539 1517 543 1512 4607 4601 539 1516 544 1513 547 1509 541 1516 544 1512 548 1508 542 2561 539 1516 544 1513 547 2555 545 1511 538 2589 522 2555 545 1511 539 1518 542 1515 545 13389 9233 2301 542 51673 9227 2306 547 +# +# file: Flipper-IRDB/Fans\Black_and_Decker\Black_and_Decker_BFSR16W.ir +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1273 401 1272 426 416 1232 1273 427 1247 426 405 1242 442 1231 442 1231 1274 426 405 1242 431 1242 431 7968 1274 400 1273 426 416 1232 1273 426 1247 426 405 1241 432 1241 432 1241 1275 425 406 1267 406 1240 433 7967 1275 398 1275 424 407 1240 1276 424 1249 424 407 1239 434 1238 435 1238 1278 422 409 1237 436 1237 436 7963 1279 394 1279 420 411 1262 1243 430 1243 430 412 1234 439 1234 439 1233 1272 428 414 1232 441 1232 441 7958 1273 426 1248 426 405 1241 1275 426 1248 425 406 1266 407 1240 433 1240 1276 424 407 1265 408 1238 435 7965 1277 422 1251 423 408 1238 1278 423 1250 423 408 1264 409 1238 435 1264 1251 422 409 1264 409 1237 436 7964 1278 422 1251 422 409 1264 1251 422 1251 422 409 1263 410 1262 411 1262 1254 420 411 1262 411 1235 438 7961 1270 429 1244 429 413 1260 1245 428 1245 427 415 1258 415 1231 432 1241 1274 425 406 1267 406 1240 433 7965 1277 423 1250 423 408 1265 1250 423 1250 423 408 1264 409 1237 436 1237 1278 421 410 1262 411 1262 411 7961 1270 429 1244 429 413 1260 1245 429 1244 429 413 1260 413 1233 440 1259 1246 427 415 1259 414 1258 415 7959 1272 427 1246 427 415 1259 1246 427 1246 427 415 1257 406 1267 406 1241 1274 425 406 1266 407 1266 407 7965 1277 422 1251 422 409 1264 1251 421 1252 421 410 1262 411 1261 412 1235 1270 429 413 1260 413 1233 440 7958 1273 426 1247 425 406 1267 1249 425 1248 424 407 1266 407 1265 408 1265 1250 423 408 1264 409 1263 410 7962 1280 420 1253 420 411 1261 1244 430 1243 429 413 1259 414 1232 441 1231 1274 427 415 1257 406 1240 433 7965 1277 423 1250 423 408 1264 1251 422 1251 422 409 1262 411 1235 438 1235 1280 420 411 1260 413 1232 441 7957 1274 426 1247 425 406 1266 1250 425 1248 424 407 1265 408 1238 435 1264 1251 423 408 1263 410 1236 437 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1280 394 1280 420 411 1236 1269 430 1254 419 412 1235 438 1234 439 1233 440 1233 440 1233 1272 427 415 8311 1279 395 1278 420 411 1236 1269 430 1243 430 412 1234 439 1234 439 1233 440 1233 440 1233 1272 427 415 8312 1277 396 1277 422 409 1264 1252 421 1252 421 410 1236 437 1235 438 1233 440 1259 414 1259 1246 427 415 8312 1277 422 1251 423 408 1264 1251 423 1250 423 408 1238 435 1237 436 1237 436 1263 410 1237 1278 421 410 8315 1274 425 1248 425 406 1240 1276 424 1249 424 407 1265 408 1238 435 1264 409 1237 436 1237 1279 421 410 8318 1271 402 1271 428 414 1233 1272 427 1246 427 415 1231 432 1241 432 1240 433 1240 433 1240 1276 424 407 8319 1271 429 1245 428 414 1233 1272 428 1245 427 415 1231 442 1231 432 1240 433 1240 433 1239 1277 423 408 8318 1271 401 1272 427 415 1232 1273 427 1246 426 405 1267 406 1240 433 1239 434 1238 435 1238 1278 422 409 8317 1272 401 1272 426 405 1242 1274 426 1248 425 406 1240 433 1239 434 1238 435 1238 435 1238 1278 421 410 8317 1272 401 1272 426 405 1242 1274 425 1249 425 406 1240 434 1239 434 1238 435 1238 435 1238 1278 421 410 8316 1273 400 1273 426 405 1241 1275 425 1248 425 406 1239 434 1239 434 1238 435 1238 435 1238 1278 421 410 +# +# file: Flipper-IRDB/Fans\Brandson\Brandson_fan_303352.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1341 395 1311 395 455 1220 1341 395 1311 396 454 1248 456 1248 457 1248 456 1247 457 1247 457 1247 1338 7184 1335 399 1307 399 450 1254 1307 399 1307 400 449 1255 450 1255 450 1254 450 1254 450 1254 450 1254 1307 8332 1306 401 1306 400 449 1256 1306 400 1306 401 449 1255 450 1255 449 1255 449 1255 449 1255 449 1255 1306 7214 1306 400 1307 400 450 1255 1306 400 1306 400 450 1255 449 1255 449 1255 449 1255 449 1255 449 1256 1306 8333 1306 401 1307 401 449 1256 1307 402 1306 402 448 1256 449 1256 448 1256 448 1256 448 1256 448 1256 1307 7215 1305 401 1306 402 448 1256 1306 402 1305 402 448 1257 447 1257 447 1257 447 1256 448 1256 448 1257 1305 8333 1304 402 1305 402 448 1257 1304 402 1304 403 447 1257 447 1257 448 1257 447 1257 447 1257 447 1257 1304 7216 1304 403 1303 403 446 1257 1304 403 1304 403 446 1258 447 1258 446 1257 447 1257 447 1258 447 1257 1304 8334 1304 402 1305 403 446 1257 1304 403 1303 403 447 1258 446 1257 448 1258 446 1258 446 1258 446 1258 1303 7217 1303 404 1303 404 445 1259 1302 404 1302 428 421 1259 446 1283 421 1259 445 1283 421 1283 421 1284 1278 8361 1277 429 1278 429 420 1284 1278 429 1277 429 420 1284 420 1284 420 1284 420 1284 420 1284 419 1285 1277 7243 1277 429 1277 429 421 1284 1277 429 1277 429 420 1284 420 1284 420 1284 420 1284 420 1284 420 1284 1277 8361 1277 430 1276 430 420 1285 1276 430 1277 430 419 1285 419 1285 419 1285 420 1284 420 1285 420 1285 1276 7244 1276 431 1276 430 419 1286 1276 430 1276 431 418 1286 418 1286 418 1286 418 1286 418 1285 419 1285 1276 8363 1275 431 1276 431 418 1286 1275 431 1276 432 417 1286 418 1286 418 1286 418 1286 419 1286 418 1286 1275 7246 1275 432 1275 432 417 1288 1274 457 1249 457 392 1312 392 1312 392 1289 415 1312 392 1312 392 1313 1249 8390 1248 458 1249 458 391 1313 1249 458 1248 458 391 1313 391 1314 390 1313 391 1314 390 1314 390 1314 1248 7273 1247 459 1223 484 390 1315 1247 460 1222 510 339 1365 364 1315 365 1339 390 1315 388 1341 339 1340 1222 8415 1222 484 1222 510 339 1365 1197 510 1197 510 339 1365 340 1365 339 1365 339 1365 339 1365 339 1365 1197 7324 1196 511 1196 511 338 1366 1196 511 1195 511 338 1366 338 1367 337 1367 337 1367 337 1367 337 1367 1195 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1341 368 1338 392 457 1219 1370 364 1341 364 485 1190 540 1164 513 1190 513 1191 512 1194 1365 366 481 8031 1338 370 1336 371 477 1226 1335 371 1335 371 477 1226 477 1226 477 1226 477 1226 477 1226 1334 371 477 9153 1334 371 1334 371 477 1226 1334 371 1335 371 477 1227 476 1227 476 1227 476 1227 476 1227 1334 372 476 8036 1334 372 1333 372 476 1227 1333 372 1333 372 476 1227 476 1227 476 1227 476 1227 476 1227 1334 373 475 9154 1334 373 1333 373 475 1228 1332 373 1332 373 475 1229 475 1228 475 1229 474 1229 474 1229 1331 374 474 8038 1331 374 1332 374 474 1229 1331 374 1331 398 450 1253 450 1253 450 1253 450 1253 450 1253 1307 398 450 9179 1307 398 1307 398 450 1253 1307 399 1306 398 450 1254 449 1254 449 1253 450 1254 449 1254 1306 398 450 8063 1306 398 1307 399 449 1254 1306 399 1306 399 449 1254 449 1254 449 1254 449 1254 449 1254 1307 399 449 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1372 339 1369 363 486 1190 1374 363 1344 363 486 1190 515 1191 513 1191 513 1192 1370 365 483 1220 484 8036 1339 371 1337 371 478 1227 1337 371 1337 371 478 1227 478 1227 478 1227 478 1227 1336 371 478 1227 478 9159 1336 372 1336 371 478 1227 1336 371 1336 372 477 1227 478 1227 477 1227 477 1227 1336 372 477 1228 477 8041 1335 372 1335 372 477 1227 1336 372 1335 372 477 1228 477 1228 477 1228 477 1228 1335 373 476 1228 477 9160 1335 373 1334 373 476 1228 1335 373 1334 373 476 1229 475 1229 476 1229 475 1229 1334 374 475 1229 475 8042 1334 375 1331 398 451 1230 1333 398 1309 398 451 1254 450 1254 451 1253 451 1253 1308 398 450 1254 450 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1342 366 1370 339 511 1191 1373 364 1343 364 511 1165 540 1165 514 1192 1371 364 484 1219 485 1220 484 8036 1339 370 1337 371 478 1227 1336 371 1336 371 478 1227 478 1227 478 1227 1336 372 477 1227 478 1227 478 9162 1336 372 1335 372 477 1228 1335 372 1335 373 476 1228 477 1228 477 1228 1336 372 477 1228 477 1228 476 8044 1336 372 1335 373 476 1228 1335 398 1309 398 451 1254 451 1254 451 1255 1308 400 449 1255 450 1256 449 9188 1306 403 1304 428 421 1260 1303 428 1279 429 419 1284 421 1284 420 1284 1279 429 420 1285 420 1284 420 8099 1276 457 1250 457 391 1313 1225 483 1224 484 364 1338 366 1338 392 1313 1225 484 364 1339 366 1339 390 9244 1225 509 1198 510 338 1366 1197 510 1197 537 311 1367 338 1393 311 1394 1169 591 256 11618 1170 539 1168 565 282 1395 1169 565 1142 538 310 1341 365 1312 419 1259 1305 400 449 1254 450 1255 449 9186 1307 400 1306 400 448 1255 1307 399 1307 400 448 1255 449 1255 449 1255 1307 400 448 1255 449 1255 449 8068 1306 400 1306 400 448 1256 1306 400 1306 401 447 1256 448 1256 448 1256 1306 401 447 1256 448 1257 447 +# +# file: Flipper-IRDB/Fans\Brandson\Brandson_Fan_304997.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 170 535 1281 413 1276 418 436 1259 1275 423 1276 444 410 1258 431 1264 435 1260 439 1256 433 1262 437 1258 1276 6529 173 475 1280 414 1275 419 435 1260 1274 450 1249 419 435 1259 430 1265 434 1261 438 1257 432 1263 436 1259 1275 7177 1280 414 1275 445 410 1260 1274 450 1249 445 410 1259 430 1266 433 1262 437 1258 431 1264 435 1260 1274 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1280 415 1274 447 407 1288 1256 442 1247 448 406 1288 411 1284 405 1291 408 1287 412 1283 1251 444 411 8009 1282 413 1276 445 409 1286 1248 450 1249 446 408 1286 403 1292 407 1262 437 1285 404 1291 1253 442 413 8007 1274 446 1253 442 402 1292 1252 447 1252 442 402 1292 407 1288 411 1284 405 1264 435 1286 1248 447 407 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1278 444 1255 439 405 1289 1255 444 1255 439 405 1290 409 1259 1275 447 407 1288 411 1257 432 1263 436 8009 1282 440 1249 446 408 1286 1248 451 1248 446 408 1286 413 1256 1278 444 410 1284 405 1264 435 1261 438 8008 1283 439 1250 444 410 1284 1250 450 1249 445 409 1284 405 1265 1279 442 412 1282 407 1262 437 1258 431 8015 1276 445 1254 440 404 1292 1252 446 1253 441 403 1292 407 1288 1256 439 405 1290 409 1286 403 1292 407 8012 1279 416 1273 448 406 1289 1255 443 1246 449 405 1289 410 1285 1249 446 408 1287 412 1283 406 1289 410 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1278 417 1282 439 405 1290 1254 444 1255 439 405 1289 410 1285 404 1292 1252 442 412 1283 406 1289 410 8010 1280 414 1275 446 408 1287 1247 451 1248 446 408 1286 413 1282 407 1263 1281 440 404 1291 408 1261 438 8007 1273 421 1278 443 411 1284 1249 449 1250 444 410 1258 431 1291 408 1288 1256 439 405 1289 410 1286 403 8017 1273 421 1278 443 411 1284 1249 449 1250 444 410 1285 404 1291 408 1262 1282 440 404 1264 435 1260 439 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1282 413 1276 445 409 1260 1274 450 1249 445 410 1259 430 1265 434 1261 438 1258 1276 445 409 1285 404 8017 1274 420 1279 442 412 1283 1251 448 1251 443 411 1283 406 1290 409 1260 439 1256 1278 443 411 1284 405 8015 1276 418 1281 440 404 1291 1253 446 1253 440 404 1291 408 1287 412 1283 406 1263 1281 440 404 1291 408 8011 1280 414 1275 446 408 1287 1247 452 1247 447 407 1261 438 1283 406 1289 410 1259 1275 447 407 1287 412 8006 1275 446 1253 441 403 1292 1252 447 1252 442 402 1292 407 1288 411 1284 405 1291 1253 442 402 1292 407 +# +# file: Flipper-IRDB/Fans\Co_Tech\CO_TECH_towerfan.ir +# +name: POWER +type: parsed +protocol: NEC +address: 30 00 00 00 +command: 97 00 00 00 +# +name: MODE +type: parsed +protocol: NEC +address: 30 00 00 00 +command: 87 00 00 00 +# +name: SPEED+ +type: parsed +protocol: NEC +address: 30 00 00 00 +command: 86 00 00 00 +# +name: TIMER +type: parsed +protocol: NEC +address: 30 00 00 00 +command: 9C 00 00 00 +# +name: ROTATE +type: parsed +protocol: NEC +address: 30 00 00 00 +command: 95 00 00 00 +# +# file: Flipper-IRDB/Fans\Daewoo\Daewoo_DDV200.ir +# +name: POWER +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 45 00 00 00 +# +name: SPEED+ +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 47 00 00 00 +# +name: TIMER +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 19 00 00 00 +# +name: ROTATE +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 1C 00 00 00 +# +# file: Flipper-IRDB/Fans\Dyson\Dyson_Air_Multiplier.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2229 716 749 747 728 715 750 720 756 714 751 719 757 1447 751 719 756 714 751 1453 755 742 723 747 729 742 754 716 749 721 754 715 729 741 724 1454 754 1450 758 1445 753 1451 757 714 751 50967 2228 717 748 1455 753 51028 2198 746 730 1449 749 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2225 719 756 741 724 720 755 715 750 720 755 716 749 1456 752 719 746 726 749 1456 731 741 755 1451 757 714 751 1455 753 718 757 1448 750 1456 752 720 755 715 750 721 754 1452 756 1449 759 51509 2201 743 732 1473 756 51069 2202 717 758 1448 750 +# +name: SPEED- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2234 712 752 743 732 713 751 720 755 716 749 722 753 1453 754 716 759 712 752 1453 754 718 757 1449 758 713 751 1455 752 1454 753 718 757 741 723 748 727 745 730 1449 758 739 725 1455 752 51252 2234 713 751 1454 753 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2229 714 750 747 727 717 757 713 751 719 755 715 749 1455 751 719 755 715 749 1455 751 1453 753 717 757 714 750 1454 752 718 756 714 750 746 728 742 722 722 752 1452 754 716 758 1445 751 50982 2229 716 727 1479 748 51048 2205 712 752 1450 756 +# +# file: Flipper-IRDB/Fans\Dyson\Dyson_Air_Purifier_Fan.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2258 688 781 718 751 694 775 696 784 687 782 690 779 1427 782 690 779 693 776 1431 778 721 748 724 756 716 753 719 750 722 747 725 744 727 773 1407 781 1426 783 1425 774 1433 776 696 773 51015 2224 748 721 1458 783 51084 2249 697 783 1425 784 51089 2253 694 775 1432 756 +# +# file: Flipper-IRDB/Fans\Dyson\Dyson_AM06_33_Fan.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2212 836 751 1591 749 825 752 817 750 1577 753 806 750 804 752 796 750 857 751 828 749 825 752 816 751 813 743 816 751 803 743 805 752 102392 2214 834 743 1599 751 823 744 825 752 1575 745 840 727 801 745 804 752 854 744 835 752 822 745 824 743 821 746 813 743 810 746 802 744 +# +# file: Flipper-IRDB/Fans\Dyson\Dyson_AM07.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2214 838 748 1596 751 824 751 819 746 1584 753 807 747 807 747 803 751 857 750 830 745 830 745 825 750 814 751 810 745 1574 752 798 746 101740 2213 838 748 1597 750 824 751 819 746 1583 754 806 748 807 747 802 752 856 751 830 745 829 746 824 751 814 751 809 745 1574 753 797 747 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2216 836 750 1594 754 821 754 816 749 1580 747 813 752 803 751 798 746 1626 753 827 748 1591 746 824 751 1578 749 811 754 1566 750 799 745 99411 2218 833 753 1591 746 829 746 823 752 1577 749 810 755 800 754 795 749 1623 745 835 751 1588 749 821 754 1574 752 807 747 1572 755 795 749 +# +# file: Flipper-IRDB/Fans\Dyson\Dyson_AM09.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2219 732 750 729 753 722 749 1384 755 1374 755 705 746 708 753 697 754 754 749 731 751 723 749 721 750 715 746 713 748 1370 749 701 749 99627 2216 735 747 732 750 725 747 1387 753 1376 753 706 755 700 751 698 753 755 748 732 750 725 747 722 749 716 745 714 747 1372 747 702 749 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2215 735 746 730 751 722 749 1383 745 1381 747 711 749 704 746 702 748 1422 748 730 751 722 749 720 751 712 748 1373 745 1372 746 702 748 102284 2218 732 749 729 752 720 751 1380 748 1378 750 709 751 701 749 700 750 1420 750 728 753 719 752 717 754 709 752 1370 748 1369 749 699 751 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2221 729 752 725 746 727 754 1377 751 1375 753 706 755 699 751 697 753 753 749 729 752 1384 755 1377 751 713 747 711 749 1367 751 1361 746 101691 2216 734 747 731 750 723 748 1383 745 1381 747 711 749 705 745 703 747 759 754 725 746 1390 749 1383 756 708 752 706 754 1362 745 1366 752 +# +# file: Flipper-IRDB/Fans\Dyson\Dyson_Cool_Fan.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2220 831 751 1618 729 820 751 818 753 1575 751 835 726 829 721 802 748 885 728 851 720 854 728 815 756 809 752 807 754 1565 750 825 725 101743 2220 830 752 1618 729 819 752 844 727 1574 752 835 726 802 748 801 749 884 729 850 721 827 755 815 746 845 726 806 755 1590 725 798 752 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2218 857 725 1592 754 846 725 844 727 1574 752 834 727 827 723 826 724 883 720 1597 750 851 720 1586 750 840 721 1577 749 831 730 1557 748 99247 2221 854 728 1590 746 854 728 841 720 1583 753 832 729 825 725 824 726 881 722 1596 751 849 722 1585 751 839 722 1576 750 831 719 1568 747 +# +name: SPEED- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2217 832 750 1594 753 821 750 819 752 1576 750 809 804 750 800 748 750 1622 756 1587 749 1589 747 1586 750 1578 748 1575 751 1568 747 802 748 101181 2218 831 751 1592 755 819 752 817 754 1574 752 808 753 801 749 800 751 1620 748 1596 751 1587 749 1584 752 1576 750 1574 752 1566 749 800 803 +# +# file: Flipper-IRDB/Fans\Dyson\Dyson_Fan_HP04.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2274 662 756 711 749 718 752 715 797 669 801 1399 749 718 783 684 797 670 800 1400 748 720 750 716 754 713 747 720 750 718 752 714 777 718 752 1448 752 714 756 711 749 1450 750 1423 777 51569 2192 718 752 1447 753 50954 2223 712 748 1423 798 50911 2245 661 746 1451 749 50917 2218 715 755 1415 754 50965 2191 716 754 1445 755 50923 2223 710 750 1421 800 50893 2190 717 753 1445 776 50902 2242 664 796 1402 777 50907 2217 717 753 1418 803 50880 2223 710 750 1421 800 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2225 712 747 719 751 716 754 713 757 711 748 1451 748 718 752 715 754 712 747 1451 748 718 752 716 754 1445 754 1444 724 1449 750 716 754 713 746 1453 746 720 749 1450 749 1451 727 1446 753 50693 2219 717 752 1445 754 50927 2194 714 756 1442 747 +# +# file: Flipper-IRDB/Fans\Dyson\Dyson_HP01.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2216 733 744 734 754 1382 751 1381 752 712 744 714 753 700 746 702 754 753 745 733 755 719 748 720 747 717 750 709 747 706 750 1361 751 99476 2211 738 749 729 748 1389 754 1377 745 718 748 710 746 707 749 699 747 760 748 730 747 726 751 718 748 715 752 706 750 703 753 1359 753 49283 2217 670 745 1350 751 50661 2212 676 749 1345 746 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2213 737 751 727 750 1387 746 1385 748 716 751 707 749 704 752 696 750 1420 754 724 753 720 747 721 746 718 749 1373 749 1367 745 703 753 102141 2215 735 753 726 751 1385 747 1384 748 715 752 706 750 704 752 695 751 1419 755 723 754 720 747 721 746 718 749 1399 723 1367 755 693 753 +# +# file: Flipper-IRDB/Fans\Dyson\Dyson_HP09.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 33 2223 753 725 720 748 750 728 743 725 746 722 1458 750 749 750 722 726 747 721 1460 748 724 755 744 724 721 747 724 754 744 724 747 752 720 748 1458 750 722 756 715 753 718 750 1456 752 51488 2221 727 721 1460 748 51156 2203 744 724 1456 752 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 33 2225 718 750 719 749 721 747 722 746 723 745 1458 750 720 748 722 726 744 724 1452 756 741 727 742 726 1451 746 1457 750 1454 754 716 752 717 720 1483 725 745 723 1454 754 1450 747 1456 752 50811 2199 744 745 1433 754 51049 2229 715 743 1435 752 +# +# file: Flipper-IRDB/Fans\Dyson\Dyson_Pure_HotCool_HP02.ir +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2221 721 727 1450 779 1452 756 714 744 1487 721 723 756 714 754 715 774 774 726 1505 724 772 748 1482 726 770 751 1454 754 1477 721 1484 745 101867 2197 745 723 1453 776 1455 722 748 720 1483 756 713 755 714 744 725 775 774 726 1478 751 771 729 1475 754 769 720 1483 756 1448 750 1481 727 50476 2201 714 755 1448 781 50602 2221 720 748 1454 775 50604 2250 743 694 1456 773 50628 2226 715 743 1433 775 50652 2191 748 720 1430 778 +# +name: SPEED- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2193 750 729 1421 777 1454 754 715 753 1478 751 719 728 715 753 716 773 1510 729 1501 728 1477 752 1505 755 1475 754 1477 721 749 751 772 696 102110 2246 748 720 1455 774 1430 747 723 746 1484 724 745 723 720 748 721 779 1477 752 1478 751 1480 749 1508 752 1478 751 1479 729 741 748 748 721 50743 2195 747 721 1454 775 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2247 750 729 1447 782 1450 748 722 726 1506 723 720 748 722 757 713 776 772 728 769 751 1505 755 1476 753 1452 756 740 749 747 753 1452 756 101517 2220 749 719 1457 772 1433 754 715 753 1478 719 750 729 715 753 716 773 776 724 772 748 1508 752 1479 750 1481 727 769 731 739 750 1454 754 50114 2228 742 726 1450 779 50645 2197 746 722 1454 775 +# +# file: Flipper-IRDB/Fans\Equatlon\Equatlon_Fan.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1275 434 1253 430 408 1275 1251 431 1257 427 411 1272 415 1241 436 1248 439 1244 433 1250 437 1247 1279 7142 1276 433 1255 428 410 1247 1279 430 1247 435 414 1269 408 1249 438 1272 415 1241 436 1248 439 1244 1282 8244 1274 434 1253 429 409 1274 1252 430 1247 435 414 1242 435 1275 412 1270 407 1277 411 1246 441 1242 1274 7146 1282 426 1251 431 407 1276 1250 432 1255 426 412 1271 406 1276 411 1272 415 1242 435 1248 439 1244 1282 8243 1275 433 1255 428 410 1272 1254 429 1248 434 415 1267 410 1273 414 1269 408 1275 412 1245 432 1251 1275 7144 1273 435 1252 430 408 1274 1252 430 1247 436 413 1269 408 1249 438 1245 442 1267 410 1274 413 1270 1256 8241 1277 431 1257 425 413 1270 1256 425 1252 430 408 1275 412 1270 407 1276 411 1246 441 1267 410 1247 1279 7140 1277 431 1256 426 412 1270 1256 425 1252 430 408 1274 413 1270 407 1276 411 1245 442 1267 410 1247 1279 8245 1273 435 1252 430 408 1274 1252 430 1247 435 414 1269 408 1275 412 1270 407 1277 410 1246 441 1268 1248 7145 1273 435 1252 430 408 1274 1252 430 1247 435 414 1242 435 1248 439 1244 433 1250 437 1246 441 1242 1274 8249 1279 403 1274 434 415 1242 1274 434 1253 429 409 1247 440 1242 435 1248 439 1244 433 1250 437 1246 1280 7138 1279 403 1274 434 415 1268 1247 434 1253 429 409 1246 441 1268 409 1248 439 1244 433 1250 437 1245 1281 8241 1277 405 1283 426 412 1270 1256 426 1251 430 408 1274 413 1270 407 1276 411 1271 416 1267 410 1246 1280 7138 1279 429 1248 434 415 1268 1247 434 1274 407 442 1240 416 1267 410 1247 440 1243 434 1249 438 1271 1255 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1279 430 1247 436 413 1270 1256 427 1250 432 406 1277 410 1273 414 1269 408 1275 1251 432 406 1277 410 7983 1284 425 1252 430 408 1275 1251 431 1256 426 412 1270 407 1250 437 1272 415 1242 1274 435 414 1270 407 9092 1275 433 1254 428 410 1273 1253 428 1249 434 415 1268 409 1274 413 1269 408 1276 1250 432 406 1277 410 7984 1283 425 1252 431 407 1275 1251 431 1256 426 412 1270 407 1276 411 1272 415 1241 1275 435 414 1269 408 9090 1277 431 1256 426 412 1270 1256 426 1251 431 407 1275 412 1270 407 1276 411 1272 1254 428 410 1273 414 7978 1278 430 1247 435 414 1269 1247 435 1252 430 408 1274 413 1243 434 1275 412 1271 1255 427 411 1272 415 9082 1275 434 1253 428 410 1273 1253 428 1249 433 405 1277 410 1272 415 1268 409 1274 1252 430 408 1275 412 7980 1276 432 1255 427 411 1271 1255 427 1250 432 406 1276 411 1271 416 1267 410 1247 1279 430 408 1275 412 9085 1282 426 1251 431 407 1276 1250 432 1255 426 412 1270 407 1276 411 1272 415 1268 1247 435 414 1269 408 7985 1282 427 1250 432 406 1277 1249 433 1254 428 410 1272 415 1267 410 1274 413 1269 1257 426 412 1271 406 +# +# file: Flipper-IRDB/Fans\Homezest\Homezest_LWTF-04.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9204 4469 604 562 604 562 604 562 604 563 603 564 602 565 601 567 599 568 598 1642 598 1643 607 1634 606 1634 606 1634 606 1635 605 1636 604 1637 603 1638 602 565 601 1641 599 568 598 569 607 560 606 1635 605 588 578 562 604 1637 603 563 603 1638 602 1639 601 1641 599 594 572 1643 607 39280 9217 2212 601 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9225 4468 605 563 603 564 602 565 601 566 600 568 598 569 597 570 606 561 605 1636 604 1638 602 1640 600 1641 599 1643 607 1634 606 1636 603 1637 603 1639 601 1640 600 1641 599 595 571 568 598 569 597 1645 605 588 578 562 604 563 603 564 602 1639 601 1641 599 1643 597 596 580 1635 605 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9214 4475 598 568 598 597 579 560 606 588 578 589 577 563 603 590 576 564 602 1666 574 1667 573 1641 599 1669 571 1643 597 1644 606 1635 605 1663 577 563 603 564 602 591 575 592 574 592 574 593 573 1668 572 594 572 1669 571 1669 571 1670 570 1644 606 1635 605 1636 604 590 576 1637 603 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9275 4475 608 560 606 563 603 565 601 568 598 570 606 563 603 565 601 567 599 1645 605 1638 602 1642 598 1645 605 1639 601 1642 598 1645 605 1637 603 1641 599 569 607 561 605 1639 601 1642 608 560 606 563 603 565 601 568 598 1644 606 1637 603 565 601 567 599 1644 606 1636 604 1639 601 +# +# file: Flipper-IRDB/Fans\Honeywell\Honeywell_Fan_CL18PE.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1279 428 1246 434 413 1265 1246 434 1250 430 407 1271 413 1240 434 1245 439 1240 434 1245 439 1240 1271 7282 1276 430 1244 436 411 1267 1255 426 1248 432 405 1248 437 1243 431 1248 436 1243 431 1248 436 1243 1279 7276 1272 434 1250 430 407 1271 1251 430 1244 436 411 1267 407 1247 437 1241 433 1246 438 1241 433 1246 1276 7279 1279 427 1247 433 404 1248 1274 433 1251 429 408 1271 413 1239 435 1245 440 1239 435 1244 430 1249 1273 7282 1276 430 1244 436 411 1267 1244 436 1248 432 405 1273 411 1242 432 1247 437 1241 433 1247 437 1241 1281 7274 1274 432 1252 428 409 1270 1252 428 1246 434 413 1266 408 1244 441 1239 435 1244 440 1239 435 1244 1278 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1275 405 1279 401 436 1243 1279 401 1273 407 440 1238 436 1244 1278 429 408 1244 440 1239 435 1244 440 8113 1272 434 1250 430 407 1246 1276 430 1254 426 411 1242 432 1247 1275 432 405 1247 437 1242 432 1247 437 8115 1280 426 1248 432 405 1248 1274 433 1251 428 409 1244 440 1239 1272 434 413 1239 435 1245 439 1239 435 8118 1277 429 1245 435 412 1240 1271 436 1248 431 406 1247 437 1242 1280 427 410 1242 432 1247 437 1242 432 8121 1274 406 1278 428 409 1244 1278 402 1272 408 439 1240 434 1245 1277 404 433 1246 438 1240 434 1245 439 8114 1281 399 1275 405 432 1247 1275 406 1278 401 436 1244 430 1249 1273 407 440 1240 434 1245 439 1239 435 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1248 412 1274 438 405 1284 1245 445 1251 435 408 1281 405 1282 404 1285 411 1251 435 1253 1276 437 406 8011 1242 445 1251 435 408 1255 1274 442 1244 443 410 1278 408 1280 406 1282 435 1254 411 1277 1242 445 408 8011 1242 443 1243 444 409 1279 1250 440 1246 441 412 1277 409 1279 407 1281 405 1282 404 1286 1243 443 410 8008 1245 442 1244 443 410 1278 1251 440 1246 441 402 1286 410 1278 408 1280 406 1256 430 1284 1276 411 411 8006 1247 439 1247 439 404 1285 1244 446 1250 437 406 1282 404 1283 403 1285 411 1278 408 1254 1275 438 405 8013 1251 436 1250 410 433 1282 1247 443 1243 443 410 1279 407 1281 405 1282 404 1258 438 1276 1243 444 409 7981 1272 414 1272 441 412 1250 1269 448 1248 438 405 1257 429 1259 437 1277 429 1232 433 1281 1248 412 431 7986 1267 446 1250 436 407 1255 1274 443 1243 443 410 1253 433 1280 406 1282 404 1258 428 1287 1273 387 435 7981 1272 414 1272 415 438 1276 1243 447 1249 411 432 1282 435 1228 489 1198 436 1278 408 1280 1249 411 432 +# +# file: Flipper-IRDB/Fans\Honeywell\Honeywell_Fan_HYF290E4.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1281 410 1289 429 415 1276 1257 435 1264 428 416 1248 440 1250 438 1253 435 1282 1261 404 440 1277 411 8127 1288 404 1284 434 410 1281 1262 403 1285 432 412 1280 408 1256 443 1249 439 1278 1265 401 443 1275 413 8125 1289 429 1260 432 412 1253 1291 401 1287 431 413 1251 437 1253 446 1246 442 1249 1284 435 409 1256 443 8122 1282 437 1262 429 415 1277 1256 409 1290 428 416 1249 439 1251 437 1254 445 1247 1286 433 411 1254 445 8120 1283 409 1290 428 416 1275 1258 434 1254 437 418 1274 414 1249 439 1252 436 1281 1262 404 440 1251 437 8128 1286 432 1256 436 408 1257 1286 405 1283 435 409 1282 417 1247 441 1250 438 1253 1290 428 416 1249 439 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1286 406 1282 438 416 1275 1257 435 1263 430 1258 434 410 1282 416 1276 412 1254 444 1248 1284 436 1262 7278 1288 403 1285 435 408 1257 1285 433 1255 438 1260 431 413 1279 409 1283 415 1250 438 1254 1288 405 1283 7285 1281 411 1287 432 412 1253 1289 430 1258 435 1263 429 415 1250 438 1254 444 1248 440 1252 1290 429 1259 7283 1283 408 1290 428 416 1249 1283 436 1262 431 1257 435 408 1256 442 1250 438 1255 443 1248 1284 436 1262 7278 1288 430 1258 435 408 1256 1286 433 1255 437 1261 431 413 1252 436 1282 416 1249 439 1254 1288 404 1284 7282 1284 408 1290 428 416 1249 1283 436 1262 430 1258 434 410 1255 443 1249 439 1253 445 1247 1285 408 1290 +# +# file: Flipper-IRDB/Fans\Honeywell\Honeywell_HO-5500RE.ir +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1276 403 1271 435 412 1241 1270 409 1276 431 1254 427 410 1242 1280 427 1247 433 404 1249 1273 407 430 8123 1273 433 1251 429 408 1245 1277 429 1245 435 1250 430 407 1272 1250 430 1255 426 411 1268 1254 426 411 8117 1279 401 1273 433 404 1249 1273 433 1251 429 1245 435 412 1240 1271 435 1249 431 406 1246 1276 431 406 8122 1274 406 1278 427 410 1270 1252 428 1246 434 1251 429 408 1271 1251 403 1271 436 411 1267 1244 436 411 8116 1279 427 1247 433 404 1275 1247 433 1251 429 1245 434 413 1266 1245 435 1250 430 407 1272 1250 431 406 8121 1274 431 1254 427 410 1269 1253 427 1247 433 1251 429 408 1271 1251 429 1245 434 413 1266 1245 435 412 +# +# file: Flipper-IRDB/Fans\Lasko\Lasko_Fan.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1280 457 1229 426 468 1236 1282 456 1230 427 468 1236 470 1235 471 1235 471 1235 471 1235 492 1240 1289 7171 1290 422 1284 399 464 1238 1291 422 1284 399 464 1239 467 1238 468 1238 468 1238 489 1217 500 1233 1285 7176 1285 426 1280 403 471 1232 1286 426 1281 403 471 1232 464 1242 496 1210 496 1237 469 1236 470 1236 1282 7206 1286 399 1287 422 441 1262 1287 398 1288 449 435 1215 491 1241 465 1240 466 1240 466 1240 466 1240 1289 7199 1283 429 1257 426 469 1235 1283 428 1258 426 469 1234 473 1234 472 1234 472 1233 474 1233 463 1243 1306 7182 1289 448 1258 398 465 1238 1291 448 1258 425 438 1239 467 1238 468 1238 468 1237 490 1216 490 1242 1287 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1289 448 1227 454 441 1238 1280 457 1228 454 441 1238 468 1239 1289 448 436 1215 491 1242 475 1233 473 8012 1281 457 1249 406 468 1237 1281 457 1260 396 467 1238 468 1239 1290 448 436 1242 475 1233 473 1234 472 8013 1291 421 1285 397 466 1238 1291 421 1285 398 465 1239 467 1240 1288 423 472 1233 473 1233 473 1234 472 8014 1289 449 1257 398 465 1239 1289 422 1284 398 465 1239 467 1240 1309 403 471 1233 473 1234 472 1235 471 8015 1309 402 1283 426 437 1241 1308 403 1283 427 436 1241 496 1237 1281 404 470 1235 471 1235 471 1236 491 8021 1282 402 1284 452 443 1235 1283 402 1284 452 443 1209 497 1236 1282 402 472 1233 463 1243 495 1212 494 8019 1284 427 1258 450 445 1233 1285 426 1259 450 444 1233 473 1233 1285 426 437 1240 497 1209 497 1236 470 8016 1288 450 1225 431 464 1241 1288 451 1255 402 472 1232 474 1232 1286 452 443 1235 523 1183 471 1235 471 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1286 424 1251 430 465 1241 1287 423 1252 457 437 1241 465 1242 464 1243 474 1234 472 1235 1314 423 440 8017 1286 451 1255 401 462 1242 1286 452 1254 402 472 1232 474 1233 473 1234 472 1234 493 1241 1287 424 439 8014 1289 422 1284 426 437 1241 1287 451 1255 403 471 1234 472 1234 472 1235 492 1215 491 1242 1286 399 464 8018 1285 426 1280 403 471 1234 1284 454 1252 404 470 1235 471 1236 491 1215 491 1243 526 1181 1285 427 436 8019 1315 423 1262 395 468 1236 1313 400 1286 424 439 1238 489 1218 499 1235 471 1236 470 1236 1282 430 464 8019 1284 401 1284 426 468 1236 1282 404 1281 456 438 1240 466 1240 466 1241 465 1241 465 1242 1286 426 468 8015 1288 424 1261 448 436 1242 1286 426 1259 451 444 1234 472 1234 472 1235 471 1235 471 1236 1282 456 438 +# +# file: Flipper-IRDB/Fans\Lasko\Lasko_Fan_Simple.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9090 4295 561 1708 570 561 563 569 565 567 567 565 569 563 561 570 564 568 566 565 569 1701 567 1702 566 1703 565 1705 563 1706 562 1707 561 1708 570 1699 569 1700 568 564 570 562 562 570 564 567 567 565 569 1700 568 563 591 563 561 1708 571 1699 569 1700 568 1702 566 1703 565 565 569 40667 9086 2139 562 97339 9092 2132 569 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9092 4292 563 1732 536 569 565 567 567 591 543 589 534 597 537 595 539 566 568 564 570 1699 569 1700 568 1702 566 1703 565 1705 563 1707 561 1708 570 1700 568 1701 567 591 543 1700 568 564 570 588 535 570 564 1732 556 571 563 568 566 1703 565 567 567 1702 566 1703 565 1705 563 567 567 40657 9086 2135 566 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9091 4292 564 1706 562 569 565 567 567 565 569 562 561 570 564 568 566 565 569 562 561 1708 570 1698 570 1700 568 1728 540 1703 565 1705 563 1706 562 1708 570 1699 569 1700 568 563 571 561 562 569 565 566 568 1701 587 566 568 563 571 561 562 1706 562 1707 561 1708 570 1699 569 562 561 +# +# file: Flipper-IRDB/Fans\LeaderPro\LeaderPro_DC_Motor_Floor_Fan.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9000 4466 564 1681 564 566 572 559 569 561 567 564 564 567 571 558 570 560 568 563 565 1678 567 1679 566 1681 564 1682 564 1679 566 1678 567 1686 570 1676 569 1674 571 559 569 563 565 1679 566 564 564 566 572 550 567 563 565 565 563 1679 566 1677 568 563 565 1678 567 1676 569 1681 564 1680 565 1680 565 565 563 569 569 1674 571 560 567 563 565 555 573 558 570 559 569 1674 571 1670 565 564 564 1678 567 1676 569 1675 570 12978 9003 2207 566 96147 9000 2203 570 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9005 4459 570 1701 544 560 568 563 565 566 572 559 569 563 565 566 572 559 569 561 567 1678 567 1676 569 1675 570 1673 572 1671 564 1680 565 1685 571 1671 564 1677 568 561 567 562 566 564 564 565 563 565 563 557 571 557 571 557 571 1670 565 1678 567 1674 571 1668 567 1671 564 1686 570 1670 565 1675 570 559 569 560 568 561 567 562 566 563 565 553 564 563 565 564 564 1677 569 1673 573 1671 564 1678 567 1674 571 1671 564 13005 8998 2203 570 96194 8995 2204 569 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9004 4451 568 1683 573 558 570 561 567 565 563 568 570 560 568 562 566 564 564 566 572 1680 565 1688 568 1685 571 1685 571 1684 572 1683 573 1674 571 1681 564 567 571 1679 566 1686 570 561 566 565 563 567 571 551 566 563 565 1690 566 565 563 569 569 1684 572 1682 563 1690 566 1681 564 1689 567 564 564 1689 567 1687 569 563 565 566 572 559 569 551 566 563 565 1684 572 558 570 560 567 1682 563 1687 569 1683 562 1688 568 12989 8992 2208 565 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9005 4457 572 1673 572 559 569 561 567 563 565 566 562 567 571 558 570 560 568 562 566 1676 569 1673 572 1698 537 1708 537 1704 541 1703 542 1708 537 567 571 1669 566 1701 544 558 570 560 568 561 567 564 564 557 571 1671 564 565 563 566 572 1670 565 1703 542 1673 562 1678 567 1683 562 566 562 1677 568 1701 544 559 569 561 567 563 565 565 563 557 571 1668 567 563 565 563 565 1676 569 1699 546 1669 566 1678 567 1676 569 +# +# file: Flipper-IRDB/Fans\LeaderPro\LeaderPro_Desk_Fan.ir +# +name: POWER +type: parsed +protocol: NEC +address: 30 00 00 00 +command: 8C 00 00 00 +# +name: SPEED- +type: parsed +protocol: NEC +address: 30 00 00 00 +command: 83 00 00 00 +# +name: SPEED+ +type: parsed +protocol: NEC +address: 30 00 00 00 +command: 85 00 00 00 +# +# file: Flipper-IRDB/Fans\LeaderPro\LeaderPro_Floor-Fan.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8958 4439 570 1663 563 561 562 563 560 564 569 556 567 557 566 558 565 559 564 560 563 1669 567 1663 563 1670 566 1665 561 1670 566 1666 560 1680 567 1665 561 1670 566 558 565 560 563 1669 567 557 566 559 564 552 561 563 560 565 568 1663 563 1668 568 556 567 1665 561 1670 566 1674 562 1668 568 1663 563 561 562 562 561 1670 566 558 565 559 564 552 561 563 560 564 569 1661 565 1667 569 555 568 1664 562 1668 568 1663 563 12896 8966 2197 565 95701 8962 2200 562 95719 8975 2194 568 95705 8970 2195 567 95693 8970 2196 566 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8965 4443 566 1668 568 557 566 559 564 562 561 564 569 583 540 559 564 561 562 563 560 1673 563 1671 565 1669 567 1666 560 1673 563 1670 566 1676 560 1673 563 1670 566 558 565 561 562 564 569 556 567 559 564 553 560 565 568 558 565 1668 568 1666 570 1663 563 1670 566 1667 569 1671 565 1668 568 1665 561 564 569 557 566 559 564 562 561 564 569 547 566 560 563 562 561 1672 564 1669 567 1666 570 1664 562 1671 565 1668 568 12942 8972 2198 564 95779 8964 2201 561 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8970 4439 570 1665 561 564 569 556 567 558 565 561 562 563 560 566 567 557 566 559 564 1669 567 1667 569 1665 561 1672 564 1670 566 1668 569 1674 562 563 560 1673 563 1671 565 561 562 564 569 556 567 559 564 553 560 1673 563 563 560 566 567 1667 569 1664 562 1672 564 1669 567 1676 560 566 567 1667 569 1664 562 563 570 555 568 558 565 560 563 553 560 1674 562 563 560 565 569 1667 570 1664 562 1671 565 1667 569 1663 563 12935 8969 2204 568 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8963 4430 569 1673 563 561 562 562 561 564 570 555 568 557 566 559 564 561 562 563 560 1680 567 1674 562 1680 567 1675 561 1681 566 1676 561 1671 565 1675 562 563 560 1682 565 1678 569 557 566 559 564 562 561 555 568 557 566 1675 562 564 569 555 568 1674 563 1678 569 1673 564 1670 566 1675 561 563 570 1672 564 1677 570 555 568 558 565 560 563 552 561 564 559 1682 565 560 563 563 560 1681 566 1675 561 1681 566 1676 561 12950 8975 2195 567 95870 8966 2201 561 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8973 4429 570 1673 563 562 561 565 568 557 566 559 564 561 562 564 569 557 566 559 564 1679 568 1674 562 1680 567 1676 560 1682 565 1676 571 1663 563 1679 568 558 565 1677 570 1673 563 562 561 565 568 557 566 1667 559 565 568 1673 563 563 560 565 568 1674 562 1679 568 1675 561 556 567 1675 561 564 569 1672 564 1677 570 556 567 559 564 561 562 1670 566 559 564 1676 571 555 568 557 566 1675 562 1680 567 1675 561 564 569 12939 8975 2197 565 +# +name: SPEED- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8972 4427 561 1681 566 560 563 562 561 565 568 557 566 559 564 561 562 563 560 565 568 1673 563 1676 571 1671 565 1676 571 1672 564 1677 570 1664 562 1679 568 1674 562 562 561 1680 567 558 565 560 563 562 561 555 568 556 567 558 565 1676 560 564 569 1670 566 1675 561 1680 567 1665 561 1680 567 1675 561 564 569 1673 563 562 561 564 569 556 567 548 565 561 562 562 561 1680 567 558 565 1677 570 1672 564 1678 569 1673 563 12942 8971 2195 567 +# +# file: Flipper-IRDB/Fans\MainStays\MainStays_Fan_FZ10-19JR.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9024 4477 566 1725 541 537 575 530 572 534 568 537 565 540 572 533 569 537 565 540 572 1690 566 1697 569 1720 546 1690 566 1697 569 1694 572 1691 565 1698 568 1694 572 533 569 537 565 540 572 533 569 536 566 540 572 532 570 536 566 1696 570 1692 574 1715 541 1696 570 1693 573 1689 567 1696 570 1693 573 532 570 536 566 539 573 532 570 535 567 538 574 531 571 534 568 1695 571 1691 565 1725 541 1695 571 1692 574 1688 568 11738 9017 2223 574 95995 9023 2216 570 95998 9020 2219 567 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9025 4477 576 1687 569 564 548 531 571 534 568 537 565 540 572 533 569 536 566 539 573 1689 567 1696 570 1693 573 1689 567 1696 570 1693 573 1690 566 1697 569 1694 572 560 542 1694 572 560 542 537 565 540 572 533 569 536 566 539 573 1689 567 565 547 1689 567 1696 570 1692 574 1689 567 1696 570 1693 573 559 543 1693 573 559 543 536 566 539 573 532 570 535 567 538 574 1688 568 564 548 1688 568 1695 572 1691 575 1688 568 11738 9016 2223 574 95995 9022 2216 570 96000 9019 2219 630 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9022 4480 573 1691 565 540 572 533 569 537 565 540 572 533 569 536 566 540 572 532 570 1693 573 1690 566 1697 569 1694 572 1717 539 1724 542 1721 545 1718 548 1715 541 1722 544 535 567 538 574 531 571 535 567 538 574 531 571 534 568 538 564 1698 568 1695 571 1692 574 1689 567 1722 544 1719 547 1716 540 1723 543 536 566 540 572 533 569 536 566 539 573 532 570 536 566 539 573 1689 567 1696 570 1693 573 1690 566 1724 542 11737 9015 2224 572 95995 9025 2215 571 95997 9020 2219 567 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9021 4481 572 1692 574 531 571 535 567 538 574 531 571 534 568 538 564 541 571 534 568 1694 572 1691 575 1688 568 1722 544 1719 547 1690 566 1697 569 1694 572 1691 565 540 572 533 569 1694 572 533 569 537 565 540 572 533 569 537 565 1698 568 1694 572 533 569 1695 571 1692 574 1715 541 1722 544 1693 573 531 571 535 567 1696 570 535 567 539 573 532 570 535 567 538 574 1689 567 1696 570 535 567 1696 570 1693 573 1716 540 11739 9024 2216 570 95999 9020 2219 567 96001 9020 2220 566 +# +# file: Flipper-IRDB/Fans\Meaco\MeacoFan_1056_P.ir +# +name: POWER +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 92 00 00 00 +# +name: SPEED+ +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 89 00 00 00 +# +name: ROTATE +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 87 00 00 00 +# +name: MODE +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 81 00 00 00 +# +# file: Flipper-IRDB/Fans\oneConcept\oneConcept_Hightower-2G.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1286 402 1289 426 414 1241 1280 408 1283 431 409 1245 435 1246 434 1247 433 1249 442 1239 441 1240 1281 7121 1281 404 1276 436 414 1239 1282 429 1251 433 407 1246 434 1246 434 1247 433 1247 433 1247 433 1247 1284 8216 1275 408 1283 428 412 1267 1253 430 1250 432 408 1245 435 1244 436 1244 436 1244 436 1244 436 1243 1277 7120 1282 401 1279 403 437 1243 1277 404 1276 407 433 1247 433 1246 434 1246 434 1246 434 1246 434 1245 1275 8224 1277 405 1275 407 433 1247 1273 409 1282 400 440 1240 440 1239 441 1239 441 1239 441 1238 442 1238 1282 7115 1276 405 1275 407 433 1247 1273 409 1281 400 440 1240 440 1239 441 1239 441 1239 441 1238 432 1248 1283 8216 1275 407 1283 399 441 1238 1282 400 1280 402 438 1241 439 1241 439 1240 440 1239 441 1239 441 1238 1282 7114 1277 405 1275 406 434 1246 1274 407 1273 408 432 1248 432 1247 433 1247 1246 434 1245 435 1245 1275 8223 1279 403 1277 404 436 1244 1276 406 1274 407 433 1247 433 1246 434 1245 435 1245 435 1244 436 1244 1276 7120 1282 400 1280 401 439 1241 1279 402 1278 404 436 1244 436 1243 437 1243 437 1242 438 1241 439 1241 1279 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1286 401 1279 434 406 1249 1282 404 1276 436 414 1240 440 1241 1280 432 408 1247 433 1248 432 1248 443 7955 1277 408 1283 430 410 1244 1276 408 1283 429 411 1243 437 1243 1278 408 432 1248 432 1249 441 1265 415 9057 1286 400 1280 431 409 1271 1250 435 1256 429 411 1243 437 1243 1278 433 407 1248 432 1248 432 1248 432 7966 1277 407 1284 427 413 1241 1280 431 1249 435 405 1249 442 1239 1282 402 438 1243 437 1243 437 1243 437 9062 1280 404 1276 435 405 1248 1283 401 1279 432 408 1245 435 1246 1275 436 414 1239 441 1239 441 1239 441 7956 1276 407 1284 427 413 1241 1280 404 1276 434 406 1247 433 1247 1284 400 440 1240 440 1240 440 1240 440 9058 1284 399 1281 429 411 1243 1278 432 1248 435 405 1249 431 1248 1283 401 439 1241 439 1241 439 1241 439 7957 1275 408 1283 401 439 1241 1280 430 1250 406 434 1246 434 1246 1275 409 441 1238 432 1249 431 1248 432 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1292 403 1288 431 409 1246 1285 406 1285 432 408 1247 433 1249 442 1240 1280 407 443 1239 441 1267 413 7957 1286 401 1279 434 406 1248 1283 404 1287 427 413 1241 439 1241 439 1241 1280 407 433 1248 432 1248 443 9055 1277 409 1282 431 409 1244 1276 409 1282 431 409 1244 436 1245 435 1245 1286 426 414 1267 413 1241 439 7956 1276 409 1282 430 410 1244 1277 408 1283 429 411 1269 411 1243 437 1243 1278 407 433 1248 432 1248 432 9065 1277 407 1284 428 412 1242 1278 406 1285 427 413 1241 439 1241 439 1241 1280 406 434 1247 433 1247 433 7962 1281 405 1275 436 414 1266 1254 431 1249 436 414 1265 415 1239 441 1240 1280 432 408 1246 434 1247 433 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1274 408 1283 426 414 1239 1282 427 1253 428 412 1241 439 1240 440 1240 440 1239 1281 427 413 1267 413 7957 1275 434 1246 436 404 1275 1256 427 1253 429 411 1267 413 1267 413 1240 440 1240 1280 428 412 1267 413 9060 1282 400 1280 428 412 1267 1253 429 1251 430 410 1243 437 1243 437 1242 438 1242 1278 429 411 1241 439 7958 1274 434 1246 436 414 1264 1256 426 1254 428 412 1266 414 1240 492 1188 440 1240 1280 428 412 1240 440 9059 1272 436 1254 426 414 1239 1281 426 1254 427 413 1240 440 1239 441 1239 441 1238 1282 426 414 1239 441 7955 1277 405 1275 407 433 1246 1274 408 1282 399 441 1239 441 1239 441 1239 441 1239 1281 400 440 1240 440 +# +# file: Flipper-IRDB/Fans\Orbrgozo\Orbegozo_SF0243.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1309 376 1276 409 433 1252 1305 379 1273 410 463 1222 441 1244 460 1221 463 1221 442 1242 462 1222 1283 7692 1310 375 1309 377 464 1220 1305 379 1273 410 463 1223 460 1222 441 1242 462 1221 431 1252 463 1220 1305 7668 1281 401 1303 378 432 1252 1284 399 1305 378 464 1220 464 1217 466 1216 467 1215 468 1214 459 1223 1303 7665 1305 379 1304 381 440 1244 1282 405 1278 409 433 1254 440 1246 437 1248 467 1219 433 1252 463 1224 1312 7687 1304 385 1309 380 461 1227 1278 410 1305 382 439 1250 433 1253 462 1228 466 1222 461 1226 468 1219 1306 7689 1313 375 1308 380 441 1248 1309 379 1284 402 460 1228 466 1222 441 1248 467 1222 462 1227 467 1222 1304 7688 1283 403 1312 374 468 1219 1306 382 1312 377 464 1224 439 1249 434 1252 442 1245 459 1228 435 1253 1304 7683 1277 411 1304 383 438 1249 1308 380 1303 381 461 1225 438 1248 435 1252 442 1247 436 1252 442 1246 1311 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1274 436 1247 436 406 1277 1249 437 1257 427 415 1269 415 1270 413 1272 1254 432 410 1274 410 1271 413 8525 1277 431 1253 430 412 1272 1254 430 1254 428 413 1270 414 1271 413 1272 1254 430 412 1271 413 1272 412 8537 1275 435 1249 437 415 1270 1256 427 1257 427 415 1268 405 1279 415 1268 1247 437 404 1279 415 1269 415 8528 1274 433 1251 432 410 1272 1254 430 1254 431 411 1273 411 1271 413 1244 1282 429 413 1271 413 1271 413 8532 1281 429 1255 430 412 1272 1254 429 1255 428 414 1271 413 1245 439 1273 1253 432 410 1274 410 1273 411 8539 1273 435 1249 433 409 1273 1253 429 1255 430 412 1271 413 1270 414 1267 1248 434 408 1274 410 1273 410 8532 1280 428 1256 427 414 1268 1247 436 1248 436 406 1250 434 1275 409 1272 1254 429 413 1270 414 1270 414 8534 1278 431 1253 433 409 1273 1253 429 1255 429 413 1269 415 1267 406 1277 1249 436 405 1277 407 1249 435 8531 1281 427 1246 436 406 1275 1251 434 1250 433 409 1272 412 1270 414 1269 1246 436 405 1277 407 1274 410 8537 1275 435 1249 435 407 1278 1248 437 1257 428 414 1268 405 1277 407 1276 1250 434 408 1274 410 1272 412 8531 1281 429 1255 429 413 1243 1283 427 1257 428 414 1271 413 1272 412 1272 1254 432 410 1273 411 1247 437 8536 1276 432 1252 432 410 1273 1253 432 1252 433 409 1275 409 1275 409 1275 1251 435 407 1278 405 1277 407 8535 1278 430 1254 428 414 1268 1247 436 1248 435 406 1276 408 1277 407 1277 1249 435 407 1277 407 1277 407 8540 1273 435 1249 434 408 1273 1253 429 1255 429 413 1271 413 1270 414 1270 1256 430 412 1271 413 1271 413 8538 1275 435 1249 435 407 1275 1251 432 1252 433 409 1275 409 1274 410 1274 1252 432 410 1275 409 1276 408 8542 1281 429 1255 431 411 1273 1253 431 1253 432 410 1273 411 1271 413 1271 1255 431 411 1273 411 1272 412 8529 1273 436 1258 427 415 1268 1258 427 1257 429 413 1272 412 1273 411 1249 1277 436 406 1279 415 1268 415 8536 1276 432 1252 430 412 1271 1255 431 1253 432 410 1275 409 1274 410 1273 1253 432 410 1274 410 1272 412 8527 1275 435 1249 435 407 1276 1250 433 1251 434 408 1277 407 1279 415 1269 1257 427 415 1271 413 1270 413 8556 1277 436 1258 431 411 1277 1259 430 1254 436 406 1280 414 1272 412 1275 1251 438 414 1272 412 1272 412 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1280 431 1253 432 410 1275 1250 433 1251 434 408 1277 406 1280 414 1272 412 1274 410 1276 1250 436 405 8543 1331 352 1280 432 410 1275 1251 433 1251 435 407 1275 409 1272 412 1271 413 1272 412 1273 1253 432 410 8527 1275 435 1249 436 405 1276 1250 431 1253 429 413 1270 413 1270 413 1269 414 1269 415 1268 1247 436 405 8534 1278 430 1253 428 414 1268 1247 435 1248 435 407 1277 406 1276 408 1274 410 1274 410 1248 1277 436 405 8558 1275 438 1256 431 411 1277 1259 428 1256 431 411 1275 409 1278 416 1271 413 1273 411 1277 1259 429 413 8559 1285 428 1256 430 412 1273 1253 433 1251 434 408 1277 406 1280 414 1274 410 1279 415 1273 1253 437 415 8550 1283 430 1254 433 409 1279 1257 431 1253 434 408 1279 415 1274 410 1278 416 1274 410 1278 1258 431 411 8553 1280 432 1252 435 407 1279 1257 427 1256 427 404 1277 406 1276 408 1248 435 1274 410 1273 1253 430 412 8535 1277 433 1251 435 406 1279 1257 429 1255 431 411 1275 409 1277 406 1278 416 1271 413 1272 1254 431 411 8545 1278 433 1251 434 408 1278 1258 428 1255 432 410 1274 410 1279 415 1273 411 1278 416 1273 1253 437 415 8557 1286 429 1254 437 415 1274 1252 436 1258 430 412 1277 406 1283 411 1278 405 1282 412 1275 1250 438 414 8561 1282 433 1251 438 414 1274 1252 438 1256 433 409 1277 407 1280 414 1272 412 1275 409 1278 1258 429 413 8549 1284 430 1254 434 408 1279 1257 429 1255 433 409 1279 415 1273 411 1277 407 1280 414 1274 1252 436 405 8557 1276 436 1258 431 411 1274 1252 434 1250 437 415 1272 412 1275 408 1280 414 1275 409 1280 1256 433 409 8558 1285 428 1256 431 411 1276 1250 438 1256 432 410 1278 416 1272 412 1273 411 1273 411 1273 1253 432 410 8539 1273 437 1247 436 405 1277 1249 434 1250 435 406 1276 408 1275 409 1275 409 1275 409 1275 1251 435 406 8543 1280 430 1254 431 411 1274 1252 431 1253 431 411 1273 410 1272 412 1273 411 1274 410 1276 1250 434 408 8542 1280 432 1252 434 408 1279 1257 430 1254 433 408 1277 407 1278 416 1270 413 1272 412 1275 1251 435 406 8540 1283 427 1257 429 413 1272 1254 431 1253 432 410 1275 409 1276 408 1278 406 1277 406 1276 1250 435 407 8538 1274 434 1250 434 408 1277 1249 436 1258 428 414 1273 411 1272 412 1270 414 1271 412 1273 1253 433 409 8535 1277 433 1251 436 406 1282 1254 433 1250 438 414 1274 410 1278 405 1280 414 1271 413 1276 1260 429 412 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1280 433 1251 436 405 1281 1255 431 1253 434 408 1278 405 1279 1257 431 411 1277 407 1280 414 1274 410 8547 1275 437 1257 428 413 1270 1255 430 1254 430 412 1273 411 1275 1251 436 405 1280 414 1271 412 1273 410 8550 1283 431 1253 434 408 1278 1258 427 1256 428 414 1271 412 1272 1254 434 408 1279 415 1271 412 1247 436 8544 1279 433 1251 435 407 1279 1257 430 1254 434 407 1278 405 1277 1249 437 415 1269 414 1269 415 1269 415 8537 1275 435 1248 435 406 1276 1250 436 1248 436 406 1278 406 1277 1248 437 404 1280 414 1269 414 1271 412 8532 1280 428 1255 428 413 1269 1246 437 1246 435 406 1276 408 1277 1248 436 406 1278 406 1279 415 1268 416 8538 1274 436 1258 427 415 1269 1257 427 1257 430 412 1272 412 1273 1252 434 408 1277 407 1280 414 1272 412 8553 1280 405 1279 434 408 1276 1250 435 1259 429 413 1273 411 1274 1252 434 408 1277 407 1279 415 1270 414 8548 1275 436 1258 428 414 1272 1254 433 1250 435 406 1277 406 1278 1258 429 413 1272 412 1275 409 1277 406 8549 1284 427 1257 430 412 1274 1251 433 1251 434 407 1277 406 1278 1248 437 415 1269 415 1271 412 1273 410 +# +# file: Flipper-IRDB/Fans\Pelonis\Pelonis_PFS40D6ABB_Fan.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8982 4433 598 1657 570 519 594 547 566 522 591 549 575 540 573 541 572 542 571 543 570 1659 568 1635 592 1637 600 1655 572 1657 570 1660 566 1636 601 1654 572 1630 597 517 596 545 568 520 593 547 566 548 576 539 574 540 573 540 573 1629 598 1631 596 1633 593 1635 592 1637 600 1629 597 1631 596 1633 593 521 592 522 591 549 575 540 573 514 599 542 571 543 570 544 569 1659 568 1635 592 1637 600 1628 598 1630 597 1632 595 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8990 4430 601 1628 598 517 596 519 594 547 566 549 574 540 573 542 571 544 569 546 567 1663 574 1628 598 1658 568 1662 575 1654 572 1658 568 1660 566 1663 574 1656 570 544 569 1660 566 548 575 539 574 541 572 542 571 544 569 545 568 1662 575 539 574 1656 570 1658 568 1661 565 1664 573 1656 570 1659 567 548 565 1664 573 542 571 543 570 545 568 546 567 548 565 549 574 1655 571 543 570 1659 567 1661 576 1628 598 1658 568 +# +# file: Flipper-IRDB/Fans\Rowenta\Rowenta_Eole_Infinite.ir +# +name: SPEED+ +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 11 00 00 00 +# +name: ROTATE +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 0E 00 00 00 +# +name: TIMER +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 05 00 00 00 +# +# file: Flipper-IRDB/Fans\Rowenta\Rowenta_Mosquito_Silence_VU6410FD.ir +# +name: ROTATE +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 18 00 00 00 +# +name: TIMER +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 40 00 00 00 +# +# file: Flipper-IRDB/Fans\ServilleClassics\SC-UltraSlimLine-Oscillating-Tower-Fan.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1313 407 1306 414 432 1273 1306 415 1308 447 409 1275 438 1275 437 1275 438 1273 1306 449 407 1278 434 7939 1307 438 1285 408 427 1278 1312 409 1304 424 484 1229 432 1280 433 1280 433 1277 1313 415 431 1282 430 7925 1310 408 1304 414 432 1274 1305 415 1308 420 426 1286 427 1285 428 1284 429 1282 1308 420 426 1286 427 7944 1312 407 1306 413 433 1272 1307 413 1310 418 428 1284 429 1283 481 1230 431 1279 1311 417 429 1283 430 7922 1313 406 1307 412 434 1271 1308 412 1311 416 430 1283 429 1282 431 1281 432 1277 1313 415 431 1281 431 7935 1310 409 1365 353 482 1222 1306 415 1308 420 426 1285 428 1284 429 1283 429 1280 1310 418 428 1284 429 7922 1303 415 1308 411 435 1270 1310 411 1312 415 431 1280 432 1279 433 1278 435 1274 1305 423 433 1278 435 7930 1305 413 1310 409 426 1277 1313 408 1305 422 434 1277 436 1275 427 1284 429 1280 1310 418 428 1283 430 7918 1307 411 1312 407 428 1275 1304 416 1307 420 436 1275 427 1283 430 1281 431 1277 1313 414 432 1279 433 7928 1307 411 1312 406 429 1274 1305 414 1309 419 427 1283 430 1281 432 1279 434 1275 1304 449 407 1277 435 7909 1305 412 1311 408 427 1276 1303 416 1307 421 435 1275 427 1283 430 1281 431 1277 1313 414 432 1279 433 7925 1310 408 1305 414 432 1271 1308 412 1311 417 429 1281 431 1279 433 1276 436 1272 1308 420 426 1284 429 7914 1311 407 1368 351 433 1271 1308 412 1311 416 430 1281 431 1278 434 1276 426 1281 1309 419 427 1283 430 7928 1307 410 1364 354 481 1221 1307 414 1309 418 428 1282 431 1280 433 1277 436 1272 1307 420 436 1274 428 7913 1312 406 1307 412 434 1269 1310 410 1313 414 432 1278 434 1275 427 1282 431 1277 1313 415 431 1279 433 7922 1313 405 1307 411 435 1268 1311 409 1304 423 433 1277 435 1274 428 1281 431 1276 1314 414 432 1278 434 7905 1310 409 1314 404 431 1271 1308 412 1311 417 429 1280 432 1277 436 1274 428 1279 1311 417 429 1280 432 7922 1313 432 1281 438 408 1267 1312 435 1288 440 406 1277 436 1273 429 1280 432 1275 1315 413 433 1278 434 7903 1311 409 1314 404 431 1269 1310 413 1310 418 428 1306 407 1276 437 1273 429 1278 1312 419 427 1306 407 7921 1315 406 1307 412 434 1292 1287 410 1313 415 431 1302 411 1298 404 1279 434 1274 1316 415 431 1302 411 7901 1314 407 1306 413 433 1294 1285 411 1312 417 429 1304 409 1300 402 1281 432 1275 1315 416 430 1303 410 7917 1308 412 1311 409 426 1274 1305 417 1306 422 434 1274 428 1280 432 1277 436 1297 1283 421 435 1273 429 7906 1309 411 1312 407 428 1274 1306 416 1307 422 434 1274 428 1280 433 1276 426 1281 1309 421 435 1273 429 7901 1313 407 1306 414 432 1270 1310 412 1311 418 428 1280 433 1276 426 1282 431 1276 1314 416 430 1278 435 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1310 411 1312 407 428 1300 1279 417 1306 419 1304 423 433 1302 410 1302 400 1282 1307 421 1302 425 431 7882 1312 409 1304 414 432 1296 1283 413 1310 415 1308 445 401 1308 404 1280 432 1276 1314 414 1309 418 428 7849 1314 406 1306 412 434 1293 1286 410 1302 422 1311 416 430 1304 409 1276 437 1272 1307 420 1303 423 433 7876 1307 413 1309 408 427 1300 1279 416 1307 418 1305 421 435 1299 403 1281 431 1277 1313 415 1308 418 428 7844 1308 411 1302 416 430 1297 1282 413 1310 415 1308 418 428 1305 407 1303 409 1271 1308 419 1304 422 434 7869 1304 416 1307 411 424 1302 1277 418 1305 419 1304 422 434 1299 403 1306 407 1275 1304 422 1301 425 431 7837 1305 414 1309 408 427 1299 1280 414 1309 415 1307 418 428 1305 408 1301 401 1280 1309 416 1307 419 427 7874 1309 410 1303 414 432 1294 1285 409 1303 446 1277 423 433 1299 403 1305 407 1273 1306 420 1303 423 433 7830 1312 407 1305 412 434 1292 1277 417 1306 418 1305 421 425 1307 406 1303 409 1271 1308 417 1305 420 426 7871 1312 407 1306 411 424 1275 1304 416 1307 417 1306 419 427 1280 432 1275 427 1279 1311 415 1308 417 429 7833 1309 410 1303 414 432 1268 1311 408 1305 419 1304 421 425 1282 430 1277 436 1296 1283 416 1307 419 427 7868 1305 414 1309 408 427 1272 1307 412 1310 413 1310 416 430 1277 425 1282 430 1301 1278 421 1302 424 432 7829 1303 415 1308 409 426 1274 1305 414 1308 415 1308 418 428 1279 433 1274 428 1278 1311 413 1310 416 430 7866 1307 411 1301 415 431 1270 1309 410 1303 421 1302 423 433 1275 427 1279 433 1273 1306 419 1304 422 434 7826 1306 413 1310 407 428 1272 1307 412 1311 413 1310 416 430 1277 425 1282 430 1275 1304 421 1302 424 432 7844 1308 410 1302 415 430 1269 1310 410 1302 421 1302 424 432 1274 428 1279 433 1299 1280 419 1304 422 434 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1306 440 1282 436 410 1269 1310 437 1286 442 404 1283 429 1282 430 1282 430 1283 429 1281 1308 419 427 7925 1309 436 1286 406 429 1275 1304 417 1306 447 409 1277 435 1276 436 1276 426 1286 426 1284 1305 448 408 7898 1305 440 1283 435 411 1268 1311 435 1277 450 406 1279 433 1278 434 1277 435 1276 436 1273 1306 448 408 7914 1309 435 1277 440 406 1272 1307 440 1283 444 402 1283 429 1282 430 1281 431 1280 432 1277 1312 442 404 7898 1305 440 1283 436 410 1267 1312 435 1288 440 406 1278 434 1277 435 1276 436 1274 428 1282 1307 446 410 7910 1313 431 1281 437 409 1268 1311 436 1287 440 406 1278 434 1277 435 1275 427 1284 428 1281 1308 445 401 7899 1304 441 1282 436 410 1267 1312 435 1288 439 407 1278 434 1276 436 1275 427 1283 429 1280 1309 444 401 7914 1309 436 1287 431 404 1272 1307 439 1283 443 403 1281 431 1279 433 1277 435 1275 427 1281 1308 445 401 7898 1305 439 1284 434 401 1275 1304 442 1280 446 410 1273 429 1281 431 1279 433 1278 434 1273 1306 448 408 7905 1308 437 1286 432 403 1273 1306 440 1283 444 402 1281 431 1279 433 1276 436 1274 428 1280 1309 444 401 7894 1309 435 1288 430 405 1271 1308 438 1285 442 404 1278 434 1275 437 1273 429 1280 432 1276 1313 440 406 7905 1308 437 1286 431 404 1272 1307 439 1284 442 403 1279 433 1276 436 1273 429 1280 432 1275 1314 439 407 7885 1307 437 1286 431 404 1271 1308 438 1285 442 404 1278 434 1274 428 1282 430 1279 433 1274 1305 448 408 7901 1312 432 1280 436 410 1266 1313 432 1280 446 410 1272 430 1278 434 1275 427 1282 430 1276 1314 440 406 7906 1307 436 1286 431 404 1270 1309 437 1286 440 406 1276 436 1273 429 1279 433 1276 426 1280 1309 444 402 7882 1311 434 1278 438 408 1267 1312 434 1278 447 409 1273 429 1279 433 1275 427 1281 431 1276 1313 439 407 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1316 405 1307 412 434 1270 1309 413 1310 416 1307 421 435 1276 436 1276 436 1275 427 1283 1307 421 1312 7037 1310 411 1312 407 428 1274 1305 418 1305 420 1303 425 431 1278 434 1277 435 1276 436 1274 1305 423 1310 7006 1310 411 1312 406 429 1274 1305 416 1306 419 1304 423 433 1303 409 1275 427 1284 428 1281 1308 420 1303 7043 1314 407 1305 412 434 1295 1284 412 1310 414 1309 419 427 1308 404 1280 432 1279 433 1275 1314 413 1310 7003 1313 407 1305 413 433 1294 1285 411 1301 424 1309 418 428 1306 406 1304 408 1276 436 1273 1306 421 1302 7041 1306 414 1309 410 425 1301 1278 418 1305 420 1303 424 432 1302 400 1310 402 1282 430 1277 1312 415 1307 7003 1313 407 1305 413 433 1294 1285 410 1302 423 1310 416 430 1304 408 1302 400 1284 428 1279 1310 417 1306 7033 1314 406 1307 412 434 1292 1287 408 1304 420 1303 424 432 1301 401 1308 404 1279 433 1274 1305 422 1311 6995 1311 410 1302 415 431 1295 1284 411 1301 423 1310 416 430 1303 409 1299 403 1280 432 1275 1304 422 1301 7034 1313 406 1307 411 424 1301 1278 417 1305 419 1303 423 433 1299 403 1305 407 1275 427 1281 1308 418 1304 6997 1309 411 1301 416 430 1295 1284 411 1301 422 1301 425 431 1301 401 1307 405 1277 435 1271 1308 418 1305 7028 1308 411 1301 415 431 1294 1285 410 1302 422 1301 425 431 1300 402 1306 406 1276 426 1280 1309 416 1307 6993 1312 407 1305 412 434 1291 1278 416 1307 417 1306 420 426 1306 406 1301 401 1281 431 1275 1304 422 1301 7029 1308 411 1301 415 431 1268 1311 409 1303 420 1303 423 433 1273 429 1278 434 1274 428 1277 1312 414 1309 6989 1306 412 1310 406 429 1270 1309 411 1301 422 1301 424 432 1274 428 1279 433 1275 427 1278 1311 414 1309 7019 1307 411 1301 415 431 1268 1311 408 1304 419 1304 421 435 1271 431 1276 426 1282 430 1275 1304 421 1302 6994 1312 406 1306 410 425 1274 1305 414 1309 414 1339 386 429 1277 425 1281 431 1276 426 1305 1284 414 1309 7018 1308 409 1303 413 433 1267 1302 417 1337 386 1337 388 458 1248 433 1273 429 1278 434 1271 1308 416 1338 6956 1308 410 1333 382 464 1236 1333 386 1337 386 1337 388 458 1248 454 1252 429 1277 435 1270 1340 384 1338 6949 1336 382 1330 386 460 1239 1330 388 1335 388 1335 391 455 1250 462 1244 458 1249 463 1241 1338 386 1336 +# +# file: Flipper-IRDB/Fans\SHE\SHE_Fan_SHE40ST1801F.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1289 402 1282 405 442 1268 1263 400 1284 403 433 1276 418 1242 442 1245 439 1248 446 1240 444 1243 1288 7090 1288 402 1282 405 442 1268 1263 400 1284 402 434 1276 418 1241 443 1244 440 1247 447 1240 444 1243 1288 7090 1288 402 1282 405 442 1269 1262 400 1284 402 445 1267 417 1243 441 1246 438 1249 445 1242 442 1245 1286 7092 1286 403 1291 395 441 1244 1287 402 1282 404 443 1242 442 1245 439 1249 445 1242 442 1245 439 1248 1293 7086 1292 398 1286 401 435 1248 1283 407 1287 399 437 1247 437 1250 444 1243 441 1246 438 1249 445 1242 1289 7090 1288 402 1282 405 442 1269 1262 401 1283 403 444 1268 416 1244 440 1247 437 1250 444 1243 441 1247 1284 7096 1293 397 1287 401 435 1275 1256 407 1287 400 436 1274 410 1250 444 1243 441 1247 437 1250 444 1243 1288 7092 1286 404 1280 408 439 1272 1259 403 1281 406 441 1270 414 1246 438 1250 444 1243 441 1246 438 1250 1291 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1291 399 1285 404 443 1243 1288 401 1283 404 443 1243 441 1245 439 1249 1282 407 440 1246 438 1249 445 7935 1291 401 1283 404 443 1268 1263 400 1284 403 444 1268 416 1245 439 1248 1283 408 439 1272 412 1249 445 7935 1291 400 1284 403 444 1268 1263 400 1284 403 433 1277 417 1244 440 1274 1257 407 440 1272 412 1248 446 7935 1290 401 1283 404 443 1242 1289 400 1284 404 443 1242 442 1245 439 1275 1256 407 440 1246 438 1249 445 7936 1290 400 1284 404 443 1243 1288 400 1284 404 443 1243 441 1245 439 1248 1283 407 440 1246 438 1249 445 7935 1290 401 1283 404 443 1268 1263 401 1283 404 443 1268 416 1245 439 1248 1283 408 439 1273 411 1250 444 7937 1288 403 1281 406 441 1271 1260 403 1281 406 441 1270 414 1247 447 1241 1290 400 436 1275 419 1241 443 7940 1286 405 1289 398 438 1273 1258 404 1280 408 439 1272 412 1249 445 1242 1289 402 435 1276 418 1242 442 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1293 395 1289 398 438 1248 1293 395 1289 398 438 1248 446 1241 443 1245 439 1249 1292 396 440 1245 439 7942 1294 395 1289 398 438 1247 1284 404 1290 397 439 1246 438 1250 444 1243 440 1247 1284 405 442 1244 440 7940 1285 404 1290 396 440 1246 1285 403 1291 396 440 1245 438 1249 445 1242 442 1245 1286 403 444 1242 442 7939 1286 402 1292 395 441 1245 1286 402 1292 394 442 1244 440 1248 446 1241 443 1245 1286 402 445 1242 442 7941 1284 404 1290 397 439 1248 1293 395 1289 398 438 1248 446 1242 442 1246 438 1250 1291 396 440 1247 447 7934 1291 398 1286 401 446 1241 1290 399 1285 402 445 1242 442 1246 438 1250 444 1244 1287 401 446 1241 443 7940 1285 403 1291 396 440 1247 1284 404 1290 397 439 1247 437 1251 443 1245 439 1249 1292 396 440 1246 438 7945 1291 398 1286 401 446 1240 1291 398 1286 401 446 1240 444 1244 439 1248 446 1242 1289 399 437 1249 445 +# +# file: Flipper-IRDB/Fans\Silver_Crest\SilverCrest_Fan.ir +# +name: POWER +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 46 00 00 00 +# +name: SPEED+ +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 44 00 00 00 +# +name: ROTATE +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 43 00 00 00 +# +name: TIMER +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 16 00 00 00 +# +name: MODE +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 0D 00 00 00 +# +# file: Flipper-IRDB/Fans\Taurus\Taurus_Babel_RC.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1308 408 1311 402 442 1250 1314 412 1307 405 449 1242 446 1250 449 1246 453 1243 445 1250 449 1248 1316 7148 1306 411 1308 405 449 1242 1311 415 1304 408 446 1246 453 1244 444 1251 448 1247 451 1244 444 1252 1312 7154 1309 406 1303 410 444 1247 1306 420 1309 404 450 1241 447 1249 450 1247 451 1244 444 1252 447 1249 1315 7150 1314 403 1306 407 447 1245 1308 417 1302 412 442 1250 449 1248 450 1246 442 1254 444 1251 448 1249 1304 7160 1314 429 1280 433 421 1248 1305 445 1284 429 415 1252 447 1250 449 1247 441 1254 445 1252 447 1250 1303 7164 1310 404 1305 410 444 1251 1302 420 1309 404 440 1257 441 1255 443 1252 447 1250 449 1248 440 1256 1307 7159 1304 409 1310 403 441 1254 1309 413 1306 407 447 1248 440 1255 443 1252 446 1249 450 1246 442 1253 1362 7102 1310 404 1305 409 445 1251 1302 420 1310 403 441 1254 444 1251 447 1248 440 1255 443 1253 446 1250 1303 7163 1311 403 1306 408 446 1249 1304 418 1301 412 442 1253 446 1250 449 1248 440 1256 442 1254 445 1251 1302 7162 1302 413 1306 407 447 1248 1305 417 1302 412 442 1254 445 1251 448 1248 440 1256 442 1253 446 1249 1304 7155 1308 405 1304 409 445 1251 1302 420 1309 404 440 1255 443 1253 445 1250 448 1248 440 1255 495 1202 1310 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1317 406 1313 409 445 1250 1324 410 1319 403 451 1243 445 1252 447 1250 500 1196 1316 408 446 1248 451 7997 1311 408 1311 407 447 1245 1319 411 1308 408 446 1248 450 1247 452 1246 453 1244 1309 411 443 1251 448 8000 1308 411 1308 408 446 1247 1317 412 1307 410 444 1248 451 1246 442 1253 446 1251 1313 407 447 1246 452 7995 1313 406 1313 404 450 1244 1320 410 1309 409 445 1248 451 1245 454 1243 445 1251 1313 434 420 1245 453 7992 1317 430 1279 437 417 1251 1313 442 1277 439 415 1252 447 1250 449 1248 451 1247 1317 411 454 1241 447 8003 1315 402 1307 407 447 1244 1309 417 1302 411 443 1249 450 1246 442 1253 446 1251 1313 406 448 1272 416 8004 1315 404 1305 410 444 1277 1286 413 1306 408 446 1274 425 1272 416 1253 446 1278 1286 408 446 1274 425 7994 1314 406 1313 406 448 1273 1291 415 1314 406 448 1274 425 1273 415 1253 446 1252 1312 411 443 1278 421 7997 1312 410 1309 409 445 1275 1289 413 1306 412 442 1279 420 1277 422 1275 424 1273 1280 414 440 1253 446 7999 1309 411 1308 409 445 1250 1303 422 1308 409 445 1250 449 1247 441 1255 444 1252 1312 407 447 1248 440 8004 1315 404 1305 412 442 1253 1311 414 1305 410 444 1250 449 1246 442 1253 446 1250 1314 404 440 1257 442 8001 1307 411 1308 408 446 1248 1305 421 1308 407 447 1247 441 1254 445 1252 447 1250 1314 404 440 1257 442 8005 1314 404 1305 413 441 1254 1310 416 1303 413 441 1254 445 1251 448 1248 440 1257 1307 410 444 1252 447 7998 1310 407 1312 405 439 1255 1309 416 1303 411 443 1251 448 1248 440 1254 445 1250 1303 411 443 1251 448 7994 1304 414 1305 411 443 1251 1302 422 1308 408 446 1248 440 1254 445 1251 448 1248 1305 411 443 1253 446 7997 1312 406 1303 413 441 1253 1311 413 1306 408 446 1248 440 1255 444 1253 446 1251 1313 404 440 1256 443 8002 1307 411 1308 408 446 1248 1305 419 1300 414 440 1254 445 1250 449 1247 441 1255 1309 409 445 1249 450 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1313 405 1314 405 449 1250 1313 420 1320 406 448 1252 447 1253 446 1254 445 1255 443 1255 1319 404 450 8002 1316 406 1313 409 445 1253 1311 422 1318 407 499 1202 445 1253 446 1253 445 1254 445 1254 1320 404 450 7999 1309 408 1311 406 448 1248 1305 421 1308 411 443 1253 446 1251 447 1249 449 1248 440 1257 1306 409 445 8000 1308 408 1311 405 449 1247 1306 418 1311 405 449 1248 440 1256 443 1253 446 1251 448 1250 1313 404 450 7996 1312 436 1283 407 447 1250 1313 414 1315 405 449 1250 448 1249 449 1248 450 1246 442 1255 1319 402 452 7991 1307 439 1280 412 442 1255 1308 420 1309 411 443 1255 444 1254 445 1253 446 1253 446 1253 1321 406 448 7998 1320 406 1323 403 451 1249 1314 421 1319 408 446 1254 444 1255 443 1255 443 1256 442 1256 1318 408 446 8004 1314 412 1317 409 445 1255 1318 417 1323 404 450 1250 448 1251 447 1252 447 1253 445 1255 1319 407 447 8003 1315 410 1319 407 447 1252 1322 414 1315 410 444 1256 453 1247 451 1248 450 1247 441 1256 1307 438 416 8002 1316 431 1288 429 415 1252 1311 444 1285 431 423 1241 447 1249 449 1247 451 1248 450 1246 1317 402 442 8002 1316 403 1306 411 443 1251 1312 416 1313 404 450 1244 444 1252 447 1251 447 1249 449 1247 1316 402 442 8002 1316 403 1306 410 444 1250 1313 414 1305 410 444 1249 450 1246 452 1244 444 1253 446 1252 1311 407 447 +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1313 405 1314 405 449 1250 1313 420 1320 406 448 1252 447 1253 446 1254 445 1255 443 1255 1319 404 450 8002 1316 406 1313 409 445 1253 1311 422 1318 407 499 1202 445 1253 446 1253 445 1254 445 1254 1320 404 450 7999 1309 408 1311 406 448 1248 1305 421 1308 411 443 1253 446 1251 447 1249 449 1248 440 1257 1306 409 445 8000 1308 408 1311 405 449 1247 1306 418 1311 405 449 1248 440 1256 443 1253 446 1251 448 1250 1313 404 450 7996 1312 436 1283 407 447 1250 1313 414 1315 405 449 1250 448 1249 449 1248 450 1246 442 1255 1319 402 452 7991 1307 439 1280 412 442 1255 1308 420 1309 411 443 1255 444 1254 445 1253 446 1253 446 1253 1321 406 448 7998 1320 406 1323 403 451 1249 1314 421 1319 408 446 1254 444 1255 443 1255 443 1256 442 1256 1318 408 446 8004 1314 412 1317 409 445 1255 1318 417 1323 404 450 1250 448 1251 447 1252 447 1253 445 1255 1319 407 447 8003 1315 410 1319 407 447 1252 1322 414 1315 410 444 1256 453 1247 451 1248 450 1247 441 1256 1307 438 416 8002 1316 431 1288 429 415 1252 1311 444 1285 431 423 1241 447 1249 449 1247 451 1248 450 1246 1317 402 442 8002 1316 403 1306 411 443 1251 1312 416 1313 404 450 1244 444 1252 447 1251 447 1249 449 1247 1316 402 442 8002 1316 403 1306 410 444 1250 1313 414 1305 410 444 1249 450 1246 452 1244 444 1253 446 1252 1311 407 447 +# +# file: Flipper-IRDB/Fans\Thomson\Thomson_Fan_THEVL484K.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1292 433 1265 432 406 1261 1286 438 1260 436 413 1255 443 1253 444 1252 435 1260 438 1259 439 1257 1290 7192 1288 436 1262 434 415 1279 1257 440 1258 438 411 1284 414 1256 442 1254 444 1253 445 1252 435 1261 1286 7196 1284 440 1258 438 411 1257 1290 434 1264 432 417 1252 435 1260 438 1259 439 1257 441 1255 443 1253 1283 7198 1292 431 1256 440 409 1259 1288 436 1262 434 415 1253 434 1261 437 1259 439 1257 441 1255 443 1253 1283 7198 1292 431 1256 439 410 1258 1289 435 1263 433 416 1252 435 1261 437 1258 440 1256 442 1254 444 1252 1284 7198 1292 405 1282 440 409 1258 1289 435 1263 433 416 1252 435 1260 438 1258 440 1256 442 1254 444 1252 1284 7196 1284 440 1258 438 411 1257 1290 433 1265 431 407 1260 438 1284 414 1256 442 1254 444 1252 435 1260 1287 7195 1285 438 1260 436 413 1255 1292 405 1282 440 409 1259 439 1257 441 1255 443 1254 444 1252 435 1260 1287 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1287 410 1288 435 414 1281 1255 414 1284 439 410 1259 439 1283 415 1254 444 1252 435 1261 1286 437 412 8042 1287 410 1288 434 415 1255 1281 440 1258 438 411 1258 440 1255 443 1253 434 1261 437 1259 1288 408 441 8039 1290 406 1292 431 407 1262 1285 411 1287 435 414 1256 442 1253 445 1251 436 1260 438 1258 1289 434 415 8039 1290 406 1281 441 408 1287 1260 409 1289 434 415 1254 433 1261 437 1259 439 1283 415 1255 1292 405 433 8046 1283 413 1285 438 411 1285 1262 434 1264 431 407 1288 410 1259 439 1257 441 441 1253 1283 413 436 8044 1285 412 1286 436 413 1257 1290 405 1282 440 409 1287 411 1284 414 1281 417 1253 434 1261 1286 437 412 8042 1287 436 1262 434 415 1281 1256 440 1258 411 438 1258 440 1255 443 1253 434 1261 437 1258 1289 434 415 8039 1290 406 1281 440 409 1287 1260 409 1289 433 416 1253 434 1261 437 1259 439 1256 442 1254 1293 404 434 8046 1283 413 1285 411 438 1257 1290 406 1281 414 435 1287 411 1257 441 1255 443 1253 434 1261 1286 438 411 8042 1287 409 1289 433 416 1280 1257 439 1259 436 413 1256 442 1253 445 1251 436 1286 412 1283 1264 433 416 8037 1292 404 1283 412 437 1285 1262 408 1290 432 417 1278 409 1259 439 1257 441 1255 443 1253 1283 439 410 8043 1285 437 1261 435 414 1281 1255 440 1258 438 411 1283 415 1254 444 1252 435 1260 438 1258 1289 434 414 8038 1291 432 1255 440 409 1286 1261 435 1263 433 416 1251 436 1259 439 1257 441 1255 443 1253 1283 440 409 8044 1284 411 1287 436 413 1254 1293 431 1256 439 410 1257 441 1281 417 1253 434 1261 437 1259 1288 435 413 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1288 437 1260 435 414 1254 1292 431 1256 440 409 1259 438 1258 1288 435 413 1255 442 1253 444 1252 435 8046 1292 431 1256 440 409 1259 1288 436 1261 434 414 1254 443 1253 1283 440 409 1259 438 1258 439 1256 441 8040 1287 436 1261 434 414 1254 1292 431 1256 439 409 1258 491 1204 1291 433 415 1253 434 1261 436 1260 438 8044 1284 440 1257 438 410 1257 1290 434 1263 432 417 1251 436 1259 1287 436 412 1255 442 1254 443 1252 435 8045 1293 431 1256 439 410 1258 1289 435 1262 433 416 1253 434 1261 1285 439 410 1258 440 1256 442 1255 442 8038 1290 433 1264 431 407 1260 1287 437 1261 435 413 1254 443 1253 1283 440 408 1259 439 1257 440 1255 442 8038 1289 434 1263 432 417 1251 1285 438 1260 436 413 1255 442 1253 1283 441 408 1260 438 1258 440 1256 442 +# +# file: Flipper-IRDB/Fans\Vornado\Vornado.ir +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1289 408 1289 434 414 1245 1291 433 1264 432 416 1270 417 1243 444 1243 444 1243 444 1244 443 1244 1292 7134 1291 405 1292 431 417 1242 1294 429 1268 427 411 1248 439 1248 439 1274 413 1247 440 1247 440 1247 1289 8241 1295 400 1287 436 412 1247 1289 434 1263 432 416 1242 445 1242 445 1242 445 1241 446 1241 435 1251 1295 7130 1295 400 1287 436 412 1246 1290 406 1291 431 417 1268 419 1241 446 1241 435 1251 436 1277 410 1250 1286 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1369 328 1296 427 411 1275 1261 436 1261 434 414 1245 442 1245 442 1244 443 1244 443 1244 1291 431 417 7972 1291 404 1293 429 409 1251 1295 400 1287 436 412 1273 414 1246 441 1245 442 1245 442 1245 1290 405 443 9076 1287 408 1289 433 415 1271 1264 430 1267 428 410 1276 411 1249 438 1248 439 1248 439 1274 1261 434 414 7974 1289 406 1291 431 417 1242 1294 428 1259 436 412 1273 414 1273 414 1245 442 1245 442 1244 1292 430 418 +# +# file: Flipper-IRDB/Fans\Xpelair\Xpelair_XPA360CF_Fan.ir +# +name: POWER +type: parsed +protocol: NECext +address: 00 FC 00 00 +command: 80 7F 00 00 +# +name: SPEED+ +type: parsed +protocol: NECext +address: 00 FC 00 00 +command: 85 7A 00 00 +# +name: MODE +type: parsed +protocol: NECext +address: 00 FC 00 00 +command: 81 7E 00 00 +# +name: TIMER +type: parsed +protocol: NECext +address: 00 FC 00 00 +command: 86 79 00 00 diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir index fb7f2123e2..c672a02310 100755 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -7,9 +7,9 @@ Version: 1 # Compiled by Hyper_Mash # Support/testing/additions from UberGuidoZ # Thank you to ChaoticDynamic aka c-nagy for cleanup -############################################################ +# # Also a HUGE thank you to Amec0e for continued maintenance! -############################################################ +# # # Updated on 25th August 2022 # @@ -2326,7 +2326,8 @@ type: parsed protocol: NEC address: 04 00 00 00 command: 1A 00 00 00 -######################START OF NEW IR's###################### +# +# New IRs # # BAIRD # From 293d5f722d12801e1f0d990016daca1788e387c5 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 26 Aug 2022 20:15:15 +0300 Subject: [PATCH 45/78] update changelog & docs --- CHANGELOG.md | 8 ++++---- documentation/HowToInstall.md | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 872bf8654c..980949e700 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,18 +1,18 @@ ### New changes * UniRF (Sub-GHz Remote) - All protocols support, long button press support (by @darmiel & @xMasterX) (PR #47) +* Universal remote for Fans, new buttons for universal AC remote, icons by @Svaarich * Frequency Analyzer feedback modes (by @darmiel) (PR #49) * RFID EM4100 Fuzzer plugin (by @Ganapati & some fixes by @xMasterX) (PR #48) * Updated universal remote assets (by @Amec0e) -* New UniRF Animated icon (by @Svaarich) +* New UniRF Animated icon & New Spectrum Analyzer icon (by @Svaarich) * Fixed Keeloq seed display +* OFW: nfc: Change furi_assert to furi_crash for default switch cases * OFW: SubGhz: fix CAME, Chamberlain protocol * OFW: LFRFID RC fixes **Note: Prefer installing using web updater or by self update package, all needed assets will be installed** -**Build naming has been changed - all same as before but `cg - codegrabber` changed to `un - unleashed`** - -Self-update package (update from microSD) - `flipper-z-f7-update-(version).zip` +Self-update package (update from microSD) - `flipper-z-f7-update-(version).zip` or `.tgz` for iOS mobile app DFU for update using qFlipper - `flipper-z-f7-full-(version).dfu` diff --git a/documentation/HowToInstall.md b/documentation/HowToInstall.md index 956b8ef65f..18021418b4 100644 --- a/documentation/HowToInstall.md +++ b/documentation/HowToInstall.md @@ -13,7 +13,7 @@ ## With Web Updater -- Be sure you updated to latest official release before, and verify that microSD card is installed +- Be sure you updated to latest official release before(if installing for the first time), and verify that microSD card is installed - Open latest release page - [Releases](https://github.com/Eng1n33r/flipperzero-firmware/releases/latest) - Connect your device and select `Install via Web Updater` after that on web updater page - press `Connect` button @@ -25,6 +25,20 @@ 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 +- Open latest release page - [Releases](https://github.com/Eng1n33r/flipperzero-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 +- In flipper app click green `Update` button, be sure it shows `Custom flipper-z-f7-update...` in Update Channel +- Wait until update is finished +- And if all flashed successfully - you will have all needed assets pre installed +- Done + +
+
+ ## With offline update on flipper ### **Replace (CURRENT VERSION) with version that you downloaded from releases** @@ -76,4 +90,4 @@ then select **`flipper-z-f7-full-(CURRENT VERSION).dfu`** - ## [Read instructions how to use plugins and more](https://github.com/Eng1n33r/flipperzero-firmware#instructions) -- ## [How To: Configure UniversalRF Remix App](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/UniRFRemix.md) +- ## [How To: Configure Sub-GHz Remote App](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/SubGHzRemotePlugin.md) From 9bd6d956ca3ade77ad5738c542fd3c9c5c9494dc Mon Sep 17 00:00:00 2001 From: Daniel <71837281+darmiel@users.noreply.github.com> Date: Sat, 27 Aug 2022 00:44:12 +0200 Subject: [PATCH 46/78] fix[infrared]: select first button on remote change --- applications/gui/modules/button_panel.c | 9 +++++++++ applications/gui/modules/button_panel.h | 6 ++++++ .../scenes/common/infrared_scene_universal_common.c | 1 + 3 files changed, 16 insertions(+) diff --git a/applications/gui/modules/button_panel.c b/applications/gui/modules/button_panel.c index e3ae59a367..ff52ebd8c9 100644 --- a/applications/gui/modules/button_panel.c +++ b/applications/gui/modules/button_panel.c @@ -83,6 +83,15 @@ ButtonPanel* button_panel_alloc() { return button_panel; } +void button_panel_reset_selection(ButtonPanel* button_panel) { + with_view_model( + button_panel->view, (ButtonPanelModel * model) { + model->selected_item_x = 0; + model->selected_item_y = 0; + return true; + }); +} + void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t reserve_y) { furi_check(reserve_x > 0); furi_check(reserve_y > 0); diff --git a/applications/gui/modules/button_panel.h b/applications/gui/modules/button_panel.h index 0c17e3a7c6..9c944ca463 100644 --- a/applications/gui/modules/button_panel.h +++ b/applications/gui/modules/button_panel.h @@ -35,6 +35,12 @@ void button_panel_free(ButtonPanel* button_panel); */ void button_panel_reset(ButtonPanel* button_panel); +/** Resets selected_item_x and selected_item_y. + * + * @param button_panel ButtonPanel instance + */ +void button_panel_reset_selection(ButtonPanel* button_panel); + /** Reserve space for adding items. * * One does not simply use button_panel_add_item() without this function. It diff --git a/applications/infrared/scenes/common/infrared_scene_universal_common.c b/applications/infrared/scenes/common/infrared_scene_universal_common.c index 57ac81168e..9f1eabd24c 100644 --- a/applications/infrared/scenes/common/infrared_scene_universal_common.c +++ b/applications/infrared/scenes/common/infrared_scene_universal_common.c @@ -33,6 +33,7 @@ static void infrared_scene_universal_common_hide_popup(Infrared* infrared) { void infrared_scene_universal_common_on_enter(void* context) { Infrared* infrared = context; + button_panel_reset_selection(infrared->button_panel); view_stack_add_view(infrared->view_stack, button_panel_get_view(infrared->button_panel)); } From 885bb0c730dcbdfd90439e154b86336712e76862 Mon Sep 17 00:00:00 2001 From: Daniel <71837281+darmiel@users.noreply.github.com> Date: Sat, 27 Aug 2022 01:39:06 +0200 Subject: [PATCH 47/78] fix[infrared]: clear records on remote switch --- applications/infrared/infrared_brute_force.c | 4 ++++ applications/infrared/infrared_brute_force.h | 1 + .../infrared/scenes/common/infrared_scene_universal_common.c | 1 + 3 files changed, 6 insertions(+) diff --git a/applications/infrared/infrared_brute_force.c b/applications/infrared/infrared_brute_force.c index 8dbc230127..89272de7e7 100644 --- a/applications/infrared/infrared_brute_force.c +++ b/applications/infrared/infrared_brute_force.c @@ -35,6 +35,10 @@ InfraredBruteForce* infrared_brute_force_alloc() { return brute_force; } +void infrared_brute_force_clear_records(InfraredBruteForce* brute_force) { + InfraredBruteForceRecordDict_reset(brute_force->records); +} + void infrared_brute_force_free(InfraredBruteForce* brute_force) { furi_assert(!brute_force->ff); InfraredBruteForceRecordDict_clear(brute_force->records); diff --git a/applications/infrared/infrared_brute_force.h b/applications/infrared/infrared_brute_force.h index acf0d7b6e1..fff472e792 100644 --- a/applications/infrared/infrared_brute_force.h +++ b/applications/infrared/infrared_brute_force.h @@ -16,6 +16,7 @@ bool infrared_brute_force_start( bool infrared_brute_force_is_started(InfraredBruteForce* brute_force); void infrared_brute_force_stop(InfraredBruteForce* brute_force); bool infrared_brute_force_send_next(InfraredBruteForce* brute_force); +void infrared_brute_force_clear_records(InfraredBruteForce* brute_force); void infrared_brute_force_add_record( InfraredBruteForce* brute_force, uint32_t index, diff --git a/applications/infrared/scenes/common/infrared_scene_universal_common.c b/applications/infrared/scenes/common/infrared_scene_universal_common.c index 9f1eabd24c..1072549ffe 100644 --- a/applications/infrared/scenes/common/infrared_scene_universal_common.c +++ b/applications/infrared/scenes/common/infrared_scene_universal_common.c @@ -33,6 +33,7 @@ static void infrared_scene_universal_common_hide_popup(Infrared* infrared) { void infrared_scene_universal_common_on_enter(void* context) { Infrared* infrared = context; + infrared_brute_force_clear_records(infrared->brute_force); button_panel_reset_selection(infrared->button_panel); view_stack_add_view(infrared->view_stack, button_panel_get_view(infrared->button_panel)); } From ab5bcd71f53b09571ad71ebad8055cd3af2c2ec8 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 27 Aug 2022 03:15:59 +0300 Subject: [PATCH 48/78] update assets and changelog --- CHANGELOG.md | 1 + assets/resources/Manifest | 12 +- assets/resources/infrared/assets/ac.ir | 189 ++++-------------- assets/resources/infrared/assets/audio.ir | 110 +--------- assets/resources/infrared/assets/fans.ir | 130 +----------- .../resources/infrared/assets/projectors.ir | 132 +++++------- assets/resources/infrared/assets/tv.ir | 76 +------ 7 files changed, 118 insertions(+), 532 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 980949e700..822e6466ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ### New changes * UniRF (Sub-GHz Remote) - All protocols support, long button press support (by @darmiel & @xMasterX) (PR #47) * Universal remote for Fans, new buttons for universal AC remote, icons by @Svaarich +* Bugfix for universal remotes (by @darmiel) (PR #50) * Frequency Analyzer feedback modes (by @darmiel) (PR #49) * RFID EM4100 Fuzzer plugin (by @Ganapati & some fixes by @xMasterX) (PR #48) * Updated universal remote assets (by @Amec0e) diff --git a/assets/resources/Manifest b/assets/resources/Manifest index 186624c83d..3533f7a8d0 100644 --- a/assets/resources/Manifest +++ b/assets/resources/Manifest @@ -1,5 +1,5 @@ V:0 -T:1661527982 +T:1661559205 D:badusb D:dolphin D:infrared @@ -241,11 +241,11 @@ F:33b8fde22f34ef556b64b77164bc19b0:578:dolphin/L3_Lab_research_128x54/frame_8.bm F:f267f0654781049ca323b11bb4375519:581:dolphin/L3_Lab_research_128x54/frame_9.bm F:41106c0cbc5144f151b2b2d3daaa0527:727:dolphin/L3_Lab_research_128x54/meta.txt D:infrared/assets -F:379d21e5faf46466e6cad85eddb074a3:108241:infrared/assets/ac.ir -F:5bdb39269623772d93c2dd6f5e946bd5:48419:infrared/assets/audio.ir -F:9ce3babecb5fab4cca66422c5542bb38:81486:infrared/assets/fans.ir -F:63ca357ca0b85a6ad900539e7b6a0fed:5086:infrared/assets/projectors.ir -F:fa586695d245aecdd0b3669e75defdcf:127999:infrared/assets/tv.ir +F:dad1530d4887052c0ec7e6319cdf50dd:112920:infrared/assets/ac.ir +F:58345d120303340413a70215099dca1e:47410:infrared/assets/audio.ir +F:7c72029cf4f8e4d8a38dbfb54eec7854:78119:infrared/assets/fans.ir +F:88ac3e7ae8be5a0df84c1d7f81989cae:4170:infrared/assets/projectors.ir +F:77bc8314d113b8618942589f21a491fc:127350:infrared/assets/tv.ir F:a157a80f5a668700403d870c23b9567d:470:music_player/Marble_Machine.fmf D:nfc/assets F:81dc04c7b181f94b644079a71476dff4:4742:nfc/assets/aid.nfc diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index 1c1e7b8e13..2e811ba754 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -1,13 +1,24 @@ Filetype: IR signals file Version: 1 +# Last Updated 27th Aug, 2022 # -# Universal AC IR codes - Brute force updated by jaroslavmraz -# Fixes and tweaks provided by MX (MasterX) -# Updates and Maintenance by amec0e +name: TEMP+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 447 442 417 417 442 446 413 449 421 414 445 25361 3456 1743 422 1275 444 418 441 447 412 449 421 1303 416 445 414 448 411 450 420 415 444 1306 413 449 421 1302 417 1307 412 422 448 1276 443 1281 438 1285 444 1306 413 1311 418 416 443 418 441 1310 419 442 417 417 442 419 440 421 449 440 419 443 416 445 414 420 439 422 448 441 418 1305 414 421 438 1312 418 444 415 446 413 448 422 1302 417 1280 439 422 448 441 418 416 443 446 413 421 438 450 420 442 417 444 415 419 440 449 421 441 418 416 443 445 414 447 412 450 420 415 444 1306 413 1310 419 1304 415 447 412 1311 418 444 415 1308 421 1302 417 34793 3458 1713 441 1310 419 415 444 417 442 447 412 1311 418 443 416 445 414 448 411 423 447 1304 415 446 413 1311 418 1305 414 421 438 1312 417 1279 440 1310 419 1305 414 1282 447 441 418 417 442 1308 422 440 419 442 417 444 415 447 412 449 421 441 418 443 416 445 414 447 412 423 447 415 444 1306 413 448 422 440 419 442 417 418 441 1309 421 441 418 443 416 445 414 448 411 450 420 415 444 444 415 419 440 448 422 440 419 443 416 445 414 447 412 449 421 441 418 443 416 445 414 421 438 450 420 1277 442 446 413 1310 419 416 443 1307 412 422 448 34789 3464 1735 419 1277 442 447 412 449 421 414 445 1278 441 448 411 450 420 442 417 444 415 1308 421 414 445 1305 414 1309 420 415 444 1306 413 1283 446 1304 415 1309 421 1303 416 446 413 421 438 1312 417 417 442 447 412 449 421 414 445 443 416 445 414 448 411 450 420 442 417 444 415 446 413 422 448 440 419 443 416 445 414 447 412 449 421 414 445 1305 414 421 438 450 420 1277 442 1309 420 1303 416 418 441 420 439 450 420 1304 415 446 413 1310 419 442 417 1307 412 449 421 414 445 444 415 419 440 448 411 450 420 442 417 444 415 447 412 449 421 1303 416 1280 439 1312 417 1306 413 1310 419 1305 414 1309 420 441 418 444 415 446 413 448 422 440 419 442 417 445 414 447 412 449 421 441 418 416 443 446 413 448 411 450 420 442 417 444 415 446 413 449 421 1303 416 1307 412 450 420 415 444 444 415 419 440 449 421 440 419 443 416 445 414 447 412 449 421 1303 416 1308 421 440 419 415 444 445 414 447 412 449 421 441 418 443 416 446 413 448 411 450 420 442 417 444 415 447 412 449 421 441 418 443 416 445 414 448 411 450 420 442 417 444 415 446 413 449 421 1302 417 1307 412 449 421 441 418 444 415 446 413 448 422 413 446 443 416 445 414 447 412 449 421 441 418 443 416 446 413 448 411 450 420 442 417 444 415 1309 420 441 418 1305 414 1309 420 442 417 417 442 446 413 # -# BETA version - Aug 26, 2022 +name: TEMP- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 439 422 448 441 418 443 416 419 440 421 438 25369 3459 1739 415 1281 449 413 446 443 416 445 414 1309 421 441 418 443 416 419 440 448 411 1312 418 417 442 1308 421 1302 417 418 441 1309 421 1303 416 1307 412 1312 418 1306 413 421 449 440 419 1277 442 447 412 449 421 441 418 443 416 445 414 447 412 450 420 441 418 444 415 446 413 1283 447 415 444 1306 413 449 421 414 445 443 416 1307 412 1312 417 417 442 419 440 421 438 450 420 442 417 444 415 446 413 449 421 440 419 443 416 445 414 447 412 449 421 441 418 443 416 418 441 1309 420 1303 416 1281 438 450 420 1304 415 447 412 1311 419 1278 441 34795 3459 1740 414 1283 447 415 444 444 415 419 440 1310 420 442 417 417 442 420 439 449 421 1276 443 445 414 1309 421 1276 443 446 413 1310 420 1304 415 1308 421 1302 417 1280 439 449 421 414 445 1305 414 421 438 450 420 415 444 417 442 446 413 421 438 450 420 442 417 444 415 420 439 449 421 1303 416 418 441 420 439 422 448 441 418 1305 414 421 438 450 420 442 417 444 415 446 413 448 411 450 420 442 417 444 415 446 413 449 421 441 418 443 416 445 414 447 412 422 448 441 418 443 416 445 414 1310 420 441 418 1306 413 421 438 1312 418 417 442 34795 3459 1712 442 1308 422 413 446 443 416 418 441 1309 421 441 418 416 443 445 414 448 411 1312 418 444 415 1308 421 1302 417 418 441 1309 421 1276 443 1307 412 1312 418 1306 413 449 421 414 445 1305 414 447 412 450 420 441 418 444 415 446 413 421 438 450 420 442 417 444 415 446 413 449 421 440 419 443 416 445 414 447 412 449 421 441 418 443 416 1307 412 423 447 415 444 1279 440 1310 419 1304 415 447 412 422 448 441 418 443 416 418 441 1309 421 414 445 1306 413 421 438 423 447 442 417 417 442 446 413 449 421 441 418 443 416 445 414 447 412 1311 419 1305 414 1283 446 1277 442 1281 449 1303 416 1280 439 422 448 414 445 417 442 446 413 448 411 450 420 442 417 444 415 420 439 449 421 441 418 443 416 418 441 447 412 449 421 441 418 416 443 418 441 1310 419 1304 415 419 440 421 449 440 419 442 417 418 441 420 439 422 448 441 418 443 416 445 414 1309 421 1303 416 446 413 448 411 423 447 442 417 417 442 446 413 422 448 440 419 442 417 444 415 447 412 449 421 414 445 443 416 445 414 447 412 449 421 441 418 443 416 445 414 448 411 450 420 442 417 1306 413 1310 420 415 444 444 415 420 439 422 448 414 445 443 416 445 414 447 412 450 420 441 418 417 442 446 413 448 411 450 420 442 417 444 415 446 413 449 421 441 418 1305 414 1309 421 414 445 444 415 446 413 # -# Old SAMSUNG AC +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 447 415 444 417 442 419 440 421 438 423 447 25361 3456 1742 412 1312 418 417 442 446 413 448 411 1286 443 445 414 420 439 449 421 414 445 1278 441 447 412 1285 444 1279 440 448 411 1286 443 1280 439 1311 418 1305 414 1310 419 415 444 417 442 1282 448 414 445 443 416 445 414 420 439 449 421 414 445 443 416 446 413 448 411 423 447 1304 415 446 413 1284 445 443 416 418 441 420 439 1311 419 1306 413 421 438 450 420 415 444 417 442 446 413 448 422 413 446 416 443 445 414 447 412 449 421 441 418 443 416 445 414 448 411 450 420 1304 415 1281 449 1302 417 418 441 1282 447 414 445 1305 414 1310 419 34790 3463 1709 445 1305 414 421 438 423 447 442 417 1306 413 448 422 413 446 443 416 418 441 1309 421 441 418 1278 441 1283 446 415 444 1306 413 1311 419 1305 414 1282 447 1303 416 446 413 421 449 1275 444 418 441 420 439 449 421 441 418 443 416 445 414 421 438 423 447 442 417 444 415 446 413 1283 446 442 417 418 441 447 412 422 448 1303 416 446 413 448 411 450 420 442 417 444 415 446 413 449 421 441 418 443 416 445 414 447 412 450 420 441 418 444 415 446 413 448 411 451 419 442 417 445 414 1309 420 414 445 1278 441 421 438 1312 417 444 415 34795 3457 1741 413 1311 419 416 443 445 414 420 439 1285 444 444 415 419 440 448 422 440 419 1304 415 420 439 1311 419 1305 414 448 411 1312 417 1279 440 1284 445 1278 441 1282 447 415 444 444 415 1308 421 414 445 443 416 418 441 420 439 449 421 414 445 444 415 446 413 448 422 440 419 416 443 445 414 420 439 449 421 441 418 443 416 446 413 421 438 1312 417 444 415 419 440 1311 419 1305 414 1309 420 414 445 417 442 419 440 448 411 450 420 1304 415 447 412 1311 419 443 416 445 414 421 438 450 420 442 417 444 415 446 413 448 422 440 419 442 417 1307 412 1284 445 1305 414 1283 446 1304 415 1308 421 1302 417 418 441 447 412 449 421 441 418 444 415 446 413 448 411 450 420 442 417 444 415 447 412 449 421 414 445 443 416 445 414 447 412 450 420 442 417 1306 413 1310 420 442 417 417 442 447 412 449 421 441 418 443 416 445 414 447 412 450 420 442 417 1306 413 1310 419 415 444 445 414 447 412 449 421 441 418 443 416 446 413 448 411 450 420 442 417 444 415 447 412 449 421 441 418 443 416 445 414 447 412 450 420 442 417 444 415 446 413 448 411 451 419 1304 415 1309 421 441 418 416 443 445 414 447 412 450 420 442 417 444 415 446 413 448 422 440 419 442 417 445 414 447 412 449 421 441 418 443 416 446 413 448 411 450 420 1304 415 1281 449 413 446 416 443 418 441 # name: POWER type: raw @@ -15,16 +26,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 3027 9039 538 1530 514 558 490 557 491 582 486 560 488 559 488 584 464 583 464 582 486 1554 490 583 485 562 486 1554 490 584 484 1556 488 1554 510 562 485 1555 509 1531 533 1535 509 1558 569 1473 591 1475 517 1550 566 1475 517 556 492 581 487 559 488 558 490 557 491 582 486 560 487 559 488 558 489 583 464 582 486 560 508 565 482 1584 460 1556 508 1558 517 1524 572 1495 518 1551 513 1527 517 555 493 581 487 559 488 558 510 562 485 561 486 560 487 1579 485 1557 518 1523 541 1526 466 # -# file: Flipper-IRDB/ACs\Insigna\Insigna_AC_NSRC2AC9.ir -# -name: SWING -type: parsed -protocol: NECext -address: 10 E7 00 00 -command: 06 F9 00 00 -# -# Airmet AC by JEREMYNO -# name: POWER type: raw frequency: 38000 @@ -49,8 +50,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 8943 4491 586 565 534 1692 567 559 539 1660 588 1663 565 561 568 557 542 584 535 1664 564 588 541 558 561 1664 564 562 567 559 540 1659 589 563 535 1664 584 1667 561 1664 564 1661 587 564 535 591 538 562 567 558 540 1659 589 562 537 589 540 560 559 566 533 593 536 564 565 560 538 587 532 567 562 1663 565 1661 567 1658 590 1662 566 1659 559 1666 593 559 540 586 533 567 562 563 536 590 539 560 559 1692 536 1664 564 1661 587 1664 564 1662 566 1659 589 562 536 589 540 560 559 566 533 593 536 564 565 560 538 587 532 567 562 1663 565 561 568 1657 561 1665 563 588 541 1658 560 592 537 # -# Amcor AC -# name: TEMP+ type: parsed protocol: NEC @@ -63,8 +62,17 @@ protocol: NEC address: 80 00 00 00 command: 95 00 00 00 # -# Ariston AC A-MW09-IGX -# On and Off buttons set to 26 C° cool +name: TIMER +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 19 00 00 00 +# +name: SWING +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8918 4489 568 584 535 1664 564 588 541 1658 560 1666 593 558 540 1659 589 562 537 1663 585 566 533 593 536 1664 564 1661 587 564 535 591 538 1661 567 1658 590 1662 566 1659 559 1667 592 559 539 586 533 567 562 563 536 1664 584 567 542 584 535 564 565 560 539 587 542 558 561 564 535 591 538 561 568 1658 560 1666 562 1663 586 1666 562 1663 565 1660 588 563 536 590 539 560 559 567 542 584 535 564 565 1660 568 1658 560 1665 594 1658 560 1666 562 1663 585 566 533 593 536 563 566 559 540 586 533 567 562 563 536 590 539 560 559 1667 561 564 565 1661 567 1658 560 591 538 1662 566 585 534 # name: POWER type: raw @@ -72,16 +80,12 @@ frequency: 38000 duty_cycle: 0.330000 data: 4482 4413 596 1596 594 527 562 1602 588 1603 587 535 565 530 570 1595 595 526 563 532 568 1597 593 528 561 534 566 1599 591 1599 591 531 569 1596 594 1597 593 528 561 1603 587 1604 596 1595 595 1596 594 1597 593 1598 592 529 560 1604 596 525 564 531 569 526 563 532 568 527 562 533 567 1598 592 1599 591 530 570 1595 595 526 563 532 568 527 562 506 594 528 561 507 593 1598 592 529 571 1595 595 1596 594 1597 593 1598 592 5251 4505 4417 592 1599 591 530 570 1595 595 1596 594 527 562 533 567 1598 592 529 561 535 565 1600 590 531 569 526 563 1602 588 1603 587 534 566 1599 591 1600 590 531 569 1596 594 1597 593 1598 592 1599 591 1600 590 1601 589 532 568 1597 593 529 561 534 566 503 597 499 590 504 596 500 589 1601 589 1602 588 533 567 1599 591 530 570 499 591 504 596 526 563 505 595 501 589 1602 588 533 567 1598 592 1599 591 1600 590 1601 589 # -# Bonaire DurangoAC -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 1305 435 1280 432 415 1255 1307 432 1272 439 418 1252 442 1255 1307 431 416 1255 439 1258 447 1251 443 8174 1302 437 1278 433 414 1255 1307 432 1273 438 419 1250 444 1254 1298 440 417 1253 441 1256 438 1259 445 8170 1306 433 1271 439 418 1251 1301 438 1277 434 413 1256 449 1249 1303 435 412 1258 446 1251 443 1254 440 8176 1300 438 1277 434 413 1283 1279 433 1271 440 417 1278 416 1255 1307 431 416 1253 441 1257 447 1250 444 8171 1305 433 1272 439 418 1278 1274 438 1277 433 414 1282 412 1259 1303 434 413 1256 448 1249 445 1252 442 8173 1303 435 1270 440 417 1279 1273 438 1277 433 414 1282 412 1258 1304 433 414 1282 412 1258 446 1250 444 8171 1305 433 1272 438 419 1276 1276 435 1270 441 416 1252 442 1255 1297 440 417 1279 415 1255 439 1257 447 8168 1297 439 1276 434 413 1256 1306 431 1273 436 411 1258 446 1250 1302 409 438 1284 421 1249 445 1252 442 # -# Boulanger AC -# name: POWER type: parsed protocol: NEC @@ -106,23 +110,17 @@ protocol: NEC address: 81 00 00 00 command: 66 00 00 00 # -# Ciatronic AC -# name: TEMP- type: raw frequency: 38000 duty_cycle: 0.330000 data: 9013 4502 575 560 574 562 572 1671 565 569 565 570 543 592 542 540 594 567 546 1697 571 1672 575 560 574 1695 541 1702 545 1671 597 1673 574 563 1670 1703 575 560 542 592 542 540 593 568 545 590 544 564 569 565 548 587 547 1670 566 1702 566 1677 570 1674 573 1670 598 1698 538 1704 543 39972 9017 2251 568 96272 9021 2249 570 96268 9013 2256 574 96264 9015 2254 56 # -# Daikin TB industrial AC -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 5050 2165 361 1803 367 716 363 718 361 721 358 1806 364 718 362 720 359 723 367 715 364 1800 359 722 368 1797 362 1802 368 714 365 1799 360 1803 367 1798 361 1803 367 1797 362 720 359 1805 365 717 363 719 360 722 368 714 365 717 362 719 360 1804 366 1798 361 721 358 723 367 715 364 718 361 720 359 1805 365 717 362 720 359 722 368 714 365 717 362 719 361 722 368 714 365 716 363 719 360 721 358 724 366 716 363 718 361 1803 367 1797 362 1802 368 1797 362 719 360 722 368 714 365 29579 5061 2156 360 1804 366 717 362 719 360 722 357 1806 364 719 360 721 358 724 366 716 363 1801 358 723 367 1798 361 1802 368 715 364 1800 359 1804 366 1799 360 1804 366 1798 361 721 359 1806 364 718 362 721 359 723 367 715 364 718 362 720 359 1805 365 1799 360 722 368 714 365 717 362 719 361 721 358 724 366 716 363 719 361 721 358 724 366 716 363 1801 358 1806 364 718 361 721 358 1805 365 1800 359 1805 365 717 362 720 359 722 368 714 365 717 362 719 360 722 368 714 365 717 362 1802 368 714 365 717 362 719 361 722 368 1796 363 719 360 721 358 724 366 716 363 719 360 721 358 724 366 716 363 718 362 721 359 723 367 715 364 718 361 720 360 723 367 715 364 718 362 720 359 722 368 715 364 1799 360 1805 365 1799 360 722 368 714 365 716 363 1801 358 724 366 1799 360 721 358 1806 364 718 361 721 358 723 367 716 363 718 362 721 359 723 367 715 364 718 362 720 359 723 367 715 364 718 362 720 359 723 367 715 364 1800 359 722 368 714 365 1799 360 1804 366 1799 360 1804 366 1799 360 1804 366 1798 361 1803 367 -# -# Daikin AC # name: POWER type: raw @@ -130,8 +128,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 9823 9795 9821 9799 4615 2493 385 343 389 924 386 931 389 348 384 929 381 355 387 345 387 357 386 343 379 934 386 350 382 350 382 354 388 929 381 355 387 357 386 343 379 357 386 350 382 928 382 931 379 938 382 355 388 356 387 919 381 355 387 349 383 927 383 930 380 356 386 346 386 358 384 344 388 348 384 352 380 352 380 933 387 348 384 351 381 363 379 349 383 353 379 357 386 347 385 927 383 354 388 344 388 356 386 919 381 355 388 349 383 350 382 353 379 938 382 354 389 356 386 919 381 355 387 930 380 934 386 349 383 934 386 350 382 358 385 20350 4620 # -# DeLonghi Pinguino Air-to-Air PAC N81 by JEREMYNO -# name: TEMP+ type: parsed protocol: NECext @@ -144,8 +140,6 @@ protocol: NECext address: 48 44 00 00 command: 88 08 00 00 # -# Friedrich AC -# name: POWER type: raw frequency: 38000 @@ -164,16 +158,12 @@ frequency: 38000 duty_cycle: 0.330000 data: 5626 5579 569 549 562 582 539 581 540 578 543 577 544 575 536 1702 541 1703 540 549 562 557 564 1700 543 1670 563 1677 566 1698 545 547 564 586 535 1674 569 550 571 1668 565 1674 569 578 543 550 571 1670 563 587 545 1665 568 1671 562 1677 566 1700 543 577 544 548 563 1704 539 557 564 1698 545 574 537 1677 566 552 569 577 544 1668 565 554 567 583 538 1670 563 1702 541 1671 572 547 564 583 538 553 568 552 569 1700 543 545 566 582 539 1698 535 558 563 557 564 554 567 1671 562 585 536 # -# Fujitsu AC -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 3302 1644 408 419 410 416 413 1233 405 423 406 1239 409 419 410 417 412 415 414 1232 406 1241 407 419 410 417 412 416 413 1233 405 1241 407 394 435 419 410 417 412 416 413 387 432 422 407 420 409 418 411 416 413 415 404 423 406 421 408 420 409 1237 411 416 413 413 406 422 407 420 409 418 411 417 412 415 414 1232 406 421 408 420 409 418 411 416 413 1232 406 1240 408 1238 410 1236 412 1234 414 1232 406 1240 408 1238 410 417 412 416 413 1233 405 422 407 421 408 419 410 417 412 414 404 397 432 421 408 420 409 1237 411 1234 414 387 432 422 407 1239 409 418 411 416 413 414 405 423 406 1240 408 1237 411 417 412 415 414 414 405 422 407 421 408 418 411 416 413 414 405 423 406 421 408 419 410 417 412 416 413 414 405 422 407 421 408 419 410 416 413 414 405 423 406 421 408 419 410 417 412 416 413 414 404 423 406 421 408 419 410 417 412 414 405 423 406 421 408 419 410 417 412 416 413 414 404 423 406 421 408 419 410 417 412 416 413 413 406 422 407 420 409 418 411 416 413 1233 405 422 407 421 408 1237 411 1235 413 1206 432 1240 408 420 409 418 411 1235 413 415 414 # -# GE Air Conditioner -# name: POWER type: raw frequency: 38000 @@ -198,8 +188,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 8523 4266 544 1595 516 1597 545 1594 538 544 516 1597 545 564 486 1601 541 1599 543 4213 545 1594 538 1576 545 563 518 565 516 540 521 563 518 565 516 540 624 19269 8522 4265 545 1595 537 1576 546 1594 538 571 489 1623 519 564 517 1595 516 1597 545 4209 539 1600 542 1597 514 568 513 569 512 571 490 567 514 568 513 570 594 19272 8519 4266 544 1595 516 1597 545 1593 539 543 518 1621 521 562 488 1598 544 1595 537 4217 541 1598 544 1569 542 566 515 568 513 543 518 565 516 567 514 542 622 # -# GE Window AC -# name: POWER type: parsed protocol: NECext @@ -224,8 +212,6 @@ protocol: NECext address: 98 6F 00 00 command: 08 F7 00 00 # -# Hisense Window AC -# name: POWER type: raw frequency: 38000 @@ -250,8 +236,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 8954 4428 565 539 562 542 559 544 567 537 564 540 561 1650 563 1650 563 540 561 543 558 546 566 538 563 1649 564 1649 564 1648 565 539 562 542 559 1653 560 1652 561 543 558 546 565 1647 566 537 564 540 561 543 558 545 566 537 564 540 561 542 559 545 567 537 564 539 562 542 559 544 568 537 564 539 562 542 559 544 567 537 564 539 562 542 559 544 568 537 564 539 562 542 559 544 568 536 565 539 562 542 559 544 568 537 564 539 562 542 559 544 568 537 564 539 562 542 559 545 567 537 564 540 561 542 559 545 567 537 564 540 561 543 558 546 565 538 563 541 560 544 568 536 565 539 562 542 559 544 568 537 564 540 561 542 559 545 567 538 563 540 561 543 558 546 566 538 563 541 560 544 568 536 565 539 562 542 559 545 567 537 564 540 561 543 558 546 566 538 563 541 560 544 567 537 564 539 562 542 559 545 566 538 563 541 560 543 558 546 566 565 536 542 559 544 568 537 564 540 561 543 558 545 567 538 563 541 560 544 568 537 564 539 562 542 559 545 567 538 563 541 560 544 568 536 565 539 562 542 559 545 566 538 563 541 560 544 568 536 565 539 562 542 559 545 567 538 563 541 560 544 568 537 564 540 561 543 558 545 567 538 563 541 560 544 568 536 565 539 562 542 559 545 566 538 563 541 560 544 568 537 564 540 561 543 558 545 566 538 563 541 560 1653 560 543 558 547 565 539 562 542 559 545 567 537 564 540 561 543 569 536 565 539 562 542 559 544 568 537 564 540 561 543 558 546 566 538 563 541 560 544 568 537 564 540 561 543 558 546 566 1647 566 538 563 541 560 544 568 537 564 540 561 542 590 # -# Inventum AC -# name: POWER type: raw frequency: 38000 @@ -270,8 +254,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 4424 4381 559 1621 565 529 564 1647 539 1615 561 533 560 534 559 1648 538 532 561 535 1627 559 560 533 535 568 1639 537 1617 559 535 568 1618 568 554 539 556 537 531 562 1618 558 1649 537 1617 559 1621 565 1644 532 1628 558 1622 564 1616 560 534 559 562 541 552 541 527 566 557 536 560 533 1625 561 559 534 1625 561 1619 567 553 540 528 565 532 561 1621 565 529 564 1647 539 528 565 556 537 1617 559 1621 565 1616 560 5229 4425 4363 567 1613 563 557 536 1622 564 1617 559 561 532 562 541 1613 563 559 534 562 541 1617 559 535 568 552 541 1613 563 1617 559 562 541 1618 568 528 565 529 564 556 537 1618 558 1622 564 1616 560 1646 540 1642 534 1627 559 1647 539 1615 561 533 560 561 532 562 541 527 566 556 537 559 534 1624 562 558 535 1623 563 1643 533 561 542 526 567 555 538 1619 567 527 566 1618 558 536 567 527 566 1641 535 1619 567 1617 559 # -# Kenmore Window AC -# name: POWER type: parsed protocol: NECext @@ -284,24 +266,18 @@ protocol: NECext address: 08 F5 00 00 command: 0E F1 00 00 # -# Koldfront_WAC12001 -# name: MODE type: parsed protocol: NECext address: 01 FF 00 00 command: 02 FD 00 00 # -# LG Home AC -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 8445 4206 542 1566 541 539 519 534 514 541 517 1564 543 537 521 533 515 539 519 534 514 540 518 536 512 542 516 537 521 532 516 538 520 534 514 1568 539 541 517 536 522 1560 547 533 515 1567 540 540 518 536 512 1570 547 1561 546 534 514 1568 539 # -# LG AC LP1417GSR -# name: MODE type: raw frequency: 38000 @@ -326,8 +302,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 9007 4379 601 1628 591 1643 597 526 599 529 596 537 598 535 600 538 597 1641 599 517 597 1632 597 1639 590 535 600 529 596 537 598 536 599 526 599 1630 599 521 593 533 592 535 600 531 594 541 594 543 592 534 591 525 600 1630 599 525 600 530 595 1647 593 540 595 543 592 533 592 524 590 528 597 526 599 528 597 533 592 540 595 543 592 535 600 517 597 522 592 530 595 532 593 535 590 542 593 543 592 516 598 7876 594 523 591 528 597 528 597 531 594 538 597 537 598 1651 599 1639 590 525 600 520 594 529 596 531 594 535 590 543 592 544 591 534 591 524 590 529 596 526 599 527 598 531 594 539 596 540 595 529 596 520 594 525 600 522 592 533 592 538 597 536 599 538 597 529 596 519 595 525 600 523 591 535 600 531 594 539 596 541 594 533 592 524 590 528 597 524 590 536 599 531 594 538 597 540 595 531 594 523 591 530 595 529 596 530 595 536 599 534 591 547 599 528 597 1632 597 1637 592 532 593 536 599 1641 599 535 600 1651 599 1623 596 7879 591 526 599 520 594 527 598 528 597 532 593 538 597 538 597 528 597 519 595 1636 593 529 596 533 592 538 597 537 598 541 594 534 591 527 598 523 591 532 593 533 592 540 595 538 597 540 595 532 593 524 601 519 595 528 597 529 596 534 591 544 591 547 599 529 596 520 594 526 599 524 590 1645 595 1646 594 1653 597 541 594 534 591 525 600 519 595 528 597 529 596 535 600 533 592 546 600 528 597 520 594 1637 592 532 593 1647 593 1649 591 1656 594 543 592 518 596 # -# LG AC -# name: POWER type: parsed protocol: NECext @@ -346,8 +320,6 @@ protocol: NECext address: 81 66 00 00 command: 85 7A 00 00 # -# LG Portable AC LP1015WNR -# name: POWER type: parsed protocol: NECext @@ -366,8 +338,6 @@ protocol: NECext address: 10 E7 00 00 command: 0D F2 00 00 # -# Midea_AC_MAW05R1WBL -# name: POWER type: raw frequency: 38000 @@ -392,8 +362,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 4408 4423 570 1585 567 537 539 1590 561 542 544 533 542 535 541 537 539 1589 563 1593 569 534 541 1588 563 539 537 541 545 532 543 534 541 536 539 537 539 1590 562 1593 569 1586 566 538 538 539 537 1592 570 1585 567 1587 565 1590 561 1594 568 1586 565 1590 561 1593 569 1586 566 1589 562 1592 570 1584 568 1587 564 1590 561 1594 568 1586 565 1590 572 1583 568 534 541 1588 564 540 536 1593 569 534 541 1587 564 539 537 1592 570 5186 4455 4374 567 537 539 1590 561 542 544 1584 567 1588 563 1591 560 1594 568 535 541 537 539 1590 561 541 545 1584 568 1587 564 1590 561 1593 569 1586 565 1589 562 540 536 542 544 533 542 1586 566 1588 563 540 536 542 544 533 542 535 540 537 539 538 538 539 537 541 535 542 544 534 541 535 540 537 539 538 537 540 536 541 545 532 543 534 541 536 539 1589 562 540 536 1593 569 534 541 1588 563 540 535 1593 569 534 541 # -# Mitsubishi AC MSG-GE10VA -# name: POWER type: raw frequency: 38000 @@ -418,8 +386,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 3467 1697 456 1270 458 1306 412 424 456 440 408 432 437 1315 413 427 442 451 408 1321 438 1293 435 405 433 1319 430 411 437 455 414 1312 416 1307 432 435 413 1286 463 1291 417 422 437 457 412 1313 436 438 410 454 405 1292 436 431 438 424 435 432 458 438 410 432 437 454 436 410 438 452 407 430 439 430 460 409 460 411 437 427 442 425 434 431 459 415 433 458 432 417 442 432 458 414 434 1315 413 423 436 458 411 434 456 417 442 432 437 456 413 1308 431 412 436 427 463 406 463 404 465 404 434 433 436 1314 435 410 438 426 464 432 406 434 435 432 437 1287 462 405 433 462 407 1318 410 1316 433 438 410 430 439 1285 433 1292 436 431 459 412 436 431 459 1269 439 1316 412 428 431 1321 407 1318 410 1316 433 409 440 1308 431 1298 430 1297 431 436 412 428 462 436 412 428 431 436 464 405 433 432 437 432 437 429 461 448 411 428 462 412 436 428 441 448 431 411 437 456 413 454 405 436 433 460 409 427 432 436 464 405 433 436 433 458 432 413 435 429 440 423 436 433 457 413 456 415 433 431 438 429 440 425 454 419 440 425 465 411 437 436 464 407 441 424 435 428 441 452 407 436 433 432 437 432 437 456 434 411 437 425 465 404 434 433 457 1276 463 409 439 429 461 1294 434 1293 414 450 409 1317 411 456 413 17057 3603 1727 415 1310 408 1318 431 436 433 407 462 412 436 1287 431 462 438 405 433 1319 440 1290 407 461 429 1299 408 432 458 411 437 1289 439 1310 429 443 416 1305 434 1297 431 435 413 452 438 1292 436 411 437 453 416 1293 456 444 415 432 437 456 413 425 434 458 411 456 413 427 442 449 430 415 433 431 459 415 433 442 458 414 434 430 460 433 405 436 464 416 463 410 438 429 440 451 428 1301 438 436 412 426 433 437 432 432 437 432 437 430 439 1313 405 434 435 434 435 460 409 432 437 430 439 423 456 1298 430 410 438 429 440 427 432 433 436 431 438 1314 414 448 431 409 460 1294 413 1284 434 459 431 438 410 1289 460 1270 437 458 432 413 435 434 435 1315 434 1268 460 406 463 1291 416 1307 411 1313 436 409 439 1312 406 1318 410 1317 432 409 439 427 432 462 407 436 464 405 464 402 457 413 435 456 413 429 440 431 438 427 432 435 434 431 459 408 440 427 442 425 434 431 438 428 441 424 435 432 437 430 439 454 436 407 462 405 433 436 464 406 432 432 437 432 458 410 459 412 436 428 441 422 437 430 439 430 439 452 407 436 433 434 456 415 433 430 460 409 439 428 462 409 460 409 460 409 439 425 465 405 433 429 440 454 436 407 441 1308 410 457 412 429 440 1312 406 1319 409 429 440 1288 461 408 461 # -# Rinnai AC -# name: POWER type: raw frequency: 38000 @@ -438,22 +404,18 @@ frequency: 38000 duty_cycle: 0.330000 data: 9032 4512 586 1711 569 1704 566 577 568 575 560 585 560 560 595 1656 614 1689 591 1707 563 1709 561 1713 567 576 569 1682 588 1689 591 1687 593 576 569 573 562 580 565 578 567 576 569 575 560 1691 589 1689 591 1685 595 572 563 579 566 576 569 574 561 583 562 558 587 561 594 575 560 582 563 578 567 576 569 574 561 583 562 1689 591 1686 594 576 569 573 562 580 565 577 568 576 569 575 560 560 595 552 593 577 568 574 561 580 565 578 567 577 568 576 569 1682 588 559 586 584 561 580 565 577 568 575 560 584 561 583 562 558 587 560 595 575 560 581 564 578 567 575 560 584 561 583 562 582 563 558 587 583 562 579 566 576 569 574 561 582 563 581 564 1687 593 554 591 579 566 575 560 582 563 580 565 578 567 577 568 553 592 555 590 579 566 1707 563 579 566 576 569 575 560 584 561 559 586 561 594 575 560 1712 568 1705 565 578 567 1707 563 1687 593 1684 586 561 594 1705 565 # -# Samsung Wind-Free AC -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 608 17795 3020 8937 519 502 495 1493 492 475 522 472 525 469 518 476 521 472 525 469 518 476 521 1493 492 503 494 499 498 1490 495 500 517 503 494 1493 492 1497 498 1463 521 1467 517 1470 525 470 517 503 494 500 497 497 490 504 493 501 496 497 490 504 493 528 469 498 519 474 513 481 516 505 492 501 496 498 499 468 519 502 495 499 498 468 519 502 495 499 498 496 491 503 494 499 498 496 491 530 467 500 497 496 521 500 487 480 517 503 494 473 524 1464 521 1467 517 1471 524 1491 493 2972 2993 8939 517 1523 472 495 492 502 495 499 518 502 495 499 488 506 491 503 494 472 525 1490 495 472 525 496 491 1470 525 496 491 1497 498 1517 467 1494 490 1497 518 1470 514 1474 521 473 524 470 517 503 494 473 524 470 517 504 493 474 523 497 490 504 493 501 496 498 489 504 493 528 469 525 462 504 513 508 489 478 519 501 496 498 499 468 519 475 522 498 499 495 492 475 522 471 526 495 492 502 495 499 498 495 492 502 495 526 471 522 465 529 468 499 518 475 522 499 498 2967 2998 8933 523 1464 520 474 523 470 517 477 520 474 523 497 490 504 493 501 496 498 489 1499 496 525 493 474 513 1502 493 474 523 1465 519 1468 516 478 519 1468 517 1499 496 1492 493 1522 462 1499 496 1492 493 1495 520 1468 516 478 519 474 523 471 516 1472 523 1465 519 1469 526 495 492 502 495 498 499 495 492 529 468 499 498 495 492 529 488 1473 522 1466 518 475 522 472 525 1463 522 1466 518 502 495 499 498 496 491 503 494 499 498 496 491 503 494 1494 521 1493 492 1470 525 1463 521 -# +# name: MODE type: raw frequency: 38000 duty_cycle: 0.330000 data: 603 17909 2988 8942 524 496 491 1523 472 496 491 530 467 526 471 496 521 499 488 506 491 503 494 1467 518 503 494 500 497 1463 522 500 497 497 490 1498 497 1491 493 1494 490 1498 497 1491 514 507 490 504 493 501 496 498 499 494 493 501 496 498 489 505 492 502 495 498 499 495 492 502 495 499 498 495 492 529 468 526 471 523 494 499 488 506 491 503 494 499 498 496 491 503 494 500 497 496 491 503 494 500 497 497 490 504 493 500 497 497 490 504 493 1495 489 1498 517 1471 514 1475 520 2947 3018 8939 517 1471 524 497 490 504 493 500 497 497 490 504 493 501 496 498 489 505 492 1495 489 531 486 508 489 505 492 1469 515 1472 523 1466 518 502 495 1466 518 1470 525 1463 522 1467 517 1497 498 1491 514 1474 521 1467 517 503 494 499 498 496 491 1470 525 1463 522 1468 517 503 494 500 497 497 490 504 493 528 469 524 463 531 486 508 489 1471 524 1465 519 501 496 498 499 495 492 502 495 498 499 495 492 1496 499 495 492 502 495 499 498 523 464 1496 519 1470 515 1474 521 1467 517 # -# Suntec Wellness AC 14246 TRANSFORM 14.000 Eco R290 -# name: POWER type: parsed protocol: NEC @@ -466,8 +428,6 @@ protocol: NEC address: 80 00 00 00 command: 9D 00 00 00 # -# Toshiba AC -# name: POWER type: parsed protocol: NECext @@ -486,8 +446,6 @@ protocol: NECext address: 01 FF 00 00 command: 13 EC 00 00 # -# Toshiba RAS-13SKV2-E -# name: POWER type: raw frequency: 38000 @@ -505,9 +463,6 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 4388 4348 553 1608 553 1606 555 1605 556 1603 548 532 548 532 548 1611 550 529 552 529 552 528 552 527 553 527 554 1605 556 1603 548 532 549 1611 550 530 551 529 552 528 553 528 552 527 553 526 555 1605 556 1603 548 1612 550 1610 551 1608 553 1607 554 1605 556 1604 547 533 548 532 549 532 549 531 550 530 551 530 551 529 552 528 552 527 554 1605 556 524 556 1603 548 1612 549 530 551 529 552 529 551 528 552 528 552 527 553 526 554 525 555 525 555 524 556 523 547 533 548 1611 550 530 550 529 551 528 552 528 552 527 553 527 553 526 554 525 555 524 556 1603 548 1611 550 530 550 530 550 529 551 528 553 528 552 7451 4386 4350 550 1611 550 1609 552 1608 553 1606 555 525 555 524 556 1604 547 533 547 532 548 531 549 531 550 530 551 1609 552 1607 554 525 555 1605 556 523 547 533 547 532 548 532 549 531 550 530 551 1609 552 1607 554 1605 556 1604 557 1603 548 1612 549 1610 551 1609 552 527 553 527 553 526 554 526 554 525 555 524 556 524 546 533 547 533 548 1611 550 530 551 1609 552 1607 554 526 554 525 555 525 555 524 556 524 546 533 547 533 548 532 548 531 549 530 551 529 551 528 553 1607 554 525 555 525 555 524 556 524 556 523 547 533 547 532 549 531 549 531 550 1609 552 1607 554 526 554 525 555 525 555 524 556 524 556 -# -# Toshiba Remote Type RG57H4(B)/BGEFU1 -# Used with Toshiba Air Conditioner RAC-PD0812CRRU # POWER name: POWER type: raw @@ -533,16 +488,12 @@ frequency: 38000 duty_cycle: 0.330000 data: 4406 4356 571 1574 563 509 564 1581 566 506 567 504 569 529 544 501 562 1582 565 1580 567 505 568 503 570 1575 562 510 563 508 565 1580 567 1604 543 529 544 1574 563 1582 565 507 566 1579 568 1577 570 1575 572 500 563 1582 565 1579 568 1577 570 1575 572 1573 564 1581 566 1579 568 1577 570 1575 572 1573 564 1581 566 1579 568 1577 570 1575 572 1573 564 1582 565 506 567 1578 569 1576 571 1574 563 1582 565 1580 567 505 568 503 570 5162 4408 4354 562 535 538 1581 566 505 568 1577 570 1575 572 1573 564 1581 566 506 567 505 568 1576 571 1573 564 509 564 1580 567 1578 569 503 570 501 562 1583 564 507 566 506 567 1577 570 502 571 500 563 509 564 1580 567 505 568 503 570 501 572 499 564 508 565 506 567 531 542 503 570 501 562 536 537 534 539 506 567 504 569 529 544 527 536 510 564 1580 567 505 568 503 570 501 572 526 537 508 565 1579 568 1577 570 # -# Vornado AC -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 1347 405 1322 422 410 1332 1300 448 1289 480 383 1303 445 1298 439 1331 417 1299 438 1332 416 1302 1320 6834 1292 456 1292 450 413 1304 1328 445 1292 452 411 1302 446 1297 440 1303 445 1298 439 1303 445 1301 1321 6806 1320 453 1295 422 441 1301 1321 454 1294 422 441 1301 436 1305 443 1300 448 1295 442 1301 447 1298 1324 6802 1324 451 1297 420 443 1299 1323 424 1324 419 444 1298 439 1304 444 1298 439 1304 444 1299 438 1306 1326 6815 1321 453 1295 421 442 1302 1320 426 1322 421 442 1301 436 1306 442 1301 447 1296 441 1301 447 1299 1323 6802 1324 424 1324 418 445 1300 1322 424 1324 419 444 1298 439 1304 444 1299 438 1304 444 1299 438 1306 1326 6809 1328 420 1317 424 439 1306 1326 419 1318 424 439 1304 444 1299 438 1305 443 1299 438 1305 443 1302 1320 # -# Whynter_AC.ir -# name: POWER type: raw frequency: 38000 @@ -561,16 +512,12 @@ frequency: 38000 duty_cycle: 0.330000 data: 746 745 2927 2882 748 2180 774 2207 778 2202 752 740 747 2181 752 2229 725 2203 751 2204 729 736 772 747 751 741 746 745 753 739 748 743 776 742 756 736 751 740 747 745 805 2202 752 740 747 2181 773 746 752 2176 778 715 772 2182 772 720 777 2177 746 746 772 2182 751 2178 776 742 756 736 803 # -# Zenith_AC -# name: MODE type: parsed protocol: NECext address: 81 66 00 00 command: 9B 64 00 00 # -# SAMSUNG AC 1,8 -# name: TEMP- type: parsed protocol: NECext @@ -589,8 +536,6 @@ protocol: NECext address: 01 08 00 00 command: 3F 00 00 00 # -# file: Flipper-IRDB/ACs\Admiral\Admiral_AC.ir -# name: POWER type: parsed protocol: NEC @@ -609,21 +554,6 @@ protocol: NEC address: 20 00 00 00 command: 11 00 00 00 # -name: TIMER -type: parsed -protocol: NEC -address: 20 00 00 00 -command: 19 00 00 00 -# -# file: Flipper-IRDB/ACs\Airmet\Airmet_ac.ir -# -# -name: SWING -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 8918 4489 568 584 535 1664 564 588 541 1658 560 1666 593 558 540 1659 589 562 537 1663 585 566 533 593 536 1664 564 1661 587 564 535 591 538 1661 567 1658 590 1662 566 1659 559 1667 592 559 539 586 533 567 562 563 536 1664 584 567 542 584 535 564 565 560 539 587 542 558 561 564 535 591 538 561 568 1658 560 1666 562 1663 586 1666 562 1663 565 1660 588 563 536 590 539 560 559 567 542 584 535 564 565 1660 568 1658 560 1665 594 1658 560 1666 562 1663 585 566 533 593 536 563 566 559 540 586 533 567 562 563 536 590 539 560 559 1667 561 564 565 1661 567 1658 560 591 538 1662 566 585 534 -# name: POWER type: raw frequency: 38000 @@ -636,8 +566,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 8971 4489 568 584 535 564 565 561 537 588 541 558 561 565 534 592 537 562 567 1659 559 566 563 563 536 1664 584 567 542 584 535 1664 564 587 542 558 561 564 535 591 538 562 567 558 541 585 534 566 563 562 537 589 540 559 560 566 533 593 536 563 566 560 539 587 532 567 562 564 535 591 538 1661 567 1658 590 1662 566 1659 559 1667 592 1660 558 567 562 563 536 590 539 561 558 567 542 584 535 1664 564 1662 586 1665 563 1662 566 1659 589 1663 565 560 559 566 533 593 536 564 565 560 538 587 542 557 562 564 535 591 538 1661 567 585 534 1666 562 1663 585 566 533 1667 592 560 538 # -# file: Flipper-IRDB/ACs\Amcor\Amcor_AC.ir -# name: POWER type: parsed protocol: NEC @@ -650,24 +578,18 @@ protocol: NEC address: 80 00 00 00 command: 9F 00 00 00 # -# file: Flipper-IRDB/ACs\Ariston\Ariston_AC_A-MW09-IGX.ir -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 4481 4414 595 1596 594 527 562 1602 588 1604 586 535 565 530 570 1594 596 526 563 532 568 1596 594 528 561 534 566 1598 592 1600 590 531 569 1596 594 527 562 1603 587 1604 586 1605 648 1543 594 527 562 1603 587 1604 586 1605 595 525 564 531 569 526 563 532 568 1596 594 528 561 534 566 1598 592 1600 590 1601 589 532 568 527 562 533 567 528 561 534 566 529 560 535 565 530 570 1594 596 1596 594 1597 593 1598 592 1599 591 5252 4503 4418 590 1601 589 532 568 1597 593 1598 592 529 560 535 565 1600 590 531 569 526 563 1602 588 533 567 529 560 1604 596 1595 595 526 563 1602 588 533 567 1598 592 1599 591 1600 590 1601 589 532 568 1598 592 1599 591 1600 590 531 569 527 562 532 568 528 561 1603 587 534 566 530 559 1605 595 1596 594 1597 593 528 561 534 566 529 560 535 565 530 570 525 564 531 569 527 562 1602 588 1603 587 1604 596 1595 595 1596 594 # -# file: Flipper-IRDB/ACs\Bonaire\Bonaire_DurangoAC.ir -# name: TIMER type: raw frequency: 38000 duty_cycle: 0.330000 data: 1307 407 1308 406 441 1257 1305 435 1279 408 439 1259 1303 410 447 1251 443 1255 449 1249 445 1253 441 8177 1308 405 1299 413 444 1254 1308 405 1299 413 444 1253 1309 404 443 1255 439 1259 445 1252 442 1256 448 8169 1306 406 1309 404 443 1254 1308 405 1299 413 444 1253 1298 413 444 1253 441 1257 447 1250 444 1254 440 8176 1299 413 1302 410 447 1250 1301 411 1304 408 439 1259 1303 409 448 1249 445 1252 442 1256 448 1249 445 8171 1304 408 1307 405 442 1256 1306 406 1298 413 444 1253 1299 413 444 1253 441 1257 447 1250 444 1253 441 8175 1300 412 1303 409 448 1249 1302 409 1306 406 441 1256 1306 406 441 1256 448 1249 445 1252 442 1255 439 # -# file: Flipper-IRDB/ACs\Botti\Botti_BL-168DLR.ir -# name: POWER type: raw frequency: 38000 @@ -686,16 +608,12 @@ frequency: 38000 duty_cycle: 0.330000 data: 9611 4510 657 544 653 548 649 552 655 544 653 547 650 550 657 544 653 1637 624 1664 618 1669 623 1663 618 1668 654 1635 647 1642 650 1640 652 550 647 1644 627 1663 619 1669 623 1665 617 1671 621 577 620 578 619 580 617 581 616 581 616 580 617 579 618 578 619 1668 624 1663 619 1669 623 39867 9578 2250 615 96998 9539 2257 618 96975 9513 2250 615 # -# file: Flipper-IRDB/ACs\Boulanger\Boulanger_AC.ir -# name: TIMER type: parsed protocol: NEC address: 81 00 00 00 command: 69 00 00 00 # -# file: Flipper-IRDB/ACs\Corlitec\Cortlitec_portable_ac.ir -# name: POWER type: parsed protocol: NECext @@ -708,16 +626,12 @@ protocol: NECext address: 10 E7 00 00 command: 01 FE 00 00 # -# file: Flipper-IRDB/ACs\Daikin\Daikin_AC_industrial_TB.ir -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 5055 2191 335 1799 360 752 338 714 365 716 364 1800 359 723 367 715 365 718 361 720 359 1805 365 747 332 1802 357 1806 364 719 360 1803 367 1798 361 1803 367 1797 362 1802 368 744 335 1799 360 721 369 714 365 716 363 719 360 721 369 713 366 1798 361 1802 368 715 364 717 362 720 359 723 367 715 364 1799 360 722 368 714 365 717 363 719 361 722 368 714 365 716 363 719 360 721 369 713 366 716 363 718 361 721 359 723 367 1797 362 1802 368 1796 363 1801 358 754 336 716 363 719 361 29583 5057 2160 366 1798 361 750 329 723 367 715 364 1800 359 753 337 715 364 717 363 720 359 1804 366 747 332 1801 358 1806 364 718 361 1803 356 1798 1802 368 1797 362 1802 368 714 365 1799 360 722 368 714 365 717 362 719 360 722 368 714 365 1798 361 1803 367 715 364 718 362 721 359 723 367 715 364 718 361 720 359 723 367 715 364 717 362 720 360 1804 366 1799 360 721 369 714 365 1798 361 1803 367 1798 361 720 359 723 367 715 364 718 361 720 360 723 367 715 364 717 362 720 359 722 368 714 365 717 362 719 360 722 368 1796 363 719 360 721 369 714 365 716 363 719 361 721 369 713 366 716 363 718 361 721 358 723 367 716 363 718 362 720 359 723 367 715 364 718 361 720 359 723 367 715 364 1799 360 1804 366 1799 360 721 369 714 365 716 363 1801 358 754 336 1798 361 720 360 1805 365 748 331 720 359 723 367 715 364 717 363 720 360 722 368 714 365 717 362 720 359 722 368 714 365 717 363 719 361 722 368 714 365 1798 361 751 339 713 366 716 363 1801 359 1805 365 1800 359 1805 365 1800 359 1805 365 1799 360 # -# file: Flipper-IRDB/ACs\DeLonghi\Delonghi_portable_Pinguino-Air-to-Air-PAC-N81_ac.ir -# name: POWER type: parsed protocol: NECext @@ -730,16 +644,12 @@ protocol: NECext address: 48 44 00 00 command: C8 08 00 00 # -# file: Flipper-IRDB/ACs\Friedrich\Friedrich.ir -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 5624 5582 567 553 568 550 571 550 561 557 564 584 537 554 567 1672 571 1671 562 554 567 553 568 1696 537 1676 567 1673 570 1668 565 554 567 556 565 1671 562 557 564 1676 567 1671 562 584 537 555 566 1673 570 552 569 1666 567 1671 562 1676 567 1671 572 548 563 556 565 1672 571 554 567 547 564 556 565 1674 569 549 562 558 563 1676 567 551 570 554 568 548 563 557 564 555 566 554 567 1672 571 1667 566 1674 569 1673 570 545 566 554 567 1671 572 1667 566 554 567 1672 561 557 564 1677 566 # -# file: Flipper-IRDB/ACs\Frigidaire\Frigidaire_AC.ir -# name: POWER type: parsed protocol: NECext @@ -752,8 +662,6 @@ protocol: NECext address: 01 FF 00 00 command: 1B E4 00 00 # -# file: Flipper-IRDB/ACs\Frigidaire\Frigidaire_RG15D_AC.ir -# name: TEMP- type: parsed protocol: NECext @@ -772,16 +680,12 @@ protocol: NECext address: 08 F5 00 00 command: 00 FF 00 00 # -# file: Flipper-IRDB/ACs\Fujitsu\Fujitsu_AC.ir -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 3302 1618 435 393 436 391 438 1207 431 396 433 1213 435 392 437 391 438 388 441 1206 432 1214 434 392 437 389 440 388 431 1215 433 1213 435 392 437 390 439 388 431 396 433 395 434 392 437 390 439 388 431 396 433 394 435 392 437 390 439 388 441 1205 433 395 434 392 437 389 440 388 431 396 433 394 435 392 437 1209 439 388 431 397 432 394 435 393 436 1210 438 387 432 396 433 394 435 392 437 390 439 388 431 1215 433 394 435 1211 437 1208 440 1205 433 1213 435 1211 437 1209 439 # -# file: Flipper-IRDB/ACs\Hisense\Hisense_window_AC.ir -# name: TIMER type: raw frequency: 38000 @@ -794,7 +698,11 @@ frequency: 38000 duty_cycle: 0.330000 data: 8961 4409 563 541 570 533 568 535 566 537 564 539 562 1649 564 1648 565 539 562 541 570 533 568 536 565 1645 568 1644 569 1643 570 534 567 536 565 1646 567 1645 568 536 565 565 536 1648 565 540 572 558 543 560 541 562 539 564 537 566 546 558 543 560 541 563 538 565 536 567 544 559 542 562 539 564 537 566 546 558 543 561 540 563 538 565 536 568 544 560 541 562 539 564 537 566 546 558 543 561 540 563 538 565 536 568 544 560 541 562 539 564 537 567 545 559 542 561 540 563 538 566 545 558 543 561 540 563 538 565 536 568 544 560 541 562 539 565 536 567 544 559 542 561 540 564 537 566 545 558 543 561 540 563 538 565 536 568 543 560 541 562 539 564 537 566 545 532 569 534 567 537 564 539 562 541 571 560 541 536 565 538 563 540 572 532 569 535 566 537 564 539 573 531 570 534 567 536 565 539 562 541 571 533 568 535 566 538 563 540 572 532 569 535 566 537 564 540 572 532 569 534 567 537 564 539 573 532 569 534 567 536 565 539 562 541 571 533 568 536 565 538 563 541 571 533 568 535 566 538 563 540 572 532 569 535 566 537 564 540 572 532 569 534 567 537 564 539 562 542 570 534 567 536 565 539 562 541 570 534 567 536 565 539 562 542 570 534 567 536 565 539 562 542 570 534 567 536 565 539 562 542 570 534 567 536 565 539 562 542 570 1641 572 1640 563 543 569 535 566 538 563 540 561 543 569 535 566 538 563 540 561 543 569 535 566 538 563 541 571 533 568 536 565 539 562 541 571 534 567 537 564 539 562 542 570 534 567 537 564 1646 567 1646 567 539 562 542 570 534 567 537 564 540 561 542 590 # -# file: Flipper-IRDB/ACs\LG\LG_AC.ir +name: SWING +type: parsed +protocol: NECext +address: 10 E7 00 00 +command: 06 F9 00 00 # name: TIMER type: parsed @@ -802,16 +710,12 @@ protocol: NECext address: 81 66 00 00 command: 9F 60 00 00 # -# file: Flipper-IRDB/ACs\LG\LG_AC_2.ir -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 8455 4196 542 1566 541 539 519 535 513 541 517 1565 541 538 520 534 514 540 518 1563 544 1565 542 538 520 533 515 539 519 535 513 541 517 536 522 532 516 538 520 533 515 539 519 535 513 1569 538 542 516 1566 541 539 519 534 514 540 518 1564 542 # -# file: Flipper-IRDB/ACs\LG\LG_AC_LP1417GSR.ir -# name: TIMER type: raw frequency: 38000 @@ -830,24 +734,18 @@ frequency: 38000 duty_cycle: 0.330000 data: 8912 4459 593 1636 593 1640 599 525 600 528 597 533 602 532 593 544 601 1637 592 523 591 1639 600 1636 593 535 600 529 596 538 597 541 594 534 601 1629 600 1634 595 531 1719 1649 532 593 541 594 543 602 526 599 519 595 1640 599 525 600 529 596 1649 601 534 601 537 598 529 596 522 603 519 595 529 596 533 602 528 597 538 597 540 595 532 593 523 602 518 596 527 598 528 597 535 600 533 592 545 601 509 595 7882 598 519 595 524 601 521 593 535 600 530 595 538 597 1650 600 1637 602 514 600 517 597 526 599 527 598 532 593 541 594 544 601 525 600 515 599 519 595 527 598 529 596 534 601 532 593 545 600 526 599 519 595 551 574 524 601 526 599 533 602 532 593 545 600 526 599 517 597 523 602 522 603 525 600 532 593 541 594 543 602 525 600 516 598 522 592 530 595 533 602 529 596 539 596 541 594 532 593 524 601 518 596 527 598 528 597 533 602 531 594 543 592 533 602 1625 593 526 599 523 602 1636 603 1639 600 533 592 1657 593 1628 601 7882 597 521 593 527 598 526 599 529 596 535 600 535 600 538 597 531 594 1634 595 1641 598 527 598 531 594 535 600 532 593 542 593 535 600 518 596 524 601 521 593 533 602 528 597 537 598 539 596 528 597 520 594 525 600 521 593 533 602 528 597 536 599 537 598 527 598 517 597 522 603 521 593 1644 595 1646 593 1651 599 537 598 526 599 516 598 520 594 527 598 528 597 532 593 539 596 540 595 531 594 1638 601 1633 596 528 597 1645 594 1652 598 1649 601 535 600 509 595 # -# file: Flipper-IRDB/ACs\Midea\Midea_AC_MAW05R1WBL.ir -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 4454 4377 594 1560 591 486 589 1565 597 480 595 482 593 484 591 485 590 1564 598 1557 594 1560 591 1563 588 489 597 480 595 482 593 483 592 485 590 487 588 1565 597 1558 593 1562 589 487 588 489 597 1558 593 1561 590 1564 598 1557 594 1560 591 1563 588 1567 595 1560 591 1563 588 1566 596 1559 592 1562 589 1565 597 1558 593 1562 589 1565 597 1557 594 1561 590 486 590 488 598 479 596 1558 593 484 591 1563 588 489 597 1557 594 5161 4459 4371 601 476 589 1565 597 481 594 1560 592 1562 589 1565 597 1558 593 484 591 485 590 487 589 488 598 1556 595 1559 592 1563 588 1566 596 1559 592 1562 589 488 587 489 597 480 595 1559 592 1562 589 488 598 479 596 480 595 482 593 484 591 485 601 476 589 488 598 480 595 481 594 483 592 484 591 486 590 487 588 489 597 480 595 481 594 483 592 1562 589 1565 597 1558 593 483 592 1562 589 488 587 1567 595 482 593 # -# file: Flipper-IRDB/ACs\Mitsubishi\mitsubishi-MSY-GE10VA.ir -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 3439 1755 439 1262 435 1286 432 438 441 423 456 418 441 1282 436 433 436 431 438 1285 433 1314 435 408 461 1293 435 408 440 426 433 1289 460 1296 412 455 414 1312 406 1319 409 429 440 429 461 1267 441 426 464 406 442 1281 437 430 439 427 432 436 464 405 433 432 437 458 411 456 434 422 437 428 462 412 436 428 441 422 457 411 437 456 413 454 405 436 433 434 435 427 432 435 465 404 434 435 434 431 459 413 435 429 440 422 437 433 457 1270 438 1288 461 410 438 426 464 404 434 1293 435 1315 413 423 436 1287 462 407 431 434 435 435 434 433 467 415 433 1318 410 1286 463 409 439 1284 455 1301 438 410 438 426 464 1262 456 1269 439 429 461 410 469 407 462 1268 440 1285 433 461 408 456 413 1284 465 1261 457 414 455 1271 468 1277 431 1321 438 405 433 460 409 430 439 426 464 407 462 407 441 450 409 434 435 430 439 452 438 431 438 405 464 405 464 405 464 409 460 409 439 430 439 427 442 423 436 460 430 415 433 431 438 425 434 444 435 456 413 432 437 427 442 425 434 436 464 429 430 439 430 417 442 428 441 428 462 411 437 452 438 405 433 434 435 456 413 427 442 425 434 455 414 427 432 435 434 433 436 427 463 406 432 437 442 449 430 1268 460 1265 463 1262 466 405 464 406 442 422 437 1289 439 428 441 17052 3577 1746 407 1321 407 1294 434 460 409 431 459 439 409 1288 440 429 440 431 438 1309 430 1272 456 415 464 1289 408 433 457 412 436 1289 439 1284 465 404 434 1292 436 1289 439 428 441 450 409 1315 413 427 442 451 408 1294 434 432 437 430 439 428 462 406 432 432 458 414 455 414 434 430 439 428 441 426 433 436 433 432 437 454 405 438 441 428 431 434 456 418 441 448 431 411 437 429 440 425 434 433 436 458 411 425 434 433 436 457 412 1287 462 1263 455 419 461 408 440 430 439 1310 429 1272 435 460 409 1288 440 429 461 408 441 425 465 405 464 407 441 1286 432 1291 437 432 437 1315 413 1314 414 450 440 406 442 1283 456 1270 458 413 456 413 456 413 435 1297 431 1294 465 404 434 433 436 1314 414 1285 433 433 436 1288 440 1285 464 1264 433 433 436 453 416 425 434 460 409 434 435 432 437 454 415 423 436 431 459 424 435 430 460 413 435 430 439 423 456 413 435 431 438 455 414 427 432 435 434 455 414 426 464 406 432 437 442 422 457 414 434 431 438 424 435 435 455 414 455 416 432 433 436 457 412 426 464 410 438 453 437 412 436 437 463 409 439 425 434 455 414 426 433 437 432 433 436 433 436 457 433 412 436 453 437 406 432 435 465 1266 462 1263 434 1318 410 426 464 410 438 426 433 1293 435 434 435 # -# file: Flipper-IRDB/ACs\Mitsubishi\Mitsubishi_SRK35ZS-W.ir -# name: POWER type: raw frequency: 38000 @@ -866,8 +764,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 3200 1592 382 412 381 1206 381 414 379 414 379 1208 379 416 388 1200 387 406 387 407 386 1202 385 1176 411 1178 409 410 383 1179 408 411 382 1182 416 1172 415 1172 415 404 389 406 387 407 386 408 385 1201 386 1177 410 409 384 1179 408 412 381 1179 408 1181 406 413 380 413 380 414 379 1209 389 405 388 1199 388 406 387 408 385 1202 385 1179 408 1178 409 412 381 1180 407 1182 405 414 379 1182 416 1174 413 1174 413 1176 411 1176 411 410 383 410 383 1204 383 412 381 412 381 412 381 413 380 1209 389 1172 415 1174 413 406 387 1174 413 1177 410 1177 410 1179 408 410 383 412 381 413 380 1206 381 413 380 414 379 414 379 415 389 1199 388 1175 412 407 386 1177 410 1178 409 1178 409 1179 408 1180 407 413 380 414 379 1208 379 415 389 405 388 407 386 406 387 407 386 1201 386 1177 410 1178 409 1179 408 1180 407 412 381 1180 407 1182 405 416 388 405 388 406 387 407 386 407 386 1201 386 409 384 409 384 1204 383 1179 408 411 382 1180 407 1182 405 416 388 1172 415 1173 414 406 387 407 386 1201 386 409 384 410 383 1203 384 410 383 412 381 1206 381 1183 415 1173 414 1173 414 1174 413 1175 412 1178 409 1178 409 410 383 411 382 411 382 412 381 412 381 413 380 413 380 416 388 403 380 1208 379 1184 414 1175 412 1175 412 1176 411 1177 410 411 382 1178 409 411 382 412 381 413 380 413 380 413 380 413 380 1208 379 # -# file: Flipper-IRDB/ACs\Panasonic\Panasonic_CWA75C4179.ir -# name: POWER type: raw frequency: 38000 @@ -892,8 +788,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 3474 1742 417 456 416 1305 418 462 420 465 417 472 420 473 419 478 414 456 416 458 414 463 419 462 420 465 417 472 420 1316 418 479 413 458 414 459 413 464 418 463 419 466 416 474 418 1318 416 1325 419 1296 417 455 417 460 422 1303 421 464 418 471 421 472 420 477 415 456 416 457 415 462 420 461 421 464 418 471 421 472 420 477 415 455 417 456 416 462 420 461 421 464 418 471 421 471 421 476 416 455 417 456 416 461 421 460 422 463 419 470 422 471 421 476 416 454 418 456 416 1305 419 1306 417 467 415 474 418 475 417 480 412 437 414 10576 3468 1747 413 461 421 1299 414 467 415 470 422 467 415 478 414 483 419 451 421 452 420 458 414 467 415 470 412 477 415 1321 413 485 417 453 419 454 418 459 413 469 413 472 420 469 413 1323 421 1320 414 1301 412 460 422 456 416 1309 414 470 422 467 415 478 414 483 419 451 421 452 420 457 415 467 415 470 412 477 415 478 414 482 420 451 421 1296 417 459 413 468 414 1315 419 1314 420 1317 417 480 422 449 412 460 422 455 417 1308 415 1313 421 469 413 1323 421 476 416 455 417 1300 413 1308 415 1309 414 1314 420 1313 421 1316 418 1323 421 450 422 1295 418 458 414 468 414 471 421 1311 413 1324 420 477 415 456 415 457 415 1306 417 464 418 1311 412 476 416 477 415 482 420 450 422 451 421 456 416 466 416 469 413 476 416 477 415 481 421 450 422 451 421 1300 413 1311 412 1316 418 472 420 473 419 477 415 456 416 457 415 463 419 462 420 465 417 472 420 1316 418 1323 421 1294 419 453 419 458 414 468 414 471 421 467 415 478 414 483 419 452 420 453 419 458 414 467 415 471 421 467 415 478 414 483 419 452 420 1297 416 460 422 459 413 472 420 469 413 480 412 485 417 1297 416 457 415 462 420 461 421 464 418 471 421 472 420 477 415 455 417 457 415 462 420 461 421 464 418 471 421 471 421 476 416 455 417 456 416 461 421 1304 419 465 417 1316 418 476 416 480 422 1271 422 # -# file: Flipper-IRDB/ACs\Remko\Remko_RKL.ir -# name: POWER type: parsed protocol: NECext @@ -918,16 +812,12 @@ protocol: NECext address: 86 6B 00 00 command: 00 FF 00 00 # -# file: Flipper-IRDB/ACs\Rinnai\Rinnai_AC.ir -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 9026 4519 590 1654 616 1657 623 574 561 582 563 582 563 583 562 1688 592 1656 675 1627 593 1650 620 1654 677 521 563 1660 620 1656 614 1664 616 581 564 578 567 575 560 582 563 581 564 579 566 1684 596 1655 615 1661 619 577 568 574 561 581 564 580 565 579 566 580 565 582 563 581 564 577 568 574 561 582 563 580 565 579 566 1657 613 1664 616 582 563 578 567 575 560 583 562 581 564 580 565 582 563 584 561 582 563 578 567 575 560 583 562 581 564 580 565 1659 621 579 566 578 567 574 561 581 564 579 566 577 568 576 569 577 568 579 566 578 567 574 561 580 565 578 567 576 569 575 560 587 568 579 566 577 568 573 562 580 565 578 567 576 569 575 560 586 569 552 593 577 568 573 562 580 565 577 568 576 559 585 560 586 569 552 593 576 569 1703 567 575 560 1713 567 577 568 576 569 577 568 553 592 578 567 1704 566 1707 563 1656 614 1662 618 1659 621 577 568 553 592 1706 564 # -# file: Flipper-IRDB/ACs\Samsung\Samsung_AC_AR12K.ir -# name: POWER type: raw frequency: 38000 @@ -946,16 +836,12 @@ frequency: 38000 duty_cycle: 0.330000 data: 701 17814 3056 8923 554 441 522 1496 492 504 490 505 499 497 497 498 496 500 494 502 492 503 501 1491 497 498 496 500 494 1497 502 494 500 523 471 1520 468 1523 496 1496 492 1499 500 1492 496 499 495 501 493 503 501 494 500 496 498 497 497 499 495 501 493 502 492 531 473 522 472 524 470 525 490 506 498 498 496 499 495 501 493 503 491 504 500 495 499 497 497 499 495 500 494 502 492 504 500 495 499 497 497 525 469 527 467 528 466 530 495 501 493 1498 501 1491 497 1494 494 1498 500 2972 3004 8948 518 1500 499 470 524 498 496 500 494 529 465 531 473 522 493 530 464 505 489 1502 497 499 495 501 493 1498 501 1491 497 1494 494 1498 501 495 499 1492 496 1522 497 1495 493 502 492 1500 499 497 497 1494 494 1497 502 495 499 496 498 498 496 1496 492 1499 500 1518 470 526 468 527 498 498 496 500 494 501 493 503 491 505 499 1492 496 1495 493 1498 501 495 499 497 497 499 495 500 494 502 492 1527 472 523 523 473 490 506 498 497 497 499 495 1497 491 1500 499 1492 496 1496 492 # -# file: Flipper-IRDB/ACs\Samsung\Samsung_Wind-Free.ir -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 606 17832 2994 8936 520 501 496 1491 494 501 496 498 489 532 465 529 488 505 492 502 495 499 488 1499 496 499 498 495 492 1496 499 1463 522 499 498 1463 522 1467 517 1469 526 1491 493 1495 520 500 487 507 490 504 493 500 497 497 490 504 493 501 496 498 489 505 492 501 496 498 499 495 492 502 495 499 498 522 465 529 468 526 492 502 495 499 488 506 491 503 494 499 498 496 491 503 494 500 497 497 490 504 493 500 497 497 490 504 493 500 497 497 490 531 466 528 469 1518 487 1475 520 2947 3018 8939 517 1471 524 496 491 503 494 500 497 497 490 504 493 500 497 497 490 504 493 1521 464 530 467 527 491 1471 514 507 490 1471 524 1465 519 1468 517 1472 523 1465 520 1468 517 477 520 501 496 497 490 531 466 528 469 525 493 501 496 498 489 505 492 502 495 498 499 495 492 502 495 499 498 495 492 502 495 499 498 496 491 502 495 499 498 496 491 529 468 526 471 523 495 499 488 506 491 503 494 499 498 496 491 503 494 500 497 496 491 503 494 500 497 497 490 503 494 2973 2992 8939 517 1469 526 522 465 529 488 506 491 503 494 499 488 506 491 503 494 500 497 1490 495 499 498 496 491 1497 498 1464 520 1468 517 1470 525 524 463 1498 517 1471 524 1465 520 1468 517 1471 524 1465 520 1468 517 1472 523 497 490 504 493 501 496 1491 494 1496 519 1469 516 504 493 501 496 498 489 505 492 501 496 498 499 495 492 502 495 1492 493 1469 526 495 492 529 468 1492 513 1476 519 502 495 498 489 505 492 502 495 499 498 496 491 503 494 499 498 496 491 1497 498 1464 541 # -# file: Flipper-IRDB/ACs\Toshiba\Toshiba_RAS13SKV2E.ir -# name: POWER type: raw frequency: 38000 @@ -968,8 +854,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 4391 4345 555 1605 556 1604 547 1613 548 1611 550 530 550 529 551 1609 552 527 553 527 553 526 554 526 554 525 555 1604 547 1613 548 531 549 1611 550 529 551 529 551 529 551 528 552 527 553 526 554 1605 556 1603 548 1612 549 1611 550 1609 552 1608 553 1607 554 1605 556 524 556 524 556 523 547 533 547 533 547 532 548 531 549 530 550 529 551 1608 553 527 553 1606 555 1605 556 523 547 533 547 533 547 533 547 532 548 531 549 530 550 1609 552 527 553 527 553 527 553 526 554 1605 556 523 557 523 547 533 547 533 547 532 548 531 549 530 550 530 550 529 551 1608 553 526 554 526 554 526 554 525 555 524 556 523 547 7457 4390 4347 553 1608 553 1606 555 1605 556 1604 547 533 547 532 548 1612 549 530 550 530 550 529 551 529 552 528 552 1607 554 1605 556 524 556 1603 548 532 548 532 548 532 548 531 549 530 550 529 551 1608 553 1606 555 1605 556 1604 547 1613 548 1611 550 1610 551 1609 552 527 553 527 553 527 553 526 554 526 554 525 555 524 556 524 556 523 547 1612 549 531 549 1610 551 1609 552 527 553 527 553 527 553 526 554 526 554 525 555 524 556 1603 548 532 548 532 548 532 548 531 549 1610 551 528 552 528 552 528 552 527 553 526 554 525 555 525 555 524 556 523 547 1613 548 531 549 531 549 531 549 530 550 529 551 528 552 # -# file: Flipper-IRDB/ACs\Toshiba\Toshiba_RG57H4.ir -# name: POWER type: raw frequency: 38000 @@ -982,26 +866,21 @@ frequency: 38000 duty_cycle: 0.330000 data: 4413 4349 566 1580 567 505 568 1577 570 502 571 501 572 526 537 1582 565 507 566 506 567 504 569 503 570 501 562 510 563 535 538 507 566 1579 568 1577 570 1575 572 1573 564 1582 565 1581 566 1579 568 1578 569 1576 571 1574 563 1583 564 1582 565 1580 567 1578 569 1577 570 1575 572 1573 564 1582 565 1581 566 1579 568 1578 569 1576 571 1574 563 1583 564 1581 566 506 567 1604 543 1576 571 1574 563 1583 564 1581 566 506 567 505 568 5164 4405 4357 569 502 571 1574 563 510 563 1582 565 1580 567 1578 569 503 570 1575 572 1573 564 1582 565 1580 567 1579 568 1577 570 1575 572 1573 564 509 564 508 565 506 567 505 568 503 570 502 571 526 537 509 564 508 565 506 567 505 568 503 570 501 572 500 563 509 564 507 566 506 567 504 569 503 570 501 572 499 564 508 565 507 566 505 568 504 569 1575 572 500 563 509 564 507 566 506 567 504 569 1576 571 1574 563 # -# file: Flipper-IRDB/ACs\Vornado\Vornado.ir -# name: TIMER type: raw frequency: 38000 duty_cycle: 0.330000 data: 1296 454 1294 422 441 1304 1318 427 1321 422 441 1302 446 1297 440 1305 1317 426 437 1306 442 1301 436 7690 1321 424 1324 419 444 1301 1321 424 1324 420 443 1299 438 1304 444 1302 1320 423 440 1302 446 1297 440 7686 1325 420 1317 426 437 1308 1324 420 1317 426 437 1305 443 1300 437 1308 1324 419 444 1298 439 1304 444 7682 1318 427 1321 422 441 1304 1318 427 1321 423 471 1271 466 1277 471 1274 1317 427 467 1275 472 1270 467 7675 1325 420 1317 426 468 1277 1324 421 1316 427 436 1306 442 1301 467 1278 1323 420 443 1300 437 1305 474 7653 1316 429 1319 425 438 1306 1326 420 1317 425 438 1305 443 1300 437 1308 1324 419 444 1298 439 1304 443 7682 1318 427 1321 423 440 1305 1317 428 1320 423 471 1272 465 1277 439 1306 1316 427 467 1276 440 1302 446 7680 1320 426 1322 421 473 1272 1318 426 1322 422 472 1270 467 1276 472 1273 1317 426 468 1274 474 1269 468 7658 1321 424 1324 420 464 1281 1320 425 1354 389 464 1279 469 1274 474 1272 1318 424 470 1273 464 1279 468 7657 1322 423 1325 418 466 1280 1352 392 1345 400 463 1278 469 1273 464 1281 1351 394 469 1271 466 1277 470 7656 1323 422 1315 427 467 1278 1344 401 1347 399 464 1276 471 1272 465 1280 1321 422 472 1270 467 1276 472 7654 1325 421 1316 426 437 1308 1324 421 1316 427 436 1307 441 1302 445 1299 1323 421 442 1300 468 1274 474 # -# file: Flipper-IRDB/ACs\Whynter\Whynter_AC.ir -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 781 710 2930 2876 775 716 781 735 752 2175 779 711 776 2177 746 745 773 2232 753 2173 749 768 750 2177 745 745 773 743 754 737 750 741 746 744 754 737 771 746 751 739 748 2178 776 742 755 2172 771 719 778 2227 747 744 754 2200 754 737 750 2203 751 741 746 2181 773 744 753 737 750 741 746 # -# Old SAMSUNG AC -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 3027 9036 541 1580 484 588 491 556 492 555 482 564 484 589 459 587 481 565 483 564 484 1583 492 555 482 564 484 589 479 1561 514 1527 517 583 485 1555 489 1552 513 1581 484 1531 513 534 514 585 463 584 484 562 486 561 486 560 488 585 483 589 479 567 512 561 486 560 488 559 489 558 490 583 485 561 487 560 488 558 490 1578 486 1580 484 562 517 1577 487 559 489 558 490 583 485 1555 509 564 484 563 485 1582 483 1532 543 1576 488 559 489 584 464 583 485 587 492 555 482 564 432 1924 2973 9041 536 1531 513 559 489 584 484 563 516 557 491 556 481 591 488 559 489 558 490 1577 487 559 489 558 490 1577 487 1580 484 1530 514 1553 512 562 485 1555 509 1531 513 1555 509 1558 507 1534 510 1557 518 1524 509 1557 518 555 493 555 513 559 488 558 490 583 485 561 486 560 488 559 489 584 484 562 486 561 486 560 487 585 483 1557 487 1554 510 1557 507 1533 511 1557 538 1528 516 1578 455 591 488 559 489 558 489 557 491 582 486 560 487 559 488 584 484 562 517 1524 509 1558 465 +# diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index a07f8a7e90..958dbf3b87 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1,19 +1,6 @@ Filetype: IR signals file Version: 1 -# -# This file has all the Speakers, SoundBars and Audio Receivers. POWER,MUTE,VOL+/- buttons -# from https://github.com/UberGuidoZ/Flipper-IRDB -# Some Buttons was labeled PowerToggle,Pwr, Sleep or Off. These was assumed to be POWER functions. -# While Care was taken to remove all possible duplicates, some may still be lurking. -##################################################### -# HUGE thank you to Amec0e for continued maintenance! -##################################################### -# -# Updated 26th August 2022 -# -# | SPEAKERS | -# -# Audioengine +# Last Updated 27th Aug, 2022 # name: POWER type: parsed @@ -39,8 +26,6 @@ protocol: NECext address: 00 FD 00 00 command: 07 F8 00 00 # -# BOSE -# name: POWER type: raw frequency: 38000 @@ -101,8 +86,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 1012 1503 483 514 489 1475 511 483 510 486 517 478 515 481 512 483 510 486 517 1473 513 508 485 1480 516 1475 511 1479 507 1483 513 1477 509 1480 588 50646 1012 1476 510 512 491 1473 513 508 485 485 508 488 515 480 513 482 511 512 481 1482 514 482 511 1480 516 1473 513 1478 508 1482 514 1476 510 1479 590 50651 1007 1507 489 507 485 1478 508 514 489 506 487 509 484 485 508 488 515 506 487 1503 483 513 490 1474 512 1478 508 1483 513 1477 509 1481 515 1473 513 50721 1009 1505 491 478 515 1475 511 510 483 486 517 478 515 507 486 483 510 512 491 1472 514 508 485 1505 491 1473 513 1477 509 1481 587 1403 510 1478 508 50733 1008 1506 490 479 514 1477 509 512 481 514 489 506 487 508 485 484 509 513 490 1473 513 509 483 1481 515 1474 512 1479 507 1482 514 1476 510 1478 590 50642 1006 1508 488 508 485 1478 508 487 516 479 514 481 512 510 483 486 517 504 489 1474 512 510 483 1482 514 1475 511 1479 507 1483 513 1477 509 1480 516 # -# Craig -# name: POWER type: parsed protocol: NEC @@ -187,8 +170,6 @@ protocol: NEC address: 00 00 00 00 command: 09 00 00 00 # -# EDIFIER -# name: POWER type: parsed protocol: NECext @@ -212,7 +193,7 @@ type: parsed protocol: NECext address: 78 0E 00 00 command: 09 F6 00 00 -# +# name: VOL+ type: parsed protocol: NECext @@ -225,16 +206,12 @@ protocol: NECext address: 78 0E 00 00 command: 02 FD 00 00 # -# GENEVA -# name: VOL- type: parsed protocol: NEC address: 00 00 00 00 command: 06 00 00 00 # -# KLIPSCH -# name: POWER type: parsed protocol: NEC @@ -259,8 +236,6 @@ protocol: NEC address: 02 00 00 00 command: 07 00 00 00 # -# JBL -# name: VOL+ type: parsed protocol: NEC @@ -315,8 +290,6 @@ protocol: NECext address: 40 AF 00 00 command: 19 E6 00 00 # -# JVC -# name: VOL+ type: parsed protocol: NECext @@ -341,8 +314,6 @@ protocol: NECext address: 02 BD 00 00 command: AD 52 00 00 # -# SONY -# name: POWER type: parsed protocol: SIRC @@ -361,9 +332,6 @@ protocol: SIRC address: 10 00 00 00 command: 13 00 00 00 # -# -# STEJES -# name: POWER type: parsed protocol: NECext @@ -387,9 +355,6 @@ type: parsed protocol: NECext address: 85 23 00 00 command: 47 B8 00 00 -# -# -# CREATIVE # name: POWER type: parsed @@ -403,10 +368,6 @@ protocol: NEC address: 08 00 00 00 command: 16 00 00 00 # -# | SOUNDBARS | -# -# Audac -# name: VOL+ type: parsed protocol: NECext @@ -419,8 +380,6 @@ protocol: NECext address: 86 FF 00 00 command: 2B D4 00 00 # -# BOSE -# name: VOL+ type: parsed protocol: NECext @@ -493,8 +452,6 @@ protocol: NECext address: BA 4B 00 00 command: 01 FE 00 00 # -# BRAND UNKNOWN -# name: VOL+ type: parsed protocol: NECext @@ -536,8 +493,6 @@ type: parsed protocol: NECext address: 83 22 00 00 command: 08 F7 00 00 -# -# COMHEAR # name: VOL+ type: parsed @@ -550,7 +505,7 @@ type: parsed protocol: NECext address: 0A 1D 00 00 command: 0A F5 00 00 -# +# name: MUTE type: parsed protocol: NECext @@ -562,8 +517,6 @@ type: parsed protocol: NECext address: 0A 1D 00 00 command: 01 FE 00 00 -# -# CREATIVE # name: VOL+ type: parsed @@ -583,8 +536,6 @@ protocol: NEC address: 20 00 00 00 command: 1E 00 00 00 # -# KLIPSCH -# name: MUTE type: parsed protocol: NEC @@ -603,8 +554,6 @@ protocol: NEC address: 80 00 00 00 command: 06 00 00 00 # -# LG -# name: VOL+ type: parsed protocol: Samsung32 @@ -617,8 +566,6 @@ protocol: Samsung32 address: 2C 00 00 00 command: 16 00 00 00 # -# ONN -# name: VOL+ type: parsed protocol: NECext @@ -643,8 +590,6 @@ protocol: NECext address: 83 22 00 00 command: 15 EA 00 00 # -# PANASONIC -# name: VOL+ type: raw frequency: 38000 @@ -669,8 +614,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 3486 1728 448 448 420 1318 419 423 445 451 417 452 416 454 425 444 424 445 423 446 422 447 421 448 420 421 447 449 419 1319 418 451 417 453 415 453 426 444 424 445 423 446 422 447 421 1317 420 449 419 1319 418 451 417 452 416 453 415 454 425 445 423 446 422 447 421 447 421 421 447 1291 446 423 445 425 443 1322 415 1322 425 444 424 445 423 446 422 1289 448 448 420 422 446 1292 445 451 417 452 416 1322 415 74924 3486 1755 421 447 421 1317 420 449 419 450 418 451 417 452 416 453 415 454 425 417 451 445 423 446 422 420 448 448 420 1317 420 450 418 451 417 452 416 426 442 427 452 444 424 445 423 1315 422 447 421 1317 420 449 419 450 418 451 417 425 443 453 415 454 425 444 424 418 450 446 422 1315 422 448 420 421 447 1291 446 1319 418 451 417 452 416 454 414 1323 424 445 423 419 449 1316 421 422 446 450 418 1293 444 74912 3487 1755 421 448 420 1290 447 423 445 451 417 452 416 453 415 454 425 445 423 446 422 446 422 447 421 421 447 449 419 1319 418 452 416 426 442 454 425 444 424 445 423 446 422 447 421 1290 447 449 419 1319 418 452 416 452 416 453 415 427 451 445 423 446 422 447 421 448 420 449 419 1319 418 424 444 452 416 1322 415 1323 424 444 424 445 423 446 422 1317 420 449 419 423 445 1320 417 453 415 427 452 1313 424 # -# POLK AUDIO -# name: POWER type: parsed protocol: NECext @@ -695,27 +638,24 @@ protocol: NECext address: C8 91 00 00 command: 1F E0 00 00 # -# PHILLIPS -# name: VOL+ type: parsed protocol: RC6 address: 10 00 00 00 command: 10 00 00 00 -# +# name: VOL- type: parsed protocol: RC6 address: 10 00 00 00 command: 11 00 00 00 +# name: POWER type: parsed protocol: RC6 address: 10 00 00 00 command: 0C 00 00 00 # -# SAMSUNG -# name: VOL+ type: raw frequency: 38000 @@ -739,7 +679,7 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 4492 4434 510 505 486 505 486 504 487 503 488 1481 511 1484 518 499 492 498 493 1476 516 1479 513 1483 519 1469 596 402 516 500 491 499 492 498 493 4447 518 498 493 497 483 507 484 506 485 504 487 503 488 494 517 1485 486 1483 519 1476 516 1480 512 504 486 1508 484 1486 517 1479 565 425 513 502 488 501 490 492 509 1467 515 -# +# name: VOL+ type: raw frequency: 38000 @@ -824,8 +764,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 4555 4483 516 516 488 519 495 512 492 515 489 1525 493 1519 489 518 496 511 493 1521 487 1525 493 1520 488 1524 494 513 491 517 487 520 494 514 490 4501 519 513 491 516 488 520 494 513 491 517 487 521 493 514 490 518 486 1527 491 1522 496 1517 491 516 488 1525 493 1520 488 1525 493 1520 488 519 495 512 492 516 488 1525 493 # -# SENNHEISER -# name: VOL+ type: parsed protocol: RC5 @@ -850,8 +788,6 @@ protocol: RC5 address: 13 00 00 00 command: 0C 00 00 00 # -# SONY -# name: VOL+ type: parsed protocol: SIRC @@ -924,8 +860,6 @@ protocol: SIRC15 address: 30 00 00 00 command: 14 00 00 00 # -# TCL -# name: POWER type: parsed protocol: NECext @@ -938,8 +872,6 @@ protocol: NECext address: 86 FF 00 00 command: 1D E2 00 00 # -# TAOTRONICS -# name: VOL+ type: parsed protocol: NEC @@ -964,9 +896,6 @@ protocol: NEC address: 80 00 00 00 command: 1E 00 00 00 # -# TEUFEL -# -# name: POWER type: parsed protocol: NECext @@ -991,8 +920,6 @@ protocol: NECext address: EF 01 00 00 command: 28 D7 00 00 # -# VIZIO -# name: POWER type: parsed protocol: NEC @@ -1017,8 +944,6 @@ protocol: NEC address: 00 00 00 00 command: 48 00 00 00 # -# XIAOMI -# name: VOL+ type: raw frequency: 38000 @@ -1043,8 +968,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 1051 550 627 1135 626 551 626 1136 625 845 619 850 624 553 675 794 629 842 622 555 622 555 622 13780 1047 555 622 1140 621 557 620 1141 620 850 624 845 619 558 619 850 624 846 618 559 618 559 618 13782 1045 558 619 1143 618 559 618 1144 627 842 622 847 627 550 627 842 622 848 626 551 626 551 626 13774 1053 549 618 1144 627 550 627 1135 626 843 621 849 625 551 626 844 620 850 624 553 624 552 625 13776 1051 551 626 1137 624 553 624 1138 623 846 618 851 623 554 623 846 628 841 623 554 623 554 623 13776 1051 551 626 1136 625 552 625 1137 624 845 619 850 624 553 624 846 618 852 622 555 622 554 623 13778 1049 554 623 1139 622 555 622 1140 621 849 625 844 620 557 620 850 624 846 618 559 618 558 619 # -# YAMAHA -# name: POWER type: parsed protocol: NEC @@ -1069,10 +992,6 @@ protocol: NEC address: 7A 00 00 00 command: 1C 00 00 00 # -# | Audio Receivers | -# -# Denon -# name: POWER type: raw frequency: 38000 @@ -1103,8 +1022,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 275 762 271 1800 277 786 278 784 249 813 241 795 248 814 219 817 247 789 254 1818 249 1824 274 1798 279 1820 278 759 274 788 245 43887 274 789 275 1798 279 783 250 812 252 784 249 1823 274 1798 279 1820 247 1826 271 765 278 809 224 812 252 784 249 1823 275 1798 279 43880 281 782 251 1821 277 760 273 789 244 818 246 790 253 808 246 791 252 809 224 1822 275 1797 280 1819 248 1825 273 790 253 808 246 # -# NAD -# name: POWER type: raw frequency: 39105 @@ -1116,21 +1033,19 @@ type: raw frequency: 39105 duty_cycle: 0.330000 data: 5472 53216 8899 4450 563 1662 563 1662 563 1662 563 563 563 563 563 563 563 563 563 1662 563 563 563 563 563 1662 563 1662 563 1662 563 1662 563 1662 563 563 563 563 563 563 563 563 563 1662 563 563 563 563 563 563 563 1662 563 1662 563 1662 563 1662 563 563 563 1662 563 1662 563 1662 563 563 563 38358 8899 2199 563 95052 -# +# name: VOL- type: raw frequency: 39105 duty_cycle: 0.330000 data: 5472 53344 8899 4424 563 1662 563 1662 563 1662 563 563 563 563 563 563 563 563 563 1662 563 563 563 563 563 1662 563 1662 563 1662 563 1662 563 1662 563 563 563 563 563 563 563 1662 563 1662 563 563 563 563 563 563 563 1662 563 1662 563 1662 563 563 563 563 563 1662 563 1662 563 1662 563 563 563 38358 8899 2225 563 95052 -# +# name: MUTE type: raw frequency: 39105 duty_cycle: 0.330000 data: 5498 53523 8899 4450 563 1662 563 1662 563 1662 563 563 563 563 563 563 563 563 563 1662 563 563 563 563 563 1662 563 1662 563 1662 563 1662 563 1662 563 563 563 563 563 563 563 1662 563 563 563 1662 563 563 563 563 563 1662 563 1662 563 1662 563 563 563 1662 563 563 563 1662 563 1662 563 563 563 38358 8899 2199 563 95052 # -# Onkyo -# name: POWER type: parsed protocol: NECext @@ -1179,8 +1094,6 @@ protocol: NECext address: D2 03 00 00 command: 05 FA 00 00 # -# PHILLIPS -# name: POWER type: parsed protocol: RC5 @@ -1199,8 +1112,6 @@ protocol: RC5 address: 14 00 00 00 command: 10 00 00 00 # -# REGA -# name: MUTE type: parsed protocol: RC5 @@ -1219,8 +1130,6 @@ protocol: RC5 address: 10 00 00 00 command: 11 00 00 00 # -# SONY -# name: POWER type: parsed protocol: SIRC15 @@ -1251,8 +1160,6 @@ protocol: SIRC15 address: 10 00 00 00 command: 13 00 00 00 # -# YAMAHA -# name: POWER type: parsed protocol: NECext @@ -1312,3 +1219,4 @@ type: parsed protocol: NEC address: 78 00 00 00 command: 1F 00 00 00 +# diff --git a/assets/resources/infrared/assets/fans.ir b/assets/resources/infrared/assets/fans.ir index cec82bf178..00062b3756 100644 --- a/assets/resources/infrared/assets/fans.ir +++ b/assets/resources/infrared/assets/fans.ir @@ -1,27 +1,6 @@ Filetype: IR signals file Version: 1 -# -# Created by amec0e with help from Edhel90 -# Special Thanks to Darmiel for the scrape script! -# -# Last Updated 26th Aug, 2022 -# -# Some Power functions was labelled Power,pwr,pwr_on/off,sleep,power_toggle,fan_power -# These was assumed to be POWER functions and added to the file. -# -# Some Rotate functions was labelled turn,tilt,horizontal_move,oscx,osc_hor these -# Was assumed to be ROTATE functions and added to the file. -# -# Some Speed functions was labelled speed,fan_speed,strength,slower,faster these -# Was assumed to be SPEED functions and added to the file. -# -# (Only added horizontal movement as it is the most common form of rotate for most fans) -# -# As such you may encounter some odd behaviour when using SOME power,rotate and speed -# functions. If you do, let me know and I will try my best to fix the issue! -# -# -# file: Flipper-IRDB/Fans\Big_Ass_Fans_Haiku.ir +# Last Updated 27th Aug, 2022 # name: POWER type: parsed @@ -29,23 +8,17 @@ protocol: NECext address: BA F0 00 00 command: 03 FC 00 00 # -name: SPEED- +name: SPEED+ type: parsed protocol: NECext address: BA F0 00 00 -command: 41 BE 00 00 +command: 50 AF 00 00 # name: SPEED- type: parsed protocol: NECext -address: 80 DE 00 00 -command: 10 EF 00 00 -# -name: SPEED+ -type: parsed -protocol: NECext address: BA F0 00 00 -command: 50 AF 00 00 +command: 41 BE 00 00 # name: TIMER type: parsed @@ -59,14 +32,6 @@ protocol: NECext address: BA F0 00 00 command: 53 AC 00 00 # -name: SPEED- -type: parsed -protocol: NEC -address: 80 00 00 00 -command: 9F 00 00 00 -# -# file: Flipper-IRDB/Fans\Generic_Floor_Fan.ir -# name: POWER type: raw frequency: 38000 @@ -91,8 +56,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 9038 4530 589 1665 590 559 594 555 598 551 613 510 592 558 595 553 590 532 590 559 594 1686 590 1690 617 1637 598 1683 593 1687 620 1634 591 1691 595 1685 622 1632 593 557 596 1684 592 530 592 557 596 552 591 558 616 506 596 553 590 1690 596 526 596 1684 592 1688 588 1692 563 1690 596 1684 592 1687 620 503 589 1691 595 553 621 501 591 558 595 553 590 532 590 558 595 1689 597 551 623 1630 595 1686 590 1689 587 1666 589 # -# file: Flipper-IRDB/Fans\Amazon\Amazon_Basics_Fan.ir -# name: POWER type: raw frequency: 38000 @@ -117,8 +80,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 4606 4604 546 1509 541 1516 544 1512 548 1509 541 1516 544 1512 548 2554 546 1510 540 1517 543 2559 541 1515 545 2557 543 2558 542 1514 546 1511 539 1517 543 1512 4607 4601 539 1516 544 1513 547 1509 541 1516 544 1512 548 1508 542 2561 539 1516 544 1513 547 2555 545 1511 538 2589 522 2555 545 1511 539 1518 542 1515 545 13389 9233 2301 542 51673 9227 2306 547 # -# file: Flipper-IRDB/Fans\Black_and_Decker\Black_and_Decker_BFSR16W.ir -# name: ROTATE type: raw frequency: 38000 @@ -131,8 +92,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 1280 394 1280 420 411 1236 1269 430 1254 419 412 1235 438 1234 439 1233 440 1233 440 1233 1272 427 415 8311 1279 395 1278 420 411 1236 1269 430 1243 430 412 1234 439 1234 439 1233 440 1233 440 1233 1272 427 415 8312 1277 396 1277 422 409 1264 1252 421 1252 421 410 1236 437 1235 438 1233 440 1259 414 1259 1246 427 415 8312 1277 422 1251 423 408 1264 1251 423 1250 423 408 1238 435 1237 436 1237 436 1263 410 1237 1278 421 410 8315 1274 425 1248 425 406 1240 1276 424 1249 424 407 1265 408 1238 435 1264 409 1237 436 1237 1279 421 410 8318 1271 402 1271 428 414 1233 1272 427 1246 427 415 1231 432 1241 432 1240 433 1240 433 1240 1276 424 407 8319 1271 429 1245 428 414 1233 1272 428 1245 427 415 1231 442 1231 432 1240 433 1240 433 1239 1277 423 408 8318 1271 401 1272 427 415 1232 1273 427 1246 426 405 1267 406 1240 433 1239 434 1238 435 1238 1278 422 409 8317 1272 401 1272 426 405 1242 1274 426 1248 425 406 1240 433 1239 434 1238 435 1238 435 1238 1278 421 410 8317 1272 401 1272 426 405 1242 1274 425 1249 425 406 1240 434 1239 434 1238 435 1238 435 1238 1278 421 410 8316 1273 400 1273 426 405 1241 1275 425 1248 425 406 1239 434 1239 434 1238 435 1238 435 1238 1278 421 410 # -# file: Flipper-IRDB/Fans\Brandson\Brandson_fan_303352.ir -# name: POWER type: raw frequency: 38000 @@ -157,8 +116,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 1342 366 1370 339 511 1191 1373 364 1343 364 511 1165 540 1165 514 1192 1371 364 484 1219 485 1220 484 8036 1339 370 1337 371 478 1227 1336 371 1336 371 478 1227 478 1227 478 1227 1336 372 477 1227 478 1227 478 9162 1336 372 1335 372 477 1228 1335 372 1335 373 476 1228 477 1228 477 1228 1336 372 477 1228 477 1228 476 8044 1336 372 1335 373 476 1228 1335 398 1309 398 451 1254 451 1254 451 1255 1308 400 449 1255 450 1256 449 9188 1306 403 1304 428 421 1260 1303 428 1279 429 419 1284 421 1284 420 1284 1279 429 420 1285 420 1284 420 8099 1276 457 1250 457 391 1313 1225 483 1224 484 364 1338 366 1338 392 1313 1225 484 364 1339 366 1339 390 9244 1225 509 1198 510 338 1366 1197 510 1197 537 311 1367 338 1393 311 1394 1169 591 256 11618 1170 539 1168 565 282 1395 1169 565 1142 538 310 1341 365 1312 419 1259 1305 400 449 1254 450 1255 449 9186 1307 400 1306 400 448 1255 1307 399 1307 400 448 1255 449 1255 449 1255 1307 400 448 1255 449 1255 449 8068 1306 400 1306 400 448 1256 1306 400 1306 401 447 1256 448 1256 448 1256 1306 401 447 1256 448 1257 447 # -# file: Flipper-IRDB/Fans\Brandson\Brandson_Fan_304997.ir -# name: POWER type: raw frequency: 38000 @@ -189,8 +146,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 1282 413 1276 445 409 1260 1274 450 1249 445 410 1259 430 1265 434 1261 438 1258 1276 445 409 1285 404 8017 1274 420 1279 442 412 1283 1251 448 1251 443 411 1283 406 1290 409 1260 439 1256 1278 443 411 1284 405 8015 1276 418 1281 440 404 1291 1253 446 1253 440 404 1291 408 1287 412 1283 406 1263 1281 440 404 1291 408 8011 1280 414 1275 446 408 1287 1247 452 1247 447 407 1261 438 1283 406 1289 410 1259 1275 447 407 1287 412 8006 1275 446 1253 441 403 1292 1252 447 1252 442 402 1292 407 1288 411 1284 405 1291 1253 442 402 1292 407 # -# file: Flipper-IRDB/Fans\Co_Tech\CO_TECH_towerfan.ir -# name: POWER type: parsed protocol: NEC @@ -221,8 +176,6 @@ protocol: NEC address: 30 00 00 00 command: 95 00 00 00 # -# file: Flipper-IRDB/Fans\Daewoo\Daewoo_DDV200.ir -# name: POWER type: parsed protocol: NEC @@ -247,8 +200,6 @@ protocol: NEC address: 00 00 00 00 command: 1C 00 00 00 # -# file: Flipper-IRDB/Fans\Dyson\Dyson_Air_Multiplier.ir -# name: POWER type: raw frequency: 38000 @@ -273,24 +224,18 @@ frequency: 38000 duty_cycle: 0.330000 data: 2229 714 750 747 727 717 757 713 751 719 755 715 749 1455 751 719 755 715 749 1455 751 1453 753 717 757 714 750 1454 752 718 756 714 750 746 728 742 722 722 752 1452 754 716 758 1445 751 50982 2229 716 727 1479 748 51048 2205 712 752 1450 756 # -# file: Flipper-IRDB/Fans\Dyson\Dyson_Air_Purifier_Fan.ir -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 2258 688 781 718 751 694 775 696 784 687 782 690 779 1427 782 690 779 693 776 1431 778 721 748 724 756 716 753 719 750 722 747 725 744 727 773 1407 781 1426 783 1425 774 1433 776 696 773 51015 2224 748 721 1458 783 51084 2249 697 783 1425 784 51089 2253 694 775 1432 756 # -# file: Flipper-IRDB/Fans\Dyson\Dyson_AM06_33_Fan.ir -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 2212 836 751 1591 749 825 752 817 750 1577 753 806 750 804 752 796 750 857 751 828 749 825 752 816 751 813 743 816 751 803 743 805 752 102392 2214 834 743 1599 751 823 744 825 752 1575 745 840 727 801 745 804 752 854 744 835 752 822 745 824 743 821 746 813 743 810 746 802 744 # -# file: Flipper-IRDB/Fans\Dyson\Dyson_AM07.ir -# name: POWER type: raw frequency: 38000 @@ -303,8 +248,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 2216 836 750 1594 754 821 754 816 749 1580 747 813 752 803 751 798 746 1626 753 827 748 1591 746 824 751 1578 749 811 754 1566 750 799 745 99411 2218 833 753 1591 746 829 746 823 752 1577 749 810 755 800 754 795 749 1623 745 835 751 1588 749 821 754 1574 752 807 747 1572 755 795 749 # -# file: Flipper-IRDB/Fans\Dyson\Dyson_AM09.ir -# name: POWER type: raw frequency: 38000 @@ -323,8 +266,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 2221 729 752 725 746 727 754 1377 751 1375 753 706 755 699 751 697 753 753 749 729 752 1384 755 1377 751 713 747 711 749 1367 751 1361 746 101691 2216 734 747 731 750 723 748 1383 745 1381 747 711 749 705 745 703 747 759 754 725 746 1390 749 1383 756 708 752 706 754 1362 745 1366 752 # -# file: Flipper-IRDB/Fans\Dyson\Dyson_Cool_Fan.ir -# name: POWER type: raw frequency: 38000 @@ -343,8 +284,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 2217 832 750 1594 753 821 750 819 752 1576 750 809 804 750 800 748 750 1622 756 1587 749 1589 747 1586 750 1578 748 1575 751 1568 747 802 748 101181 2218 831 751 1592 755 819 752 817 754 1574 752 808 753 801 749 800 751 1620 748 1596 751 1587 749 1584 752 1576 750 1574 752 1566 749 800 803 # -# file: Flipper-IRDB/Fans\Dyson\Dyson_Fan_HP04.ir -# name: POWER type: raw frequency: 38000 @@ -357,8 +296,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 2225 712 747 719 751 716 754 713 757 711 748 1451 748 718 752 715 754 712 747 1451 748 718 752 716 754 1445 754 1444 724 1449 750 716 754 713 746 1453 746 720 749 1450 749 1451 727 1446 753 50693 2219 717 752 1445 754 50927 2194 714 756 1442 747 # -# file: Flipper-IRDB/Fans\Dyson\Dyson_HP01.ir -# name: POWER type: raw frequency: 38000 @@ -371,8 +308,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 2213 737 751 727 750 1387 746 1385 748 716 751 707 749 704 752 696 750 1420 754 724 753 720 747 721 746 718 749 1373 749 1367 745 703 753 102141 2215 735 753 726 751 1385 747 1384 748 715 752 706 750 704 752 695 751 1419 755 723 754 720 747 721 746 718 749 1399 723 1367 755 693 753 # -# file: Flipper-IRDB/Fans\Dyson\Dyson_HP09.ir -# name: POWER type: raw frequency: 38000 @@ -385,8 +320,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 33 2225 718 750 719 749 721 747 722 746 723 745 1458 750 720 748 722 726 744 724 1452 756 741 727 742 726 1451 746 1457 750 1454 754 716 752 717 720 1483 725 745 723 1454 754 1450 747 1456 752 50811 2199 744 745 1433 754 51049 2229 715 743 1435 752 # -# file: Flipper-IRDB/Fans\Dyson\Dyson_Pure_HotCool_HP02.ir -# name: SPEED+ type: raw frequency: 38000 @@ -405,8 +338,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 2247 750 729 1447 782 1450 748 722 726 1506 723 720 748 722 757 713 776 772 728 769 751 1505 755 1476 753 1452 756 740 749 747 753 1452 756 101517 2220 749 719 1457 772 1433 754 715 753 1478 719 750 729 715 753 716 773 776 724 772 748 1508 752 1479 750 1481 727 769 731 739 750 1454 754 50114 2228 742 726 1450 779 50645 2197 746 722 1454 775 # -# file: Flipper-IRDB/Fans\Equatlon\Equatlon_Fan.ir -# name: POWER type: raw frequency: 38000 @@ -419,8 +350,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 1279 430 1247 436 413 1270 1256 427 1250 432 406 1277 410 1273 414 1269 408 1275 1251 432 406 1277 410 7983 1284 425 1252 430 408 1275 1251 431 1256 426 412 1270 407 1250 437 1272 415 1242 1274 435 414 1270 407 9092 1275 433 1254 428 410 1273 1253 428 1249 434 415 1268 409 1274 413 1269 408 1276 1250 432 406 1277 410 7984 1283 425 1252 431 407 1275 1251 431 1256 426 412 1270 407 1276 411 1272 415 1241 1275 435 414 1269 408 9090 1277 431 1256 426 412 1270 1256 426 1251 431 407 1275 412 1270 407 1276 411 1272 1254 428 410 1273 414 7978 1278 430 1247 435 414 1269 1247 435 1252 430 408 1274 413 1243 434 1275 412 1271 1255 427 411 1272 415 9082 1275 434 1253 428 410 1273 1253 428 1249 433 405 1277 410 1272 415 1268 409 1274 1252 430 408 1275 412 7980 1276 432 1255 427 411 1271 1255 427 1250 432 406 1276 411 1271 416 1267 410 1247 1279 430 408 1275 412 9085 1282 426 1251 431 407 1276 1250 432 1255 426 412 1270 407 1276 411 1272 415 1268 1247 435 414 1269 408 7985 1282 427 1250 432 406 1277 1249 433 1254 428 410 1272 415 1267 410 1274 413 1269 1257 426 412 1271 406 # -# file: Flipper-IRDB/Fans\Homezest\Homezest_LWTF-04.ir -# name: POWER type: raw frequency: 38000 @@ -445,8 +374,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 9275 4475 608 560 606 563 603 565 601 568 598 570 606 563 603 565 601 567 599 1645 605 1638 602 1642 598 1645 605 1639 601 1642 598 1645 605 1637 603 1641 599 569 607 561 605 1639 601 1642 608 560 606 563 603 565 601 568 598 1644 606 1637 603 565 601 567 599 1644 606 1636 604 1639 601 # -# file: Flipper-IRDB/Fans\Honeywell\Honeywell_Fan_CL18PE.ir -# name: POWER type: raw frequency: 38000 @@ -465,8 +392,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 1248 412 1274 438 405 1284 1245 445 1251 435 408 1281 405 1282 404 1285 411 1251 435 1253 1276 437 406 8011 1242 445 1251 435 408 1255 1274 442 1244 443 410 1278 408 1280 406 1282 435 1254 411 1277 1242 445 408 8011 1242 443 1243 444 409 1279 1250 440 1246 441 412 1277 409 1279 407 1281 405 1282 404 1286 1243 443 410 8008 1245 442 1244 443 410 1278 1251 440 1246 441 402 1286 410 1278 408 1280 406 1256 430 1284 1276 411 411 8006 1247 439 1247 439 404 1285 1244 446 1250 437 406 1282 404 1283 403 1285 411 1278 408 1254 1275 438 405 8013 1251 436 1250 410 433 1282 1247 443 1243 443 410 1279 407 1281 405 1282 404 1258 438 1276 1243 444 409 7981 1272 414 1272 441 412 1250 1269 448 1248 438 405 1257 429 1259 437 1277 429 1232 433 1281 1248 412 431 7986 1267 446 1250 436 407 1255 1274 443 1243 443 410 1253 433 1280 406 1282 404 1258 428 1287 1273 387 435 7981 1272 414 1272 415 438 1276 1243 447 1249 411 432 1282 435 1228 489 1198 436 1278 408 1280 1249 411 432 # -# file: Flipper-IRDB/Fans\Honeywell\Honeywell_Fan_HYF290E4.ir -# name: POWER type: raw frequency: 38000 @@ -479,16 +404,12 @@ frequency: 38000 duty_cycle: 0.330000 data: 1286 406 1282 438 416 1275 1257 435 1263 430 1258 434 410 1282 416 1276 412 1254 444 1248 1284 436 1262 7278 1288 403 1285 435 408 1257 1285 433 1255 438 1260 431 413 1279 409 1283 415 1250 438 1254 1288 405 1283 7285 1281 411 1287 432 412 1253 1289 430 1258 435 1263 429 415 1250 438 1254 444 1248 440 1252 1290 429 1259 7283 1283 408 1290 428 416 1249 1283 436 1262 431 1257 435 408 1256 442 1250 438 1255 443 1248 1284 436 1262 7278 1288 430 1258 435 408 1256 1286 433 1255 437 1261 431 413 1252 436 1282 416 1249 439 1254 1288 404 1284 7282 1284 408 1290 428 416 1249 1283 436 1262 430 1258 434 410 1255 443 1249 439 1253 445 1247 1285 408 1290 # -# file: Flipper-IRDB/Fans\Honeywell\Honeywell_HO-5500RE.ir -# name: TIMER type: raw frequency: 38000 duty_cycle: 0.330000 data: 1276 403 1271 435 412 1241 1270 409 1276 431 1254 427 410 1242 1280 427 1247 433 404 1249 1273 407 430 8123 1273 433 1251 429 408 1245 1277 429 1245 435 1250 430 407 1272 1250 430 1255 426 411 1268 1254 426 411 8117 1279 401 1273 433 404 1249 1273 433 1251 429 1245 435 412 1240 1271 435 1249 431 406 1246 1276 431 406 8122 1274 406 1278 427 410 1270 1252 428 1246 434 1251 429 408 1271 1251 403 1271 436 411 1267 1244 436 411 8116 1279 427 1247 433 404 1275 1247 433 1251 429 1245 434 413 1266 1245 435 1250 430 407 1272 1250 431 406 8121 1274 431 1254 427 410 1269 1253 427 1247 433 1251 429 408 1271 1251 429 1245 434 413 1266 1245 435 412 # -# file: Flipper-IRDB/Fans\Lasko\Lasko_Fan.ir -# name: POWER type: raw frequency: 38000 @@ -507,8 +428,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 1286 424 1251 430 465 1241 1287 423 1252 457 437 1241 465 1242 464 1243 474 1234 472 1235 1314 423 440 8017 1286 451 1255 401 462 1242 1286 452 1254 402 472 1232 474 1233 473 1234 472 1234 493 1241 1287 424 439 8014 1289 422 1284 426 437 1241 1287 451 1255 403 471 1234 472 1234 472 1235 492 1215 491 1242 1286 399 464 8018 1285 426 1280 403 471 1234 1284 454 1252 404 470 1235 471 1236 491 1215 491 1243 526 1181 1285 427 436 8019 1315 423 1262 395 468 1236 1313 400 1286 424 439 1238 489 1218 499 1235 471 1236 470 1236 1282 430 464 8019 1284 401 1284 426 468 1236 1282 404 1281 456 438 1240 466 1240 466 1241 465 1241 465 1242 1286 426 468 8015 1288 424 1261 448 436 1242 1286 426 1259 451 444 1234 472 1234 472 1235 471 1235 471 1236 1282 456 438 # -# file: Flipper-IRDB/Fans\Lasko\Lasko_Fan_Simple.ir -# name: POWER type: raw frequency: 38000 @@ -527,8 +446,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 9091 4292 564 1706 562 569 565 567 567 565 569 562 561 570 564 568 566 565 569 562 561 1708 570 1698 570 1700 568 1728 540 1703 565 1705 563 1706 562 1708 570 1699 569 1700 568 563 571 561 562 569 565 566 568 1701 587 566 568 563 571 561 562 1706 562 1707 561 1708 570 1699 569 562 561 # -# file: Flipper-IRDB/Fans\LeaderPro\LeaderPro_DC_Motor_Floor_Fan.ir -# name: POWER type: raw frequency: 38000 @@ -553,8 +470,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 9005 4457 572 1673 572 559 569 561 567 563 565 566 562 567 571 558 570 560 568 562 566 1676 569 1673 572 1698 537 1708 537 1704 541 1703 542 1708 537 567 571 1669 566 1701 544 558 570 560 568 561 567 564 564 557 571 1671 564 565 563 566 572 1670 565 1703 542 1673 562 1678 567 1683 562 566 562 1677 568 1701 544 559 569 561 567 563 565 565 563 557 571 1668 567 563 565 563 565 1676 569 1699 546 1669 566 1678 567 1676 569 # -# file: Flipper-IRDB/Fans\LeaderPro\LeaderPro_Desk_Fan.ir -# name: POWER type: parsed protocol: NEC @@ -573,8 +488,6 @@ protocol: NEC address: 30 00 00 00 command: 85 00 00 00 # -# file: Flipper-IRDB/Fans\LeaderPro\LeaderPro_Floor-Fan.ir -# name: POWER type: raw frequency: 38000 @@ -611,8 +524,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 8972 4427 561 1681 566 560 563 562 561 565 568 557 566 559 564 561 562 563 560 565 568 1673 563 1676 571 1671 565 1676 571 1672 564 1677 570 1664 562 1679 568 1674 562 562 561 1680 567 558 565 560 563 562 561 555 568 556 567 558 565 1676 560 564 569 1670 566 1675 561 1680 567 1665 561 1680 567 1675 561 564 569 1673 563 562 561 564 569 556 567 548 565 561 562 562 561 1680 567 558 565 1677 570 1672 564 1678 569 1673 563 12942 8971 2195 567 # -# file: Flipper-IRDB/Fans\MainStays\MainStays_Fan_FZ10-19JR.ir -# name: POWER type: raw frequency: 38000 @@ -637,8 +548,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 9021 4481 572 1692 574 531 571 535 567 538 574 531 571 534 568 538 564 541 571 534 568 1694 572 1691 575 1688 568 1722 544 1719 547 1690 566 1697 569 1694 572 1691 565 540 572 533 569 1694 572 533 569 537 565 540 572 533 569 537 565 1698 568 1694 572 533 569 1695 571 1692 574 1715 541 1722 544 1693 573 531 571 535 567 1696 570 535 567 539 573 532 570 535 567 538 574 1689 567 1696 570 535 567 1696 570 1693 573 1716 540 11739 9024 2216 570 95999 9020 2219 567 96001 9020 2220 566 # -# file: Flipper-IRDB/Fans\Meaco\MeacoFan_1056_P.ir -# name: POWER type: parsed protocol: NEC @@ -651,6 +560,12 @@ protocol: NEC address: 80 00 00 00 command: 89 00 00 00 # +name: SPEED- +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 9F 00 00 00 +# name: ROTATE type: parsed protocol: NEC @@ -663,8 +578,6 @@ protocol: NEC address: 80 00 00 00 command: 81 00 00 00 # -# file: Flipper-IRDB/Fans\oneConcept\oneConcept_Hightower-2G.ir -# name: POWER type: raw frequency: 38000 @@ -689,8 +602,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 1274 408 1283 426 414 1239 1282 427 1253 428 412 1241 439 1240 440 1240 440 1239 1281 427 413 1267 413 7957 1275 434 1246 436 404 1275 1256 427 1253 429 411 1267 413 1267 413 1240 440 1240 1280 428 412 1267 413 9060 1282 400 1280 428 412 1267 1253 429 1251 430 410 1243 437 1243 437 1242 438 1242 1278 429 411 1241 439 7958 1274 434 1246 436 414 1264 1256 426 1254 428 412 1266 414 1240 492 1188 440 1240 1280 428 412 1240 440 9059 1272 436 1254 426 414 1239 1281 426 1254 427 413 1240 440 1239 441 1239 441 1238 1282 426 414 1239 441 7955 1277 405 1275 407 433 1246 1274 408 1282 399 441 1239 441 1239 441 1239 441 1239 1281 400 440 1240 440 # -# file: Flipper-IRDB/Fans\Orbrgozo\Orbegozo_SF0243.ir -# name: POWER type: raw frequency: 38000 @@ -715,8 +626,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 1280 433 1251 436 405 1281 1255 431 1253 434 408 1278 405 1279 1257 431 411 1277 407 1280 414 1274 410 8547 1275 437 1257 428 413 1270 1255 430 1254 430 412 1273 411 1275 1251 436 405 1280 414 1271 412 1273 410 8550 1283 431 1253 434 408 1278 1258 427 1256 428 414 1271 412 1272 1254 434 408 1279 415 1271 412 1247 436 8544 1279 433 1251 435 407 1279 1257 430 1254 434 407 1278 405 1277 1249 437 415 1269 414 1269 415 1269 415 8537 1275 435 1248 435 406 1276 1250 436 1248 436 406 1278 406 1277 1248 437 404 1280 414 1269 414 1271 412 8532 1280 428 1255 428 413 1269 1246 437 1246 435 406 1276 408 1277 1248 436 406 1278 406 1279 415 1268 416 8538 1274 436 1258 427 415 1269 1257 427 1257 430 412 1272 412 1273 1252 434 408 1277 407 1280 414 1272 412 8553 1280 405 1279 434 408 1276 1250 435 1259 429 413 1273 411 1274 1252 434 408 1277 407 1279 415 1270 414 8548 1275 436 1258 428 414 1272 1254 433 1250 435 406 1277 406 1278 1258 429 413 1272 412 1275 409 1277 406 8549 1284 427 1257 430 412 1274 1251 433 1251 434 407 1277 406 1278 1248 437 415 1269 415 1271 412 1273 410 # -# file: Flipper-IRDB/Fans\Pelonis\Pelonis_PFS40D6ABB_Fan.ir -# name: POWER type: raw frequency: 38000 @@ -729,8 +638,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 8990 4430 601 1628 598 517 596 519 594 547 566 549 574 540 573 542 571 544 569 546 567 1663 574 1628 598 1658 568 1662 575 1654 572 1658 568 1660 566 1663 574 1656 570 544 569 1660 566 548 575 539 574 541 572 542 571 544 569 545 568 1662 575 539 574 1656 570 1658 568 1661 565 1664 573 1656 570 1659 567 548 565 1664 573 542 571 543 570 545 568 546 567 548 565 549 574 1655 571 543 570 1659 567 1661 576 1628 598 1658 568 # -# file: Flipper-IRDB/Fans\Rowenta\Rowenta_Eole_Infinite.ir -# name: SPEED+ type: parsed protocol: NEC @@ -749,8 +656,6 @@ protocol: NEC address: 00 00 00 00 command: 05 00 00 00 # -# file: Flipper-IRDB/Fans\Rowenta\Rowenta_Mosquito_Silence_VU6410FD.ir -# name: ROTATE type: parsed protocol: NEC @@ -763,8 +668,6 @@ protocol: NEC address: 00 00 00 00 command: 40 00 00 00 # -# file: Flipper-IRDB/Fans\ServilleClassics\SC-UltraSlimLine-Oscillating-Tower-Fan.ir -# name: POWER type: raw frequency: 38000 @@ -789,8 +692,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 1316 405 1307 412 434 1270 1309 413 1310 416 1307 421 435 1276 436 1276 436 1275 427 1283 1307 421 1312 7037 1310 411 1312 407 428 1274 1305 418 1305 420 1303 425 431 1278 434 1277 435 1276 436 1274 1305 423 1310 7006 1310 411 1312 406 429 1274 1305 416 1306 419 1304 423 433 1303 409 1275 427 1284 428 1281 1308 420 1303 7043 1314 407 1305 412 434 1295 1284 412 1310 414 1309 419 427 1308 404 1280 432 1279 433 1275 1314 413 1310 7003 1313 407 1305 413 433 1294 1285 411 1301 424 1309 418 428 1306 406 1304 408 1276 436 1273 1306 421 1302 7041 1306 414 1309 410 425 1301 1278 418 1305 420 1303 424 432 1302 400 1310 402 1282 430 1277 1312 415 1307 7003 1313 407 1305 413 433 1294 1285 410 1302 423 1310 416 430 1304 408 1302 400 1284 428 1279 1310 417 1306 7033 1314 406 1307 412 434 1292 1287 408 1304 420 1303 424 432 1301 401 1308 404 1279 433 1274 1305 422 1311 6995 1311 410 1302 415 431 1295 1284 411 1301 423 1310 416 430 1303 409 1299 403 1280 432 1275 1304 422 1301 7034 1313 406 1307 411 424 1301 1278 417 1305 419 1303 423 433 1299 403 1305 407 1275 427 1281 1308 418 1304 6997 1309 411 1301 416 430 1295 1284 411 1301 422 1301 425 431 1301 401 1307 405 1277 435 1271 1308 418 1305 7028 1308 411 1301 415 431 1294 1285 410 1302 422 1301 425 431 1300 402 1306 406 1276 426 1280 1309 416 1307 6993 1312 407 1305 412 434 1291 1278 416 1307 417 1306 420 426 1306 406 1301 401 1281 431 1275 1304 422 1301 7029 1308 411 1301 415 431 1268 1311 409 1303 420 1303 423 433 1273 429 1278 434 1274 428 1277 1312 414 1309 6989 1306 412 1310 406 429 1270 1309 411 1301 422 1301 424 432 1274 428 1279 433 1275 427 1278 1311 414 1309 7019 1307 411 1301 415 431 1268 1311 408 1304 419 1304 421 435 1271 431 1276 426 1282 430 1275 1304 421 1302 6994 1312 406 1306 410 425 1274 1305 414 1309 414 1339 386 429 1277 425 1281 431 1276 426 1305 1284 414 1309 7018 1308 409 1303 413 433 1267 1302 417 1337 386 1337 388 458 1248 433 1273 429 1278 434 1271 1308 416 1338 6956 1308 410 1333 382 464 1236 1333 386 1337 386 1337 388 458 1248 454 1252 429 1277 435 1270 1340 384 1338 6949 1336 382 1330 386 460 1239 1330 388 1335 388 1335 391 455 1250 462 1244 458 1249 463 1241 1338 386 1336 # -# file: Flipper-IRDB/Fans\SHE\SHE_Fan_SHE40ST1801F.ir -# name: POWER type: raw frequency: 38000 @@ -809,8 +710,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 1293 395 1289 398 438 1248 1293 395 1289 398 438 1248 446 1241 443 1245 439 1249 1292 396 440 1245 439 7942 1294 395 1289 398 438 1247 1284 404 1290 397 439 1246 438 1250 444 1243 440 1247 1284 405 442 1244 440 7940 1285 404 1290 396 440 1246 1285 403 1291 396 440 1245 438 1249 445 1242 442 1245 1286 403 444 1242 442 7939 1286 402 1292 395 441 1245 1286 402 1292 394 442 1244 440 1248 446 1241 443 1245 1286 402 445 1242 442 7941 1284 404 1290 397 439 1248 1293 395 1289 398 438 1248 446 1242 442 1246 438 1250 1291 396 440 1247 447 7934 1291 398 1286 401 446 1241 1290 399 1285 402 445 1242 442 1246 438 1250 444 1244 1287 401 446 1241 443 7940 1285 403 1291 396 440 1247 1284 404 1290 397 439 1247 437 1251 443 1245 439 1249 1292 396 440 1246 438 7945 1291 398 1286 401 446 1240 1291 398 1286 401 446 1240 444 1244 439 1248 446 1242 1289 399 437 1249 445 # -# file: Flipper-IRDB/Fans\Silver_Crest\SilverCrest_Fan.ir -# name: POWER type: parsed protocol: NEC @@ -841,8 +740,6 @@ protocol: NEC address: 00 00 00 00 command: 0D 00 00 00 # -# file: Flipper-IRDB/Fans\Taurus\Taurus_Babel_RC.ir -# name: POWER type: raw frequency: 38000 @@ -866,8 +763,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 1313 405 1314 405 449 1250 1313 420 1320 406 448 1252 447 1253 446 1254 445 1255 443 1255 1319 404 450 8002 1316 406 1313 409 445 1253 1311 422 1318 407 499 1202 445 1253 446 1253 445 1254 445 1254 1320 404 450 7999 1309 408 1311 406 448 1248 1305 421 1308 411 443 1253 446 1251 447 1249 449 1248 440 1257 1306 409 445 8000 1308 408 1311 405 449 1247 1306 418 1311 405 449 1248 440 1256 443 1253 446 1251 448 1250 1313 404 450 7996 1312 436 1283 407 447 1250 1313 414 1315 405 449 1250 448 1249 449 1248 450 1246 442 1255 1319 402 452 7991 1307 439 1280 412 442 1255 1308 420 1309 411 443 1255 444 1254 445 1253 446 1253 446 1253 1321 406 448 7998 1320 406 1323 403 451 1249 1314 421 1319 408 446 1254 444 1255 443 1255 443 1256 442 1256 1318 408 446 8004 1314 412 1317 409 445 1255 1318 417 1323 404 450 1250 448 1251 447 1252 447 1253 445 1255 1319 407 447 8003 1315 410 1319 407 447 1252 1322 414 1315 410 444 1256 453 1247 451 1248 450 1247 441 1256 1307 438 416 8002 1316 431 1288 429 415 1252 1311 444 1285 431 423 1241 447 1249 449 1247 451 1248 450 1246 1317 402 442 8002 1316 403 1306 411 443 1251 1312 416 1313 404 450 1244 444 1252 447 1251 447 1249 449 1247 1316 402 442 8002 1316 403 1306 410 444 1250 1313 414 1305 410 444 1249 450 1246 452 1244 444 1253 446 1252 1311 407 447 # -# file: Flipper-IRDB/Fans\Thomson\Thomson_Fan_THEVL484K.ir -# name: POWER type: raw frequency: 38000 @@ -886,8 +781,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 1288 437 1260 435 414 1254 1292 431 1256 440 409 1259 438 1258 1288 435 413 1255 442 1253 444 1252 435 8046 1292 431 1256 440 409 1259 1288 436 1261 434 414 1254 443 1253 1283 440 409 1259 438 1258 439 1256 441 8040 1287 436 1261 434 414 1254 1292 431 1256 439 409 1258 491 1204 1291 433 415 1253 434 1261 436 1260 438 8044 1284 440 1257 438 410 1257 1290 434 1263 432 417 1251 436 1259 1287 436 412 1255 442 1254 443 1252 435 8045 1293 431 1256 439 410 1258 1289 435 1262 433 416 1253 434 1261 1285 439 410 1258 440 1256 442 1255 442 8038 1290 433 1264 431 407 1260 1287 437 1261 435 413 1254 443 1253 1283 440 408 1259 439 1257 440 1255 442 8038 1289 434 1263 432 417 1251 1285 438 1260 436 413 1255 442 1253 1283 441 408 1260 438 1258 440 1256 442 # -# file: Flipper-IRDB/Fans\Vornado\Vornado.ir -# name: POWER type: raw frequency: 38000 @@ -900,8 +793,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 1369 328 1296 427 411 1275 1261 436 1261 434 414 1245 442 1245 442 1244 443 1244 443 1244 1291 431 417 7972 1291 404 1293 429 409 1251 1295 400 1287 436 412 1273 414 1246 441 1245 442 1245 442 1245 1290 405 443 9076 1287 408 1289 433 415 1271 1264 430 1267 428 410 1276 411 1249 438 1248 439 1248 439 1274 1261 434 414 7974 1289 406 1291 431 417 1242 1294 428 1259 436 412 1273 414 1273 414 1245 442 1245 442 1244 1292 430 418 # -# file: Flipper-IRDB/Fans\Xpelair\Xpelair_XPA360CF_Fan.ir -# name: POWER type: parsed protocol: NECext @@ -925,3 +816,4 @@ type: parsed protocol: NECext address: 00 FC 00 00 command: 86 79 00 00 +# diff --git a/assets/resources/infrared/assets/projectors.ir b/assets/resources/infrared/assets/projectors.ir index 413fdd5e71..33f8e46c8f 100644 --- a/assets/resources/infrared/assets/projectors.ir +++ b/assets/resources/infrared/assets/projectors.ir @@ -1,318 +1,283 @@ -Filetype: IR signals file +Filetype: IR library file Version: 1 -# -# file: Flipper-IRDB/Projectors/Anker/NebulaMarsLite.ir -# +# Last Updated 27th Aug, 2022 +# name: POWER type: parsed protocol: NECext address: 80 19 00 00 command: 10 EF 00 00 -# +# name: VOL+ type: parsed protocol: NECext address: 80 19 00 00 command: 1C E3 00 00 -# +# name: VOL- type: parsed protocol: NECext address: 80 19 00 00 command: 46 B9 00 00 -# -# file: Flipper-IRDB/Projectors/Anker/Nebula_Capsule_Mini_Projector.ir -# +# name: POWER type: parsed protocol: NEC address: 80 00 00 00 command: 51 00 00 00 -# -# file: Flipper-IRDB/Projectors/BenQ/BenQ.ir -# +# name: POWER type: parsed protocol: NECext address: 40 40 00 00 command: 0A F5 00 00 -# -# file: Flipper-IRDB/Projectors/BenQ/BenQ_W1050.ir -# +# name: POWER type: parsed protocol: NECext address: 00 30 00 00 command: 4E B1 00 00 -# +# name: VOL+ type: parsed protocol: NECext address: 00 30 00 00 command: 0E F1 00 00 -# +# name: VOL- type: parsed protocol: NECext address: 00 30 00 00 command: 0D F2 00 00 -# -# file: Flipper-IRDB/Projectors/BenQ/BenQ_W1070.ir -# +# name: POWER type: parsed protocol: NECext address: 00 30 00 00 command: 4F B0 00 00 -# +# name: MUTE type: parsed protocol: NECext address: 00 30 00 00 command: 14 EB 00 00 -# -# file: Flipper-IRDB/Projectors/BrandUnknown/LED_Smart_Home_Theater_Projector.ir -# +# name: POWER type: parsed protocol: NECext address: 08 16 00 00 command: 87 78 00 00 -# +# name: MUTE type: parsed protocol: NECext address: 08 16 00 00 command: C8 37 00 00 -# -# file: Flipper-IRDB/Projectors/Byintek/Byintek_P10.ir -# +# name: POWER type: parsed protocol: NEC address: 01 00 00 00 command: 01 00 00 00 -# +# name: MUTE type: parsed protocol: NEC address: 01 00 00 00 command: 02 00 00 00 -# +# name: VOL+ type: parsed protocol: NEC address: 01 00 00 00 command: 28 00 00 00 -# +# name: VOL- type: parsed protocol: NEC address: 01 00 00 00 command: 29 00 00 00 -# -# file: Flipper-IRDB/Projectors/Casio/Casio_YT-130.ir -# +# name: POWER type: parsed protocol: NECext address: 84 F4 00 00 command: 0B F4 00 00 -# -# file: Flipper-IRDB/Projectors/Eiki/Eiki_Projector.ir -# +# name: POWER type: parsed protocol: NECext address: 33 00 00 00 command: 00 FF 00 00 -# +# name: VOL- type: parsed protocol: NECext address: 33 00 00 00 command: 1E E1 00 00 -# +# name: VOL+ type: parsed protocol: NECext address: 33 00 00 00 command: 1D E2 00 00 -# +# name: MUTE type: parsed protocol: NECext address: 33 00 00 00 command: 0B F4 00 00 -# -# file: Flipper-IRDB/Projectors/Epson/Epson.ir -# +# name: POWER type: parsed protocol: NECext address: 83 55 00 00 command: 90 6F 00 00 -# +# name: VOL- type: parsed protocol: NECext address: 83 55 00 00 command: 99 66 00 00 -# +# name: VOL+ type: parsed protocol: NECext address: 83 55 00 00 command: 98 67 00 00 -# -# file: Flipper-IRDB/Projectors/Minolta/Minolta_MN674.ir -# +# name: POWER type: parsed protocol: NECext address: 00 DF 00 00 command: 1C E3 00 00 -# +# name: VOL- type: parsed protocol: NECext address: 00 DF 00 00 command: 4F B0 00 00 -# +# name: VOL+ type: parsed protocol: NECext address: 00 DF 00 00 command: 4B B4 00 00 -# -# file: Flipper-IRDB/Projectors/Optoma/Optoma_Profomo_L-27-5KEY.ir -# +# name: POWER type: parsed protocol: NEC address: 32 00 00 00 command: 02 00 00 00 -# +# name: POWER type: parsed protocol: NEC address: 32 00 00 00 command: 2E 00 00 00 -# +# name: MUTE type: parsed protocol: NEC address: 32 00 00 00 command: 52 00 00 00 -# -# file: Flipper-IRDB/Projectors/Philips/Philips_NeoPix_Prime_Projector.ir -# +# name: POWER type: parsed protocol: NEC address: 20 00 00 00 command: 41 00 00 00 -# +# name: VOL+ type: parsed protocol: NEC address: 20 00 00 00 command: 51 00 00 00 -# +# name: VOL- type: parsed protocol: NEC address: 20 00 00 00 command: 56 00 00 00 -# +# name: MUTE type: parsed protocol: NEC address: 20 00 00 00 command: 5A 00 00 00 -# -# file: Flipper-IRDB/Projectors/Sony/Sony_RM_PJ24.ir -# +# name: POWER type: parsed protocol: SIRC15 address: 54 00 00 00 command: 15 00 00 00 -# -# file: Flipper-IRDB/Projectors/ViewSonic/ViewSonic_Projector_PA503W-2.ir -# +# name: VOL+ type: parsed protocol: NECext address: 83 F4 00 00 command: 82 7D 00 00 -# +# name: VOL- type: parsed protocol: NECext address: 83 F4 00 00 command: 83 7C 00 00 -# +# name: MUTE type: parsed protocol: NECext address: 83 F4 00 00 command: 14 EB 00 00 -# -# file: Flipper-IRDB/Projectors/Vivitek/Vivitek.ir -# +# name: POWER type: parsed protocol: NEC address: 31 00 00 00 command: 91 00 00 00 -# +# name: POWER type: parsed protocol: NEC address: 31 00 00 00 command: 90 00 00 00 -# +# name: VOL+ type: parsed protocol: NEC address: 31 00 00 00 command: D0 00 00 00 -# +# name: MUTE type: parsed protocol: NEC address: 31 00 00 00 command: 89 00 00 00 -# -# 3M -# +# name: POWER type: parsed protocol: NECext address: 86 00 00 00 command: 00 00 00 00 -# +# name: VOL+ type: parsed protocol: NECext address: 86 00 00 00 command: 30 00 00 00 -# +# name: VOL- type: parsed protocol: NECext address: 86 00 00 00 command: 31 00 00 00 -# +# name: MUTE type: parsed protocol: NECext address: 86 00 00 00 command: 32 00 00 00 # -# Boxlight -# name: POWER type: parsed protocol: NECext @@ -324,3 +289,4 @@ type: parsed protocol: NECext address: 87 4E 00 00 command: 0D 00 00 00 +# diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir index c672a02310..a946944acd 100755 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -1,18 +1,7 @@ Filetype: IR library file Version: 1 +# Last Updated 27 Aug, 2022 # -# Recompiled Universal Remote for ALL buttons! -# (Now includes Volume and Channel brute forcing) -# -# Compiled by Hyper_Mash -# Support/testing/additions from UberGuidoZ -# Thank you to ChaoticDynamic aka c-nagy for cleanup -# -# Also a HUGE thank you to Amec0e for continued maintenance! -# -# -# Updated on 25th August 2022 -# name: POWER type: parsed protocol: SIRC @@ -109,8 +98,6 @@ protocol: Samsung32 address: 0e 00 00 00 command: 0d 00 00 00 # -# Keep an eye on this, it could be power. -# name: VOL+ type: parsed protocol: Samsung32 @@ -1755,8 +1742,6 @@ protocol: NECext address: 02 7D 00 00 command: 57 A8 00 00 # -# Keep an eye on this it might be volume down -# name: VOL+ type: parsed protocol: NECext @@ -2326,10 +2311,6 @@ type: parsed protocol: NEC address: 04 00 00 00 command: 1A 00 00 00 -# -# New IRs -# -# BAIRD # name: POWER type: parsed @@ -2367,15 +2348,11 @@ protocol: NEC address: 01 00 00 00 command: 17 00 00 00 # -# BRANDT -# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 data: 9028 4480 593 1667 589 541 597 532 596 534 594 562 566 564 564 539 589 567 571 558 570 1663 594 1666 591 1696 571 1662 595 1666 591 1669 598 1662 595 562 566 563 565 539 589 567 571 1661 596 561 567 563 565 564 564 1669 598 1662 595 1691 566 1668 599 558 570 1663 594 1692 565 575 1669 -# -# BUSH # name: POWER type: parsed @@ -2413,8 +2390,6 @@ protocol: NEC address: 08 00 00 00 command: DF 00 00 00 # -# CONTINENTAL -# name: POWER type: parsed protocol: RC5 @@ -2451,8 +2426,6 @@ protocol: RC5 address: 01 00 00 00 command: 21 00 00 00 # -# DENVER -# name: MUTE type: parsed protocol: NECext @@ -2483,8 +2456,6 @@ protocol: NECext address: 00 7F 00 00 command: 5C A3 00 00 # -# FETCH -# name: POWER type: parsed protocol: NECext @@ -2503,8 +2474,6 @@ protocol: NECext address: 64 46 00 00 command: DB 24 00 00 # -# FURRION -# name: POWER type: parsed protocol: NEC @@ -2541,8 +2510,6 @@ protocol: NEC address: 20 00 00 00 command: 41 00 00 00 # -# HISENSE -# name: POWER type: parsed protocol: NECext @@ -2579,8 +2546,6 @@ protocol: NECext address: 00 BF 00 00 command: 4B B4 00 00 # -# HITACHI -# name: POWER type: parsed protocol: RC5 @@ -2617,8 +2582,6 @@ protocol: RC5 address: 03 00 00 00 command: 0D 00 00 00 # -# MANTA -# name: POWER type: parsed protocol: NECext @@ -2643,8 +2606,6 @@ protocol: NECext address: 00 BF 00 00 command: 01 FE 00 00 # -# MATSUI -# name: POWER type: parsed protocol: Samsung32 @@ -2681,8 +2642,6 @@ protocol: Samsung32 address: 17 00 00 00 command: 15 00 00 00 # -# PANASONIC -# name: POWER type: raw frequency: 38000 @@ -2719,8 +2678,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 3477 1763 420 453 416 1330 418 455 424 449 420 453 415 458 421 452 417 456 423 450 419 454 425 448 421 452 417 456 423 1324 424 448 421 453 416 457 422 451 418 455 424 449 420 453 416 457 422 451 418 1329 419 454 415 458 421 452 417 456 423 450 419 427 452 448 421 452 417 456 423 1324 424 449 420 453 416 1330 418 1328 420 453 416 457 422 451 418 1329 419 454 415 458 421 1298 450 1323 425 448 421 1326 422 # -# PHILLIPS -# name: POWER type: parsed protocol: RC5 @@ -2769,8 +2726,6 @@ protocol: RC6 address: 00 00 00 00 command: 21 00 00 00 # -# RCA -# name: VOL+ type: raw frequency: 38000 @@ -2794,37 +2749,37 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 182 7824 176 2328 181 2323 176 2328 181 2324 175 1312 183 1323 182 2322 177 1330 175 2309 179 2325 174 1332 173 1333 183 1305 179 1327 178 1328 177 1328 177 2308 180 262 177 1885 175 295 175 861 174 2330 179 99 313 911 573 915 590 1916 180 64 349 1910 176 265 174 7896 177 3081 835 3912 182 2322 177 207 179 1942 180 2304 174 268 181 1881 179 263 176 889 177 264 175 886 583 1925 182 271 178 855 180 240 178 1907 174 2331 178 1327 178 1309 176 1329 590 916 589 919 173 306 175 833 181 317 174 1832 175 2329 180 1325 180 309 182 1833 174 1313 182 1325 180 289 181 1853 175 2329 180 8313 178 7845 176 2309 179 2325 174 2331 178 2326 173 1333 183 1304 180 2324 175 1332 173 2330 179 2325 174 1314 181 1325 180 1326 179 1327 178 1308 177 1330 175 2329 180 2324 175 1312 183 2322 177 1329 176 1329 176 2329 180 2304 174 8339 173 351 3575 3902 594 1911 588 1916 593 1911 588 1916 583 904 591 916 589 1915 594 911 584 1920 579 1907 592 915 590 915 591 916 579 908 597 909 596 909 586 1919 580 1907 179 1326 592 1912 597 908 587 901 594 1911 588 1916 593 -# +# name: POWER type: parsed protocol: RCA address: 0F 00 00 00 command: 2A 00 00 00 -# +# name: CH- type: parsed protocol: RCA address: 0F 00 00 00 command: 2C 00 00 00 -# +# name: CH+ type: parsed protocol: RCA address: 0F 00 00 00 command: 2D 00 00 00 -# +# name: VOL- type: parsed protocol: RCA address: 0F 00 00 00 command: 2E 00 00 00 -# +# name: VOL+ type: parsed protocol: RCA address: 0F 00 00 00 command: 2F 00 00 00 -# +# name: MUTE type: parsed protocol: RCA @@ -2867,8 +2822,6 @@ protocol: NEC address: A0 00 00 00 command: 1F 00 00 00 # -# SAMSUNG -# name: CH+ type: raw frequency: 38000 @@ -2917,8 +2870,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 4497 4474 564 1690 537 1691 536 1666 572 556 537 564 539 562 541 560 543 558 545 1683 544 1683 544 1684 543 532 571 556 537 564 539 562 541 560 543 1659 568 1686 541 1661 566 1662 565 562 541 560 543 558 535 565 538 563 540 561 542 558 545 556 537 1665 562 1666 572 1656 571 1684 543 557 546 555 538 564 539 562 541 42966 4502 4466 562 1692 535 1693 545 1657 570 556 537 565 538 562 541 560 543 543 1656 571 1656 571 1657 570 557 536 565 538 563 540 560 543 558 545 1683 544 1683 544 1657 570 1684 543 531 562 565 538 563 540 560 543 558 545 556 537 564 539 561 542 1660 567 1686 541 1687 540 1662 565 562 541 533 570 557 536 565 538 # -# SANYO -# name: POWER type: parsed protocol: NEC @@ -2955,8 +2906,6 @@ protocol: NEC address: 38 00 00 00 command: 0B 00 00 00 # -# SHARP -# name: POWER type: raw frequency: 38000 @@ -2993,8 +2942,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 281 1803 278 771 274 782 274 775 281 769 276 1807 274 1817 274 1835 256 766 280 1804 277 780 276 773 283 767 278 1831 250 780 276 44910 276 1835 256 766 280 777 279 771 275 774 282 767 278 779 277 773 283 1800 281 768 277 1814 277 1806 275 1808 283 766 279 1811 280 44937 280 1803 278 771 274 783 283 766 279 770 275 1808 273 1819 272 1811 280 768 277 1807 274 782 274 776 280 769 276 1833 248 784 282 # -# SONY -# name: POWER type: parsed protocol: SIRC @@ -3007,16 +2954,12 @@ protocol: SIRC address: 01 00 00 00 command: 2F 00 00 00 # -# TCL -# name: POWER type: parsed protocol: NECext address: EA C7 00 00 command: 97 68 00 00 # -# TELEKOM -# name: POWER type: raw frequency: 38000 @@ -3053,8 +2996,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 332 601 314 290 646 286 307 594 321 282 644 590 648 582 323 281 645 586 641 290 313 583 644 # -# THOMSON -# name: POWER type: raw frequency: 38000 @@ -3085,8 +3026,6 @@ frequency: 38000 duty_cycle: 0.330000 data: 3994 3986 512 1989 515 1986 518 1982 512 1989 515 985 517 983 519 2008 486 988 514 1987 517 1983 521 979 513 987 515 986 516 984 518 982 520 980 512 1988 516 1985 519 981 521 1980 514 986 516 984 518 2009 485 1990 514 9041 3994 3986 511 1989 515 1985 519 1982 512 1989 515 984 518 982 520 1981 513 987 515 1986 518 1982 512 988 514 986 516 984 518 983 519 981 521 979 513 1987 517 1984 520 980 512 1989 515 984 518 982 520 2007 487 1988 516 9038 4028 3952 514 1986 518 1982 512 1989 515 1985 519 980 512 989 513 2013 491 983 519 1982 512 1989 515 984 519 982 520 980 522 979 513 987 515 985 517 1983 521 1980 514 986 516 1985 519 980 512 989 513 2013 491 1984 520 # -# WBOX -# name: POWER type: parsed protocol: NECext @@ -3122,3 +3061,4 @@ type: parsed protocol: NECext address: 40 40 00 00 command: 0F F0 00 00 +# From fc62762ce4bdbf862371adbe0b8211e0440d89d0 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 27 Aug 2022 04:41:35 +0300 Subject: [PATCH 49/78] fix assets header, doesnt affect bruteforce work --- assets/resources/Manifest | 8 ++++---- assets/resources/infrared/assets/ac.ir | 2 +- assets/resources/infrared/assets/audio.ir | 2 +- assets/resources/infrared/assets/fans.ir | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/assets/resources/Manifest b/assets/resources/Manifest index 3533f7a8d0..fbe090d355 100644 --- a/assets/resources/Manifest +++ b/assets/resources/Manifest @@ -1,5 +1,5 @@ V:0 -T:1661559205 +T:1661564433 D:badusb D:dolphin D:infrared @@ -241,9 +241,9 @@ F:33b8fde22f34ef556b64b77164bc19b0:578:dolphin/L3_Lab_research_128x54/frame_8.bm F:f267f0654781049ca323b11bb4375519:581:dolphin/L3_Lab_research_128x54/frame_9.bm F:41106c0cbc5144f151b2b2d3daaa0527:727:dolphin/L3_Lab_research_128x54/meta.txt D:infrared/assets -F:dad1530d4887052c0ec7e6319cdf50dd:112920:infrared/assets/ac.ir -F:58345d120303340413a70215099dca1e:47410:infrared/assets/audio.ir -F:7c72029cf4f8e4d8a38dbfb54eec7854:78119:infrared/assets/fans.ir +F:9620fc175c5b5c0dabf075af74ed59a2:112920:infrared/assets/ac.ir +F:da34b5968815387f1bcebcb3d8c4bf54:47410:infrared/assets/audio.ir +F:50718b2cfc6fae7b79a35eab5cccc6c0:78119:infrared/assets/fans.ir F:88ac3e7ae8be5a0df84c1d7f81989cae:4170:infrared/assets/projectors.ir F:77bc8314d113b8618942589f21a491fc:127350:infrared/assets/tv.ir F:a157a80f5a668700403d870c23b9567d:470:music_player/Marble_Machine.fmf diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index 2e811ba754..b37ff6d2c1 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -1,4 +1,4 @@ -Filetype: IR signals file +Filetype: IR library file Version: 1 # Last Updated 27th Aug, 2022 # diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index 958dbf3b87..955c113be4 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1,4 +1,4 @@ -Filetype: IR signals file +Filetype: IR library file Version: 1 # Last Updated 27th Aug, 2022 # diff --git a/assets/resources/infrared/assets/fans.ir b/assets/resources/infrared/assets/fans.ir index 00062b3756..ca740821f3 100644 --- a/assets/resources/infrared/assets/fans.ir +++ b/assets/resources/infrared/assets/fans.ir @@ -1,4 +1,4 @@ -Filetype: IR signals file +Filetype: IR library file Version: 1 # Last Updated 27th Aug, 2022 # From db4976c501f3a250143d77ef5a6c270afdbb23a2 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 27 Aug 2022 05:15:49 +0300 Subject: [PATCH 50/78] update ac asset by @Amec0e --- assets/resources/Manifest | 4 +-- assets/resources/infrared/assets/ac.ir | 36 ++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/assets/resources/Manifest b/assets/resources/Manifest index fbe090d355..de759514af 100644 --- a/assets/resources/Manifest +++ b/assets/resources/Manifest @@ -1,5 +1,5 @@ V:0 -T:1661564433 +T:1661566522 D:badusb D:dolphin D:infrared @@ -241,7 +241,7 @@ F:33b8fde22f34ef556b64b77164bc19b0:578:dolphin/L3_Lab_research_128x54/frame_8.bm F:f267f0654781049ca323b11bb4375519:581:dolphin/L3_Lab_research_128x54/frame_9.bm F:41106c0cbc5144f151b2b2d3daaa0527:727:dolphin/L3_Lab_research_128x54/meta.txt D:infrared/assets -F:9620fc175c5b5c0dabf075af74ed59a2:112920:infrared/assets/ac.ir +F:665b09ef2a1849306b56d1afb0fdd67a:118089:infrared/assets/ac.ir F:da34b5968815387f1bcebcb3d8c4bf54:47410:infrared/assets/audio.ir F:50718b2cfc6fae7b79a35eab5cccc6c0:78119:infrared/assets/fans.ir F:88ac3e7ae8be5a0df84c1d7f81989cae:4170:infrared/assets/projectors.ir diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index b37ff6d2c1..ee09035fbc 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -884,3 +884,39 @@ frequency: 38000 duty_cycle: 0.330000 data: 3027 9036 541 1580 484 588 491 556 492 555 482 564 484 589 459 587 481 565 483 564 484 1583 492 555 482 564 484 589 479 1561 514 1527 517 583 485 1555 489 1552 513 1581 484 1531 513 534 514 585 463 584 484 562 486 561 486 560 488 585 483 589 479 567 512 561 486 560 488 559 489 558 490 583 485 561 487 560 488 558 490 1578 486 1580 484 562 517 1577 487 559 489 558 490 583 485 1555 509 564 484 563 485 1582 483 1532 543 1576 488 559 489 584 464 583 485 587 492 555 482 564 432 1924 2973 9041 536 1531 513 559 489 584 484 563 516 557 491 556 481 591 488 559 489 558 490 1577 487 559 489 558 490 1577 487 1580 484 1530 514 1553 512 562 485 1555 509 1531 513 1555 509 1558 507 1534 510 1557 518 1524 509 1557 518 555 493 555 513 559 488 558 490 583 485 561 486 560 488 559 489 584 484 562 486 561 486 560 487 585 483 1557 487 1554 510 1557 507 1533 511 1557 538 1528 516 1578 455 591 488 559 489 558 489 557 491 582 486 560 487 559 488 584 484 562 517 1524 509 1558 465 # +name: MODE +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 09 00 00 00 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1303 438 1287 429 418 1254 1308 434 1281 434 423 1250 444 1255 439 1259 1303 439 418 1254 440 1258 446 8172 1313 428 1276 411 446 1252 1310 404 1311 403 444 1255 439 1259 445 1253 1309 405 442 1257 447 1250 444 8173 1302 412 1303 410 447 1251 1300 439 1276 410 447 1251 443 1255 439 1259 1303 437 420 1250 496 1202 439 8177 1308 434 1281 433 414 1256 1306 435 1280 434 413 1284 420 1251 443 1255 1307 433 414 1283 421 1250 444 8173 1302 438 1277 436 421 1276 1275 438 1277 436 421 1275 419 1252 442 1256 1306 434 413 1284 420 1250 444 8173 1302 438 1277 436 421 1276 1275 437 1278 435 412 1285 419 1278 416 1281 1281 432 415 1282 412 1285 419 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3197 1595 390 404 379 1210 388 406 388 406 388 1201 386 407 386 1202 386 408 385 409 384 1205 383 1204 383 1206 382 412 381 1206 381 413 381 1207 381 1208 380 1209 389 405 389 406 387 405 389 407 387 1200 388 1201 386 408 385 1203 384 412 382 1205 383 1204 384 412 382 412 382 412 382 1207 381 413 381 1208 380 414 380 414 380 1209 389 1199 389 1201 386 1200 387 1202 385 408 385 409 384 1204 384 1205 383 1205 382 1205 383 412 382 413 380 1207 381 1209 389 406 388 405 389 405 389 405 389 1200 387 1203 384 1201 386 409 384 1203 384 1205 382 1205 383 1205 383 411 383 412 382 412 382 1207 380 414 380 415 389 404 379 417 387 1199 389 1199 389 1201 386 1204 384 1203 384 1203 384 1203 384 1204 384 411 382 412 382 412 382 412 382 413 380 413 381 414 380 414 380 1209 389 1199 389 1199 389 1200 387 1201 386 408 385 1203 385 1203 384 409 384 412 381 410 383 413 381 411 383 1206 382 413 381 413 380 1207 381 1209 389 404 379 1209 389 1199 389 407 386 1201 386 1202 385 408 385 410 384 1203 384 410 383 411 383 1204 384 412 382 412 382 1206 381 1207 380 1208 379 1211 387 1199 389 1201 386 1201 386 1202 385 408 385 410 383 409 385 409 385 410 384 410 384 410 383 411 383 412 382 1207 381 1206 382 1209 389 1197 380 1210 388 1199 389 406 387 1200 387 408 385 407 386 408 385 409 384 408 385 409 384 1204 384 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3467 1749 420 452 420 1301 412 468 414 472 420 468 414 479 413 484 418 453 419 454 418 459 413 469 413 472 420 469 413 1323 421 476 416 455 417 457 415 462 420 461 421 464 418 471 421 1315 419 1322 422 1293 420 452 420 458 414 1311 412 472 420 469 413 480 412 485 417 453 419 455 417 460 422 459 413 472 420 469 413 480 412 485 417 453 419 455 417 460 412 469 413 472 420 469 413 480 412 485 417 453 419 455 417 460 422 459 413 472 420 469 413 480 412 485 417 453 419 455 417 1304 419 1305 418 466 416 473 419 474 418 479 413 436 415 10538 3465 1751 419 454 418 1303 420 461 421 464 418 471 421 472 420 477 415 455 417 457 415 462 420 461 421 464 418 471 421 1315 418 479 413 457 415 459 412 464 418 463 419 466 416 473 419 1318 415 1325 419 1295 418 455 416 461 421 1303 420 465 417 472 420 473 419 478 414 456 416 458 414 463 419 462 420 465 417 472 420 473 419 478 414 456 416 1301 412 465 417 464 418 1311 412 476 416 477 415 482 420 451 421 452 420 457 415 1310 413 471 421 468 414 1323 421 476 416 455 417 456 416 462 420 461 421 464 418 471 421 471 421 476 416 1299 414 1302 421 1299 414 1311 412 1316 417 471 421 1316 417 479 413 1302 421 1295 418 459 412 1312 421 1307 416 472 420 473 419 478 414 457 415 458 414 464 418 463 419 466 416 473 419 473 419 478 414 457 415 458 414 1307 416 1309 414 1314 419 469 413 480 422 475 417 454 418 455 417 460 422 459 413 473 419 469 413 1324 420 1321 412 1302 421 452 420 457 415 466 416 469 413 476 416 477 415 482 420 451 421 452 420 457 414 467 415 470 412 477 415 478 414 483 419 451 421 1296 417 460 412 469 413 472 420 469 413 480 412 485 417 1297 416 457 415 462 420 461 421 464 418 471 421 472 420 477 415 456 416 457 414 462 420 461 421 464 418 471 421 472 420 477 415 456 416 457 414 1306 417 1307 416 1312 421 1311 412 481 421 1319 414 1279 414 +# +name: MODE +type: parsed +protocol: NECext +address: 86 6B 00 00 +command: 02 FD 00 00 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 552 17959 3004 8946 521 530 474 1490 519 477 517 505 499 497 497 498 496 500 494 501 493 503 501 1464 524 497 497 499 495 1470 518 504 500 495 499 1493 495 1496 492 1499 520 1472 516 1475 524 498 496 500 494 501 493 503 501 494 500 496 498 497 497 499 495 501 493 502 492 531 473 522 472 524 470 525 490 506 498 497 497 499 495 501 493 502 492 504 500 495 499 497 497 498 496 500 494 501 493 503 501 494 500 496 498 524 470 526 468 527 467 529 496 1469 519 1472 527 1465 523 1468 520 2979 2997 8954 523 1469 519 502 492 504 500 495 499 524 470 525 469 527 467 528 497 499 495 1470 518 503 501 495 499 1466 522 500 494 1471 528 1464 524 497 497 1468 520 1446 604 1440 496 525 469 1496 523 499 495 1470 518 1473 526 497 497 498 496 500 494 1471 528 1464 524 1467 521 501 493 529 465 531 473 522 472 524 491 1474 525 497 497 1469 519 502 492 1474 525 1466 522 500 494 1471 528 494 500 496 498 1494 494 528 466 529 475 521 494 502 492 503 491 1474 525 1467 521 1470 518 1474 525 +# From 99a7d06f71f40b3dea27622f27b71010624291c4 Mon Sep 17 00:00:00 2001 From: SG Date: Sat, 27 Aug 2022 14:25:47 +1000 Subject: [PATCH 51/78] Speedup SD card & enlarge your RAM. (#1649) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * FuriHal: sram2 memory manager * FuriHal: sram2 memory allocator * FuriHal: allow NULL buffers for txrx in spi hal * SD card: sector cache * FuriHal: fix init in memory hal * RPC: STARTUP instead SERVICE * Memory: pool "free" command * Thread: service can be statically allocated in a memory pool Co-authored-by: あく --- applications/cli/cli_commands.c | 3 + applications/meta/application.fam | 2 +- applications/rpc/application.fam | 12 +- applications/rpc/rpc.c | 4 +- firmware/targets/f7/Inc/FreeRTOSConfig.h | 2 +- firmware/targets/f7/fatfs/sector_cache.c | 59 +++++++++ firmware/targets/f7/fatfs/sector_cache.h | 36 ++++++ firmware/targets/f7/fatfs/stm32_adafruit_sd.c | 35 +++--- firmware/targets/f7/furi_hal/furi_hal.c | 2 + .../targets/f7/furi_hal/furi_hal_memory.c | 119 ++++++++++++++++++ firmware/targets/f7/furi_hal/furi_hal_spi.c | 18 ++- firmware/targets/f7/stm32wb55xx_flash.ld | 12 +- firmware/targets/f7/stm32wb55xx_ram_fw.ld | 12 +- .../furi_hal_include/furi_hal_memory.h | 44 +++++++ furi/core/memmgr.c | 16 +++ furi/core/memmgr.h | 22 ++++ furi/core/thread.c | 38 ++++-- furi/core/thread.h | 7 ++ furi/flipper.c | 20 +++ 19 files changed, 410 insertions(+), 53 deletions(-) create mode 100644 firmware/targets/f7/fatfs/sector_cache.c create mode 100644 firmware/targets/f7/fatfs/sector_cache.h create mode 100644 firmware/targets/f7/furi_hal/furi_hal_memory.c create mode 100644 firmware/targets/furi_hal_include/furi_hal_memory.h diff --git a/applications/cli/cli_commands.c b/applications/cli/cli_commands.c index 177a274a10..a6dd672fc1 100644 --- a/applications/cli/cli_commands.c +++ b/applications/cli/cli_commands.c @@ -281,6 +281,9 @@ void cli_command_free(Cli* cli, string_t args, void* context) { printf("Total heap size: %d\r\n", memmgr_get_total_heap()); printf("Minimum heap size: %d\r\n", memmgr_get_minimum_free_heap()); printf("Maximum heap block: %d\r\n", memmgr_heap_get_max_free_block()); + + printf("Pool free: %d\r\n", memmgr_pool_get_free()); + printf("Maximum pool block: %d\r\n", memmgr_pool_get_max_block()); } void cli_command_free_blocks(Cli* cli, string_t args, void* context) { diff --git a/applications/meta/application.fam b/applications/meta/application.fam index a447b94ae4..8b873b5fba 100644 --- a/applications/meta/application.fam +++ b/applications/meta/application.fam @@ -3,7 +3,7 @@ App( name="Basic services", apptype=FlipperAppType.METAPACKAGE, provides=[ - "rpc", + "rpc_start", "bt", "desktop", "loader", diff --git a/applications/rpc/application.fam b/applications/rpc/application.fam index 683396e32c..3a139cb3b0 100644 --- a/applications/rpc/application.fam +++ b/applications/rpc/application.fam @@ -1,12 +1,8 @@ App( - appid="rpc", - name="RpcSrv", - apptype=FlipperAppType.SERVICE, - entry_point="rpc_srv", + appid="rpc_start", + apptype=FlipperAppType.STARTUP, + entry_point="rpc_on_system_start", cdefines=["SRV_RPC"], - requires=[ - "cli", - ], - stack_size=4 * 1024, + requires=["cli"], order=10, ) diff --git a/applications/rpc/rpc.c b/applications/rpc/rpc.c index d767a928d6..abba6ea42a 100644 --- a/applications/rpc/rpc.c +++ b/applications/rpc/rpc.c @@ -395,7 +395,7 @@ void rpc_session_close(RpcSession* session) { furi_thread_flags_set(furi_thread_get_id(session->thread), RpcEvtDisconnect); } -int32_t rpc_srv(void* p) { +void rpc_on_system_start(void* p) { UNUSED(p); Rpc* rpc = malloc(sizeof(Rpc)); @@ -406,8 +406,6 @@ int32_t rpc_srv(void* p) { cli, "start_rpc_session", CliCommandFlagParallelSafe, rpc_cli_command_start_session, rpc); furi_record_create(RECORD_RPC, rpc); - - return 0; } void rpc_add_handler(RpcSession* session, pb_size_t message_tag, RpcHandler* handler) { diff --git a/firmware/targets/f7/Inc/FreeRTOSConfig.h b/firmware/targets/f7/Inc/FreeRTOSConfig.h index f54d774caa..ab2dc14ef4 100644 --- a/firmware/targets/f7/Inc/FreeRTOSConfig.h +++ b/firmware/targets/f7/Inc/FreeRTOSConfig.h @@ -14,7 +14,7 @@ extern uint32_t SystemCoreClock; #define configENABLE_MPU 0 #define configUSE_PREEMPTION 1 -#define configSUPPORT_STATIC_ALLOCATION 0 +#define configSUPPORT_STATIC_ALLOCATION 1 #define configSUPPORT_DYNAMIC_ALLOCATION 1 #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 diff --git a/firmware/targets/f7/fatfs/sector_cache.c b/firmware/targets/f7/fatfs/sector_cache.c new file mode 100644 index 0000000000..5a4f1b9789 --- /dev/null +++ b/firmware/targets/f7/fatfs/sector_cache.c @@ -0,0 +1,59 @@ +#include "sector_cache.h" + +#include +#include +#include +#include +#include + +#define SECTOR_SIZE 512 +#define N_SECTORS 8 + +typedef struct { + uint32_t itr; + uint32_t sectors[N_SECTORS]; + uint8_t sector_data[N_SECTORS][SECTOR_SIZE]; +} SectorCache; + +static SectorCache* cache = NULL; + +void sector_cache_init() { + if(cache == NULL) { + cache = furi_hal_memory_alloc(sizeof(SectorCache)); + } + + if(cache != NULL) { + FURI_LOG_I("SectorCache", "Initializing sector cache"); + memset(cache, 0, sizeof(SectorCache)); + } else { + FURI_LOG_E("SectorCache", "Cannot enable sector cache"); + } +} + +uint8_t* sector_cache_get(uint32_t n_sector) { + if(cache != NULL && n_sector != 0) { + for(int sector_i = 0; sector_i < N_SECTORS; ++sector_i) { + if(cache->sectors[sector_i] == n_sector) { + return cache->sector_data[sector_i]; + } + } + } + return NULL; +} + +void sector_cache_put(uint32_t n_sector, uint8_t* data) { + if(cache == NULL) return; + cache->sectors[cache->itr % N_SECTORS] = n_sector; + memcpy(cache->sector_data[cache->itr % N_SECTORS], data, SECTOR_SIZE); + cache->itr++; +} + +void sector_cache_invalidate_range(uint32_t start_sector, uint32_t end_sector) { + if(cache == NULL) return; + for(int sector_i = 0; sector_i < N_SECTORS; ++sector_i) { + if((cache->sectors[sector_i] >= start_sector) && + (cache->sectors[sector_i] <= end_sector)) { + cache->sectors[sector_i] = 0; + } + } +} \ No newline at end of file diff --git a/firmware/targets/f7/fatfs/sector_cache.h b/firmware/targets/f7/fatfs/sector_cache.h new file mode 100644 index 0000000000..5fe4a2ed86 --- /dev/null +++ b/firmware/targets/f7/fatfs/sector_cache.h @@ -0,0 +1,36 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Init sector cache system + */ +void sector_cache_init(); + +/** + * @brief Get sector data from cache + * @param n_sector Sector number + * @return Pointer to sector data or NULL if not found + */ +uint8_t* sector_cache_get(uint32_t n_sector); + +/** + * @brief Put sector data to cache + * @param n_sector Sector number + * @param data Pointer to sector data + */ +void sector_cache_put(uint32_t n_sector, uint8_t* data); + +/** + * @brief Invalidate sector cache for given range + * @param start_sector Start sector number + * @param end_sector End sector number + */ +void sector_cache_invalidate_range(uint32_t start_sector, uint32_t end_sector); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/fatfs/stm32_adafruit_sd.c b/firmware/targets/f7/fatfs/stm32_adafruit_sd.c index 6db430a535..07cae31fe8 100644 --- a/firmware/targets/f7/fatfs/stm32_adafruit_sd.c +++ b/firmware/targets/f7/fatfs/stm32_adafruit_sd.c @@ -92,6 +92,7 @@ #include "string.h" #include "stdio.h" #include +#include "sector_cache.h" /** @addtogroup BSP * @{ @@ -377,6 +378,8 @@ uint8_t BSP_SD_Init(bool reset_card) { furi_hal_sd_spi_handle = NULL; furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_slow); + sector_cache_init(); + /* SD initialized and set to SPI mode properly */ return res; } @@ -427,9 +430,15 @@ uint8_t uint32_t offset = 0; uint32_t addr; uint8_t retr = BSP_SD_ERROR; - uint8_t* ptr = NULL; SD_CmdAnswer_typedef response; uint16_t BlockSize = 512; + uint8_t* cached_data; + + bool single_sector_read = (NumOfBlocks == 1); + if(single_sector_read && (cached_data = sector_cache_get(ReadAddr))) { + memcpy(pData, cached_data, BlockSize); + return BSP_SD_OK; + } /* Send CMD16 (SD_CMD_SET_BLOCKLEN) to set the size of the block and Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */ @@ -440,12 +449,6 @@ uint8_t goto error; } - ptr = malloc(sizeof(uint8_t) * BlockSize); - if(ptr == NULL) { - goto error; - } - memset(ptr, SD_DUMMY_BYTE, sizeof(uint8_t) * BlockSize); - /* Initialize the address */ addr = (ReadAddr * ((flag_SDHC == 1) ? 1 : BlockSize)); @@ -461,7 +464,7 @@ uint8_t /* Now look for the data token to signify the start of the data */ if(SD_WaitData(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ) == BSP_SD_OK) { /* Read the SD block data : read NumByteToRead data */ - SD_IO_WriteReadData(ptr, (uint8_t*)pData + offset, BlockSize); + SD_IO_WriteReadData(NULL, (uint8_t*)pData + offset, BlockSize); /* Set next read address*/ offset += BlockSize; @@ -479,13 +482,16 @@ uint8_t SD_IO_WriteByte(SD_DUMMY_BYTE); } + if(single_sector_read) { + sector_cache_put(ReadAddr, (uint8_t*)pData); + } + retr = BSP_SD_OK; error: /* Send dummy byte: 8 Clock pulses of delay */ SD_IO_CSState(1); SD_IO_WriteByte(SD_DUMMY_BYTE); - if(ptr != NULL) free(ptr); /* Return the reponse */ return retr; @@ -509,9 +515,9 @@ uint8_t BSP_SD_WriteBlocks( uint32_t offset = 0; uint32_t addr; uint8_t retr = BSP_SD_ERROR; - uint8_t* ptr = NULL; SD_CmdAnswer_typedef response; uint16_t BlockSize = 512; + sector_cache_invalidate_range(WriteAddr, WriteAddr + NumOfBlocks); /* Send CMD16 (SD_CMD_SET_BLOCKLEN) to set the size of the block and Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */ @@ -522,11 +528,6 @@ uint8_t BSP_SD_WriteBlocks( goto error; } - ptr = malloc(sizeof(uint8_t) * BlockSize); - if(ptr == NULL) { - goto error; - } - /* Initialize the address */ addr = (WriteAddr * ((flag_SDHC == 1) ? 1 : BlockSize)); @@ -547,7 +548,7 @@ uint8_t BSP_SD_WriteBlocks( SD_IO_WriteByte(SD_TOKEN_START_DATA_SINGLE_BLOCK_WRITE); /* Write the block data to SD */ - SD_IO_WriteReadData((uint8_t*)pData + offset, ptr, BlockSize); + SD_IO_WriteReadData((uint8_t*)pData + offset, NULL, BlockSize); /* Set next write address */ offset += BlockSize; @@ -569,7 +570,7 @@ uint8_t BSP_SD_WriteBlocks( retr = BSP_SD_OK; error: - if(ptr != NULL) free(ptr); + /* Send dummy byte: 8 Clock pulses of delay */ SD_IO_CSState(1); SD_IO_WriteByte(SD_DUMMY_BYTE); diff --git a/firmware/targets/f7/furi_hal/furi_hal.c b/firmware/targets/f7/furi_hal/furi_hal.c index d0856127ac..141efdb603 100644 --- a/firmware/targets/f7/furi_hal/furi_hal.c +++ b/firmware/targets/f7/furi_hal/furi_hal.c @@ -1,5 +1,6 @@ #include #include +#include #include @@ -78,6 +79,7 @@ void furi_hal_init() { furi_hal_rfid_init(); #endif furi_hal_bt_init(); + furi_hal_memory_init(); furi_hal_compress_icon_init(); // FatFS driver initialization diff --git a/firmware/targets/f7/furi_hal/furi_hal_memory.c b/firmware/targets/f7/furi_hal/furi_hal_memory.c new file mode 100644 index 0000000000..43dc56f11b --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_memory.c @@ -0,0 +1,119 @@ +#include +#include +#include + +#define TAG "FuriHalMemory" + +typedef enum { + SRAM_A, + SRAM_B, + SRAM_MAX, +} SRAM; + +typedef struct { + void* start; + uint32_t size; +} FuriHalMemoryRegion; + +typedef struct { + FuriHalMemoryRegion region[SRAM_MAX]; +} FuriHalMemory; + +static FuriHalMemory* furi_hal_memory = NULL; + +extern const void __sram2a_start__; +extern const void __sram2a_free__; +extern const void __sram2b_start__; + +void furi_hal_memory_init() { + if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { + return; + } + + if(!ble_glue_wait_for_c2_start(FURI_HAL_BT_C2_START_TIMEOUT)) { + FURI_LOG_E(TAG, "C2 start timeout"); + return; + } + + FuriHalMemory* memory = malloc(sizeof(FuriHalMemory)); + + const BleGlueC2Info* c2_ver = ble_glue_get_c2_info(); + + if(c2_ver->mode == BleGlueC2ModeStack) { + uint32_t sram2a_busy_size = (uint32_t)&__sram2a_free__ - (uint32_t)&__sram2a_start__; + uint32_t sram2a_unprotected_size = (32 - c2_ver->MemorySizeSram2A) * 1024; + uint32_t sram2b_unprotected_size = (32 - c2_ver->MemorySizeSram2B) * 1024; + + memory->region[SRAM_A].start = (uint8_t*)&__sram2a_free__; + memory->region[SRAM_B].start = (uint8_t*)&__sram2b_start__; + + if(sram2a_unprotected_size > sram2a_busy_size) { + memory->region[SRAM_A].size = sram2a_unprotected_size - sram2a_busy_size; + } else { + memory->region[SRAM_A].size = 0; + } + memory->region[SRAM_B].size = sram2b_unprotected_size; + + FURI_LOG_I( + TAG, "SRAM2A: 0x%p, %d", memory->region[SRAM_A].start, memory->region[SRAM_A].size); + FURI_LOG_I( + TAG, "SRAM2B: 0x%p, %d", memory->region[SRAM_B].start, memory->region[SRAM_B].size); + + if((memory->region[SRAM_A].size > 0) || (memory->region[SRAM_B].size > 0)) { + if((memory->region[SRAM_A].size > 0)) { + FURI_LOG_I(TAG, "SRAM2A clear"); + memset(memory->region[SRAM_A].start, 0, memory->region[SRAM_A].size); + } + if((memory->region[SRAM_B].size > 0)) { + FURI_LOG_I(TAG, "SRAM2B clear"); + memset(memory->region[SRAM_B].start, 0, memory->region[SRAM_B].size); + } + furi_hal_memory = memory; + FURI_LOG_I(TAG, "Enabled"); + } else { + free(memory); + FURI_LOG_E(TAG, "No SRAM2 available"); + } + } else { + free(memory); + FURI_LOG_E(TAG, "No Core2 available"); + } +} + +void* furi_hal_memory_alloc(size_t size) { + if(furi_hal_memory == NULL) { + return NULL; + } + + for(int i = 0; i < SRAM_MAX; i++) { + if(furi_hal_memory->region[i].size >= size) { + void* ptr = furi_hal_memory->region[i].start; + furi_hal_memory->region[i].start += size; + furi_hal_memory->region[i].size -= size; + return ptr; + } + } + return NULL; +} + +size_t furi_hal_memory_get_free() { + if(furi_hal_memory == NULL) return 0; + + size_t free = 0; + for(int i = 0; i < SRAM_MAX; i++) { + free += furi_hal_memory->region[i].size; + } + return free; +} + +size_t furi_hal_memory_max_pool_block() { + if(furi_hal_memory == NULL) return 0; + + size_t max = 0; + for(int i = 0; i < SRAM_MAX; i++) { + if(furi_hal_memory->region[i].size > max) { + max = furi_hal_memory->region[i].size; + } + } + return max; +} \ No newline at end of file diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi.c b/firmware/targets/f7/furi_hal/furi_hal_spi.c index f8c5a2c782..2d54278d64 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_spi.c +++ b/firmware/targets/f7/furi_hal/furi_hal_spi.c @@ -139,8 +139,6 @@ bool furi_hal_spi_bus_trx( uint32_t timeout) { furi_assert(handle); furi_assert(handle->bus->current_handle == handle); - furi_assert(tx_buffer); - furi_assert(rx_buffer); furi_assert(size > 0); bool ret = true; @@ -149,15 +147,23 @@ bool furi_hal_spi_bus_trx( while(size > 0) { if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE(handle->bus->spi) && tx_allowed) { - LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer); - tx_buffer++; + if(tx_buffer) { + LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer); + tx_buffer++; + } else { + LL_SPI_TransmitData8(handle->bus->spi, 0xFF); + } tx_size--; tx_allowed = false; } if(LL_SPI_IsActiveFlag_RXNE(handle->bus->spi)) { - *rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi); - rx_buffer++; + if(rx_buffer) { + *rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi); + rx_buffer++; + } else { + LL_SPI_ReceiveData8(handle->bus->spi); + } size--; tx_allowed = true; } diff --git a/firmware/targets/f7/stm32wb55xx_flash.ld b/firmware/targets/f7/stm32wb55xx_flash.ld index 20314ba3c8..4124c096d9 100644 --- a/firmware/targets/f7/stm32wb55xx_flash.ld +++ b/firmware/targets/f7/stm32wb55xx_flash.ld @@ -57,7 +57,8 @@ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K RAM1 (xrw) : ORIGIN = 0x20000008, LENGTH = 0x2FFF8 -RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K +RAM2A (xrw) : ORIGIN = 0x20030000, LENGTH = 10K +RAM2B (xrw) : ORIGIN = 0x20038000, LENGTH = 10K } /* Define output sections */ @@ -186,9 +187,12 @@ SECTIONS } .ARM.attributes 0 : { *(.ARM.attributes) } - MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED - MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED - MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED + ._sram2a_start : { . = ALIGN(4); __sram2a_start__ = .; } >RAM2A + MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM2A + MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM2A + MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM2A + ._sram2a_free : { . = ALIGN(4); __sram2a_free__ = .; } >RAM2A + ._sram2b_start : { . = ALIGN(4); __sram2b_start__ = .; } >RAM2B } diff --git a/firmware/targets/f7/stm32wb55xx_ram_fw.ld b/firmware/targets/f7/stm32wb55xx_ram_fw.ld index 8c4d41c5b2..1b7fe3600a 100644 --- a/firmware/targets/f7/stm32wb55xx_ram_fw.ld +++ b/firmware/targets/f7/stm32wb55xx_ram_fw.ld @@ -57,7 +57,8 @@ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K RAM1 (xrw) : ORIGIN = 0x20000000, LENGTH = 0x30000 -RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K +RAM2A (xrw) : ORIGIN = 0x20030000, LENGTH = 10K +RAM2B (xrw) : ORIGIN = 0x20038000, LENGTH = 10K } /* Define output sections */ @@ -184,9 +185,12 @@ SECTIONS } .ARM.attributes 0 : { *(.ARM.attributes) } - MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED - MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED - MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED + ._sram2a_start : { . = ALIGN(4); __sram2a_start__ = .; } >RAM2A + MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM2A + MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM2A + MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM2A + ._sram2a_free : { . = ALIGN(4); __sram2a_free__ = .; } >RAM2A + ._sram2b_start : { . = ALIGN(4); __sram2b_start__ = .; } >RAM2B } diff --git a/firmware/targets/furi_hal_include/furi_hal_memory.h b/firmware/targets/furi_hal_include/furi_hal_memory.h new file mode 100644 index 0000000000..e9efa08c15 --- /dev/null +++ b/firmware/targets/furi_hal_include/furi_hal_memory.h @@ -0,0 +1,44 @@ +/** + * @file furi_hal_memory.h + * Memory HAL API + */ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Init memory pool manager + */ +void furi_hal_memory_init(); + +/** + * @brief Allocate memory from separate memory pool. That memory can't be freed. + * + * @param size + * @return void* + */ +void* furi_hal_memory_alloc(size_t size); + +/** + * @brief Get free memory pool size + * + * @return size_t + */ +size_t furi_hal_memory_get_free(); + +/** + * @brief Get max free block size from memory pool + * + * @return size_t + */ +size_t furi_hal_memory_max_pool_block(); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/furi/core/memmgr.c b/furi/core/memmgr.c index 80f87b930e..dba1a70740 100644 --- a/furi/core/memmgr.c +++ b/furi/core/memmgr.c @@ -1,6 +1,7 @@ #include "memmgr.h" #include "common_defines.h" #include +#include extern void* pvPortMalloc(size_t xSize); extern void vPortFree(void* pv); @@ -77,3 +78,18 @@ void* __wrap__realloc_r(struct _reent* r, void* ptr, size_t size) { UNUSED(r); return realloc(ptr, size); } + +void* memmgr_alloc_from_pool(size_t size) { + void* p = furi_hal_memory_alloc(size); + if(p == NULL) p = malloc(size); + + return p; +} + +size_t memmgr_pool_get_free(void) { + return furi_hal_memory_get_free(); +} + +size_t memmgr_pool_get_max_block(void) { + return furi_hal_memory_max_pool_block(); +} \ No newline at end of file diff --git a/furi/core/memmgr.h b/furi/core/memmgr.h index d7285fb238..fdecfd72da 100644 --- a/furi/core/memmgr.h +++ b/furi/core/memmgr.h @@ -35,6 +35,28 @@ size_t memmgr_get_total_heap(void); */ size_t memmgr_get_minimum_free_heap(void); +/** + * @brief Allocate memory from separate memory pool. That memory can't be freed. + * + * @param size + * @return void* + */ +void* memmgr_alloc_from_pool(size_t size); + +/** + * @brief Get free memory pool size + * + * @return size_t + */ +size_t memmgr_pool_get_free(void); + +/** + * @brief Get max free block size from memory pool + * + * @return size_t + */ +size_t memmgr_pool_get_max_block(void); + #ifdef __cplusplus } #endif diff --git a/furi/core/thread.c b/furi/core/thread.c index 044f83711b..a68472b56a 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -7,7 +7,9 @@ #include "mutex.h" #include +#include "log.h" #include +#include #include #define THREAD_NOTIFY_INDEX 1 // Index 0 is used for stream buffers @@ -20,6 +22,7 @@ struct FuriThreadStdout { }; struct FuriThread { + bool is_service; FuriThreadState state; int32_t ret; @@ -84,6 +87,11 @@ static void furi_thread_body(void* context) { furi_assert(thread->state == FuriThreadStateRunning); furi_thread_set_state(thread, FuriThreadStateStopped); + if(thread->is_service) { + FURI_LOG_E( + "Service", "%s thread exited. Thread memory cannot be reclaimed.", thread->name); + } + // clear thread local storage __furi_thread_stdout_flush(thread); furi_assert(pvTaskGetThreadLocalStoragePointer(NULL, 0) != NULL); @@ -96,7 +104,7 @@ static void furi_thread_body(void* context) { FuriThread* furi_thread_alloc() { FuriThread* thread = malloc(sizeof(FuriThread)); string_init(thread->output.buffer); - + thread->is_service = false; return thread; } @@ -117,6 +125,10 @@ void furi_thread_set_name(FuriThread* thread, const char* name) { thread->name = name ? strdup(name) : NULL; } +void furi_thread_mark_as_service(FuriThread* thread) { + thread->is_service = true; +} + void furi_thread_set_stack_size(FuriThread* thread, size_t stack_size) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); @@ -168,15 +180,23 @@ void furi_thread_start(FuriThread* thread) { furi_thread_set_state(thread, FuriThreadStateStarting); - BaseType_t ret = xTaskCreate( - furi_thread_body, - thread->name, - thread->stack_size / 4, - thread, - thread->priority ? thread->priority : FuriThreadPriorityNormal, - &thread->task_handle); + uint32_t stack = thread->stack_size / 4; + UBaseType_t priority = thread->priority ? thread->priority : FuriThreadPriorityNormal; + if(thread->is_service) { + thread->task_handle = xTaskCreateStatic( + furi_thread_body, + thread->name, + stack, + thread, + priority, + memmgr_alloc_from_pool(sizeof(StackType_t) * stack), + memmgr_alloc_from_pool(sizeof(StaticTask_t))); + } else { + BaseType_t ret = xTaskCreate( + furi_thread_body, thread->name, stack, thread, priority, &thread->task_handle); + furi_check(ret == pdPASS); + } - furi_check(ret == pdPASS); furi_check(thread->task_handle); } diff --git a/furi/core/thread.h b/furi/core/thread.h index 7f746f03fa..f15b9ff661 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -73,6 +73,13 @@ void furi_thread_free(FuriThread* thread); */ void furi_thread_set_name(FuriThread* thread, const char* name); +/** Mark thread as service + * The service cannot be stopped or removed, and cannot exit from the thread body + * + * @param thread + */ +void furi_thread_mark_as_service(FuriThread* thread); + /** Set FuriThread stack size * * @param thread FuriThread instance diff --git a/furi/flipper.c b/furi/flipper.c index c7d7c5a6c2..2acfea0151 100755 --- a/furi/flipper.c +++ b/furi/flipper.c @@ -2,6 +2,7 @@ #include #include #include +#include #define TAG "Flipper" @@ -38,9 +39,28 @@ void flipper_init() { furi_thread_set_name(thread, FLIPPER_SERVICES[i].name); furi_thread_set_stack_size(thread, FLIPPER_SERVICES[i].stack_size); furi_thread_set_callback(thread, FLIPPER_SERVICES[i].app); + furi_thread_mark_as_service(thread); furi_thread_start(thread); } FURI_LOG_I(TAG, "services startup complete"); } + +void vApplicationGetIdleTaskMemory( + StaticTask_t** tcb_ptr, + StackType_t** stack_ptr, + uint32_t* stack_size) { + *tcb_ptr = memmgr_alloc_from_pool(sizeof(StaticTask_t)); + *stack_ptr = memmgr_alloc_from_pool(sizeof(StackType_t) * configMINIMAL_STACK_SIZE); + *stack_size = configMINIMAL_STACK_SIZE; +} + +void vApplicationGetTimerTaskMemory( + StaticTask_t** tcb_ptr, + StackType_t** stack_ptr, + uint32_t* stack_size) { + *tcb_ptr = memmgr_alloc_from_pool(sizeof(StaticTask_t)); + *stack_ptr = memmgr_alloc_from_pool(sizeof(StackType_t) * configTIMER_TASK_STACK_DEPTH); + *stack_size = configTIMER_TASK_STACK_DEPTH; +} \ No newline at end of file From 1a4a6d4625aa3205c845e1e38c4f4b14419662b4 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Sat, 27 Aug 2022 12:06:25 +0400 Subject: [PATCH 52/78] [FL-2769] SubGhz: out debug data to external pin #1665 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../targets/f7/furi_hal/furi_hal_subghz.c | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.c b/firmware/targets/f7/furi_hal/furi_hal_subghz.c index ade4623898..7afb88bc33 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.c +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.c @@ -17,6 +17,28 @@ #define TAG "FuriHalSubGhz" + +/* + * Uncomment define to enable duplication of + * IO GO0 CC1101 to an external comb. + * Debug pin can be assigned + * gpio_ext_pc0 + * gpio_ext_pc1 + * gpio_ext_pc3 + * gpio_ext_pb2 + * gpio_ext_pb3 + * gpio_ext_pa4 + * gpio_ext_pa6 + * gpio_ext_pa7 + * Attention this setting switches pin to output. + * Make sure it is not connected directly to power or ground + */ + +//#define SUBGHZ_DEBUG_CC1101_PIN gpio_ext_pa7 +#ifdef SUBGHZ_DEBUG_CC1101_PIN +uint32_t subghz_debug_gpio_buff[2]; +#endif + typedef struct { volatile SubGhzState state; volatile SubGhzRegulation regulation; @@ -361,6 +383,9 @@ static void furi_hal_subghz_capture_ISR() { LL_TIM_ClearFlag_CC1(TIM2); furi_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1(TIM2); if(furi_hal_subghz_capture_callback) { +#ifdef SUBGHZ_DEBUG_CC1101_PIN + furi_hal_gpio_write(&SUBGHZ_DEBUG_CC1101_PIN, false); +#endif furi_hal_subghz_capture_callback( true, furi_hal_subghz_capture_delta_duration, @@ -371,6 +396,9 @@ static void furi_hal_subghz_capture_ISR() { if(LL_TIM_IsActiveFlag_CC2(TIM2)) { LL_TIM_ClearFlag_CC2(TIM2); if(furi_hal_subghz_capture_callback) { +#ifdef SUBGHZ_DEBUG_CC1101_PIN + furi_hal_gpio_write(&SUBGHZ_DEBUG_CC1101_PIN, true); +#endif furi_hal_subghz_capture_callback( false, LL_TIM_IC_GetCaptureCH2(TIM2) - furi_hal_subghz_capture_delta_duration, @@ -432,6 +460,11 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* LL_TIM_SetCounter(TIM2, 0); LL_TIM_EnableCounter(TIM2); +#ifdef SUBGHZ_DEBUG_CC1101_PIN + furi_hal_gpio_init( + &SUBGHZ_DEBUG_CC1101_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); +#endif + // Switch to RX furi_hal_subghz_rx(); } @@ -445,6 +478,11 @@ void furi_hal_subghz_stop_async_rx() { FURI_CRITICAL_ENTER(); LL_TIM_DeInit(TIM2); + +#ifdef SUBGHZ_DEBUG_CC1101_PIN + furi_hal_gpio_init(&SUBGHZ_DEBUG_CC1101_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow); +#endif + FURI_CRITICAL_EXIT(); furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); @@ -630,6 +668,32 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* LL_TIM_SetCounter(TIM2, 0); LL_TIM_EnableCounter(TIM2); + +#ifdef SUBGHZ_DEBUG_CC1101_PIN + furi_hal_gpio_init( + &SUBGHZ_DEBUG_CC1101_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + + const GpioPin* gpio = &SUBGHZ_DEBUG_CC1101_PIN; + subghz_debug_gpio_buff[0] = gpio->pin; + subghz_debug_gpio_buff[1] = (uint32_t)gpio->pin << GPIO_NUMBER; + + dma_config.MemoryOrM2MDstAddress = (uint32_t)subghz_debug_gpio_buff; + 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; + dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + dma_config.NbData = 2; + dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH; + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config); + LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, 2); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); + +#endif + return true; } @@ -661,6 +725,12 @@ void furi_hal_subghz_stop_async_tx() { // Deinitialize GPIO furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + +#ifdef SUBGHZ_DEBUG_CC1101_PIN + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); + furi_hal_gpio_init(&SUBGHZ_DEBUG_CC1101_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow); +#endif + FURI_CRITICAL_EXIT(); free(furi_hal_subghz_async_tx.buffer); From 689da15346e22e8b0857923155aadaa698d37a7d Mon Sep 17 00:00:00 2001 From: Max Andreev Date: Sat, 27 Aug 2022 15:38:13 +0300 Subject: [PATCH 53/78] workflows and fbtenv improovements (#1661) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add --restore option, improove clearing * fix trap * fix unset * fix fbtenv clearing * disabling pvs studio and amap analyses in forks, fbtenv.sh fixes * fbtenv fix Co-authored-by: あく --- .github/workflows/amap_analyse.yml | 1 + .github/workflows/pvs_studio.yml | 1 + scripts/toolchain/fbtenv.sh | 50 ++++++++++++++++++++++++------ 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/.github/workflows/amap_analyse.yml b/.github/workflows/amap_analyse.yml index a87857e74b..11dac543ae 100644 --- a/.github/workflows/amap_analyse.yml +++ b/.github/workflows/amap_analyse.yml @@ -14,6 +14,7 @@ env: jobs: amap_analyse: + if: ${{ !github.event.pull_request.head.repo.fork }} runs-on: [self-hosted,FlipperZeroMacShell] timeout-minutes: 15 steps: diff --git a/.github/workflows/pvs_studio.yml b/.github/workflows/pvs_studio.yml index c238b1c6f9..5733fd2749 100644 --- a/.github/workflows/pvs_studio.yml +++ b/.github/workflows/pvs_studio.yml @@ -15,6 +15,7 @@ env: jobs: analyse_c_cpp: + if: ${{ !github.event.pull_request.head.repo.fork }} runs-on: [self-hosted, FlipperZeroShell] steps: - name: 'Decontaminate previous build leftovers' diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index 6f3e8c661a..cbbb7b94db 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -13,6 +13,9 @@ fbtenv_show_usage() echo "Running this script manually is wrong, please source it"; echo "Example:"; printf "\tsource scripts/toolchain/fbtenv.sh\n"; + echo "To restore your enviroment source fbtenv.sh with '--restore'." + echo "Example:"; + printf "\tsource scripts/toolchain/fbtenv.sh --restore\n"; } fbtenv_curl() @@ -25,9 +28,27 @@ fbtenv_wget() wget --show-progress --progress=bar:force -qO "$1" "$2"; } +fbtenv_restore_env() +{ + TOOLCHAIN_ARCH_DIR_SED="$(echo "$TOOLCHAIN_ARCH_DIR" | sed 's/\//\\\//g')" + PATH="$(echo "$PATH" | /usr/bin/sed "s/$TOOLCHAIN_ARCH_DIR_SED\/python\/bin://g")"; + PATH="$(echo "$PATH" | /usr/bin/sed "s/$TOOLCHAIN_ARCH_DIR_SED\/bin://g")"; + PATH="$(echo "$PATH" | /usr/bin/sed "s/$TOOLCHAIN_ARCH_DIR_SED\/protobuf\/bin://g")"; + PATH="$(echo "$PATH" | /usr/bin/sed "s/$TOOLCHAIN_ARCH_DIR_SED\/openocd\/bin://g")"; + if [ -n "${PS1:-""}" ]; then + PS1="$(echo "$PS1" | sed 's/\[fbt\]//g')"; + elif [ -n "${PROMPT:-""}" ]; then + PROMPT="$(echo "$PROMPT" | sed 's/\[fbt\]//g')"; + fi + unset SCRIPT_PATH; + unset FBT_TOOLCHAIN_VERSION; + unset FBT_TOOLCHAIN_PATH; +} + fbtenv_check_sourced() { case "${ZSH_EVAL_CONTEXT:-""}" in *:file:*) + setopt +o nomatch; # disabling 'no match found' warning in zsh return 0;; esac if [ ${0##*/} = "fbtenv.sh" ]; then # exluding script itself @@ -138,15 +159,17 @@ fbtenv_download_toolchain_tar() { echo "Downloading toolchain:"; mkdir -p "$FBT_TOOLCHAIN_PATH/toolchain" || return 1; - "$FBT_DOWNLOADER" "$FBT_TOOLCHAIN_PATH/toolchain/$TOOLCHAIN_TAR" "$TOOLCHAIN_URL" || return 1; + "$FBT_DOWNLOADER" "$FBT_TOOLCHAIN_PATH/toolchain/$TOOLCHAIN_TAR.part" "$TOOLCHAIN_URL" || return 1; + # restoring oroginal filename if file downloaded successfully + mv "$FBT_TOOLCHAIN_PATH/toolchain/$TOOLCHAIN_TAR.part" "$FBT_TOOLCHAIN_PATH/toolchain/$TOOLCHAIN_TAR" echo "done"; return 0; } fbtenv_remove_old_tooclhain() { - printf "Removing old toolchain (if exist).."; - rm -rf "${TOOLCHAIN_ARCH_DIR}"; + printf "Removing old toolchain.."; + rm -rf "${TOOLCHAIN_ARCH_DIR:?}"; echo "done"; } @@ -175,8 +198,12 @@ fbtenv_unpack_toolchain() fbtenv_clearing() { printf "Clearing.."; - rm -rf "${FBT_TOOLCHAIN_PATH:?}/toolchain/$TOOLCHAIN_TAR"; + if [ -n "${FBT_TOOLCHAIN_PATH:-""}" ]; then + rm -rf "${FBT_TOOLCHAIN_PATH:?}/toolchain/"*.tar.gz; + rm -rf "${FBT_TOOLCHAIN_PATH:?}/toolchain/"*.part; + fi echo "done"; + trap - 2; return 0; } @@ -222,12 +249,13 @@ fbtenv_download_toolchain() fbtenv_check_tar || return 1; TOOLCHAIN_TAR="$(basename "$TOOLCHAIN_URL")"; TOOLCHAIN_DIR="$(echo "$TOOLCHAIN_TAR" | sed "s/-$FBT_TOOLCHAIN_VERSION.tar.gz//g")"; + trap fbtenv_clearing 2; # trap will be restored in fbtenv_clearing if ! fbtenv_check_downloaded_toolchain; then fbtenv_curl_wget_check || return 1; - fbtenv_download_toolchain_tar; + fbtenv_download_toolchain_tar || return 1; fi fbtenv_remove_old_tooclhain; - fbtenv_unpack_toolchain || { fbtenv_clearing && return 1; }; + fbtenv_unpack_toolchain || return 1; fbtenv_clearing; return 0; } @@ -235,15 +263,19 @@ fbtenv_download_toolchain() fbtenv_main() { fbtenv_check_sourced || return 1; + fbtenv_get_kernel_type || return 1; + if [ "$1" = "--restore" ]; then + fbtenv_restore_env; + return 0; + fi fbtenv_chck_many_source; # many source it's just a warning - fbtenv_set_shell_prompt; fbtenv_check_script_path || return 1; - fbtenv_get_kernel_type || return 1; fbtenv_check_download_toolchain || return 1; + fbtenv_set_shell_prompt; PATH="$TOOLCHAIN_ARCH_DIR/python/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/protobuf/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/openocd/bin:$PATH"; } -fbtenv_main; +fbtenv_main "${1:-""}"; From 194727515b58a5f449f251c3e9c5493b5695bfbc Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 28 Aug 2022 04:46:59 +0300 Subject: [PATCH 54/78] subghz decode raw gui by qistoph --- applications/subghz/helpers/subghz_types.h | 5 + .../subghz/scenes/subghz_scene_config.h | 1 + .../subghz/scenes/subghz_scene_decode_raw.c | 272 ++++++++++++++++++ .../subghz/scenes/subghz_scene_more_raw.c | 13 + .../subghz/scenes/subghz_scene_receiver.c | 5 +- applications/subghz/subghz_i.h | 3 + applications/subghz/views/receiver.c | 51 +++- applications/subghz/views/receiver.h | 8 + assets/icons/SubGhz/Decoding_123x52.png | Bin 0 -> 11929 bytes lib/subghz/subghz_file_encoder_worker.c | 12 + lib/subghz/subghz_file_encoder_worker.h | 9 + 11 files changed, 370 insertions(+), 9 deletions(-) create mode 100644 applications/subghz/scenes/subghz_scene_decode_raw.c create mode 100644 assets/icons/SubGhz/Decoding_123x52.png diff --git a/applications/subghz/helpers/subghz_types.h b/applications/subghz/helpers/subghz_types.h index 55ed40f84a..d6d6d025f7 100644 --- a/applications/subghz/helpers/subghz_types.h +++ b/applications/subghz/helpers/subghz_types.h @@ -81,3 +81,8 @@ struct SubGhzPresetDefinition { }; typedef struct SubGhzPresetDefinition SubGhzPresetDefinition; + +typedef enum { + SubGhzViewReceiverModeLive, + SubGhzViewReceiverModeFile, +} SubGhzViewReceiverMode; diff --git a/applications/subghz/scenes/subghz_scene_config.h b/applications/subghz/scenes/subghz_scene_config.h index 47cfe82128..c2731910be 100644 --- a/applications/subghz/scenes/subghz_scene_config.h +++ b/applications/subghz/scenes/subghz_scene_config.h @@ -29,6 +29,7 @@ ADD_SCENE(subghz, set_seed_bft, SetSeedBft) ADD_SCENE(subghz, frequency_analyzer, FrequencyAnalyzer) ADD_SCENE(subghz, read_raw, ReadRAW) ADD_SCENE(subghz, more_raw, MoreRAW) +ADD_SCENE(subghz, decode_raw, DecodeRAW) ADD_SCENE(subghz, delete_raw, DeleteRAW) ADD_SCENE(subghz, need_saving, NeedSaving) ADD_SCENE(subghz, rpc, Rpc) diff --git a/applications/subghz/scenes/subghz_scene_decode_raw.c b/applications/subghz/scenes/subghz_scene_decode_raw.c new file mode 100644 index 0000000000..ae77194372 --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_decode_raw.c @@ -0,0 +1,272 @@ +#include "../subghz_i.h" +#include "../views/receiver.h" + +#include + +#define TAG "SubGhzDecodeRaw" +#define SAMPLES_TO_READ_PER_TICK 400 + +// TODO: +// [X] Remember RAW file after decoding +// [X] Decode in tick events instead of on_enter +// [X] Make "Config" label optional in subghz_view_receiver_draw (../views/receiver.c) +// [X] Make "Scanning..." label optional in subghz_view_receiver_draw (../views/receiver.c) +// [X] Add Decoding logo +// [ ] Design nicer Decoding logo +// [X] Check progress in stream_buffer, instead of raw stream +// [X] Blink led while decoding +// [X] Stop rx blink (blue, fast) on history item view +// [X] Don't reparse file on back +// [X] Fix: RX animation+LED returning from decoded detail view +// [X] Find good value for SAMPLES_TO_READ_PER_TICK +// [X] Fix: read errors (slow flash) after aborting decode read + +typedef enum { + SubGhzDecodeRawStateStart, + SubGhzDecodeRawStateLoading, + SubGhzDecodeRawStateLoaded, +} SubGhzDecodeRawState; + +SubGhzDecodeRawState decode_raw_state = SubGhzDecodeRawStateStart; +SubGhzFileEncoderWorker* file_worker_encoder; + +static void subghz_scene_receiver_update_statusbar(void* context) { + SubGhz* subghz = context; + string_t history_stat_str; + string_init(history_stat_str); + if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { + string_t frequency_str; + string_t modulation_str; + + string_init(frequency_str); + string_init(modulation_str); + + subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + + subghz_view_receiver_add_data_statusbar( + subghz->subghz_receiver, + string_get_cstr(frequency_str), + string_get_cstr(modulation_str), + string_get_cstr(history_stat_str)); + + string_clear(frequency_str); + string_clear(modulation_str); + } else { + subghz_view_receiver_add_data_statusbar( + subghz->subghz_receiver, string_get_cstr(history_stat_str), "", ""); + } + string_clear(history_stat_str); +} + +void subghz_scene_decode_raw_callback(SubGhzCustomEvent event, void* context) { + furi_assert(context); + SubGhz* subghz = context; + view_dispatcher_send_custom_event(subghz->view_dispatcher, event); +} + +static void subghz_scene_add_to_history_callback( + SubGhzReceiver* receiver, + SubGhzProtocolDecoderBase* decoder_base, + void* context) { + furi_assert(context); + SubGhz* subghz = context; + string_t str_buff; + string_init(str_buff); + + if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) { + string_reset(str_buff); + + subghz->state_notifications = SubGhzNotificationStateRxDone; + + subghz_history_get_text_item_menu( + subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1); + subghz_view_receiver_add_item_to_menu( + subghz->subghz_receiver, + string_get_cstr(str_buff), + subghz_history_get_type_protocol( + subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1)); + + subghz_scene_receiver_update_statusbar(subghz); + } + subghz_receiver_reset(receiver); + string_clear(str_buff); +} + +bool subghz_scene_decode_raw_start(SubGhz* subghz) { + string_t file_name; + string_init(file_name); + bool success = false; + do { + if(!flipper_format_rewind(subghz->txrx->fff_data)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + + if(!flipper_format_read_string(subghz->txrx->fff_data, "File_name", file_name)) { + FURI_LOG_E(TAG, "Missing File_name"); + break; + } + + success = true; + } while(false); + + if(success) { + FURI_LOG_I(TAG, "Listening at \033[0;33m%s\033[0m.", string_get_cstr(file_name)); + + file_worker_encoder = subghz_file_encoder_worker_alloc(); + if(subghz_file_encoder_worker_start(file_worker_encoder, string_get_cstr(file_name))) { + //the worker needs a file in order to open and read part of the file + furi_delay_ms(100); + } else { + success = false; + } + + if(!success) { + subghz_file_encoder_worker_free(file_worker_encoder); + } + } + + string_clear(file_name); + return success; +} + +bool subghz_scene_decode_raw_next(SubGhz* subghz) { + LevelDuration level_duration; + + for(uint32_t read = SAMPLES_TO_READ_PER_TICK; read > 0; --read) { + level_duration = subghz_file_encoder_worker_get_level_duration(file_worker_encoder); + if(!level_duration_is_reset(level_duration)) { + bool level = level_duration_get_level(level_duration); + uint32_t duration = level_duration_get_duration(level_duration); + subghz_receiver_decode(subghz->txrx->receiver, level, duration); + } else { + decode_raw_state = SubGhzDecodeRawStateLoaded; + subghz->state_notifications = SubGhzNotificationStateIDLE; + + subghz_view_receiver_add_data_progress(subghz->subghz_receiver, "100%"); + return false; // No more samples available + } + } + + // Update progress info + string_t progress_str; + string_init(progress_str); + subghz_file_encoder_worker_get_text_progress(file_worker_encoder, progress_str); + + subghz_view_receiver_add_data_progress(subghz->subghz_receiver, string_get_cstr(progress_str)); + + string_clear(progress_str); + + return true; // More samples available +} + +void subghz_scene_decode_raw_on_enter(void* context) { + SubGhz* subghz = context; + + string_t str_buff; + string_init(str_buff); + + subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock); + subghz_view_receiver_set_mode(subghz->subghz_receiver, SubGhzViewReceiverModeFile); + subghz_view_receiver_set_callback( + subghz->subghz_receiver, subghz_scene_decode_raw_callback, subghz); + + subghz_receiver_set_rx_callback( + subghz->txrx->receiver, subghz_scene_add_to_history_callback, subghz); + + if(decode_raw_state == SubGhzDecodeRawStateStart) { + //Decode RAW to history + subghz_history_reset(subghz->txrx->history); + if(subghz_scene_decode_raw_start(subghz)) { + decode_raw_state = SubGhzDecodeRawStateLoading; + subghz->state_notifications = SubGhzNotificationStateRx; + } + } else { + //Load history to receiver + subghz_view_receiver_exit(subghz->subghz_receiver); + for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) { + string_reset(str_buff); + subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i); + subghz_view_receiver_add_item_to_menu( + subghz->subghz_receiver, + string_get_cstr(str_buff), + subghz_history_get_type_protocol(subghz->txrx->history, i)); + } + string_clear(str_buff); + subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen); + } + + subghz_scene_receiver_update_statusbar(subghz); + + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver); +} + +bool subghz_scene_decode_raw_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + bool consumed = false; + if(event.type == SceneManagerEventTypeCustom) { + switch(event.event) { + case SubGhzCustomEventViewReceiverBack: + decode_raw_state = SubGhzDecodeRawStateStart; + subghz->txrx->idx_menu_chosen = 0; + subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz); + + if(subghz_file_encoder_worker_is_running(file_worker_encoder)) { + subghz_file_encoder_worker_stop(file_worker_encoder); + } + subghz_file_encoder_worker_free(file_worker_encoder); + + subghz->state_notifications = SubGhzNotificationStateIDLE; + scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneMoreRAW); + consumed = true; + break; + case SubGhzCustomEventViewReceiverOK: + subghz->txrx->idx_menu_chosen = + subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); + subghz->state_notifications = SubGhzNotificationStateIDLE; + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); + consumed = true; + break; + case SubGhzCustomEventViewReceiverConfig: + FURI_LOG_I(TAG, "No config options"); + consumed = true; + break; + case SubGhzCustomEventViewReceiverOffDisplay: + notification_message(subghz->notifications, &sequence_display_backlight_off); + consumed = true; + break; + case SubGhzCustomEventViewReceiverUnlock: + subghz->lock = SubGhzLockOff; + consumed = true; + break; + default: + break; + } + } else if(event.type == SceneManagerEventTypeTick) { + switch(subghz->state_notifications) { + case SubGhzNotificationStateRx: + notification_message(subghz->notifications, &sequence_blink_cyan_10); + break; + case SubGhzNotificationStateRxDone: + notification_message(subghz->notifications, &subghs_sequence_rx); + subghz->state_notifications = SubGhzNotificationStateRx; + break; + default: + break; + } + + switch(decode_raw_state) { + case SubGhzDecodeRawStateLoading: + subghz_scene_decode_raw_next(subghz); + break; + default: + break; + } + } + return consumed; +} + +void subghz_scene_decode_raw_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/subghz/scenes/subghz_scene_more_raw.c b/applications/subghz/scenes/subghz_scene_more_raw.c index a5bade927f..7c1b8f7bf3 100644 --- a/applications/subghz/scenes/subghz_scene_more_raw.c +++ b/applications/subghz/scenes/subghz_scene_more_raw.c @@ -1,6 +1,7 @@ #include "../subghz_i.h" enum SubmenuIndex { + SubmenuIndexDecode, SubmenuIndexEdit, SubmenuIndexDelete, }; @@ -13,6 +14,13 @@ void subghz_scene_more_raw_submenu_callback(void* context, uint32_t index) { void subghz_scene_more_raw_on_enter(void* context) { SubGhz* subghz = context; + submenu_add_item( + subghz->submenu, + "Decode", + SubmenuIndexDecode, + subghz_scene_more_raw_submenu_callback, + subghz); + submenu_add_item( subghz->submenu, "Rename", @@ -50,6 +58,11 @@ bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) { subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexEdit); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); return true; + } else if(event.event == SubmenuIndexDecode) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexDecode); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDecodeRAW); + return true; } } return false; diff --git a/applications/subghz/scenes/subghz_scene_receiver.c b/applications/subghz/scenes/subghz_scene_receiver.c index 7c1f016d09..9d65072ce9 100644 --- a/applications/subghz/scenes/subghz_scene_receiver.c +++ b/applications/subghz/scenes/subghz_scene_receiver.c @@ -1,7 +1,7 @@ #include "../subghz_i.h" #include "../views/receiver.h" -static const NotificationSequence subghs_sequence_rx = { +const NotificationSequence subghs_sequence_rx = { &message_green_255, &message_vibro_on, @@ -14,7 +14,7 @@ static const NotificationSequence subghs_sequence_rx = { NULL, }; -static const NotificationSequence subghs_sequence_rx_locked = { +const NotificationSequence subghs_sequence_rx_locked = { &message_green_255, &message_display_backlight_on, @@ -109,6 +109,7 @@ void subghz_scene_receiver_on_enter(void* context) { } subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock); + subghz_view_receiver_set_mode(subghz->subghz_receiver, SubGhzViewReceiverModeLive); //Load history to receiver subghz_view_receiver_exit(subghz->subghz_receiver); diff --git a/applications/subghz/subghz_i.h b/applications/subghz/subghz_i.h index 1f6e735724..894c7984b9 100644 --- a/applications/subghz/subghz_i.h +++ b/applications/subghz/subghz_i.h @@ -137,3 +137,6 @@ void subghz_file_name_clear(SubGhz* subghz); bool subghz_path_is_file(string_t path); uint32_t subghz_random_serial(void); void subghz_hopper_update(SubGhz* subghz); + +extern const NotificationSequence subghs_sequence_rx; +extern const NotificationSequence subghs_sequence_rx_locked; diff --git a/applications/subghz/views/receiver.c b/applications/subghz/views/receiver.c index c28c336361..234372ff4c 100644 --- a/applications/subghz/views/receiver.c +++ b/applications/subghz/views/receiver.c @@ -55,13 +55,25 @@ typedef struct { string_t frequency_str; string_t preset_str; string_t history_stat_str; + string_t progress_str; SubGhzReceiverHistory* history; uint16_t idx; uint16_t list_offset; uint16_t history_item; SubGhzViewReceiverBarShow bar_show; + SubGhzViewReceiverMode mode; } SubGhzViewReceiverModel; +void subghz_view_receiver_set_mode( + SubGhzViewReceiver* subghz_receiver, + SubGhzViewReceiverMode mode) { + with_view_model( + subghz_receiver->view, (SubGhzViewReceiverModel * model) { + model->mode = mode; + return true; + }); +} + void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock lock) { furi_assert(subghz_receiver); subghz_receiver->lock_count = 0; @@ -150,6 +162,17 @@ void subghz_view_receiver_add_data_statusbar( }); } +void subghz_view_receiver_add_data_progress( + SubGhzViewReceiver* subghz_receiver, + const char* progress_str) { + furi_assert(subghz_receiver); + with_view_model( + subghz_receiver->view, (SubGhzViewReceiverModel * model) { + string_set_str(model->progress_str, progress_str); + return true; + }); +} + static void subghz_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) { canvas_set_color(canvas, ColorBlack); canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT); @@ -169,8 +192,12 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontSecondary); - elements_button_left(canvas, "Config"); - canvas_draw_line(canvas, 46, 51, 125, 51); + if(model->mode == SubGhzViewReceiverModeLive) { + elements_button_left(canvas, "Config"); + canvas_draw_line(canvas, 46, 51, 125, 51); + } else { + canvas_draw_str(canvas, 3, 62, string_get_cstr(model->progress_str)); + } bool scrollbar = model->history_item > 4; string_t str_buff; @@ -200,11 +227,18 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { canvas_set_color(canvas, ColorBlack); if(model->history_item == 0) { - canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 63, 46, "Scanning..."); - canvas_draw_line(canvas, 46, 51, 125, 51); - canvas_set_font(canvas, FontSecondary); + if(model->mode == SubGhzViewReceiverModeLive) { + canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 63, 46, "Scanning..."); + canvas_draw_line(canvas, 46, 51, 125, 51); + canvas_set_font(canvas, FontSecondary); + } else { + canvas_draw_icon(canvas, 0, 0, &I_Decoding_123x52); + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 63, 46, "Decoding..."); + canvas_set_font(canvas, FontSecondary); + } } switch(model->bar_show) { @@ -334,6 +368,7 @@ void subghz_view_receiver_exit(void* context) { string_reset(model->frequency_str); string_reset(model->preset_str); string_reset(model->history_stat_str); + for M_EACH(item_menu, model->history->data, SubGhzReceiverMenuItemArray_t) { string_clear(item_menu->item_str); @@ -369,6 +404,7 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() { string_init(model->frequency_str); string_init(model->preset_str); string_init(model->history_stat_str); + string_init(model->progress_str); model->bar_show = SubGhzViewReceiverBarShowDefault; model->history = malloc(sizeof(SubGhzReceiverHistory)); SubGhzReceiverMenuItemArray_init(model->history->data); @@ -387,6 +423,7 @@ void subghz_view_receiver_free(SubGhzViewReceiver* subghz_receiver) { string_clear(model->frequency_str); string_clear(model->preset_str); string_clear(model->history_stat_str); + string_clear(model->progress_str); for M_EACH(item_menu, model->history->data, SubGhzReceiverMenuItemArray_t) { string_clear(item_menu->item_str); diff --git a/applications/subghz/views/receiver.h b/applications/subghz/views/receiver.h index aab7a76c54..8292771744 100644 --- a/applications/subghz/views/receiver.h +++ b/applications/subghz/views/receiver.h @@ -8,6 +8,10 @@ typedef struct SubGhzViewReceiver SubGhzViewReceiver; typedef void (*SubGhzViewReceiverCallback)(SubGhzCustomEvent event, void* context); +void subghz_view_receiver_set_mode( + SubGhzViewReceiver* subghz_receiver, + SubGhzViewReceiverMode mode); + void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock keyboard); void subghz_view_receiver_set_callback( @@ -27,6 +31,10 @@ void subghz_view_receiver_add_data_statusbar( const char* preset_str, const char* history_stat_str); +void subghz_view_receiver_add_data_progress( + SubGhzViewReceiver* subghz_receiver, + const char* progress_str); + void subghz_view_receiver_add_item_to_menu( SubGhzViewReceiver* subghz_receiver, const char* name, diff --git a/assets/icons/SubGhz/Decoding_123x52.png b/assets/icons/SubGhz/Decoding_123x52.png new file mode 100644 index 0000000000000000000000000000000000000000..0773c7b74b02b72b5627e4e0c6ff65305a44d749 GIT binary patch literal 11929 zcmeHtcT|&I)-SzEN2C*))Icbqgib(u@7(|agLDFf-m7$J(nY#7QHn^Fjufdj4b9Ul%wN*%n=!q~eFi6x?mGsfy z0q9GV01N%e`TTt<1_mR$zo98oALa{i_jGeWIKu%*KX*6)jzTzKV4xOCb2l?Ao6{n1 zdg6sX+v;RT{K#AH&X%)TF*e{(K2T$C8my|t)exXaB^=zjxf=Jl=_x#awW42ZY|cX# zqOSo&7R()8Z=TrPlw9mx84Rq;+v)8%VJADxSAPWKeDO2aKmmR%Xd6`6XqQJ ziB_&-LY4~W0#URtt5l;p{=u>6Cmnb63CRszQRkw+`pfexn*LxGx#f`2E}Qa@w5yiy za#z+bJ`ImhLFXn0VnXaL`2kyQ?k|pdPsMxR;sfIy69Q|IH5l! zD0duT(jjv(WU*#PfAX?f|1^-}+Wza|&Ouh4RAGoedvLB?pqy93_{;q-+oh-1wHsX9 z+k2Al#+F3hY*gOgI-H;WK(i+ztAe_#<&spIQGO^cqSP*z$iiO5^|Zd=>{f7@o9s&M zm&Z087hg_-@`4+Bshfy1xL8NX_a4zad;shJ5OR4+<>c(~d7gaTJ0Sk^qWNWhlg!l8 ze8Q8g^=I88*(R2kQ!FPso$g7OJMGSK+gIDm)tmB(Dve7D+XS84&?2xO=OO@b6 z6zJWsdTKOmK&p4}nv5g%!$c~X1M@QDv3C$&my%|_Swb=jqwXv_=s<_$sedvn3BGqG zvn>%e*=b&nZ7QpBLj@jjPEMU+h#bA=3VdKYl&)a#MQ^;D`F9DvQq9Y0`(E8~q4GSh zA+Uw(>nv0Kq0)47ocQ+s9Lv$hY4e(<1)zC@b6?dH@HX%j!Gmwc<}S15+xe1G?7kgK zXYzaO2@;couIYL)iDKs*fetx-nP%mqVi!bw0{eCuMp-pY=Rb3G7ZB@KK1)rDyD_>_ z6ZyzPo^ocXontraiaUV#x5`-gJnyHP$y!)5_e3BrQj%{D^NH(J)?SCKiJMH31ry)cj7z@WW%1t~ z55CCwkh$+_o!oB5{Y*CX`xg-z+M8~pm&`0xKXQisXr29<$C&xgsf}l`qW8YMLMjeT zDf;7BG{*Qiu=F=OHtIRjgZEZU7)5HYZY|FE$<5}>*Y#Yh2Vix=x<&7)u4E*p+DD3< zxo4xMn`GYHvU>vsrE%HF^^q(~WpZNp&_D09k9f^sIx3*A%DzkC6yScg>uvjVV;n-e z!Vx}xNWU(5(Bgti{gxkii&gf_ge;|%)KwZ^bmk31CoGFS@x8C~6xlsPYBSieUS`k5 znsXav&q6?E(=gAEblVF_*h>CP(5P?}mw(gv(A=f=i_st-+UGGt1g-^)DzAdNZW5R9 z#F9NC!z(dsOb3h3HCL$_g=d{~Xcx_GPUDS$oh;QEmUd8fc&=kY+>QDzc%7^lLwCgs!4#aQP_p+rjy2nh z7SD`RtJ!fooAn9M4A<%7Wql#^fx0*R-YG-!?q2YI^1wOcr3{;&?Y;EJuV)(U7LTN# zm;}hwG-ws!a9eN?c59{`8#$XVaEt(gaGc?Z8R~Ra<}0*}A&e!RSB!Qu@}f;Z(BSjL z+r5rndpT6;1tWEuSjTaVS1%fL@&Xy_Y^_7bVAVZ$>}nn!M_^?8$TypJ;pvhvc0K1g zHT>DnG=4V)qbu?QohYVowd43&Y=yPC$RTIFe{4|H{112P#Ex_ci;>eYtW6;&K6`nB zCc^n!95FbJ<{qJ3t)gLz@s=D9Nnf86sn+}Ix-(QT25@8Se++_+F@xE1_a5HvXrd?I zibYl{v7JT1)M7}XuVf~_XjLjvQx_d|ufSu##HS>d2%}hQ#n`Y`vZc}VfpC7^E#k;# z$-9uxn{%Ep=DT$7Kla5W%%k`{V@4Z;7y`nN3Hof4gakRKD>e#ViUX(sz0UT%^oNeg zErf*)LF6TQq&d&7Rb4$prw>r?y0NGzEzDbzU&_4@>$i(+C&XVq9}9f4c4x|eR(?K3 zrQAM^q@^-o+q=1d`JNWnp>iPBvKXc3v=+IcapwLQ)t!CJAt*)T?gN0FS_x<8n(F)~YcqNZpzmu^W!e2*R9Qac@}3q8PP0-0>PG!h21Fg@YXnih}{ zX6uimXh@)|wFX73_>UNHG^#mF;y4QPr6d`KGKsU?#dE*uz?OSh`c1s;l}B`VjxI5b zBB~xdF@H~J#*4iHZw0F=(#dD%`@qRppYd_#s#xa}r7pFrK6lG7@8cTTrIV249ei!unvX_y zi#ZEB9F|b0QCkfM z+~O0B;mW1K*>VR{;ZIh#ixZARdG9kyw7#06SDRch=BM!>f?&=u;3{Mb=3^(W-+$KE zvDZ)FTRp&dM~8*Rfa^jw<@*&DqFCkKSuLwdTRSH~?5PxaBx+4zt#9-?j+|UI>W)b7M|T$NBqgZhm)DF2M-QPxahLu{sAdO05dQwXWG^GKjWEp@_n8UOs0 z?@^4}`zw_F-2n*~fDSF&k9UbHW6=2ZjO%w|PjVU^#bW)IShobmBF!=CA4-bt)9oc3G{W-_b;P+qYDX~QQtRdDX2G+C&_9FdRUqIl@_8yEoygGdUIPh@zRNK8N=Pk zJq->FRZGpk;TTqSrt)b8yYoDfPj?FmuHJzsSFhE%Y#dw>*xuK~`HF4+ENG%C)+v%k z0+);Vki1(2M$qexU9Vb-EBvTv7zN@bkKM=JR#op6Iy2aouXwRJAcZ}^wWd5(T)6oH z(1-KJ&6y%~_?8YYAVl{jKQ>=STr|BhQ36DR$%IAcaFJswlW_@`>f zFyg)l3u0D+;>PF#{{wp@=1pj%OT=*j=xb2=3#i5IHR)HFxc6krm0mC?E8WM^B&Agh zr>|&bLt$i#6|n*i4$~Fy0r0bkyV`!{s3!U`m^0~SK<0JDAc+lPOT5YFte;IUn^hAS zD?0!zPRhCuP~sm9$kk2bVwE#P4Q;z)CKZcBhtf5PUbSrDHkn)$&i37zImzv>$%P`0 z-RnDe?Wr-sh5A?(%{p`+>b@+Tj*lS>;zWTIi^l4-`VRV^ijX@nQqS2*uGDO~A!Mc~)h zw$haFhB3XDRD=Kg`0zwg0c-P&i4j+DWYo6c>Ez6C(RYi-E(Qb%i>s|G@iUca+*94z zUCitFpC+Z#Z|JO_>a_tbmR;qSVbZtzG!40jA#!1%tdT0p=~8?pCZi=7a8pC_nXJSwDS>=FcH zW`DO;5vN3lw5cS=h4e_P<}cXE(-Wvq^bFWMRX;|8I{Qx?j05 zg~)cF3SSX7xXbjN5h|nb(m`h?;I}cu+aJhdPiD1|>7W>CdNrMuNbgN>5A*7TR@KPG zZFYSl68)O0J>d%#!6*7}7kuW%-XS%6T+fU3yJMl?_X{|DUJ*hRwN08cgl~FvBc`!w z6g7r`?kb*|g%D59rF=4jQw8ggQZ2H->A=GjD(H1r?rq;5iElRNdeF?=- zo_sY5*6W9t@KpI6zG=dyTHbg+$8U%*AoUV+xSs3z;Qfq>;CA*P&*7`$ zN>6;S>~x)Wbb2iJ{;B76v16Xf9~XT5zp7}(3OAUh`Q+TW|3xV zATw0|z9Hol9~iMOq?zC?B^D|e%ktIZj^dB@LPdnaT4=34v7}(P(1ftjJr&W{^a5KA zAcwL~J9L&CAS&+ymNAnsa<%El^8yo#=IL#N>_~4*`m-U&d})xdFd>^GrxuApLcX?U z_)zXcf;mc(A0VS`by^;tE*qPRk15%o)k-``vMMt72`g7$es-#-SR0~ee5%6;vo_en z(SYtdz18n_j30WZ!_eO>Af>??`$A8KGW0=BjVE@62h~!?(O2N)2sv%UM)^0(wI;8L zBxgR`?U{_U@0|5z+MJ7Si)GGCd_LTZM+q5#LpP@75?e9{wMBW{M-T9mYh2ryysrd< zoEfOBvDJo3!XtgS{QDF+wOOe%#VdA)lH9DU?TLieIRobwU9mPvhZ;+QT=I2H^QQCy zyCSd+IV;=aM|dJZ2$o{k0Jr9wL|!WH;%Y*K+8#sf*OUG|Zc41Q>`B2#%UIZ7Gs2uW z>|V2K5sjDN@+U7O%7ehbR z2Rv+d@0#RJTwCrdVojxLAzOompXE4PVg5%=-;!X1%U(0ReDS4RtsrKhrgj5g(!=0J zMA!u809FE3XRJE!>jv`q$&GZO3WoPw&oGQ8^=?&0G0*S|m0L?Yc|;TPminvkhk=my|iV z@hKlsHdmftvi7N%a1sc!I(6cxtv#D=tL@{+!aFD?>TXu!z{yeETK9?NzJ3^D9b1+r zXiH^L`_cNAq}Cjlgq77nB|CJM`1rWF>y(7-ktxjfB+Kx!Dx(u<{L!W|LqDW5%_MM% z|GT5TS2T%;CjB&-^}Q(KRe3y&(45$>S@i3tEqcHde^26!C;sf~PI<|1U$^~?&s%TO zx_R`osF=9W2kUv5TVTK z;7PXyRfA@woYuU#IhyP091nIDd=b>@Pl?MwPiBf(4pIW)uR74}gILe~5(T|8ih{?V zafs@T;54$wI}+X6{8!!~5kz!NTPx5V9CuQ3$o_5=N=$Z!6A(>?O^B+M^G<1VE0urJ zN6+80$%HxI-_YDfB`&b~s4+wOsd&XZjSJm5ezU0V&&P90WNJKnKaUDJ6a&+$A?>*G zNX;;%CHz+Q*~;_tJXO`(v;YHCW)g^{kmZpQmD-s6?TI4)%JYEea^@A1M(c^uFxxd6o-EQ;h z03zlowg&2Je0on|@O@HFN0^JIq5$*{?B? zRjrKaWYM&+RL^r^9U+6)}M47_5}M60_1bNQdLA3sR0kM5~S zlnYQd=TC<`@I&b794g-!gY9E|j>RT3jeb;1VLrj?gMEhR--klELoZdA7tg4p!&;R- zAPudzn?~Ot@1)`rxn@R7*Hr6}Bun(Oe~Efhkft)DV1buyo9+}v3DWYWxgDWST6O1Z zg2|7_S=p3R%hvcJVh&iqB~vkJbB~MkS=pk@w4{#F9<|vsX!hb`Oy%+_4%@2&vvk^J zVrEGjf91_*%oG&7&4!^H)ZRau^H~@LC{C?7`0*Z8Ua2Pa76)o5)(EL`?fdJ#m^1p( zb3JY0*-38vnY#>RY+_RG0A8Nm>g8e!Deio(Clz@@3;b9nEB5yK`#p1SZhKjh+tkkl zA$sXVEAU?NCTGej+Rk@hF)TuJx|E%8(rD(3OCB(jS$bRHm<_%EzPEd|*un?q`XNtC zmNnNpP@%>1ve24eSCRjx{~cm&$8B9`aP3FuEsu+biJcO9l+MUf-yjCPvNY}Wn!0a( zCiNBeU9SUZDrzMZgoQHvB_CWWvNcfZbZz4-H9g{Pk6|Qhjy#(h>D+Le&&XfSkF9)s zAyL1zt@J%-y~)EG+v;c^I0BWOwg}dx!}4o269IXsshkj0{79NIGdL+0#JWg%{=~L_ zcWp@pxKuT{5IleNriRn|t-|6CL2Q7Ne{$6xzIXkV)ZUfno7h+>3c+CUi5>pLsRJW7k%9IHzsuO)VD8tL zq0Fya)zJtNI8x1c$pU)`GoOZh##t9!qGs6OCfDbc5+N|xaI_8H&~{DjI3b>v_a_{g z)(FTl+X@&hsw{wdY@;7(v4>|zm6gc(9m0qV2KFe}9kQ!+A}uj*kT;m^&%^|8_e?ep zRZR^e4H5MzL{p?9M9ZKUSJkvMYI7RT*{CB6l~+2Cw;-LoH23^;^ea^33_CO4Qth%V z5{tCDUVRkvuC8YTcg@Th9d1nMX-$qk0DB`P@hN)NqXp6`p5oW%^Qpfp+kF_%jy{m- z^|Y8NLH($ZDwoQ@zwMPuE!6eAVum;?*|B-OT7~s6-VCs zLQuHqx1K8l11qu((Kt7T{J1+%GEqSyclGvi3VX4c&O z@Tbvj{)qzY1dXpG^k+t~X{KN_Rx)Ya=B@DpTXcY~YKZ|pI$}Y8` zF^e-L#w52@qW4~RDuqUJYx)d)hZn)tt{nh5T#uWUIS;{GZ2^MpiXbd~czi#dj0PlRmwPscO`f%QW8eV~U5P-r61K zsrNh|mxn!WXswGqG|}LqMn*vHYR4ZcHQX-ru792XQBx)J8NhXNM_wX+oXjAkSl5%)O$ z5l5W%zyOMonx~Avfo++PU@O1Xwf{V*mi(4zO~dI&=trQQ@0K>zdaIvXv$_?jdR1bXuA?>+ z<>Ni`iIMY?VznjmBzj}%w~?Nb-Z%PiHKXK+u+*p9i`0m8PL*cB9`2r&5gvAt z0MDA{2aah>)by-itMi<{XR{Bm)tp9MZRJW6l5_xBzMw3S-R{7JZ`NDLB<#us`D_pY zv09l=nieWYyaRSz8lRUHe-%73St7KGH;%hKSf#G})oQx;(XPz?p1o4bU=`AnRA z%jh7)=g7M=NhTWJ08dqlp=A8foRE(l7>oW<%}5s3xEZJVug&HQdigN{2>lahO)eC* z3x*|R z(Ic$s4@~DoDLuL^QSBSqUHeK&vC)LLp}5rZ#m-NO8Y7D`(?>d%-j}0@wipdZ9v5u} zoU?Ux-YGl7N=Ty$%XA|?wIzN*a`UF?6STz;R_W3CBuv@XXq3Y$HEd#i%!6IDEYc~e zan5$T_4`ccg52)*P$wz@!s&a1Pgtq5A|h-Zg@J(?g@8hJ)u7P7l?%~D!n~kV8Py(n z#y%U1Qe|FJpOn>5~`l~l-ijQc?k}eK*KYiI{T5&VXcJfKYu5zH;v{xMbW*oJ`rx?qYAe5jw zGQF-OggbuVO~zugw<`Va;$z`6lcC&O`-HtOHO2W?Nme(tG}hbD`!P;6R#`4)@J4uV zvSpT4@E1$u+_(t)y}L3xjI1>AO#HqeK04k5Y7b34@bHPFm9d1IhcO>`wv{UcCQ(?*`v6vzE~{klzTD|jjahb{ z`{TESMHhWda?znH0`IFAf1bQ>5!VUr5^*nWyqduS9jW=Z*YqWYcDSspw$=;+laFpyU&6qT>2gnP_#pF%Y3uvWvPjK! zFve>_&z>)qj*{rQ?m7Zpzctm;gxI;c2*B*!Y~cbZ7k6}h7Xw3D4&@HBdk9AYY~hXw zR~fdwH=S$%guM)#30MoH!ps%m5fUk&vo2R3okffxfAV^qHSQv=b0DAekB4H??s~7t(h(9ot z;9ho~2zMmH%@yzq6K3n?jg(!ek3xNLKqU#JpI-m_?*fbHY z-l)F|3=uAH10?JhgF<3rLSP{YVUVP-gqR5UAFPexo?htm{e>w65)k=A@@ps{=wQ%f z!hR(;8sIl9nkWd=6AnYVc^bO8Im@v9atZLu^7otoNdLj4D#8n`;rDBr{5eq!;2wY6 z{V{Kx5x+$M!0%j#!0i6$#0%yFxBuM{+U^gL-2<4bBOJXb{Fy|5Ye)Qx!4gJODI^54 z1KJCThyz7oBEmokF*^|;TmlYqfQy1*;;=u$`wQL6%>n5P^Mornq9a8|gHGDt(EzxA zQ_1tszW6?X|KbUK4hIBD0ENX2g+w7>5CkO22NH&WKx~441}yk%DfnB&(t`gdCx6nU z1ouRs1HR|!=JJ~kFC=;zLhS#27AyQ;vlz|TFZ+MR%%8JB^55G3c3t|no~?$862{H1cTs!!uNFdgRWmOP3}UKZ z7bZqd9xb{NAE~CLjQ@>*{+2Ld!Sgq-Ffg#Z)RYtqQ42e{i?xw}Tgv!fZf=Cv!y=&z z`U~-crLx&-c#LMw;x2H-goE{gt}mWA+JQ%3GQ~+)LCdXDKRB!#YEwsD7=y6yl5u+^ z2t|`mzK#R?dbBvP475-UP|6?#D>3&JYdx^Uud9@F#8NDK<5X@}suht1gtjgR8Vw!_ zgs$jcr57o!iR80JQ~(tONZ zCUSmemISRA^l$Q#mm4MVCy>#ktC^awFIW2L^7}n-8Kvr8_iqm*;wE`K4&?IF&N}wE z|30l*nimS-`Z0&P?B8asC0N+atz<8_?6|r6Idi+@OwF-1t90N??8)f#z$0H7mMq#> z4!}giF6TZ|pyh3aMX^q%{I%zzN!Sb#)}+gK9S;s-__oMq<_q83Ob+1JxdC*C2y0wY zG-i$bmvGFOAM{5R6-$xjH1~3`&=S6iGfk^bYd?ME^EoJ{YMY*%c%UoYS8VF^hvgSy zzYXf%H3)p9L~1vY>znW%nBzuDp&(@Xnzdj5=ckXJh!`$2>25QLXDc$xwcY}D0R9Bi zuTnQdeBaeRR^PpAJ27iI)_qmy0X(*LTk7iX-SLo{L=8;eFn;t&l-ebwXCZ8FdUqCi z$(=wp=wy@*^&BIOd-F25>Hv0=40+j4Szw~k-flipper_format); + size_t total_size = stream_size(stream); + size_t current_offset = stream_tell(stream); + size_t buffer_avail = xStreamBufferBytesAvailable(instance->stream); + + string_printf(output, "%03u%%", 100 * (current_offset - buffer_avail) / total_size); +} + LevelDuration subghz_file_encoder_worker_get_level_duration(void* context) { furi_assert(context); SubGhzFileEncoderWorker* instance = context; diff --git a/lib/subghz/subghz_file_encoder_worker.h b/lib/subghz/subghz_file_encoder_worker.h index a87be5cd6f..e7280a6363 100644 --- a/lib/subghz/subghz_file_encoder_worker.h +++ b/lib/subghz/subghz_file_encoder_worker.h @@ -28,6 +28,15 @@ SubGhzFileEncoderWorker* subghz_file_encoder_worker_alloc(); */ void subghz_file_encoder_worker_free(SubGhzFileEncoderWorker* instance); +/** + * Get a description of the progress. + * @param instance Pointer to a SubGhzFileEncoderWorker instance + * @param output + */ +void subghz_file_encoder_worker_get_text_progress( + SubGhzFileEncoderWorker* instance, + string_t output); + /** * Getting the level and duration of the upload to be loaded into DMA. * @param context Pointer to a SubGhzFileEncoderWorker instance From 79c4b617c1e617f60f388e488f4401ba8788cfcb Mon Sep 17 00:00:00 2001 From: mothball187 Date: Sat, 27 Aug 2022 19:47:10 -0700 Subject: [PATCH 55/78] tweak sniff parameters for more speed and reliability. clear sniff data on stop or exit. replace preamble GUI option with sample time option --- applications/nrfsniff/nrfsniff.c | 143 +++++++++++++++++-------------- lib/drivers/nrf24.c | 3 +- 2 files changed, 81 insertions(+), 65 deletions(-) diff --git a/applications/nrfsniff/nrfsniff.c b/applications/nrfsniff/nrfsniff.c index e8dee30acd..a9be614a9b 100644 --- a/applications/nrfsniff/nrfsniff.c +++ b/applications/nrfsniff/nrfsniff.c @@ -9,8 +9,10 @@ #include #define LOGITECH_MAX_CHANNEL 85 -#define COUNT_THRESHOLD 4 -#define SAMPLE_TIME 20000 +#define COUNT_THRESHOLD 2 +#define DEFAULT_SAMPLE_TIME 8000 +#define MAX_ADDRS 100 +#define MAX_CONFIRMED 32 #define NRFSNIFF_APP_PATH_FOLDER "/ext/nrfsniff" #define NRFSNIFF_APP_FILENAME "addresses.txt" @@ -32,31 +34,36 @@ typedef struct { } PluginState; char rate_text_fmt[] = "Transfer rate: %dMbps"; +char sample_text_fmt[] = "Sample Time: %d ms"; char channel_text_fmt[] = "Channel: %d"; char preamble_text_fmt[] = "Preamble: %02X"; char sniff_text_fmt[] = "Sniffing: %s Found: %d"; char addresses_header_text[] = "Address,rate"; char sniffed_address_fmt[] = "%s,%d"; char rate_text[46]; -char channel_text[42]; +char channel_text[14]; +char sample_text[32]; char preamble_text[14]; char sniff_text[38]; char sniffed_address[14]; uint8_t target_channel = 0; uint32_t found_count = 0; +uint32_t sample_time = DEFAULT_SAMPLE_TIME; uint8_t target_rate = 8; // rate can be either 8 (2Mbps) or 0 (1Mbps) uint8_t target_preamble[] = {0xAA, 0x00}; uint8_t sniffing_state = false; char top_address[12]; -uint8_t candidates[100][5] = {0}; // top 100 recurring addresses -uint32_t counts[100]; -uint8_t total_candidates = 0; -uint8_t last_cleanup_idx = 101; // avoid replacing the last replaced addr +uint8_t candidates[MAX_ADDRS][5] = {0}; // last 100 sniffed addresses +uint32_t counts[MAX_ADDRS]; +uint8_t confirmed[MAX_CONFIRMED][5] = {0}; // first 32 confirmed addresses +uint8_t confirmed_idx = 0; +uint32_t total_candidates = 0; +uint32_t candidate_idx = 0; static int get_addr_index(uint8_t* addr, uint8_t addr_size) { - for(int i = 0; i < total_candidates; i++) { + for(uint32_t i = 0; i < total_candidates; i++) { uint8_t* arr_item = candidates[i]; if(!memcmp(arr_item, addr, addr_size)) return i; } @@ -64,32 +71,10 @@ static int get_addr_index(uint8_t* addr, uint8_t addr_size) { return -1; } -/* -static uint32_t get_addr_count(uint8_t* addr, uint8_t addr_size) -{ - return counts[get_addr_index(addr, addr_size)]; -} -*/ - -static uint8_t get_lowest_idx() { - uint32_t lowest = 10000; - uint8_t lowest_idx = 0; - for(uint8_t i = 0; i < total_candidates; i++) { - if(i == last_cleanup_idx) continue; - - if(counts[i] < lowest) { - lowest = counts[i]; - lowest_idx = i; - } - } - last_cleanup_idx = lowest_idx; - return lowest_idx; -} - -static uint8_t get_highest_idx() { +static int get_highest_idx() { uint32_t highest = 0; - uint8_t highest_idx = 0; - for(uint8_t i = 0; i < total_candidates; i++) { + int highest_idx = 0; + for(uint32_t i = 0; i < total_candidates; i++) { if(counts[i] > highest) { highest = counts[i]; highest_idx = i; @@ -99,15 +84,15 @@ static uint8_t get_highest_idx() { return highest_idx; } +// if array is full, start over from beginning static void insert_addr(uint8_t* addr, uint8_t addr_size) { - uint8_t idx = total_candidates; - if(total_candidates > 99) { - // replace addr with lowest count - idx = get_lowest_idx(); - } - memcpy(candidates[idx], addr, addr_size); - counts[idx] = 1; - if(total_candidates < 100) total_candidates++; + if(candidate_idx >= MAX_ADDRS) + candidate_idx = 0; + + memcpy(candidates[candidate_idx], addr, addr_size); + counts[candidate_idx] = 1; + if(total_candidates < MAX_ADDRS) total_candidates++; + candidate_idx++; } static void render_callback(Canvas* const canvas, void* ctx) { @@ -128,13 +113,15 @@ static void render_callback(Canvas* const canvas, void* ctx) { snprintf(rate_text, sizeof(rate_text), rate_text_fmt, (int)rate); snprintf(channel_text, sizeof(channel_text), channel_text_fmt, (int)target_channel); - snprintf(preamble_text, sizeof(preamble_text), preamble_text_fmt, target_preamble[0]); + snprintf(sample_text, sizeof(sample_text), sample_text_fmt, (int)sample_time); + //snprintf(preamble_text, sizeof(preamble_text), preamble_text_fmt, target_preamble[0]); snprintf(sniff_text, sizeof(sniff_text), sniff_text_fmt, sniffing, found_count); snprintf( sniffed_address, sizeof(sniffed_address), sniffed_address_fmt, top_address, (int)rate); canvas_draw_str_aligned(canvas, 10, 10, AlignLeft, AlignBottom, rate_text); - canvas_draw_str_aligned(canvas, 10, 20, AlignLeft, AlignBottom, channel_text); - canvas_draw_str_aligned(canvas, 10, 30, AlignLeft, AlignBottom, preamble_text); + canvas_draw_str_aligned(canvas, 10, 20, AlignLeft, AlignBottom, sample_text); + canvas_draw_str_aligned(canvas, 10, 30, AlignLeft, AlignBottom, channel_text); + //canvas_draw_str_aligned(canvas, 10, 30, AlignLeft, AlignBottom, preamble_text); canvas_draw_str_aligned(canvas, 10, 40, AlignLeft, AlignBottom, sniff_text); canvas_draw_str_aligned(canvas, 30, 50, AlignLeft, AlignBottom, addresses_header_text); canvas_draw_str_aligned(canvas, 30, 60, AlignLeft, AlignBottom, sniffed_address); @@ -256,12 +243,24 @@ void alt_address(uint8_t* addr, uint8_t* altaddr) { for(int i = 0; i < 5; i++) altaddr[i] = tmpaddr[4 - i]; } +static bool previously_confirmed(uint8_t *addr){ + bool found = false; + for(int i = 0; i < MAX_CONFIRMED; i++){ + if(!memcmp(confirmed[i], addr, 5)){ + found = true; + break; + } + } + + return found; +} + static void wrap_up(Storage* storage, NotificationApp* notification) { uint8_t ch; uint8_t addr[5]; uint8_t altaddr[5]; char trying[12]; - uint8_t idx; + int idx; uint8_t rate = 0; if(target_rate == 8) rate = 2; @@ -291,14 +290,25 @@ static void wrap_up(Storage* storage, NotificationApp* notification) { hexlify(addr, 5, top_address); save_addr_to_file(storage, addr, 5, notification); found_count++; + if(confirmed_idx < MAX_CONFIRMED) + memcpy(confirmed[confirmed_idx++], addr, 5); break; } } } -static void start_sniffing() { +static void clear_cache(){ + found_count = 0; + confirmed_idx = 0; + candidate_idx = 0; + target_channel = 2; + total_candidates = 0; memset(candidates, 0, sizeof(candidates)); memset(counts, 0, sizeof(counts)); + memset(confirmed, 0, sizeof(confirmed)); +} + +static void start_sniffing() { nrf24_init_promisc_mode(nrf24_HANDLE, target_channel, target_rate); } @@ -311,8 +321,8 @@ int32_t nrfsniff_app(void* p) { PluginState* plugin_state = malloc(sizeof(PluginState)); ValueMutex state_mutex; if(!init_mutex(&state_mutex, plugin_state, sizeof(PluginState))) { - FURI_LOG_E(TAG, "cannot create mutex\r\n"); furi_message_queue_free(event_queue); + FURI_LOG_E(TAG, "cannot create mutex\r\n"); free(plugin_state); return 255; } @@ -366,18 +376,20 @@ int32_t nrfsniff_app(void* p) { break; case InputKeyRight: // increment channel - if(!sniffing_state && target_channel <= LOGITECH_MAX_CHANNEL) - target_channel++; + //if(!sniffing_state && target_channel <= LOGITECH_MAX_CHANNEL) + // target_channel++; + sample_time += 500; break; case InputKeyLeft: // decrement channel - if(!sniffing_state && target_channel > 0) target_channel--; + //if(!sniffing_state && target_channel > 0) target_channel--; + if(sample_time > 500) sample_time -= 500; break; case InputKeyOk: // toggle sniffing sniffing_state = !sniffing_state; if(sniffing_state) { - found_count = 0; + clear_cache(); start_sniffing(); start = furi_get_tick(); } else @@ -398,22 +410,26 @@ int32_t nrfsniff_app(void* p) { if(nrf24_sniff_address(nrf24_HANDLE, 5, address)) { int idx; uint8_t* top_addr; - idx = get_addr_index(address, 5); - if(idx == -1) - insert_addr(address, 5); - else - counts[idx]++; - - top_addr = candidates[get_highest_idx()]; - hexlify(top_addr, 5, top_address); + if(!previously_confirmed(address)){ + idx = get_addr_index(address, 5); + if(idx == -1) + insert_addr(address, 5); + else + counts[idx]++; + + top_addr = candidates[get_highest_idx()]; + hexlify(top_addr, 5, top_address); + } } - if(furi_get_tick() - start >= SAMPLE_TIME) { - wrap_up(storage, notification); + if(furi_get_tick() - start >= sample_time) { target_channel++; if(target_channel > LOGITECH_MAX_CHANNEL) target_channel = 2; + { + wrap_up(storage, notification); + start_sniffing(); + } - start_sniffing(); start = furi_get_tick(); } } @@ -422,6 +438,7 @@ int32_t nrfsniff_app(void* p) { release_mutex(&state_mutex, plugin_state); } + clear_cache(); furi_hal_spi_release(nrf24_HANDLE); view_port_enabled_set(view_port, false); gui_remove_view_port(gui, view_port); @@ -432,4 +449,4 @@ int32_t nrfsniff_app(void* p) { furi_message_queue_free(event_queue); return 0; -} \ No newline at end of file +} diff --git a/lib/drivers/nrf24.c b/lib/drivers/nrf24.c index f2e315d9f5..e70acad659 100644 --- a/lib/drivers/nrf24.c +++ b/lib/drivers/nrf24.c @@ -350,12 +350,11 @@ void nrf24_init_promisc_mode(FuriHalSpiBusHandle* handle, uint8_t channel, uint8 nrf24_flush_tx(handle); nrf24_write_reg(handle, REG_RF_CH, channel); nrf24_write_reg(handle, REG_RF_SETUP, rate); - furi_delay_ms(200); // prime for RX, no checksum nrf24_write_reg(handle, REG_CONFIG, 0x03); // PWR_UP and PRIM_RX, disable AA and CRC furi_hal_gpio_write(nrf24_CE_PIN, true); - furi_delay_ms(2000); + furi_delay_ms(100); } void hexlify(uint8_t* in, uint8_t size, char* out) { From 9c748860bb86a12f631bbe6f7c12c273b2093b10 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 28 Aug 2022 05:58:53 +0300 Subject: [PATCH 56/78] disable wav player, use standard icon in receiver --- applications/meta/application.fam | 2 +- applications/subghz/views/receiver.c | 3 ++- assets/icons/SubGhz/Decoding_123x52.png | Bin 11929 -> 0 bytes 3 files changed, 3 insertions(+), 2 deletions(-) delete mode 100644 assets/icons/SubGhz/Decoding_123x52.png diff --git a/applications/meta/application.fam b/applications/meta/application.fam index 7aa552de10..96de16b4de 100644 --- a/applications/meta/application.fam +++ b/applications/meta/application.fam @@ -75,7 +75,7 @@ App( "wifi_marauder", "esp8266_deauth", "wifi_scanner", - "wav_player", + #"wav_player", "multi_converter", "flipfrid", ], diff --git a/applications/subghz/views/receiver.c b/applications/subghz/views/receiver.c index 234372ff4c..747a65d63e 100644 --- a/applications/subghz/views/receiver.c +++ b/applications/subghz/views/receiver.c @@ -234,7 +234,8 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { canvas_draw_line(canvas, 46, 51, 125, 51); canvas_set_font(canvas, FontSecondary); } else { - canvas_draw_icon(canvas, 0, 0, &I_Decoding_123x52); + //canvas_draw_icon(canvas, 0, 0, &I_Decoding_123x52); + canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 63, 46, "Decoding..."); canvas_set_font(canvas, FontSecondary); diff --git a/assets/icons/SubGhz/Decoding_123x52.png b/assets/icons/SubGhz/Decoding_123x52.png deleted file mode 100644 index 0773c7b74b02b72b5627e4e0c6ff65305a44d749..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11929 zcmeHtcT|&I)-SzEN2C*))Icbqgib(u@7(|agLDFf-m7$J(nY#7QHn^Fjufdj4b9Ul%wN*%n=!q~eFi6x?mGsfy z0q9GV01N%e`TTt<1_mR$zo98oALa{i_jGeWIKu%*KX*6)jzTzKV4xOCb2l?Ao6{n1 zdg6sX+v;RT{K#AH&X%)TF*e{(K2T$C8my|t)exXaB^=zjxf=Jl=_x#awW42ZY|cX# zqOSo&7R()8Z=TrPlw9mx84Rq;+v)8%VJADxSAPWKeDO2aKmmR%Xd6`6XqQJ ziB_&-LY4~W0#URtt5l;p{=u>6Cmnb63CRszQRkw+`pfexn*LxGx#f`2E}Qa@w5yiy za#z+bJ`ImhLFXn0VnXaL`2kyQ?k|pdPsMxR;sfIy69Q|IH5l! zD0duT(jjv(WU*#PfAX?f|1^-}+Wza|&Ouh4RAGoedvLB?pqy93_{;q-+oh-1wHsX9 z+k2Al#+F3hY*gOgI-H;WK(i+ztAe_#<&spIQGO^cqSP*z$iiO5^|Zd=>{f7@o9s&M zm&Z087hg_-@`4+Bshfy1xL8NX_a4zad;shJ5OR4+<>c(~d7gaTJ0Sk^qWNWhlg!l8 ze8Q8g^=I88*(R2kQ!FPso$g7OJMGSK+gIDm)tmB(Dve7D+XS84&?2xO=OO@b6 z6zJWsdTKOmK&p4}nv5g%!$c~X1M@QDv3C$&my%|_Swb=jqwXv_=s<_$sedvn3BGqG zvn>%e*=b&nZ7QpBLj@jjPEMU+h#bA=3VdKYl&)a#MQ^;D`F9DvQq9Y0`(E8~q4GSh zA+Uw(>nv0Kq0)47ocQ+s9Lv$hY4e(<1)zC@b6?dH@HX%j!Gmwc<}S15+xe1G?7kgK zXYzaO2@;couIYL)iDKs*fetx-nP%mqVi!bw0{eCuMp-pY=Rb3G7ZB@KK1)rDyD_>_ z6ZyzPo^ocXontraiaUV#x5`-gJnyHP$y!)5_e3BrQj%{D^NH(J)?SCKiJMH31ry)cj7z@WW%1t~ z55CCwkh$+_o!oB5{Y*CX`xg-z+M8~pm&`0xKXQisXr29<$C&xgsf}l`qW8YMLMjeT zDf;7BG{*Qiu=F=OHtIRjgZEZU7)5HYZY|FE$<5}>*Y#Yh2Vix=x<&7)u4E*p+DD3< zxo4xMn`GYHvU>vsrE%HF^^q(~WpZNp&_D09k9f^sIx3*A%DzkC6yScg>uvjVV;n-e z!Vx}xNWU(5(Bgti{gxkii&gf_ge;|%)KwZ^bmk31CoGFS@x8C~6xlsPYBSieUS`k5 znsXav&q6?E(=gAEblVF_*h>CP(5P?}mw(gv(A=f=i_st-+UGGt1g-^)DzAdNZW5R9 z#F9NC!z(dsOb3h3HCL$_g=d{~Xcx_GPUDS$oh;QEmUd8fc&=kY+>QDzc%7^lLwCgs!4#aQP_p+rjy2nh z7SD`RtJ!fooAn9M4A<%7Wql#^fx0*R-YG-!?q2YI^1wOcr3{;&?Y;EJuV)(U7LTN# zm;}hwG-ws!a9eN?c59{`8#$XVaEt(gaGc?Z8R~Ra<}0*}A&e!RSB!Qu@}f;Z(BSjL z+r5rndpT6;1tWEuSjTaVS1%fL@&Xy_Y^_7bVAVZ$>}nn!M_^?8$TypJ;pvhvc0K1g zHT>DnG=4V)qbu?QohYVowd43&Y=yPC$RTIFe{4|H{112P#Ex_ci;>eYtW6;&K6`nB zCc^n!95FbJ<{qJ3t)gLz@s=D9Nnf86sn+}Ix-(QT25@8Se++_+F@xE1_a5HvXrd?I zibYl{v7JT1)M7}XuVf~_XjLjvQx_d|ufSu##HS>d2%}hQ#n`Y`vZc}VfpC7^E#k;# z$-9uxn{%Ep=DT$7Kla5W%%k`{V@4Z;7y`nN3Hof4gakRKD>e#ViUX(sz0UT%^oNeg zErf*)LF6TQq&d&7Rb4$prw>r?y0NGzEzDbzU&_4@>$i(+C&XVq9}9f4c4x|eR(?K3 zrQAM^q@^-o+q=1d`JNWnp>iPBvKXc3v=+IcapwLQ)t!CJAt*)T?gN0FS_x<8n(F)~YcqNZpzmu^W!e2*R9Qac@}3q8PP0-0>PG!h21Fg@YXnih}{ zX6uimXh@)|wFX73_>UNHG^#mF;y4QPr6d`KGKsU?#dE*uz?OSh`c1s;l}B`VjxI5b zBB~xdF@H~J#*4iHZw0F=(#dD%`@qRppYd_#s#xa}r7pFrK6lG7@8cTTrIV249ei!unvX_y zi#ZEB9F|b0QCkfM z+~O0B;mW1K*>VR{;ZIh#ixZARdG9kyw7#06SDRch=BM!>f?&=u;3{Mb=3^(W-+$KE zvDZ)FTRp&dM~8*Rfa^jw<@*&DqFCkKSuLwdTRSH~?5PxaBx+4zt#9-?j+|UI>W)b7M|T$NBqgZhm)DF2M-QPxahLu{sAdO05dQwXWG^GKjWEp@_n8UOs0 z?@^4}`zw_F-2n*~fDSF&k9UbHW6=2ZjO%w|PjVU^#bW)IShobmBF!=CA4-bt)9oc3G{W-_b;P+qYDX~QQtRdDX2G+C&_9FdRUqIl@_8yEoygGdUIPh@zRNK8N=Pk zJq->FRZGpk;TTqSrt)b8yYoDfPj?FmuHJzsSFhE%Y#dw>*xuK~`HF4+ENG%C)+v%k z0+);Vki1(2M$qexU9Vb-EBvTv7zN@bkKM=JR#op6Iy2aouXwRJAcZ}^wWd5(T)6oH z(1-KJ&6y%~_?8YYAVl{jKQ>=STr|BhQ36DR$%IAcaFJswlW_@`>f zFyg)l3u0D+;>PF#{{wp@=1pj%OT=*j=xb2=3#i5IHR)HFxc6krm0mC?E8WM^B&Agh zr>|&bLt$i#6|n*i4$~Fy0r0bkyV`!{s3!U`m^0~SK<0JDAc+lPOT5YFte;IUn^hAS zD?0!zPRhCuP~sm9$kk2bVwE#P4Q;z)CKZcBhtf5PUbSrDHkn)$&i37zImzv>$%P`0 z-RnDe?Wr-sh5A?(%{p`+>b@+Tj*lS>;zWTIi^l4-`VRV^ijX@nQqS2*uGDO~A!Mc~)h zw$haFhB3XDRD=Kg`0zwg0c-P&i4j+DWYo6c>Ez6C(RYi-E(Qb%i>s|G@iUca+*94z zUCitFpC+Z#Z|JO_>a_tbmR;qSVbZtzG!40jA#!1%tdT0p=~8?pCZi=7a8pC_nXJSwDS>=FcH zW`DO;5vN3lw5cS=h4e_P<}cXE(-Wvq^bFWMRX;|8I{Qx?j05 zg~)cF3SSX7xXbjN5h|nb(m`h?;I}cu+aJhdPiD1|>7W>CdNrMuNbgN>5A*7TR@KPG zZFYSl68)O0J>d%#!6*7}7kuW%-XS%6T+fU3yJMl?_X{|DUJ*hRwN08cgl~FvBc`!w z6g7r`?kb*|g%D59rF=4jQw8ggQZ2H->A=GjD(H1r?rq;5iElRNdeF?=- zo_sY5*6W9t@KpI6zG=dyTHbg+$8U%*AoUV+xSs3z;Qfq>;CA*P&*7`$ zN>6;S>~x)Wbb2iJ{;B76v16Xf9~XT5zp7}(3OAUh`Q+TW|3xV zATw0|z9Hol9~iMOq?zC?B^D|e%ktIZj^dB@LPdnaT4=34v7}(P(1ftjJr&W{^a5KA zAcwL~J9L&CAS&+ymNAnsa<%El^8yo#=IL#N>_~4*`m-U&d})xdFd>^GrxuApLcX?U z_)zXcf;mc(A0VS`by^;tE*qPRk15%o)k-``vMMt72`g7$es-#-SR0~ee5%6;vo_en z(SYtdz18n_j30WZ!_eO>Af>??`$A8KGW0=BjVE@62h~!?(O2N)2sv%UM)^0(wI;8L zBxgR`?U{_U@0|5z+MJ7Si)GGCd_LTZM+q5#LpP@75?e9{wMBW{M-T9mYh2ryysrd< zoEfOBvDJo3!XtgS{QDF+wOOe%#VdA)lH9DU?TLieIRobwU9mPvhZ;+QT=I2H^QQCy zyCSd+IV;=aM|dJZ2$o{k0Jr9wL|!WH;%Y*K+8#sf*OUG|Zc41Q>`B2#%UIZ7Gs2uW z>|V2K5sjDN@+U7O%7ehbR z2Rv+d@0#RJTwCrdVojxLAzOompXE4PVg5%=-;!X1%U(0ReDS4RtsrKhrgj5g(!=0J zMA!u809FE3XRJE!>jv`q$&GZO3WoPw&oGQ8^=?&0G0*S|m0L?Yc|;TPminvkhk=my|iV z@hKlsHdmftvi7N%a1sc!I(6cxtv#D=tL@{+!aFD?>TXu!z{yeETK9?NzJ3^D9b1+r zXiH^L`_cNAq}Cjlgq77nB|CJM`1rWF>y(7-ktxjfB+Kx!Dx(u<{L!W|LqDW5%_MM% z|GT5TS2T%;CjB&-^}Q(KRe3y&(45$>S@i3tEqcHde^26!C;sf~PI<|1U$^~?&s%TO zx_R`osF=9W2kUv5TVTK z;7PXyRfA@woYuU#IhyP091nIDd=b>@Pl?MwPiBf(4pIW)uR74}gILe~5(T|8ih{?V zafs@T;54$wI}+X6{8!!~5kz!NTPx5V9CuQ3$o_5=N=$Z!6A(>?O^B+M^G<1VE0urJ zN6+80$%HxI-_YDfB`&b~s4+wOsd&XZjSJm5ezU0V&&P90WNJKnKaUDJ6a&+$A?>*G zNX;;%CHz+Q*~;_tJXO`(v;YHCW)g^{kmZpQmD-s6?TI4)%JYEea^@A1M(c^uFxxd6o-EQ;h z03zlowg&2Je0on|@O@HFN0^JIq5$*{?B? zRjrKaWYM&+RL^r^9U+6)}M47_5}M60_1bNQdLA3sR0kM5~S zlnYQd=TC<`@I&b794g-!gY9E|j>RT3jeb;1VLrj?gMEhR--klELoZdA7tg4p!&;R- zAPudzn?~Ot@1)`rxn@R7*Hr6}Bun(Oe~Efhkft)DV1buyo9+}v3DWYWxgDWST6O1Z zg2|7_S=p3R%hvcJVh&iqB~vkJbB~MkS=pk@w4{#F9<|vsX!hb`Oy%+_4%@2&vvk^J zVrEGjf91_*%oG&7&4!^H)ZRau^H~@LC{C?7`0*Z8Ua2Pa76)o5)(EL`?fdJ#m^1p( zb3JY0*-38vnY#>RY+_RG0A8Nm>g8e!Deio(Clz@@3;b9nEB5yK`#p1SZhKjh+tkkl zA$sXVEAU?NCTGej+Rk@hF)TuJx|E%8(rD(3OCB(jS$bRHm<_%EzPEd|*un?q`XNtC zmNnNpP@%>1ve24eSCRjx{~cm&$8B9`aP3FuEsu+biJcO9l+MUf-yjCPvNY}Wn!0a( zCiNBeU9SUZDrzMZgoQHvB_CWWvNcfZbZz4-H9g{Pk6|Qhjy#(h>D+Le&&XfSkF9)s zAyL1zt@J%-y~)EG+v;c^I0BWOwg}dx!}4o269IXsshkj0{79NIGdL+0#JWg%{=~L_ zcWp@pxKuT{5IleNriRn|t-|6CL2Q7Ne{$6xzIXkV)ZUfno7h+>3c+CUi5>pLsRJW7k%9IHzsuO)VD8tL zq0Fya)zJtNI8x1c$pU)`GoOZh##t9!qGs6OCfDbc5+N|xaI_8H&~{DjI3b>v_a_{g z)(FTl+X@&hsw{wdY@;7(v4>|zm6gc(9m0qV2KFe}9kQ!+A}uj*kT;m^&%^|8_e?ep zRZR^e4H5MzL{p?9M9ZKUSJkvMYI7RT*{CB6l~+2Cw;-LoH23^;^ea^33_CO4Qth%V z5{tCDUVRkvuC8YTcg@Th9d1nMX-$qk0DB`P@hN)NqXp6`p5oW%^Qpfp+kF_%jy{m- z^|Y8NLH($ZDwoQ@zwMPuE!6eAVum;?*|B-OT7~s6-VCs zLQuHqx1K8l11qu((Kt7T{J1+%GEqSyclGvi3VX4c&O z@Tbvj{)qzY1dXpG^k+t~X{KN_Rx)Ya=B@DpTXcY~YKZ|pI$}Y8` zF^e-L#w52@qW4~RDuqUJYx)d)hZn)tt{nh5T#uWUIS;{GZ2^MpiXbd~czi#dj0PlRmwPscO`f%QW8eV~U5P-r61K zsrNh|mxn!WXswGqG|}LqMn*vHYR4ZcHQX-ru792XQBx)J8NhXNM_wX+oXjAkSl5%)O$ z5l5W%zyOMonx~Avfo++PU@O1Xwf{V*mi(4zO~dI&=trQQ@0K>zdaIvXv$_?jdR1bXuA?>+ z<>Ni`iIMY?VznjmBzj}%w~?Nb-Z%PiHKXK+u+*p9i`0m8PL*cB9`2r&5gvAt z0MDA{2aah>)by-itMi<{XR{Bm)tp9MZRJW6l5_xBzMw3S-R{7JZ`NDLB<#us`D_pY zv09l=nieWYyaRSz8lRUHe-%73St7KGH;%hKSf#G})oQx;(XPz?p1o4bU=`AnRA z%jh7)=g7M=NhTWJ08dqlp=A8foRE(l7>oW<%}5s3xEZJVug&HQdigN{2>lahO)eC* z3x*|R z(Ic$s4@~DoDLuL^QSBSqUHeK&vC)LLp}5rZ#m-NO8Y7D`(?>d%-j}0@wipdZ9v5u} zoU?Ux-YGl7N=Ty$%XA|?wIzN*a`UF?6STz;R_W3CBuv@XXq3Y$HEd#i%!6IDEYc~e zan5$T_4`ccg52)*P$wz@!s&a1Pgtq5A|h-Zg@J(?g@8hJ)u7P7l?%~D!n~kV8Py(n z#y%U1Qe|FJpOn>5~`l~l-ijQc?k}eK*KYiI{T5&VXcJfKYu5zH;v{xMbW*oJ`rx?qYAe5jw zGQF-OggbuVO~zugw<`Va;$z`6lcC&O`-HtOHO2W?Nme(tG}hbD`!P;6R#`4)@J4uV zvSpT4@E1$u+_(t)y}L3xjI1>AO#HqeK04k5Y7b34@bHPFm9d1IhcO>`wv{UcCQ(?*`v6vzE~{klzTD|jjahb{ z`{TESMHhWda?znH0`IFAf1bQ>5!VUr5^*nWyqduS9jW=Z*YqWYcDSspw$=;+laFpyU&6qT>2gnP_#pF%Y3uvWvPjK! zFve>_&z>)qj*{rQ?m7Zpzctm;gxI;c2*B*!Y~cbZ7k6}h7Xw3D4&@HBdk9AYY~hXw zR~fdwH=S$%guM)#30MoH!ps%m5fUk&vo2R3okffxfAV^qHSQv=b0DAekB4H??s~7t(h(9ot z;9ho~2zMmH%@yzq6K3n?jg(!ek3xNLKqU#JpI-m_?*fbHY z-l)F|3=uAH10?JhgF<3rLSP{YVUVP-gqR5UAFPexo?htm{e>w65)k=A@@ps{=wQ%f z!hR(;8sIl9nkWd=6AnYVc^bO8Im@v9atZLu^7otoNdLj4D#8n`;rDBr{5eq!;2wY6 z{V{Kx5x+$M!0%j#!0i6$#0%yFxBuM{+U^gL-2<4bBOJXb{Fy|5Ye)Qx!4gJODI^54 z1KJCThyz7oBEmokF*^|;TmlYqfQy1*;;=u$`wQL6%>n5P^Mornq9a8|gHGDt(EzxA zQ_1tszW6?X|KbUK4hIBD0ENX2g+w7>5CkO22NH&WKx~441}yk%DfnB&(t`gdCx6nU z1ouRs1HR|!=JJ~kFC=;zLhS#27AyQ;vlz|TFZ+MR%%8JB^55G3c3t|no~?$862{H1cTs!!uNFdgRWmOP3}UKZ z7bZqd9xb{NAE~CLjQ@>*{+2Ld!Sgq-Ffg#Z)RYtqQ42e{i?xw}Tgv!fZf=Cv!y=&z z`U~-crLx&-c#LMw;x2H-goE{gt}mWA+JQ%3GQ~+)LCdXDKRB!#YEwsD7=y6yl5u+^ z2t|`mzK#R?dbBvP475-UP|6?#D>3&JYdx^Uud9@F#8NDK<5X@}suht1gtjgR8Vw!_ zgs$jcr57o!iR80JQ~(tONZ zCUSmemISRA^l$Q#mm4MVCy>#ktC^awFIW2L^7}n-8Kvr8_iqm*;wE`K4&?IF&N}wE z|30l*nimS-`Z0&P?B8asC0N+atz<8_?6|r6Idi+@OwF-1t90N??8)f#z$0H7mMq#> z4!}giF6TZ|pyh3aMX^q%{I%zzN!Sb#)}+gK9S;s-__oMq<_q83Ob+1JxdC*C2y0wY zG-i$bmvGFOAM{5R6-$xjH1~3`&=S6iGfk^bYd?ME^EoJ{YMY*%c%UoYS8VF^hvgSy zzYXf%H3)p9L~1vY>znW%nBzuDp&(@Xnzdj5=ckXJh!`$2>25QLXDc$xwcY}D0R9Bi zuTnQdeBaeRR^PpAJ27iI)_qmy0X(*LTk7iX-SLo{L=8;eFn;t&l-ebwXCZ8FdUqCi z$(=wp=wy@*^&BIOd-F25>Hv0=40+j4Szw~k- Date: Sun, 28 Aug 2022 19:39:08 +0400 Subject: [PATCH 57/78] Remove obsolete info from docs (#1672) --- ReadMe.md | 14 +------------- documentation/fbt.md | 1 - scripts/ReadMe.md | 1 - 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index 7a9777121a..2e3b87a675 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -74,19 +74,7 @@ brew bundle --verbose ## Linux Prerequisites -### gcc-arm-none-eabi - -```sh -toolchain="gcc-arm-none-eabi-10.3-2021.10" -toolchain_package="$toolchain-$(uname -m)-linux" - -wget -P /opt "https://developer.arm.com/-/media/Files/downloads/gnu-rm/10.3-2021.10/$toolchain_package.tar.bz2" - -tar xjf /opt/$toolchain_package.tar.bz2 -C /opt -rm /opt/$toolchain_package.tar.bz2 - -for file in /opt/$toolchain/bin/* ; do ln -s "${file}" "/usr/bin/$(basename ${file})" ; done -``` +The FBT tool handles everything, only `git` is required. ### Optional dependencies diff --git a/documentation/fbt.md b/documentation/fbt.md index 53fc4b5e39..48726273e7 100644 --- a/documentation/fbt.md +++ b/documentation/fbt.md @@ -6,7 +6,6 @@ It is invoked by `./fbt` in the firmware project root directory. Internally, it ## Requirements Please install Python packages required by assets build scripts: `pip3 install -r scripts/requirements.txt` -Make sure that `gcc-arm-none-eabi` toolchain & OpenOCD executables are in system's PATH. ## NB diff --git a/scripts/ReadMe.md b/scripts/ReadMe.md index d06303957f..d37e67c90c 100644 --- a/scripts/ReadMe.md +++ b/scripts/ReadMe.md @@ -26,7 +26,6 @@ Also display type, region and etc... ## Core1 and Core2 firmware flashing -Main flashing sequence can be found in root `Makefile`. Core2 goes first, then Core1. Never flash FUS or you will loose your job, girlfriend and keys in secure enclave. From 4629aee29c470c1938b245fa9d4d450a8aa0a88b Mon Sep 17 00:00:00 2001 From: Kavitate <79380289+Kavitate@users.noreply.github.com> Date: Mon, 29 Aug 2022 09:46:26 -0500 Subject: [PATCH 58/78] Updated BarcodeGenerator.md Fixed minor spelling and grammatical errors. Also updated the first image to reflect the current correct image. --- documentation/BarcodeGenerator.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/documentation/BarcodeGenerator.md b/documentation/BarcodeGenerator.md index b9ea7a86f3..f2b5b2213b 100644 --- a/documentation/BarcodeGenerator.md +++ b/documentation/BarcodeGenerator.md @@ -1,15 +1,15 @@ -# This is a UPC-A Barcode generator for the flipper zero hardware. +# This is a UPC-A Barcode Generator for the Flipper Zero hardware. ## Author: [McAzzaMan](https://github.com/McAzzaMan/flipperzero-firmware/tree/UPC-A_Barcode_Generator/applications/barcode_generator) - + -It will eventually be expanded in to other barcode types. It currently only generates UPC-A type barcodes. +It will eventually be expanded into other barcode types. It currently only generates UPC-A type barcodes. -Controls-
-Hitting the centre button on the flipper toggles edit mode. +Hitting the centre button on the Flipper toggles edit mode. When in edit mode, left and right will change the digit to be changed, and up and down will adjust the digit value. From 1350dcaf63fb9883642b585cbbf272f013a9528f Mon Sep 17 00:00:00 2001 From: Sebastian Mauer Date: Mon, 29 Aug 2022 16:04:17 +0100 Subject: [PATCH 59/78] Add support for PAC/Stanley tags (#1648) * Add support for PAC/Stanley tags * Address review comments --- lib/flipper_format/flipper_format_stream.c | 2 +- lib/lfrfid/protocols/lfrfid_protocols.c | 2 + lib/lfrfid/protocols/lfrfid_protocols.h | 1 + lib/lfrfid/protocols/protocol_pac_stanley.c | 227 ++++++++++++++++++++ lib/lfrfid/protocols/protocol_pac_stanley.h | 4 + lib/lfrfid/tools/bit_lib.c | 7 + lib/lfrfid/tools/bit_lib.h | 8 + lib/nfc/nfc_device.c | 2 +- lib/toolbox/hex.c | 20 +- lib/toolbox/hex.h | 20 +- 10 files changed, 287 insertions(+), 6 deletions(-) create mode 100644 lib/lfrfid/protocols/protocol_pac_stanley.c create mode 100644 lib/lfrfid/protocols/protocol_pac_stanley.h diff --git a/lib/flipper_format/flipper_format_stream.c b/lib/flipper_format/flipper_format_stream.c index 81189b69b8..e4b7b30030 100644 --- a/lib/flipper_format/flipper_format_stream.c +++ b/lib/flipper_format/flipper_format_stream.c @@ -356,7 +356,7 @@ bool flipper_format_stream_read_value_line( uint8_t* data = _data; if(string_size(value) >= 2) { // sscanf "%02X" does not work here - if(hex_chars_to_uint8( + if(hex_char_to_uint8( string_get_char(value, 0), string_get_char(value, 1), &data[i])) { diff --git a/lib/lfrfid/protocols/lfrfid_protocols.c b/lib/lfrfid/protocols/lfrfid_protocols.c index 5df01b19e5..8014c91796 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.c +++ b/lib/lfrfid/protocols/lfrfid_protocols.c @@ -8,6 +8,7 @@ #include "protocol_fdx_b.h" #include "protocol_hid_generic.h" #include "protocol_hid_ex_generic.h" +#include "protocol_pac_stanley.h" const ProtocolBase* lfrfid_protocols[] = { [LFRFIDProtocolEM4100] = &protocol_em4100, @@ -19,4 +20,5 @@ const ProtocolBase* lfrfid_protocols[] = { [LFRFIDProtocolFDXB] = &protocol_fdx_b, [LFRFIDProtocolHidGeneric] = &protocol_hid_generic, [LFRFIDProtocolHidExGeneric] = &protocol_hid_ex_generic, + [LFRFIDProtocolPACStanley] = &protocol_pac_stanley, }; \ No newline at end of file diff --git a/lib/lfrfid/protocols/lfrfid_protocols.h b/lib/lfrfid/protocols/lfrfid_protocols.h index 4b8f6573d1..2a21641277 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.h +++ b/lib/lfrfid/protocols/lfrfid_protocols.h @@ -17,6 +17,7 @@ typedef enum { LFRFIDProtocolFDXB, LFRFIDProtocolHidGeneric, LFRFIDProtocolHidExGeneric, + LFRFIDProtocolPACStanley, LFRFIDProtocolMax, } LFRFIDProtocol; diff --git a/lib/lfrfid/protocols/protocol_pac_stanley.c b/lib/lfrfid/protocols/protocol_pac_stanley.c new file mode 100644 index 0000000000..7ab16a103e --- /dev/null +++ b/lib/lfrfid/protocols/protocol_pac_stanley.c @@ -0,0 +1,227 @@ +#include +#include +#include +#include +#include +#include "lfrfid_protocols.h" + +#define PAC_STANLEY_ENCODED_BIT_SIZE (128) +#define PAC_STANLEY_ENCODED_BYTE_SIZE (((PAC_STANLEY_ENCODED_BIT_SIZE) / 8)) +#define PAC_STANLEY_PREAMBLE_BIT_SIZE (8) +#define PAC_STANLEY_PREAMBLE_BYTE_SIZE (1) +#define PAC_STANLEY_ENCODED_BYTE_FULL_SIZE \ + (PAC_STANLEY_ENCODED_BYTE_SIZE + PAC_STANLEY_PREAMBLE_BYTE_SIZE) +#define PAC_STANLEY_BYTE_LENGTH (10) // start bit, 7 data bits, parity bit, stop bit +#define PAC_STANLEY_DATA_START_INDEX 8 + (3 * PAC_STANLEY_BYTE_LENGTH) + 1 + +#define PAC_STANLEY_DECODED_DATA_SIZE (4) +#define PAC_STANLEY_ENCODED_DATA_SIZE (sizeof(ProtocolPACStanley)) + +#define PAC_STANLEY_CLOCKS_IN_US (32) +#define PAC_STANLEY_CYCLE_LENGTH (256) +#define PAC_STANLEY_MIN_TIME (60) +#define PAC_STANLEY_MAX_TIME (4000) + +typedef struct { + bool inverted; + bool got_preamble; + size_t encoded_index; + uint8_t encoded_data[PAC_STANLEY_ENCODED_BYTE_FULL_SIZE]; + uint8_t data[PAC_STANLEY_DECODED_DATA_SIZE]; +} ProtocolPACStanley; + +ProtocolPACStanley* protocol_pac_stanley_alloc(void) { + ProtocolPACStanley* protocol = malloc(sizeof(ProtocolPACStanley)); + return (void*)protocol; +} + +void protocol_pac_stanley_free(ProtocolPACStanley* protocol) { + free(protocol); +} + +uint8_t* protocol_pac_stanley_get_data(ProtocolPACStanley* protocol) { + return protocol->data; +} + +static void protocol_pac_stanley_decode(ProtocolPACStanley* protocol) { + uint8_t asciiCardId[8]; + for(size_t idx = 0; idx < 8; idx++) { + uint8_t byte = bit_lib_reverse_8_fast(bit_lib_get_bits( + protocol->encoded_data, + PAC_STANLEY_DATA_START_INDEX + (PAC_STANLEY_BYTE_LENGTH * idx), + 8)); + asciiCardId[idx] = byte & 0x7F; // discard the parity bit + } + + hex_chars_to_uint8((char*)asciiCardId, protocol->data); +} + +static bool protocol_pac_stanley_can_be_decoded(ProtocolPACStanley* protocol) { + // Check preamble + if(bit_lib_get_bits(protocol->encoded_data, 0, 8) != 0b11111111) return false; + if(bit_lib_get_bit(protocol->encoded_data, 8) != 0) return false; + if(bit_lib_get_bit(protocol->encoded_data, 9) != 0) return false; + if(bit_lib_get_bit(protocol->encoded_data, 10) != 1) return false; + if(bit_lib_get_bits(protocol->encoded_data, 11, 8) != 0b00000010) return false; + + // Check next preamble + if(bit_lib_get_bits(protocol->encoded_data, 128, 8) != 0b11111111) return false; + + // Checksum + uint8_t checksum = 0; + uint8_t stripped_byte; + for(size_t idx = 0; idx < 9; idx++) { + uint8_t byte = bit_lib_reverse_8_fast(bit_lib_get_bits( + protocol->encoded_data, + PAC_STANLEY_DATA_START_INDEX + (PAC_STANLEY_BYTE_LENGTH * idx), + 8)); + stripped_byte = byte & 0x7F; // discard the parity bit + if(bit_lib_test_parity_32(stripped_byte, BitLibParityOdd) != (byte & 0x80) >> 7) { + return false; + } + if(idx < 8) checksum ^= stripped_byte; + } + if(stripped_byte != checksum) return false; + return true; +} + +void protocol_pac_stanley_decoder_start(ProtocolPACStanley* protocol) { + memset(protocol->data, 0, PAC_STANLEY_DECODED_DATA_SIZE); + protocol->inverted = false; + protocol->got_preamble = false; +} + +bool protocol_pac_stanley_decoder_feed(ProtocolPACStanley* protocol, bool level, uint32_t duration) { + bool pushed = false; + + if(duration > PAC_STANLEY_MAX_TIME) return false; + + uint8_t pulses = (uint8_t)round((float)duration / PAC_STANLEY_CYCLE_LENGTH); + + // Handle last stopbit & preamble (1 sb, 8 bit preamble) + if(pulses >= 9 && !protocol->got_preamble) { + pulses = 8; + protocol->got_preamble = true; + protocol->inverted = !level; + } else if(pulses >= 9 && protocol->got_preamble) { + protocol->got_preamble = false; + } else if(pulses == 0 && duration > PAC_STANLEY_MIN_TIME) { + pulses = 1; + } + + if(pulses) { + for(uint8_t i = 0; i < pulses; i++) { + bit_lib_push_bit( + protocol->encoded_data, + PAC_STANLEY_ENCODED_BYTE_FULL_SIZE, + level ^ protocol->inverted); + } + pushed = true; + } + + if(pushed && protocol_pac_stanley_can_be_decoded(protocol)) { + protocol_pac_stanley_decode(protocol); + return true; + } + + return false; +} + +bool protocol_pac_stanley_encoder_start(ProtocolPACStanley* protocol) { + memset(protocol->encoded_data, 0, PAC_STANLEY_ENCODED_BYTE_SIZE); + + uint8_t idbytes[10]; + idbytes[0] = '2'; + idbytes[1] = '0'; + + uint8_to_hex_chars(protocol->data, &idbytes[2], 8); + + // insert start and stop bits + for(size_t i = 0; i < 16; i++) protocol->encoded_data[i] = 0x40 >> (i + 3) % 5 * 2; + + protocol->encoded_data[0] = 0xFF; // mark + stop + protocol->encoded_data[1] = 0x20; // start + reflect8(STX) + + uint8_t checksum = 0; + for(size_t i = 2; i < 13; i++) { + uint8_t shift = 7 - (i + 3) % 4 * 2; + uint8_t index = i + (i - 1) / 4; + + uint16_t pattern; + if(i < 12) { + pattern = bit_lib_reverse_8_fast(idbytes[i - 2]); + pattern |= bit_lib_test_parity_32(pattern, BitLibParityOdd); + if(i > 3) checksum ^= idbytes[i - 2]; + } else { + pattern = (bit_lib_reverse_8_fast(checksum) & 0xFE) | + (bit_lib_test_parity_32(checksum, BitLibParityOdd)); + } + pattern <<= shift; + + protocol->encoded_data[index] |= pattern >> 8 & 0xFF; + protocol->encoded_data[index + 1] |= pattern & 0xFF; + } + + protocol->encoded_index = 0; + return true; +} + +LevelDuration protocol_pac_stanley_encoder_yield(ProtocolPACStanley* protocol) { + uint16_t length = PAC_STANLEY_CLOCKS_IN_US; + bool bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoded_index); + bit_lib_increment_index(protocol->encoded_index, PAC_STANLEY_ENCODED_BIT_SIZE); + while(bit_lib_get_bit(protocol->encoded_data, protocol->encoded_index) == bit) { + length += PAC_STANLEY_CLOCKS_IN_US; + bit_lib_increment_index(protocol->encoded_index, PAC_STANLEY_ENCODED_BIT_SIZE); + } + + return level_duration_make(bit, length); +} + +bool protocol_pac_stanley_write_data(ProtocolPACStanley* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_pac_stanley_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_DIRECT | LFRFID_T5577_BITRATE_RF_32 | + (4 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32); + request->t5577.block[4] = bit_lib_get_bits_32(protocol->encoded_data, 96, 32); + request->t5577.blocks_to_write = 5; + result = true; + } + return result; +} + +void protocol_pac_stanley_render_data(ProtocolPACStanley* protocol, string_t result) { + uint8_t* data = protocol->data; + string_printf(result, "CIN: %02X%02X%02X%02X", data[0], data[1], data[2], data[3]); +} + +const ProtocolBase protocol_pac_stanley = { + .name = "PAC/Stanley", + .manufacturer = "N/A", + .data_size = PAC_STANLEY_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_pac_stanley_alloc, + .free = (ProtocolFree)protocol_pac_stanley_free, + .get_data = (ProtocolGetData)protocol_pac_stanley_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_pac_stanley_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_pac_stanley_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_pac_stanley_encoder_start, + .yield = (ProtocolEncoderYield)protocol_pac_stanley_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_pac_stanley_render_data, + .render_brief_data = (ProtocolRenderData)protocol_pac_stanley_render_data, + .write_data = (ProtocolWriteData)protocol_pac_stanley_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_pac_stanley.h b/lib/lfrfid/protocols/protocol_pac_stanley.h new file mode 100644 index 0000000000..3ca329cf79 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_pac_stanley.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_pac_stanley; \ No newline at end of file diff --git a/lib/lfrfid/tools/bit_lib.c b/lib/lfrfid/tools/bit_lib.c index b57bda8a8a..2df12707af 100644 --- a/lib/lfrfid/tools/bit_lib.c +++ b/lib/lfrfid/tools/bit_lib.c @@ -262,6 +262,13 @@ uint16_t bit_lib_reverse_16_fast(uint16_t data) { return result; } +uint8_t bit_lib_reverse_8_fast(uint8_t byte) { + byte = (byte & 0xF0) >> 4 | (byte & 0x0F) << 4; + byte = (byte & 0xCC) >> 2 | (byte & 0x33) << 2; + byte = (byte & 0xAA) >> 1 | (byte & 0x55) << 1; + return byte; +} + uint16_t bit_lib_crc16( uint8_t const* data, size_t data_size, diff --git a/lib/lfrfid/tools/bit_lib.h b/lib/lfrfid/tools/bit_lib.h index 24aae0e9cc..482ae36b22 100644 --- a/lib/lfrfid/tools/bit_lib.h +++ b/lib/lfrfid/tools/bit_lib.h @@ -194,6 +194,14 @@ void bit_lib_print_regions( */ uint16_t bit_lib_reverse_16_fast(uint16_t data); +/** + * @brief Reverse bits in uint8_t, faster than generic bit_lib_reverse_bits. + * + * @param byte Byte + * @return uint8_t the reversed byte + */ +uint8_t bit_lib_reverse_8_fast(uint8_t byte); + /** * @brief Slow, but generic CRC16 implementation * diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 0bfdb3daca..c46919219a 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -782,7 +782,7 @@ static void nfc_device_load_mifare_classic_block( char hi = string_get_char(block_str, 3 * i); char low = string_get_char(block_str, 3 * i + 1); uint8_t byte = 0; - if(hex_chars_to_uint8(hi, low, &byte)) { + if(hex_char_to_uint8(hi, low, &byte)) { block_tmp.value[i] = byte; } else { FURI_BIT_SET(block_unknown_bytes_mask, i); diff --git a/lib/toolbox/hex.c b/lib/toolbox/hex.c index 41bb24bba7..7b2719b795 100644 --- a/lib/toolbox/hex.c +++ b/lib/toolbox/hex.c @@ -15,7 +15,7 @@ bool hex_char_to_hex_nibble(char c, uint8_t* nibble) { } } -bool hex_chars_to_uint8(char hi, char low, uint8_t* value) { +bool hex_char_to_uint8(char hi, char low, uint8_t* value) { uint8_t hi_nibble_value, low_nibble_value; if(hex_char_to_hex_nibble(hi, &hi_nibble_value) && @@ -27,13 +27,29 @@ bool hex_chars_to_uint8(char hi, char low, uint8_t* value) { } } +bool hex_chars_to_uint8(const char* value_str, uint8_t* value) { + bool parse_success = false; + while(*value_str && value_str[1]) { + parse_success = hex_char_to_uint8(*value_str, value_str[1], value++); + if(!parse_success) break; + value_str += 2; + } + return parse_success; +} + bool hex_chars_to_uint64(const char* value_str, uint64_t* value) { uint8_t* _value = (uint8_t*)value; bool parse_success = false; for(uint8_t i = 0; i < 8; i++) { - parse_success = hex_chars_to_uint8(value_str[i * 2], value_str[i * 2 + 1], &_value[7 - i]); + parse_success = hex_char_to_uint8(value_str[i * 2], value_str[i * 2 + 1], &_value[7 - i]); if(!parse_success) break; } return parse_success; } + +void uint8_to_hex_chars(const uint8_t* src, uint8_t* target, int length) { + const char chars[] = "0123456789ABCDEF"; + while(--length >= 0) + target[length] = chars[(src[length >> 1] >> ((1 - (length & 1)) << 2)) & 0xF]; +} diff --git a/lib/toolbox/hex.h b/lib/toolbox/hex.h index c6683a52cd..740f23b776 100644 --- a/lib/toolbox/hex.h +++ b/lib/toolbox/hex.h @@ -14,14 +14,22 @@ extern "C" { */ bool hex_char_to_hex_nibble(char c, uint8_t* nibble); -/** Convert ASCII hex values to byte +/** Convert ASCII hex value to byte * @param hi hi nibble text * @param low low nibble text * @param value output value * * @return bool conversion status */ -bool hex_chars_to_uint8(char hi, char low, uint8_t* value); +bool hex_char_to_uint8(char hi, char low, uint8_t* value); + +/** Convert ASCII hex values to uint8_t + * @param value_str ASCII data + * @param value output value + * + * @return bool conversion status + */ +bool hex_chars_to_uint8(const char* value_str, uint8_t* value); /** Convert ASCII hex values to uint64_t * @param value_str ASCII 64 bi data @@ -31,6 +39,14 @@ bool hex_chars_to_uint8(char hi, char low, uint8_t* value); */ bool hex_chars_to_uint64(const char* value_str, uint64_t* value); +/** Convert uint8_t to ASCII hex values + * @param src source data + * @param target output value + * @param length data length + * + */ +void uint8_to_hex_chars(const uint8_t* src, uint8_t* target, int length); + #ifdef __cplusplus } #endif From 39f936ce1237a9c65fe0a657f22ec92d4bd67094 Mon Sep 17 00:00:00 2001 From: Sebastian Mauer Date: Mon, 29 Aug 2022 16:08:10 +0100 Subject: [PATCH 60/78] Add support for Paradox tags (#1655) * Add support for Paradox tags --- lib/lfrfid/protocols/lfrfid_protocols.c | 2 + lib/lfrfid/protocols/lfrfid_protocols.h | 1 + lib/lfrfid/protocols/protocol_paradox.c | 201 ++++++++++++++++++++++++ lib/lfrfid/protocols/protocol_paradox.h | 4 + 4 files changed, 208 insertions(+) create mode 100644 lib/lfrfid/protocols/protocol_paradox.c create mode 100644 lib/lfrfid/protocols/protocol_paradox.h diff --git a/lib/lfrfid/protocols/lfrfid_protocols.c b/lib/lfrfid/protocols/lfrfid_protocols.c index 8014c91796..c8d8d58c34 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.c +++ b/lib/lfrfid/protocols/lfrfid_protocols.c @@ -8,6 +8,7 @@ #include "protocol_fdx_b.h" #include "protocol_hid_generic.h" #include "protocol_hid_ex_generic.h" +#include "protocol_paradox.h" #include "protocol_pac_stanley.h" const ProtocolBase* lfrfid_protocols[] = { @@ -20,5 +21,6 @@ const ProtocolBase* lfrfid_protocols[] = { [LFRFIDProtocolFDXB] = &protocol_fdx_b, [LFRFIDProtocolHidGeneric] = &protocol_hid_generic, [LFRFIDProtocolHidExGeneric] = &protocol_hid_ex_generic, + [LFRFIDProtocolParadox] = &protocol_paradox, [LFRFIDProtocolPACStanley] = &protocol_pac_stanley, }; \ No newline at end of file diff --git a/lib/lfrfid/protocols/lfrfid_protocols.h b/lib/lfrfid/protocols/lfrfid_protocols.h index 2a21641277..4f529e65f1 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.h +++ b/lib/lfrfid/protocols/lfrfid_protocols.h @@ -17,6 +17,7 @@ typedef enum { LFRFIDProtocolFDXB, LFRFIDProtocolHidGeneric, LFRFIDProtocolHidExGeneric, + LFRFIDProtocolParadox, LFRFIDProtocolPACStanley, LFRFIDProtocolMax, diff --git a/lib/lfrfid/protocols/protocol_paradox.c b/lib/lfrfid/protocols/protocol_paradox.c new file mode 100644 index 0000000000..66399a6057 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_paradox.c @@ -0,0 +1,201 @@ +#include +#include +#include +#include +#include +#include "lfrfid_protocols.h" + +#define JITTER_TIME (20) +#define MIN_TIME (64 - JITTER_TIME) +#define MAX_TIME (80 + JITTER_TIME) + +#define PARADOX_DECODED_DATA_SIZE (6) + +#define PARADOX_PREAMBLE_LENGTH (8) +#define PARADOX_ENCODED_BIT_SIZE (96) +#define PARADOX_ENCODED_DATA_SIZE (((PARADOX_ENCODED_BIT_SIZE) / 8) + 1) +#define PARADOX_ENCODED_DATA_LAST (PARADOX_ENCODED_DATA_SIZE - 1) + +typedef struct { + FSKDemod* fsk_demod; +} ProtocolParadoxDecoder; + +typedef struct { + FSKOsc* fsk_osc; + uint8_t encoded_index; +} ProtocolParadoxEncoder; + +typedef struct { + ProtocolParadoxDecoder decoder; + ProtocolParadoxEncoder encoder; + uint8_t encoded_data[PARADOX_ENCODED_DATA_SIZE]; + uint8_t data[PARADOX_DECODED_DATA_SIZE]; +} ProtocolParadox; + +ProtocolParadox* protocol_paradox_alloc(void) { + ProtocolParadox* protocol = malloc(sizeof(ProtocolParadox)); + protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5); + protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50); + + return protocol; +}; + +void protocol_paradox_free(ProtocolParadox* protocol) { + fsk_demod_free(protocol->decoder.fsk_demod); + fsk_osc_free(protocol->encoder.fsk_osc); + free(protocol); +}; + +uint8_t* protocol_paradox_get_data(ProtocolParadox* protocol) { + return protocol->data; +}; + +void protocol_paradox_decoder_start(ProtocolParadox* protocol) { + memset(protocol->encoded_data, 0, PARADOX_ENCODED_DATA_SIZE); +}; + +static bool protocol_paradox_can_be_decoded(ProtocolParadox* protocol) { + // check preamble + if(protocol->encoded_data[0] != 0b00001111 || + protocol->encoded_data[PARADOX_ENCODED_DATA_LAST] != 0b00001111) + return false; + + for(uint32_t i = PARADOX_PREAMBLE_LENGTH; i < 96; i += 2) { + if(bit_lib_get_bit(protocol->encoded_data, i) == + bit_lib_get_bit(protocol->encoded_data, i + 1)) { + return false; + } + } + + return true; +} + +static void protocol_paradox_decode(uint8_t* encoded_data, uint8_t* decoded_data) { + for(uint32_t i = PARADOX_PREAMBLE_LENGTH; i < 96; i += 2) { + if(bit_lib_get_bits(encoded_data, i, 2) == 0b01) { + bit_lib_push_bit(decoded_data, PARADOX_DECODED_DATA_SIZE, 0); + } else if(bit_lib_get_bits(encoded_data, i, 2) == 0b10) { + bit_lib_push_bit(decoded_data, PARADOX_DECODED_DATA_SIZE, 1); + } + } + bit_lib_push_bit(decoded_data, PARADOX_DECODED_DATA_SIZE, 0); + bit_lib_push_bit(decoded_data, PARADOX_DECODED_DATA_SIZE, 0); + bit_lib_push_bit(decoded_data, PARADOX_DECODED_DATA_SIZE, 0); + bit_lib_push_bit(decoded_data, PARADOX_DECODED_DATA_SIZE, 0); +} + +bool protocol_paradox_decoder_feed(ProtocolParadox* protocol, bool level, uint32_t duration) { + bool value; + uint32_t count; + + fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count); + if(count > 0) { + for(size_t i = 0; i < count; i++) { + bit_lib_push_bit(protocol->encoded_data, PARADOX_ENCODED_DATA_SIZE, value); + if(protocol_paradox_can_be_decoded(protocol)) { + protocol_paradox_decode(protocol->encoded_data, protocol->data); + + return true; + } + } + } + + return false; +}; + +static void protocol_paradox_encode(const uint8_t* decoded_data, uint8_t* encoded_data) { + // preamble + bit_lib_set_bits(encoded_data, 0, 0b00001111, 8); + + for(size_t i = 0; i < 44; i++) { + if(bit_lib_get_bit(decoded_data, i)) { + bit_lib_set_bits(encoded_data, PARADOX_PREAMBLE_LENGTH + i * 2, 0b10, 2); + } else { + bit_lib_set_bits(encoded_data, PARADOX_PREAMBLE_LENGTH + i * 2, 0b01, 2); + } + } +}; + +bool protocol_paradox_encoder_start(ProtocolParadox* protocol) { + protocol_paradox_encode(protocol->data, (uint8_t*)protocol->encoded_data); + protocol->encoder.encoded_index = 0; + fsk_osc_reset(protocol->encoder.fsk_osc); + return true; +}; + +LevelDuration protocol_paradox_encoder_yield(ProtocolParadox* protocol) { + bool level; + uint32_t duration; + + bool bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index); + bool advance = fsk_osc_next_half(protocol->encoder.fsk_osc, bit, &level, &duration); + + if(advance) { + bit_lib_increment_index(protocol->encoder.encoded_index, PARADOX_ENCODED_BIT_SIZE); + } + return level_duration_make(level, duration); +}; + +void protocol_paradox_render_data(ProtocolParadox* protocol, string_t result) { + uint8_t* decoded_data = protocol->data; + uint8_t fc = bit_lib_get_bits(decoded_data, 10, 8); + uint16_t card_id = bit_lib_get_bits_16(decoded_data, 18, 16); + + string_cat_printf(result, "Facility: %u\r\n", fc); + string_cat_printf(result, "Card: %lu\r\n", card_id); + string_cat_printf(result, "Data: "); + for(size_t i = 0; i < PARADOX_DECODED_DATA_SIZE; i++) { + string_cat_printf(result, "%02X", decoded_data[i]); + } +}; + +void protocol_paradox_render_brief_data(ProtocolParadox* protocol, string_t result) { + uint8_t* decoded_data = protocol->data; + + uint8_t fc = bit_lib_get_bits(decoded_data, 10, 8); + uint16_t card_id = bit_lib_get_bits_16(decoded_data, 18, 16); + + string_cat_printf(result, "ID: %03u,%05u", fc, card_id); +}; + +bool protocol_paradox_write_data(ProtocolParadox* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_paradox_encode(protocol->data, (uint8_t*)protocol->encoded_data); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 | + (3 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32); + request->t5577.blocks_to_write = 4; + result = true; + } + return result; +}; + +const ProtocolBase protocol_paradox = { + .name = "Paradox", + .manufacturer = "Paradox", + .data_size = PARADOX_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_paradox_alloc, + .free = (ProtocolFree)protocol_paradox_free, + .get_data = (ProtocolGetData)protocol_paradox_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_paradox_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_paradox_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_paradox_encoder_start, + .yield = (ProtocolEncoderYield)protocol_paradox_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_paradox_render_data, + .render_brief_data = (ProtocolRenderData)protocol_paradox_render_brief_data, + .write_data = (ProtocolWriteData)protocol_paradox_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_paradox.h b/lib/lfrfid/protocols/protocol_paradox.h new file mode 100644 index 0000000000..a80696c35a --- /dev/null +++ b/lib/lfrfid/protocols/protocol_paradox.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_paradox; \ No newline at end of file From f09c5889ddd85474b7b089321ce88756da07c6ae Mon Sep 17 00:00:00 2001 From: Sebastian Mauer Date: Mon, 29 Aug 2022 16:15:27 +0100 Subject: [PATCH 61/78] Add support for Jablotron tags (#1657) * Add support for Jablotron tags --- lib/lfrfid/protocols/lfrfid_protocols.c | 2 + lib/lfrfid/protocols/lfrfid_protocols.h | 2 +- lib/lfrfid/protocols/protocol_jablotron.c | 212 ++++++++++++++++++++++ lib/lfrfid/protocols/protocol_jablotron.h | 4 + 4 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 lib/lfrfid/protocols/protocol_jablotron.c create mode 100644 lib/lfrfid/protocols/protocol_jablotron.h diff --git a/lib/lfrfid/protocols/lfrfid_protocols.c b/lib/lfrfid/protocols/lfrfid_protocols.c index c8d8d58c34..6d42cf31e6 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.c +++ b/lib/lfrfid/protocols/lfrfid_protocols.c @@ -8,6 +8,7 @@ #include "protocol_fdx_b.h" #include "protocol_hid_generic.h" #include "protocol_hid_ex_generic.h" +#include "protocol_jablotron.h" #include "protocol_paradox.h" #include "protocol_pac_stanley.h" @@ -21,6 +22,7 @@ const ProtocolBase* lfrfid_protocols[] = { [LFRFIDProtocolFDXB] = &protocol_fdx_b, [LFRFIDProtocolHidGeneric] = &protocol_hid_generic, [LFRFIDProtocolHidExGeneric] = &protocol_hid_ex_generic, + [LFRFIDProtocolJablotron] = &protocol_jablotron, [LFRFIDProtocolParadox] = &protocol_paradox, [LFRFIDProtocolPACStanley] = &protocol_pac_stanley, }; \ No newline at end of file diff --git a/lib/lfrfid/protocols/lfrfid_protocols.h b/lib/lfrfid/protocols/lfrfid_protocols.h index 4f529e65f1..42113af1ec 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.h +++ b/lib/lfrfid/protocols/lfrfid_protocols.h @@ -17,9 +17,9 @@ typedef enum { LFRFIDProtocolFDXB, LFRFIDProtocolHidGeneric, LFRFIDProtocolHidExGeneric, + LFRFIDProtocolJablotron, LFRFIDProtocolParadox, LFRFIDProtocolPACStanley, - LFRFIDProtocolMax, } LFRFIDProtocol; diff --git a/lib/lfrfid/protocols/protocol_jablotron.c b/lib/lfrfid/protocols/protocol_jablotron.c new file mode 100644 index 0000000000..64b55166c5 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_jablotron.c @@ -0,0 +1,212 @@ +#include +#include "toolbox/level_duration.h" +#include "protocol_jablotron.h" +#include +#include +#include "lfrfid_protocols.h" + +#define JABLOTRON_ENCODED_BIT_SIZE (64) +#define JABLOTRON_ENCODED_BYTE_SIZE (((JABLOTRON_ENCODED_BIT_SIZE) / 8)) +#define JABLOTRON_PREAMBLE_BIT_SIZE (16) +#define JABLOTRON_PREAMBLE_BYTE_SIZE (2) +#define JABLOTRON_ENCODED_BYTE_FULL_SIZE \ + (JABLOTRON_ENCODED_BYTE_SIZE + JABLOTRON_PREAMBLE_BYTE_SIZE) + +#define JABLOTRON_DECODED_DATA_SIZE (5) + +#define JABLOTRON_SHORT_TIME (256) +#define JABLOTRON_LONG_TIME (512) +#define JABLOTRON_JITTER_TIME (120) + +#define JABLOTRON_SHORT_TIME_LOW (JABLOTRON_SHORT_TIME - JABLOTRON_JITTER_TIME) +#define JABLOTRON_SHORT_TIME_HIGH (JABLOTRON_SHORT_TIME + JABLOTRON_JITTER_TIME) +#define JABLOTRON_LONG_TIME_LOW (JABLOTRON_LONG_TIME - JABLOTRON_JITTER_TIME) +#define JABLOTRON_LONG_TIME_HIGH (JABLOTRON_LONG_TIME + JABLOTRON_JITTER_TIME) + +typedef struct { + bool last_short; + bool last_level; + size_t encoded_index; + uint8_t encoded_data[JABLOTRON_ENCODED_BYTE_FULL_SIZE]; + uint8_t data[JABLOTRON_DECODED_DATA_SIZE]; +} ProtocolJablotron; + +ProtocolJablotron* protocol_jablotron_alloc(void) { + ProtocolJablotron* protocol = malloc(sizeof(ProtocolJablotron)); + return protocol; +}; + +void protocol_jablotron_free(ProtocolJablotron* protocol) { + free(protocol); +}; + +uint8_t* protocol_jablotron_get_data(ProtocolJablotron* proto) { + return proto->data; +}; + +void protocol_jablotron_decoder_start(ProtocolJablotron* protocol) { + memset(protocol->encoded_data, 0, JABLOTRON_ENCODED_BYTE_FULL_SIZE); + protocol->last_short = false; +}; + +uint8_t protocol_jablotron_checksum(uint8_t* bits) { + uint8_t chksum = 0; + for(uint8_t i = 16; i < 56; i += 8) { + chksum += bit_lib_get_bits(bits, i, 8); + } + chksum ^= 0x3A; + return chksum; +} + +uint64_t protocol_jablotron_card_id(uint8_t* bytes) { + uint64_t id = 0; + for(int i = 0; i < 5; i++) { + id *= 100; + id += ((bytes[i] & 0xF0) >> 4) * 10 + (bytes[i] & 0x0F); + } + return id; +} + +static bool protocol_jablotron_can_be_decoded(ProtocolJablotron* protocol) { + // check 11 bits preamble + if(bit_lib_get_bits_16(protocol->encoded_data, 0, 16) != 0b1111111111111111) return false; + // check next 11 bits preamble + if(bit_lib_get_bits_16(protocol->encoded_data, 64, 16) != 0b1111111111111111) return false; + + uint8_t checksum = bit_lib_get_bits(protocol->encoded_data, 56, 8); + if(checksum != protocol_jablotron_checksum(protocol->encoded_data)) return false; + + return true; +} + +void protocol_jablotron_decode(ProtocolJablotron* protocol) { + bit_lib_copy_bits(protocol->data, 0, 40, protocol->encoded_data, 16); +} + +bool protocol_jablotron_decoder_feed(ProtocolJablotron* protocol, bool level, uint32_t duration) { + UNUSED(level); + bool pushed = false; + + // Bi-Phase Manchester decoding + if(duration >= JABLOTRON_SHORT_TIME_LOW && duration <= JABLOTRON_SHORT_TIME_HIGH) { + if(protocol->last_short == false) { + protocol->last_short = true; + } else { + pushed = true; + bit_lib_push_bit(protocol->encoded_data, JABLOTRON_ENCODED_BYTE_FULL_SIZE, false); + protocol->last_short = false; + } + } else if(duration >= JABLOTRON_LONG_TIME_LOW && duration <= JABLOTRON_LONG_TIME_HIGH) { + if(protocol->last_short == false) { + pushed = true; + bit_lib_push_bit(protocol->encoded_data, JABLOTRON_ENCODED_BYTE_FULL_SIZE, true); + } else { + // reset + protocol->last_short = false; + } + } else { + // reset + protocol->last_short = false; + } + + if(pushed && protocol_jablotron_can_be_decoded(protocol)) { + protocol_jablotron_decode(protocol); + return true; + } + + return false; +}; + +bool protocol_jablotron_encoder_start(ProtocolJablotron* protocol) { + // preamble + bit_lib_set_bits(protocol->encoded_data, 0, 0b11111111, 8); + bit_lib_set_bits(protocol->encoded_data, 8, 0b11111111, 8); + + // Full code + bit_lib_copy_bits(protocol->encoded_data, 16, 40, protocol->data, 0); + + // Checksum + bit_lib_set_bits( + protocol->encoded_data, 56, protocol_jablotron_checksum(protocol->encoded_data), 8); + + protocol->encoded_index = 0; + protocol->last_short = false; + protocol->last_level = false; + return true; +}; + +LevelDuration protocol_jablotron_encoder_yield(ProtocolJablotron* protocol) { + uint32_t duration; + protocol->last_level = !protocol->last_level; + + bool bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoded_index); + + // Bi-Phase Manchester encoder + if(bit) { + // one long pulse for 1 + duration = JABLOTRON_LONG_TIME / 8; + bit_lib_increment_index(protocol->encoded_index, JABLOTRON_ENCODED_BIT_SIZE); + } else { + // two short pulses for 0 + duration = JABLOTRON_SHORT_TIME / 8; + if(protocol->last_short) { + bit_lib_increment_index(protocol->encoded_index, JABLOTRON_ENCODED_BIT_SIZE); + protocol->last_short = false; + } else { + protocol->last_short = true; + } + } + + return level_duration_make(protocol->last_level, duration); +}; + +void protocol_jablotron_render_data(ProtocolJablotron* protocol, string_t result) { + uint64_t id = protocol_jablotron_card_id(protocol->data); + string_printf(result, "ID: %llx\r\n", id); +}; + +void protocol_jablotron_render_brief_data(ProtocolJablotron* protocol, string_t result) { + uint64_t id = protocol_jablotron_card_id(protocol->data); + string_printf(result, "ID: %llx\r\n", id); +}; + +bool protocol_jablotron_write_data(ProtocolJablotron* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_jablotron_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_DIPHASE | LFRFID_T5577_BITRATE_RF_64 | + (2 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.blocks_to_write = 3; + result = true; + } + return result; +}; + +const ProtocolBase protocol_jablotron = { + .name = "Jablotron", + .manufacturer = "Jablotron", + .data_size = JABLOTRON_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_jablotron_alloc, + .free = (ProtocolFree)protocol_jablotron_free, + .get_data = (ProtocolGetData)protocol_jablotron_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_jablotron_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_jablotron_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_jablotron_encoder_start, + .yield = (ProtocolEncoderYield)protocol_jablotron_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_jablotron_render_data, + .render_brief_data = (ProtocolRenderData)protocol_jablotron_render_brief_data, + .write_data = (ProtocolWriteData)protocol_jablotron_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_jablotron.h b/lib/lfrfid/protocols/protocol_jablotron.h new file mode 100644 index 0000000000..4de57de42a --- /dev/null +++ b/lib/lfrfid/protocols/protocol_jablotron.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_jablotron; \ No newline at end of file From 274f17ed5a48f0deaf016bd44908fe70beb29ffb Mon Sep 17 00:00:00 2001 From: Sebastian Mauer Date: Mon, 29 Aug 2022 16:19:56 +0100 Subject: [PATCH 62/78] Add support for Viking tags (#1668) * Add support for Viking tags Fix blocks_to_write for T5577 --- lib/lfrfid/protocols/lfrfid_protocols.c | 2 + lib/lfrfid/protocols/lfrfid_protocols.h | 1 + lib/lfrfid/protocols/protocol_viking.c | 201 ++++++++++++++++++++++++ lib/lfrfid/protocols/protocol_viking.h | 4 + 4 files changed, 208 insertions(+) create mode 100644 lib/lfrfid/protocols/protocol_viking.c create mode 100644 lib/lfrfid/protocols/protocol_viking.h diff --git a/lib/lfrfid/protocols/lfrfid_protocols.c b/lib/lfrfid/protocols/lfrfid_protocols.c index 6d42cf31e6..30ba24e6e5 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.c +++ b/lib/lfrfid/protocols/lfrfid_protocols.c @@ -8,6 +8,7 @@ #include "protocol_fdx_b.h" #include "protocol_hid_generic.h" #include "protocol_hid_ex_generic.h" +#include "protocol_viking.h" #include "protocol_jablotron.h" #include "protocol_paradox.h" #include "protocol_pac_stanley.h" @@ -22,6 +23,7 @@ const ProtocolBase* lfrfid_protocols[] = { [LFRFIDProtocolFDXB] = &protocol_fdx_b, [LFRFIDProtocolHidGeneric] = &protocol_hid_generic, [LFRFIDProtocolHidExGeneric] = &protocol_hid_ex_generic, + [LFRFIDProtocolViking] = &protocol_viking, [LFRFIDProtocolJablotron] = &protocol_jablotron, [LFRFIDProtocolParadox] = &protocol_paradox, [LFRFIDProtocolPACStanley] = &protocol_pac_stanley, diff --git a/lib/lfrfid/protocols/lfrfid_protocols.h b/lib/lfrfid/protocols/lfrfid_protocols.h index 42113af1ec..710b6e57ba 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.h +++ b/lib/lfrfid/protocols/lfrfid_protocols.h @@ -17,6 +17,7 @@ typedef enum { LFRFIDProtocolFDXB, LFRFIDProtocolHidGeneric, LFRFIDProtocolHidExGeneric, + LFRFIDProtocolViking, LFRFIDProtocolJablotron, LFRFIDProtocolParadox, LFRFIDProtocolPACStanley, diff --git a/lib/lfrfid/protocols/protocol_viking.c b/lib/lfrfid/protocols/protocol_viking.c new file mode 100644 index 0000000000..7fd72bd93b --- /dev/null +++ b/lib/lfrfid/protocols/protocol_viking.c @@ -0,0 +1,201 @@ +#include +#include +#include +#include +#include "lfrfid_protocols.h" + +#define VIKING_CLOCK_PER_BIT (32) + +#define VIKING_ENCODED_BIT_SIZE (64) +#define VIKING_ENCODED_BYTE_SIZE (((VIKING_ENCODED_BIT_SIZE) / 8)) +#define VIKING_PREAMBLE_BIT_SIZE (24) +#define VIKING_PREAMBLE_BYTE_SIZE (3) +#define VIKING_ENCODED_BYTE_FULL_SIZE (VIKING_ENCODED_BYTE_SIZE + VIKING_PREAMBLE_BYTE_SIZE) +#define VIKING_DECODED_DATA_SIZE 4 + +#define VIKING_READ_SHORT_TIME (128) +#define VIKING_READ_LONG_TIME (256) +#define VIKING_READ_JITTER_TIME (60) + +#define VIKING_READ_SHORT_TIME_LOW (VIKING_READ_SHORT_TIME - VIKING_READ_JITTER_TIME) +#define VIKING_READ_SHORT_TIME_HIGH (VIKING_READ_SHORT_TIME + VIKING_READ_JITTER_TIME) +#define VIKING_READ_LONG_TIME_LOW (VIKING_READ_LONG_TIME - VIKING_READ_JITTER_TIME) +#define VIKING_READ_LONG_TIME_HIGH (VIKING_READ_LONG_TIME + VIKING_READ_JITTER_TIME) + +typedef struct { + uint8_t data[VIKING_DECODED_DATA_SIZE]; + uint8_t encoded_data[VIKING_ENCODED_BYTE_FULL_SIZE]; + + uint8_t encoded_data_index; + bool encoded_polarity; + + ManchesterState decoder_manchester_state; +} ProtocolViking; + +ProtocolViking* protocol_viking_alloc(void) { + ProtocolViking* proto = malloc(sizeof(ProtocolViking)); + return (void*)proto; +}; + +void protocol_viking_free(ProtocolViking* protocol) { + free(protocol); +}; + +uint8_t* protocol_viking_get_data(ProtocolViking* protocol) { + return protocol->data; +}; + +static void protocol_viking_decode(ProtocolViking* protocol) { + // Copy Card ID + bit_lib_copy_bits(protocol->data, 0, 32, protocol->encoded_data, 24); +} + +static bool protocol_viking_can_be_decoded(ProtocolViking* protocol) { + // check 24 bits preamble + if(bit_lib_get_bits_16(protocol->encoded_data, 0, 16) != 0b1111001000000000) return false; + if(bit_lib_get_bits(protocol->encoded_data, 16, 8) != 0b00000000) return false; + + // check next 24 bits preamble + if(bit_lib_get_bits_16(protocol->encoded_data, 64, 16) != 0b1111001000000000) return false; + if(bit_lib_get_bits(protocol->encoded_data, 80, 8) != 0b00000000) return false; + + // Checksum + uint32_t checksum = bit_lib_get_bits(protocol->encoded_data, 0, 8) ^ + bit_lib_get_bits(protocol->encoded_data, 8, 8) ^ + bit_lib_get_bits(protocol->encoded_data, 16, 8) ^ + bit_lib_get_bits(protocol->encoded_data, 24, 8) ^ + bit_lib_get_bits(protocol->encoded_data, 32, 8) ^ + bit_lib_get_bits(protocol->encoded_data, 40, 8) ^ + bit_lib_get_bits(protocol->encoded_data, 48, 8) ^ + bit_lib_get_bits(protocol->encoded_data, 56, 8) ^ 0xA8; + if(checksum != 0) return false; + + return true; +} + +void protocol_viking_decoder_start(ProtocolViking* protocol) { + memset(protocol->encoded_data, 0, VIKING_ENCODED_BYTE_FULL_SIZE); + manchester_advance( + protocol->decoder_manchester_state, + ManchesterEventReset, + &protocol->decoder_manchester_state, + NULL); +}; + +bool protocol_viking_decoder_feed(ProtocolViking* protocol, bool level, uint32_t duration) { + bool result = false; + + ManchesterEvent event = ManchesterEventReset; + + if(duration > VIKING_READ_SHORT_TIME_LOW && duration < VIKING_READ_SHORT_TIME_HIGH) { + if(!level) { + event = ManchesterEventShortHigh; + } else { + event = ManchesterEventShortLow; + } + } else if(duration > VIKING_READ_LONG_TIME_LOW && duration < VIKING_READ_LONG_TIME_HIGH) { + if(!level) { + event = ManchesterEventLongHigh; + } else { + event = ManchesterEventLongLow; + } + } + + if(event != ManchesterEventReset) { + bool data; + bool data_ok = manchester_advance( + protocol->decoder_manchester_state, event, &protocol->decoder_manchester_state, &data); + + if(data_ok) { + bit_lib_push_bit(protocol->encoded_data, VIKING_ENCODED_BYTE_FULL_SIZE, data); + + if(protocol_viking_can_be_decoded(protocol)) { + protocol_viking_decode(protocol); + result = true; + } + } + } + + return result; +}; + +bool protocol_viking_encoder_start(ProtocolViking* protocol) { + // Preamble + bit_lib_set_bits(protocol->encoded_data, 0, 0b11110010, 8); + bit_lib_set_bits(protocol->encoded_data, 8, 0b00000000, 8); + bit_lib_set_bits(protocol->encoded_data, 16, 0b00000000, 8); + + // Card Id + bit_lib_copy_bits(protocol->encoded_data, 24, 32, protocol->data, 0); + + // Checksum + uint32_t id = bit_lib_get_bits_32(protocol->data, 0, 32); + uint8_t checksum = ((id >> 24) & 0xFF) ^ ((id >> 16) & 0xFF) ^ ((id >> 8) & 0xFF) ^ + (id & 0xFF) ^ 0xF2 ^ 0xA8; + bit_lib_set_bits(protocol->encoded_data, 56, checksum, 8); + + return true; +}; + +LevelDuration protocol_viking_encoder_yield(ProtocolViking* protocol) { + bool level = bit_lib_get_bit(protocol->encoded_data, protocol->encoded_data_index); + uint32_t duration = VIKING_CLOCK_PER_BIT / 2; + + if(protocol->encoded_polarity) { + protocol->encoded_polarity = false; + } else { + level = !level; + + protocol->encoded_polarity = true; + bit_lib_increment_index(protocol->encoded_data_index, VIKING_ENCODED_BIT_SIZE); + } + + return level_duration_make(level, duration); +}; + +bool protocol_viking_write_data(ProtocolViking* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_viking_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = + (LFRFID_T5577_MODULATION_MANCHESTER | LFRFID_T5577_BITRATE_RF_32 | + (2 << LFRFID_T5577_MAXBLOCK_SHIFT)); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.blocks_to_write = 3; + result = true; + } + return result; +}; + +void protocol_viking_render_data(ProtocolViking* protocol, string_t result) { + uint32_t id = bit_lib_get_bits_32(protocol->data, 0, 32); + string_printf(result, "ID: %08lx\r\n", id); +}; + +const ProtocolBase protocol_viking = { + .name = "Viking", + .manufacturer = "Viking", + .data_size = VIKING_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_viking_alloc, + .free = (ProtocolFree)protocol_viking_free, + .get_data = (ProtocolGetData)protocol_viking_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_viking_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_viking_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_viking_encoder_start, + .yield = (ProtocolEncoderYield)protocol_viking_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_viking_render_data, + .render_brief_data = (ProtocolRenderData)protocol_viking_render_data, + .write_data = (ProtocolWriteData)protocol_viking_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_viking.h b/lib/lfrfid/protocols/protocol_viking.h new file mode 100644 index 0000000000..3286e03a7d --- /dev/null +++ b/lib/lfrfid/protocols/protocol_viking.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_viking; From 611b7e15ed46ac08489edd6c477c5285dae7d1c7 Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Mon, 29 Aug 2022 18:20:57 +0200 Subject: [PATCH 63/78] Remove execute permissions from *.c and *.h files (#1651) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add permission fix (no execute bit for source files) to fbt lint|format * Remove execute bit from 59 source files using fbt format * Also list which permissions are unwanted in lint.py * Also remove exec permissions from lib/../rfal_nfc.c Co-authored-by: あく --- applications/bad_usb/views/bad_usb_view.h | 0 .../bt/bt_debug_app/views/bt_carrier_test.c | 0 applications/bt/bt_debug_app/views/bt_test.c | 0 applications/bt/bt_debug_app/views/bt_test.h | 0 .../bt/bt_hid_app/views/bt_hid_keynote.c | 0 .../bt/bt_hid_app/views/bt_hid_media.c | 0 .../bt/bt_settings_app/bt_settings_app.c | 0 .../bt/bt_settings_app/bt_settings_app.h | 0 .../scenes/bt_settings_scene_config.h | 0 .../bt_settings_scene_forget_dev_confirm.c | 0 .../bt_settings_scene_forget_dev_success.c | 0 .../scenes/bt_settings_scene_start.c | 0 applications/cli/cli_i.h | 0 applications/gpio/views/gpio_test.c | 0 applications/gpio/views/gpio_test.h | 0 applications/gpio/views/gpio_usb_uart.h | 0 applications/gui/canvas.h | 0 applications/gui/modules/dialog_ex.c | 0 applications/gui/modules/menu.h | 0 applications/gui/modules/text_box.c | 0 applications/gui/modules/text_box.h | 0 applications/gui/modules/variable_item_list.h | 0 applications/gui/modules/widget.h | 0 .../widget_elements/widget_element_frame.c | 0 .../widget_elements/widget_element_i.h | 0 .../widget_elements/widget_element_string.c | 0 applications/gui/scene_manager.c | 0 applications/gui/scene_manager.h | 0 applications/gui/scene_manager_i.h | 0 applications/gui/view_dispatcher.h | 0 applications/nfc/helpers/nfc_emv_parser.c | 0 applications/nfc/helpers/nfc_emv_parser.h | 0 applications/nfc/nfc_cli.c | 0 applications/nfc/scenes/nfc_scene.c | 0 applications/nfc/scenes/nfc_scene_config.h | 0 applications/nfc/scenes/nfc_scene_delete.c | 0 .../nfc/scenes/nfc_scene_delete_success.c | 0 .../nfc/scenes/nfc_scene_emulate_uid.c | 0 .../nfc/scenes/nfc_scene_file_select.c | 0 .../scenes/nfc_scene_mf_ultralight_emulate.c | 0 .../nfc/scenes/nfc_scene_read_card_success.c | 0 applications/nfc/scenes/nfc_scene_set_atqa.c | 0 applications/nfc/scenes/nfc_scene_set_sak.c | 0 applications/nfc/scenes/nfc_scene_set_uid.c | 0 applications/picopass/picopass_worker.h | 0 applications/picopass/scenes/picopass_scene.c | 0 .../picopass/scenes/picopass_scene_config.h | 0 .../scenes/picopass_scene_delete_success.c | 0 .../power/battery_test_app/battery_test_app.c | 0 applications/power/power_service/power_i.h | 0 .../power_settings_scene_battery_info.c | 0 .../scenes/power_settings_scene_config.h | 0 .../scenes/power_settings_scene_reboot.c | 0 .../scenes/power_settings_scene_start.c | 0 .../storage_settings_scene_formatting.c | 0 applications/system/system_settings.h | 0 lib/ST25RFAL002/source/rfal_nfc.c | 0 lib/nfc/nfc_worker.h | 0 lib/nfc/protocols/emv.h | 0 lib/nfc/protocols/nfca.c | 0 scripts/lint.py | 59 +++++++++++++------ 61 files changed, 41 insertions(+), 18 deletions(-) mode change 100755 => 100644 applications/bad_usb/views/bad_usb_view.h mode change 100755 => 100644 applications/bt/bt_debug_app/views/bt_carrier_test.c mode change 100755 => 100644 applications/bt/bt_debug_app/views/bt_test.c mode change 100755 => 100644 applications/bt/bt_debug_app/views/bt_test.h mode change 100755 => 100644 applications/bt/bt_hid_app/views/bt_hid_keynote.c mode change 100755 => 100644 applications/bt/bt_hid_app/views/bt_hid_media.c mode change 100755 => 100644 applications/bt/bt_settings_app/bt_settings_app.c mode change 100755 => 100644 applications/bt/bt_settings_app/bt_settings_app.h mode change 100755 => 100644 applications/bt/bt_settings_app/scenes/bt_settings_scene_config.h mode change 100755 => 100644 applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c mode change 100755 => 100644 applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c mode change 100755 => 100644 applications/bt/bt_settings_app/scenes/bt_settings_scene_start.c mode change 100755 => 100644 applications/cli/cli_i.h mode change 100755 => 100644 applications/gpio/views/gpio_test.c mode change 100755 => 100644 applications/gpio/views/gpio_test.h mode change 100755 => 100644 applications/gpio/views/gpio_usb_uart.h mode change 100755 => 100644 applications/gui/canvas.h mode change 100755 => 100644 applications/gui/modules/dialog_ex.c mode change 100755 => 100644 applications/gui/modules/menu.h mode change 100755 => 100644 applications/gui/modules/text_box.c mode change 100755 => 100644 applications/gui/modules/text_box.h mode change 100755 => 100644 applications/gui/modules/variable_item_list.h mode change 100755 => 100644 applications/gui/modules/widget.h mode change 100755 => 100644 applications/gui/modules/widget_elements/widget_element_frame.c mode change 100755 => 100644 applications/gui/modules/widget_elements/widget_element_i.h mode change 100755 => 100644 applications/gui/modules/widget_elements/widget_element_string.c mode change 100755 => 100644 applications/gui/scene_manager.c mode change 100755 => 100644 applications/gui/scene_manager.h mode change 100755 => 100644 applications/gui/scene_manager_i.h mode change 100755 => 100644 applications/gui/view_dispatcher.h mode change 100755 => 100644 applications/nfc/helpers/nfc_emv_parser.c mode change 100755 => 100644 applications/nfc/helpers/nfc_emv_parser.h mode change 100755 => 100644 applications/nfc/nfc_cli.c mode change 100755 => 100644 applications/nfc/scenes/nfc_scene.c mode change 100755 => 100644 applications/nfc/scenes/nfc_scene_config.h mode change 100755 => 100644 applications/nfc/scenes/nfc_scene_delete.c mode change 100755 => 100644 applications/nfc/scenes/nfc_scene_delete_success.c mode change 100755 => 100644 applications/nfc/scenes/nfc_scene_emulate_uid.c mode change 100755 => 100644 applications/nfc/scenes/nfc_scene_file_select.c mode change 100755 => 100644 applications/nfc/scenes/nfc_scene_mf_ultralight_emulate.c mode change 100755 => 100644 applications/nfc/scenes/nfc_scene_read_card_success.c mode change 100755 => 100644 applications/nfc/scenes/nfc_scene_set_atqa.c mode change 100755 => 100644 applications/nfc/scenes/nfc_scene_set_sak.c mode change 100755 => 100644 applications/nfc/scenes/nfc_scene_set_uid.c mode change 100755 => 100644 applications/picopass/picopass_worker.h mode change 100755 => 100644 applications/picopass/scenes/picopass_scene.c mode change 100755 => 100644 applications/picopass/scenes/picopass_scene_config.h mode change 100755 => 100644 applications/picopass/scenes/picopass_scene_delete_success.c mode change 100755 => 100644 applications/power/battery_test_app/battery_test_app.c mode change 100755 => 100644 applications/power/power_service/power_i.h mode change 100755 => 100644 applications/power/power_settings_app/scenes/power_settings_scene_battery_info.c mode change 100755 => 100644 applications/power/power_settings_app/scenes/power_settings_scene_config.h mode change 100755 => 100644 applications/power/power_settings_app/scenes/power_settings_scene_reboot.c mode change 100755 => 100644 applications/power/power_settings_app/scenes/power_settings_scene_start.c mode change 100755 => 100644 applications/storage_settings/scenes/storage_settings_scene_formatting.c mode change 100755 => 100644 applications/system/system_settings.h mode change 100755 => 100644 lib/ST25RFAL002/source/rfal_nfc.c mode change 100755 => 100644 lib/nfc/nfc_worker.h mode change 100755 => 100644 lib/nfc/protocols/emv.h mode change 100755 => 100644 lib/nfc/protocols/nfca.c diff --git a/applications/bad_usb/views/bad_usb_view.h b/applications/bad_usb/views/bad_usb_view.h old mode 100755 new mode 100644 diff --git a/applications/bt/bt_debug_app/views/bt_carrier_test.c b/applications/bt/bt_debug_app/views/bt_carrier_test.c old mode 100755 new mode 100644 diff --git a/applications/bt/bt_debug_app/views/bt_test.c b/applications/bt/bt_debug_app/views/bt_test.c old mode 100755 new mode 100644 diff --git a/applications/bt/bt_debug_app/views/bt_test.h b/applications/bt/bt_debug_app/views/bt_test.h old mode 100755 new mode 100644 diff --git a/applications/bt/bt_hid_app/views/bt_hid_keynote.c b/applications/bt/bt_hid_app/views/bt_hid_keynote.c old mode 100755 new mode 100644 diff --git a/applications/bt/bt_hid_app/views/bt_hid_media.c b/applications/bt/bt_hid_app/views/bt_hid_media.c old mode 100755 new mode 100644 diff --git a/applications/bt/bt_settings_app/bt_settings_app.c b/applications/bt/bt_settings_app/bt_settings_app.c old mode 100755 new mode 100644 diff --git a/applications/bt/bt_settings_app/bt_settings_app.h b/applications/bt/bt_settings_app/bt_settings_app.h old mode 100755 new mode 100644 diff --git a/applications/bt/bt_settings_app/scenes/bt_settings_scene_config.h b/applications/bt/bt_settings_app/scenes/bt_settings_scene_config.h old mode 100755 new mode 100644 diff --git a/applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c b/applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c old mode 100755 new mode 100644 diff --git a/applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c b/applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c old mode 100755 new mode 100644 diff --git a/applications/bt/bt_settings_app/scenes/bt_settings_scene_start.c b/applications/bt/bt_settings_app/scenes/bt_settings_scene_start.c old mode 100755 new mode 100644 diff --git a/applications/cli/cli_i.h b/applications/cli/cli_i.h old mode 100755 new mode 100644 diff --git a/applications/gpio/views/gpio_test.c b/applications/gpio/views/gpio_test.c old mode 100755 new mode 100644 diff --git a/applications/gpio/views/gpio_test.h b/applications/gpio/views/gpio_test.h old mode 100755 new mode 100644 diff --git a/applications/gpio/views/gpio_usb_uart.h b/applications/gpio/views/gpio_usb_uart.h old mode 100755 new mode 100644 diff --git a/applications/gui/canvas.h b/applications/gui/canvas.h old mode 100755 new mode 100644 diff --git a/applications/gui/modules/dialog_ex.c b/applications/gui/modules/dialog_ex.c old mode 100755 new mode 100644 diff --git a/applications/gui/modules/menu.h b/applications/gui/modules/menu.h old mode 100755 new mode 100644 diff --git a/applications/gui/modules/text_box.c b/applications/gui/modules/text_box.c old mode 100755 new mode 100644 diff --git a/applications/gui/modules/text_box.h b/applications/gui/modules/text_box.h old mode 100755 new mode 100644 diff --git a/applications/gui/modules/variable_item_list.h b/applications/gui/modules/variable_item_list.h old mode 100755 new mode 100644 diff --git a/applications/gui/modules/widget.h b/applications/gui/modules/widget.h old mode 100755 new mode 100644 diff --git a/applications/gui/modules/widget_elements/widget_element_frame.c b/applications/gui/modules/widget_elements/widget_element_frame.c old mode 100755 new mode 100644 diff --git a/applications/gui/modules/widget_elements/widget_element_i.h b/applications/gui/modules/widget_elements/widget_element_i.h old mode 100755 new mode 100644 diff --git a/applications/gui/modules/widget_elements/widget_element_string.c b/applications/gui/modules/widget_elements/widget_element_string.c old mode 100755 new mode 100644 diff --git a/applications/gui/scene_manager.c b/applications/gui/scene_manager.c old mode 100755 new mode 100644 diff --git a/applications/gui/scene_manager.h b/applications/gui/scene_manager.h old mode 100755 new mode 100644 diff --git a/applications/gui/scene_manager_i.h b/applications/gui/scene_manager_i.h old mode 100755 new mode 100644 diff --git a/applications/gui/view_dispatcher.h b/applications/gui/view_dispatcher.h old mode 100755 new mode 100644 diff --git a/applications/nfc/helpers/nfc_emv_parser.c b/applications/nfc/helpers/nfc_emv_parser.c old mode 100755 new mode 100644 diff --git a/applications/nfc/helpers/nfc_emv_parser.h b/applications/nfc/helpers/nfc_emv_parser.h old mode 100755 new mode 100644 diff --git a/applications/nfc/nfc_cli.c b/applications/nfc/nfc_cli.c old mode 100755 new mode 100644 diff --git a/applications/nfc/scenes/nfc_scene.c b/applications/nfc/scenes/nfc_scene.c old mode 100755 new mode 100644 diff --git a/applications/nfc/scenes/nfc_scene_config.h b/applications/nfc/scenes/nfc_scene_config.h old mode 100755 new mode 100644 diff --git a/applications/nfc/scenes/nfc_scene_delete.c b/applications/nfc/scenes/nfc_scene_delete.c old mode 100755 new mode 100644 diff --git a/applications/nfc/scenes/nfc_scene_delete_success.c b/applications/nfc/scenes/nfc_scene_delete_success.c old mode 100755 new mode 100644 diff --git a/applications/nfc/scenes/nfc_scene_emulate_uid.c b/applications/nfc/scenes/nfc_scene_emulate_uid.c old mode 100755 new mode 100644 diff --git a/applications/nfc/scenes/nfc_scene_file_select.c b/applications/nfc/scenes/nfc_scene_file_select.c old mode 100755 new mode 100644 diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_emulate.c b/applications/nfc/scenes/nfc_scene_mf_ultralight_emulate.c old mode 100755 new mode 100644 diff --git a/applications/nfc/scenes/nfc_scene_read_card_success.c b/applications/nfc/scenes/nfc_scene_read_card_success.c old mode 100755 new mode 100644 diff --git a/applications/nfc/scenes/nfc_scene_set_atqa.c b/applications/nfc/scenes/nfc_scene_set_atqa.c old mode 100755 new mode 100644 diff --git a/applications/nfc/scenes/nfc_scene_set_sak.c b/applications/nfc/scenes/nfc_scene_set_sak.c old mode 100755 new mode 100644 diff --git a/applications/nfc/scenes/nfc_scene_set_uid.c b/applications/nfc/scenes/nfc_scene_set_uid.c old mode 100755 new mode 100644 diff --git a/applications/picopass/picopass_worker.h b/applications/picopass/picopass_worker.h old mode 100755 new mode 100644 diff --git a/applications/picopass/scenes/picopass_scene.c b/applications/picopass/scenes/picopass_scene.c old mode 100755 new mode 100644 diff --git a/applications/picopass/scenes/picopass_scene_config.h b/applications/picopass/scenes/picopass_scene_config.h old mode 100755 new mode 100644 diff --git a/applications/picopass/scenes/picopass_scene_delete_success.c b/applications/picopass/scenes/picopass_scene_delete_success.c old mode 100755 new mode 100644 diff --git a/applications/power/battery_test_app/battery_test_app.c b/applications/power/battery_test_app/battery_test_app.c old mode 100755 new mode 100644 diff --git a/applications/power/power_service/power_i.h b/applications/power/power_service/power_i.h old mode 100755 new mode 100644 diff --git a/applications/power/power_settings_app/scenes/power_settings_scene_battery_info.c b/applications/power/power_settings_app/scenes/power_settings_scene_battery_info.c old mode 100755 new mode 100644 diff --git a/applications/power/power_settings_app/scenes/power_settings_scene_config.h b/applications/power/power_settings_app/scenes/power_settings_scene_config.h old mode 100755 new mode 100644 diff --git a/applications/power/power_settings_app/scenes/power_settings_scene_reboot.c b/applications/power/power_settings_app/scenes/power_settings_scene_reboot.c old mode 100755 new mode 100644 diff --git a/applications/power/power_settings_app/scenes/power_settings_scene_start.c b/applications/power/power_settings_app/scenes/power_settings_scene_start.c old mode 100755 new mode 100644 diff --git a/applications/storage_settings/scenes/storage_settings_scene_formatting.c b/applications/storage_settings/scenes/storage_settings_scene_formatting.c old mode 100755 new mode 100644 diff --git a/applications/system/system_settings.h b/applications/system/system_settings.h old mode 100755 new mode 100644 diff --git a/lib/ST25RFAL002/source/rfal_nfc.c b/lib/ST25RFAL002/source/rfal_nfc.c old mode 100755 new mode 100644 diff --git a/lib/nfc/nfc_worker.h b/lib/nfc/nfc_worker.h old mode 100755 new mode 100644 diff --git a/lib/nfc/protocols/emv.h b/lib/nfc/protocols/emv.h old mode 100755 new mode 100644 diff --git a/lib/nfc/protocols/nfca.c b/lib/nfc/protocols/nfca.c old mode 100755 new mode 100644 diff --git a/scripts/lint.py b/scripts/lint.py index b3c3e7da40..30a5699a76 100755 --- a/scripts/lint.py +++ b/scripts/lint.py @@ -88,7 +88,7 @@ def _format_sources(self, sources: list, dry_run: bool = False): def _fix_filename(self, filename: str): return filename.replace("-", "_") - def _replace_occurance(self, sources: list, old: str, new: str): + def _replace_occurrence(self, sources: list, old: str, new: str): old = old.encode() new = new.encode() for source in sources: @@ -102,7 +102,7 @@ def _apply_file_naming_convention(self, sources: list, dry_run: bool = False): pattern = re.compile(SOURCE_CODE_FILE_PATTERN) good = [] bad = [] - # Check sources for invalid filesname + # Check sources for invalid filenames for source in sources: basename = os.path.basename(source) if not pattern.match(basename): @@ -113,40 +113,63 @@ def _apply_file_naming_convention(self, sources: list, dry_run: bool = False): bad.append((source, basename, new_basename)) else: good.append(source) - # Notify about errors or replace all occurances + # Notify about errors or replace all occurrences if dry_run: if len(bad) > 0: self.logger.error(f"Found {len(bad)} incorrectly named files") self.logger.info(bad) return False else: - # Replace occurances in text files + # Replace occurrences in text files for source, old, new in bad: - self._replace_occurance(sources, old, new) + self._replace_occurrence(sources, old, new) # Rename files for source, old, new in bad: shutil.move(source, source.replace(old, new)) return True - def check(self): + def _apply_file_permissions(self, sources: list, dry_run: bool = False): + execute_permissions = 0o111 + pattern = re.compile(SOURCE_CODE_FILE_PATTERN) + good = [] + bad = [] + # Check sources for unexpected execute permissions + for source in sources: + st = os.stat(source) + perms_too_many = st.st_mode & execute_permissions + if perms_too_many: + good_perms = st.st_mode & ~perms_too_many + bad.append((source, oct(perms_too_many), good_perms)) + else: + good.append(source) + # Notify or fix + if dry_run: + if len(bad) > 0: + self.logger.error(f"Found {len(bad)} incorrect permissions") + self.logger.info([record[0:2] for record in bad]) + return False + else: + for source, perms_too_many, new_perms in bad: + os.chmod(source, new_perms) + return True + + def _perform(self, dry_run: bool): result = 0 sources = self._find_sources(self.args.input) - if not self._format_sources(sources, dry_run=True): - result |= 0b01 - if not self._apply_file_naming_convention(sources, dry_run=True): - result |= 0b10 + if not self._format_sources(sources, dry_run=dry_run): + result |= 0b001 + if not self._apply_file_naming_convention(sources, dry_run=dry_run): + result |= 0b010 + if not self._apply_file_permissions(sources, dry_run=dry_run): + result |= 0b100 self._check_folders(self.args.input) return result + def check(self): + return self._perform(dry_run=True) + def format(self): - result = 0 - sources = self._find_sources(self.args.input) - if not self._format_sources(sources): - result |= 0b01 - if not self._apply_file_naming_convention(sources): - result |= 0b10 - self._check_folders(self.args.input) - return result + return self._perform(dry_run=False) if __name__ == "__main__": From d76ba206522346763c4e7cfdb37607c9faf1e969 Mon Sep 17 00:00:00 2001 From: Sebastian Mauer Date: Mon, 29 Aug 2022 17:31:28 +0100 Subject: [PATCH 64/78] Add support for Pyramid tags (#1676) * Add support for Pyramid tags * Also add additional checks for AWID decoder to avoid missdetection * lfrfid worker: reset GPIO_LOAD pin * lfrfid: protocol viking, format * lfrfid: protocol pyramid, format * lfrfid: protocol paradox, format * lfrfid: protocol jablotron, format * lfrfid: protocol em4100, format * lfrfid: increase reading time by 0.5s since protocol viking takes longer to read Co-authored-by: SG --- lib/lfrfid/lfrfid_worker_modes.c | 46 ++-- lib/lfrfid/protocols/lfrfid_protocols.c | 2 + lib/lfrfid/protocols/lfrfid_protocols.h | 1 + lib/lfrfid/protocols/protocol_awid.c | 9 +- lib/lfrfid/protocols/protocol_em4100.c | 2 +- lib/lfrfid/protocols/protocol_jablotron.c | 9 +- lib/lfrfid/protocols/protocol_paradox.c | 2 +- lib/lfrfid/protocols/protocol_pyramid.c | 277 ++++++++++++++++++++++ lib/lfrfid/protocols/protocol_pyramid.h | 4 + lib/lfrfid/protocols/protocol_viking.c | 2 +- lib/lfrfid/tools/bit_lib.c | 69 ++++++ lib/lfrfid/tools/bit_lib.h | 44 ++++ 12 files changed, 438 insertions(+), 29 deletions(-) create mode 100644 lib/lfrfid/protocols/protocol_pyramid.c create mode 100644 lib/lfrfid/protocols/protocol_pyramid.h diff --git a/lib/lfrfid/lfrfid_worker_modes.c b/lib/lfrfid/lfrfid_worker_modes.c index 33683589c5..16936cca14 100644 --- a/lib/lfrfid/lfrfid_worker_modes.c +++ b/lib/lfrfid/lfrfid_worker_modes.c @@ -27,16 +27,16 @@ #define LFRFID_WORKER_READ_DROP_TIME_MS 50 #define LFRFID_WORKER_READ_STABILIZE_TIME_MS 450 -#define LFRFID_WORKER_READ_SWITCH_TIME_MS 1500 +#define LFRFID_WORKER_READ_SWITCH_TIME_MS 2000 -#define LFRFID_WORKER_WRITE_VERIFY_TIME_MS 1500 +#define LFRFID_WORKER_WRITE_VERIFY_TIME_MS 2000 #define LFRFID_WORKER_WRITE_DROP_TIME_MS 50 #define LFRFID_WORKER_WRITE_TOO_LONG_TIME_MS 10000 #define LFRFID_WORKER_WRITE_MAX_UNSUCCESSFUL_READS 5 #define LFRFID_WORKER_READ_BUFFER_SIZE 512 -#define LFRFID_WORKER_READ_BUFFER_COUNT 8 +#define LFRFID_WORKER_READ_BUFFER_COUNT 16 #define LFRFID_WORKER_EMULATE_BUFFER_SIZE 1024 @@ -132,6 +132,8 @@ static LFRFIDWorkerReadState lfrfid_worker_read_internal( #ifdef LFRFID_WORKER_READ_DEBUG_GPIO furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_VALUE, GpioModeOutputPushPull); furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, GpioModeOutputPushPull); + furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_VALUE, false); + furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, false); #endif LFRFIDWorkerReadContext ctx; @@ -171,10 +173,16 @@ static LFRFIDWorkerReadState lfrfid_worker_read_internal( if(buffer_stream_get_overrun_count(ctx.stream) > 0) { FURI_LOG_E(TAG, "Read overrun, recovering"); buffer_stream_reset(ctx.stream); +#ifdef LFRFID_WORKER_READ_DEBUG_GPIO + furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, false); +#endif continue; } if(buffer == NULL) { +#ifdef LFRFID_WORKER_READ_DEBUG_GPIO + furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, false); +#endif continue; } @@ -261,24 +269,26 @@ static LFRFIDWorkerReadState lfrfid_worker_read_internal( last_read_count = 0; } - string_t string_info; - string_init(string_info); - for(uint8_t i = 0; i < protocol_data_size; i++) { - if(i != 0) { - string_cat_printf(string_info, " "); + if(furi_log_get_level() >= FuriLogLevelDebug) { + string_t string_info; + string_init(string_info); + for(uint8_t i = 0; i < protocol_data_size; i++) { + if(i != 0) { + string_cat_printf(string_info, " "); + } + + string_cat_printf(string_info, "%02X", protocol_data[i]); } - string_cat_printf(string_info, "%02X", protocol_data[i]); + FURI_LOG_D( + TAG, + "%s, %d, [%s]", + protocol_dict_get_name(worker->protocols, protocol), + last_read_count, + string_get_cstr(string_info)); + string_clear(string_info); } - FURI_LOG_D( - TAG, - "%s, %d, [%s]", - protocol_dict_get_name(worker->protocols, protocol), - last_read_count, - string_get_cstr(string_info)); - string_clear(string_info); - protocol_dict_decoders_start(worker->protocols); } } @@ -321,6 +331,8 @@ static LFRFIDWorkerReadState lfrfid_worker_read_internal( free(last_data); #ifdef LFRFID_WORKER_READ_DEBUG_GPIO + furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_VALUE, false); + furi_hal_gpio_write(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, false); furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_VALUE, GpioModeAnalog); furi_hal_gpio_init_simple(LFRFID_WORKER_READ_DEBUG_GPIO_LOAD, GpioModeAnalog); #endif diff --git a/lib/lfrfid/protocols/lfrfid_protocols.c b/lib/lfrfid/protocols/lfrfid_protocols.c index 30ba24e6e5..fc65861062 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.c +++ b/lib/lfrfid/protocols/lfrfid_protocols.c @@ -8,6 +8,7 @@ #include "protocol_fdx_b.h" #include "protocol_hid_generic.h" #include "protocol_hid_ex_generic.h" +#include "protocol_pyramid.h" #include "protocol_viking.h" #include "protocol_jablotron.h" #include "protocol_paradox.h" @@ -23,6 +24,7 @@ const ProtocolBase* lfrfid_protocols[] = { [LFRFIDProtocolFDXB] = &protocol_fdx_b, [LFRFIDProtocolHidGeneric] = &protocol_hid_generic, [LFRFIDProtocolHidExGeneric] = &protocol_hid_ex_generic, + [LFRFIDProtocolPyramid] = &protocol_pyramid, [LFRFIDProtocolViking] = &protocol_viking, [LFRFIDProtocolJablotron] = &protocol_jablotron, [LFRFIDProtocolParadox] = &protocol_paradox, diff --git a/lib/lfrfid/protocols/lfrfid_protocols.h b/lib/lfrfid/protocols/lfrfid_protocols.h index 710b6e57ba..210ddd15a6 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.h +++ b/lib/lfrfid/protocols/lfrfid_protocols.h @@ -17,6 +17,7 @@ typedef enum { LFRFIDProtocolFDXB, LFRFIDProtocolHidGeneric, LFRFIDProtocolHidExGeneric, + LFRFIDProtocolPyramid, LFRFIDProtocolViking, LFRFIDProtocolJablotron, LFRFIDProtocolParadox, diff --git a/lib/lfrfid/protocols/protocol_awid.c b/lib/lfrfid/protocols/protocol_awid.c index 243b5edeb4..97c07d7b21 100644 --- a/lib/lfrfid/protocols/protocol_awid.c +++ b/lib/lfrfid/protocols/protocol_awid.c @@ -53,7 +53,7 @@ void protocol_awid_decoder_start(ProtocolAwid* protocol) { memset(protocol->encoded_data, 0, AWID_ENCODED_DATA_SIZE); }; -static bool protocol_awid_can_be_decoded(const uint8_t* data) { +static bool protocol_awid_can_be_decoded(uint8_t* data) { bool result = false; // Index map @@ -77,6 +77,12 @@ static bool protocol_awid_can_be_decoded(const uint8_t* data) { bool parity_error = bit_lib_test_parity(data, 8, 88, BitLibParityOdd, 4); if(parity_error) break; + bit_lib_remove_bit_every_nth(data, 8, 88, 4); + + // Avoid detection for invalid formats + uint8_t len = bit_lib_get_bits(data, 8, 8); + if(len != 26 && len != 50 && len != 37 && len != 34) break; + result = true; } while(false); @@ -84,7 +90,6 @@ static bool protocol_awid_can_be_decoded(const uint8_t* data) { } static void protocol_awid_decode(uint8_t* encoded_data, uint8_t* decoded_data) { - bit_lib_remove_bit_every_nth(encoded_data, 8, 88, 4); bit_lib_copy_bits(decoded_data, 0, 66, encoded_data, 8); } diff --git a/lib/lfrfid/protocols/protocol_em4100.c b/lib/lfrfid/protocols/protocol_em4100.c index 92721fcdc1..17f57421a0 100644 --- a/lib/lfrfid/protocols/protocol_em4100.c +++ b/lib/lfrfid/protocols/protocol_em4100.c @@ -264,7 +264,7 @@ bool protocol_em4100_write_data(ProtocolEM4100* protocol, void* data) { void protocol_em4100_render_data(ProtocolEM4100* protocol, string_t result) { uint8_t* data = protocol->data; - string_printf(result, "ID: %03u,%05u", data[2], (uint16_t)((data[3] << 8) | (data[4]))); + string_printf(result, "FC: %03u, Card: %05u", data[2], (uint16_t)((data[3] << 8) | (data[4]))); }; const ProtocolBase protocol_em4100 = { diff --git a/lib/lfrfid/protocols/protocol_jablotron.c b/lib/lfrfid/protocols/protocol_jablotron.c index 64b55166c5..e00b1e59c9 100644 --- a/lib/lfrfid/protocols/protocol_jablotron.c +++ b/lib/lfrfid/protocols/protocol_jablotron.c @@ -162,12 +162,7 @@ LevelDuration protocol_jablotron_encoder_yield(ProtocolJablotron* protocol) { void protocol_jablotron_render_data(ProtocolJablotron* protocol, string_t result) { uint64_t id = protocol_jablotron_card_id(protocol->data); - string_printf(result, "ID: %llx\r\n", id); -}; - -void protocol_jablotron_render_brief_data(ProtocolJablotron* protocol, string_t result) { - uint64_t id = protocol_jablotron_card_id(protocol->data); - string_printf(result, "ID: %llx\r\n", id); + string_printf(result, "ID: %llX\r\n", id); }; bool protocol_jablotron_write_data(ProtocolJablotron* protocol, void* data) { @@ -207,6 +202,6 @@ const ProtocolBase protocol_jablotron = { .yield = (ProtocolEncoderYield)protocol_jablotron_encoder_yield, }, .render_data = (ProtocolRenderData)protocol_jablotron_render_data, - .render_brief_data = (ProtocolRenderData)protocol_jablotron_render_brief_data, + .render_brief_data = (ProtocolRenderData)protocol_jablotron_render_data, .write_data = (ProtocolWriteData)protocol_jablotron_write_data, }; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_paradox.c b/lib/lfrfid/protocols/protocol_paradox.c index 66399a6057..be627600bc 100644 --- a/lib/lfrfid/protocols/protocol_paradox.c +++ b/lib/lfrfid/protocols/protocol_paradox.c @@ -155,7 +155,7 @@ void protocol_paradox_render_brief_data(ProtocolParadox* protocol, string_t resu uint8_t fc = bit_lib_get_bits(decoded_data, 10, 8); uint16_t card_id = bit_lib_get_bits_16(decoded_data, 18, 16); - string_cat_printf(result, "ID: %03u,%05u", fc, card_id); + string_cat_printf(result, "FC: %03u, Card: %05u", fc, card_id); }; bool protocol_paradox_write_data(ProtocolParadox* protocol, void* data) { diff --git a/lib/lfrfid/protocols/protocol_pyramid.c b/lib/lfrfid/protocols/protocol_pyramid.c new file mode 100644 index 0000000000..a0404b4856 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_pyramid.c @@ -0,0 +1,277 @@ +#include +#include +#include +#include +#include "lfrfid_protocols.h" +#include + +#define JITTER_TIME (20) +#define MIN_TIME (64 - JITTER_TIME) +#define MAX_TIME (80 + JITTER_TIME) + +#define PYRAMID_DATA_SIZE 13 +#define PYRAMID_PREAMBLE_SIZE 3 + +#define PYRAMID_ENCODED_DATA_SIZE \ + (PYRAMID_PREAMBLE_SIZE + PYRAMID_DATA_SIZE + PYRAMID_PREAMBLE_SIZE) +#define PYRAMID_ENCODED_BIT_SIZE ((PYRAMID_PREAMBLE_SIZE + PYRAMID_DATA_SIZE) * 8) +#define PYRAMID_DECODED_DATA_SIZE (4) +#define PYRAMID_DECODED_BIT_SIZE ((PYRAMID_ENCODED_BIT_SIZE - PYRAMID_PREAMBLE_SIZE * 8) / 2) + +typedef struct { + FSKDemod* fsk_demod; +} ProtocolPyramidDecoder; + +typedef struct { + FSKOsc* fsk_osc; + uint8_t encoded_index; + uint32_t pulse; +} ProtocolPyramidEncoder; + +typedef struct { + ProtocolPyramidDecoder decoder; + ProtocolPyramidEncoder encoder; + uint8_t encoded_data[PYRAMID_ENCODED_DATA_SIZE]; + uint8_t data[PYRAMID_DECODED_DATA_SIZE]; +} ProtocolPyramid; + +ProtocolPyramid* protocol_pyramid_alloc(void) { + ProtocolPyramid* protocol = malloc(sizeof(ProtocolPyramid)); + protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5); + protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50); + + return protocol; +}; + +void protocol_pyramid_free(ProtocolPyramid* protocol) { + fsk_demod_free(protocol->decoder.fsk_demod); + fsk_osc_free(protocol->encoder.fsk_osc); + free(protocol); +}; + +uint8_t* protocol_pyramid_get_data(ProtocolPyramid* protocol) { + return protocol->data; +}; + +void protocol_pyramid_decoder_start(ProtocolPyramid* protocol) { + memset(protocol->encoded_data, 0, PYRAMID_ENCODED_DATA_SIZE); +}; + +static bool protocol_pyramid_can_be_decoded(uint8_t* data) { + // check preamble + if(bit_lib_get_bits_16(data, 0, 16) != 0b0000000000000001 || + bit_lib_get_bits(data, 16, 8) != 0b00000001) { + return false; + } + + if(bit_lib_get_bits_16(data, 128, 16) != 0b0000000000000001 || + bit_lib_get_bits(data, 136, 8) != 0b00000001) { + return false; + } + + uint8_t checksum = bit_lib_get_bits(data, 120, 8); + uint8_t checksum_data[13] = {0x00}; + for(uint8_t i = 0; i < 13; i++) { + checksum_data[i] = bit_lib_get_bits(data, 16 + (i * 8), 8); + } + + uint8_t calc_checksum = bit_lib_crc8(checksum_data, 13, 0x31, 0x00, true, true, 0x00); + if(checksum != calc_checksum) return false; + + // Remove parity + bit_lib_remove_bit_every_nth(data, 8, 15 * 8, 8); + + // Determine Startbit and format + int j; + for(j = 0; j < 105; ++j) { + if(bit_lib_get_bit(data, j)) break; + } + uint8_t fmt_len = 105 - j; + + // Only suppport 26bit format for now + if(fmt_len != 26) return false; + + return true; +} + +static void protocol_pyramid_decode(ProtocolPyramid* protocol) { + // Format + bit_lib_set_bits(protocol->data, 0, 26, 8); + + // Facility Code + bit_lib_copy_bits(protocol->data, 8, 8, protocol->encoded_data, 73 + 8); + + // Card Number + bit_lib_copy_bits(protocol->data, 16, 16, protocol->encoded_data, 81 + 8); +} + +bool protocol_pyramid_decoder_feed(ProtocolPyramid* protocol, bool level, uint32_t duration) { + bool value; + uint32_t count; + bool result = false; + + fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count); + if(count > 0) { + for(size_t i = 0; i < count; i++) { + bit_lib_push_bit(protocol->encoded_data, PYRAMID_ENCODED_DATA_SIZE, value); + if(protocol_pyramid_can_be_decoded(protocol->encoded_data)) { + protocol_pyramid_decode(protocol); + result = true; + } + } + } + + return result; +}; + +bool protocol_pyramid_get_parity(const uint8_t* bits, uint8_t type, int length) { + int x; + for(x = 0; length > 0; --length) x += bit_lib_get_bit(bits, length - 1); + x %= 2; + return x ^ type; +} + +void protocol_pyramid_add_wiegand_parity( + uint8_t* target, + uint8_t target_position, + uint8_t* source, + uint8_t length) { + bit_lib_set_bit( + target, target_position, protocol_pyramid_get_parity(source, 0 /* even */, length / 2)); + bit_lib_copy_bits(target, target_position + 1, length, source, 0); + bit_lib_set_bit( + target, + target_position + length + 1, + protocol_pyramid_get_parity(source + length / 2, 1 /* odd */, length / 2)); +} + +static void protocol_pyramid_encode(ProtocolPyramid* protocol) { + memset(protocol->encoded_data, 0, sizeof(protocol->encoded_data)); + + uint8_t pre[16]; + memset(pre, 0, sizeof(pre)); + + // Format start bit + bit_lib_set_bit(pre, 79, 1); + + uint8_t wiegand[3]; + memset(wiegand, 0, sizeof(wiegand)); + + // FC + bit_lib_copy_bits(wiegand, 0, 8, protocol->data, 8); + + // CardNum + bit_lib_copy_bits(wiegand, 8, 16, protocol->data, 16); + + // Wiegand parity + protocol_pyramid_add_wiegand_parity(pre, 80, wiegand, 24); + + bit_lib_add_parity(pre, 8, protocol->encoded_data, 8, 102, 8, 1); + + // Add checksum + uint8_t checksum_buffer[13]; + for(uint8_t i = 0; i < 13; i++) + checksum_buffer[i] = bit_lib_get_bits(protocol->encoded_data, 16 + (i * 8), 8); + + uint8_t crc = bit_lib_crc8(checksum_buffer, 13, 0x31, 0x00, true, true, 0x00); + bit_lib_set_bits(protocol->encoded_data, 120, crc, 8); +} + +bool protocol_pyramid_encoder_start(ProtocolPyramid* protocol) { + protocol->encoder.encoded_index = 0; + protocol->encoder.pulse = 0; + protocol_pyramid_encode(protocol); + + return true; +}; + +LevelDuration protocol_pyramid_encoder_yield(ProtocolPyramid* protocol) { + bool level = 0; + uint32_t duration = 0; + + // if pulse is zero, we need to output high, otherwise we need to output low + if(protocol->encoder.pulse == 0) { + // get bit + uint8_t bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index); + + // get pulse from oscillator + bool advance = fsk_osc_next(protocol->encoder.fsk_osc, bit, &duration); + + if(advance) { + bit_lib_increment_index(protocol->encoder.encoded_index, PYRAMID_ENCODED_BIT_SIZE); + } + + // duration diveded by 2 because we need to output high and low + duration = duration / 2; + protocol->encoder.pulse = duration; + level = true; + } else { + // output low half and reset pulse + duration = protocol->encoder.pulse; + protocol->encoder.pulse = 0; + level = false; + } + + return level_duration_make(level, duration); +}; + +bool protocol_pyramid_write_data(ProtocolPyramid* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_pyramid_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 | + (4 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32); + request->t5577.block[4] = bit_lib_get_bits_32(protocol->encoded_data, 96, 32); + request->t5577.blocks_to_write = 5; + result = true; + } + return result; +}; + +void protocol_pyramid_render_data(ProtocolPyramid* protocol, string_t result) { + uint8_t* decoded_data = protocol->data; + uint8_t format_length = decoded_data[0]; + + string_cat_printf(result, "Format: 26\r\n", format_length); + if(format_length == 26) { + uint8_t facility; + bit_lib_copy_bits(&facility, 0, 8, decoded_data, 8); + + uint16_t card_id; + bit_lib_copy_bits((uint8_t*)&card_id, 8, 8, decoded_data, 16); + bit_lib_copy_bits((uint8_t*)&card_id, 0, 8, decoded_data, 24); + string_cat_printf(result, "FC: %03u, Card: %05u", facility, card_id); + } else { + string_cat_printf(result, "Data: unknown"); + } +}; + +const ProtocolBase protocol_pyramid = { + .name = "Pyramid", + .manufacturer = "Farpointe", + .data_size = PYRAMID_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_pyramid_alloc, + .free = (ProtocolFree)protocol_pyramid_free, + .get_data = (ProtocolGetData)protocol_pyramid_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_pyramid_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_pyramid_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_pyramid_encoder_start, + .yield = (ProtocolEncoderYield)protocol_pyramid_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_pyramid_render_data, + .render_brief_data = (ProtocolRenderData)protocol_pyramid_render_data, + .write_data = (ProtocolWriteData)protocol_pyramid_write_data, +}; diff --git a/lib/lfrfid/protocols/protocol_pyramid.h b/lib/lfrfid/protocols/protocol_pyramid.h new file mode 100644 index 0000000000..940ecaec20 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_pyramid.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_pyramid; diff --git a/lib/lfrfid/protocols/protocol_viking.c b/lib/lfrfid/protocols/protocol_viking.c index 7fd72bd93b..6119b73483 100644 --- a/lib/lfrfid/protocols/protocol_viking.c +++ b/lib/lfrfid/protocols/protocol_viking.c @@ -173,7 +173,7 @@ bool protocol_viking_write_data(ProtocolViking* protocol, void* data) { void protocol_viking_render_data(ProtocolViking* protocol, string_t result) { uint32_t id = bit_lib_get_bits_32(protocol->data, 0, 32); - string_printf(result, "ID: %08lx\r\n", id); + string_printf(result, "ID: %08lX\r\n", id); }; const ProtocolBase protocol_viking = { diff --git a/lib/lfrfid/tools/bit_lib.c b/lib/lfrfid/tools/bit_lib.c index 2df12707af..c84f4b7ed2 100644 --- a/lib/lfrfid/tools/bit_lib.c +++ b/lib/lfrfid/tools/bit_lib.c @@ -129,6 +129,45 @@ bool bit_lib_test_parity( return result; } +size_t bit_lib_add_parity( + const uint8_t* data, + size_t position, + uint8_t* dest, + size_t dest_position, + uint8_t source_length, + uint8_t parity_length, + BitLibParity parity) { + uint32_t parity_word = 0; + size_t j = 0, bit_count = 0; + for(int word = 0; word < source_length; word += parity_length - 1) { + for(int bit = 0; bit < parity_length - 1; bit++) { + parity_word = (parity_word << 1) | bit_lib_get_bit(data, position + word + bit); + bit_lib_set_bit( + dest, dest_position + j++, bit_lib_get_bit(data, position + word + bit)); + } + // if parity fails then return 0 + switch(parity) { + case BitLibParityAlways0: + bit_lib_set_bit(dest, dest_position + j++, 0); + break; // marker bit which should be a 0 + case BitLibParityAlways1: + bit_lib_set_bit(dest, dest_position + j++, 1); + break; // marker bit which should be a 1 + default: + bit_lib_set_bit( + dest, + dest_position + j++, + (bit_lib_test_parity_32(parity_word, BitLibParityOdd) ^ parity) ^ 1); + break; + } + bit_count += parity_length; + parity_word = 0; + } + // if we got here then all the parities passed + // return bit count + return bit_count; +} + size_t bit_lib_remove_bit_every_nth(uint8_t* data, size_t position, uint8_t length, uint8_t n) { size_t counter = 0; size_t result_counter = 0; @@ -269,6 +308,36 @@ uint8_t bit_lib_reverse_8_fast(uint8_t byte) { return byte; } +uint16_t bit_lib_crc8( + uint8_t const* data, + size_t data_size, + uint8_t polynom, + uint8_t init, + bool ref_in, + bool ref_out, + uint8_t xor_out) { + uint8_t crc = init; + + for(size_t i = 0; i < data_size; ++i) { + uint8_t byte = data[i]; + if(ref_in) bit_lib_reverse_bits(&byte, 0, 8); + crc ^= byte; + + for(size_t j = 8; j > 0; --j) { + if(crc & TOPBIT(8)) { + crc = (crc << 1) ^ polynom; + } else { + crc = (crc << 1); + } + } + } + + if(ref_out) bit_lib_reverse_bits(&crc, 0, 8); + crc ^= xor_out; + + return crc; +} + uint16_t bit_lib_crc16( uint8_t const* data, size_t data_size, diff --git a/lib/lfrfid/tools/bit_lib.h b/lib/lfrfid/tools/bit_lib.h index 482ae36b22..1b048db352 100644 --- a/lib/lfrfid/tools/bit_lib.h +++ b/lib/lfrfid/tools/bit_lib.h @@ -7,6 +7,8 @@ extern "C" { #endif +#define TOPBIT(X) (1 << (X - 1)) + typedef enum { BitLibParityEven, BitLibParityOdd, @@ -114,6 +116,27 @@ bool bit_lib_test_parity( BitLibParity parity, uint8_t parity_length); +/** + * @brief Add parity to bit array + * + * @param data Source bit array + * @param position Start position + * @param dest Destination bit array + * @param dest_position Destination position + * @param source_length Source bit count + * @param parity_length Parity block length + * @param parity Parity to test against + * @return size_t + */ +size_t bit_lib_add_parity( + const uint8_t* data, + size_t position, + uint8_t* dest, + size_t dest_position, + uint8_t source_length, + uint8_t parity_length, + BitLibParity parity); + /** * @brief Remove bit every n in array and shift array left. Useful to remove parity. * @@ -202,6 +225,27 @@ uint16_t bit_lib_reverse_16_fast(uint16_t data); */ uint8_t bit_lib_reverse_8_fast(uint8_t byte); +/** + * @brief Slow, but generic CRC8 implementation + * + * @param data + * @param data_size + * @param polynom CRC polynom + * @param init init value + * @param ref_in true if the right bit is older + * @param ref_out true to reverse output + * @param xor_out xor output with this value + * @return uint8_t + */ +uint16_t bit_lib_crc8( + uint8_t const* data, + size_t data_size, + uint8_t polynom, + uint8_t init, + bool ref_in, + bool ref_out, + uint8_t xor_out); + /** * @brief Slow, but generic CRC16 implementation * From 5e2a90c6f1a56874e2319c5ed087d760a55fc549 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Tue, 30 Aug 2022 12:20:35 +0300 Subject: [PATCH 65/78] [FL-2773] Fix crash after cancelling Learn New Remote #1675 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/infrared/scenes/infrared_scene_learn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/infrared/scenes/infrared_scene_learn.c b/applications/infrared/scenes/infrared_scene_learn.c index 0edb74ca2b..37f9b3e054 100644 --- a/applications/infrared/scenes/infrared_scene_learn.c +++ b/applications/infrared/scenes/infrared_scene_learn.c @@ -25,7 +25,6 @@ bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == InfraredCustomEventTypeSignalReceived) { - infrared_worker_rx_set_received_signal_callback(infrared->worker, NULL, NULL); infrared_play_notification_message(infrared, InfraredNotificationMessageSuccess); scene_manager_next_scene(infrared->scene_manager, InfraredSceneLearnSuccess); consumed = true; @@ -38,6 +37,7 @@ bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) { void infrared_scene_learn_on_exit(void* context) { Infrared* infrared = context; Popup* popup = infrared->popup; + infrared_worker_rx_set_received_signal_callback(infrared->worker, NULL, NULL); infrared_worker_rx_stop(infrared->worker); infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop); popup_set_icon(popup, 0, 0, NULL); From f70ec8f70e70539c8243539e0c7d8998c39071ad Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 30 Aug 2022 13:15:46 +0300 Subject: [PATCH 66/78] update assets and subghz settings assets by @Amec0e --- assets/resources/Manifest | 12 +++--- assets/resources/infrared/assets/ac.ir | 37 ++++++++++++++++++- assets/resources/infrared/assets/audio.ir | 6 +++ assets/resources/infrared/assets/fans.ir | 37 ++++++++++++++++++- .../resources/infrared/assets/projectors.ir | 26 ++++++++++++- assets/resources/subghz/assets/setting_user | 3 +- 6 files changed, 111 insertions(+), 10 deletions(-) diff --git a/assets/resources/Manifest b/assets/resources/Manifest index de759514af..b928457b35 100644 --- a/assets/resources/Manifest +++ b/assets/resources/Manifest @@ -1,5 +1,5 @@ V:0 -T:1661566522 +T:1661854501 D:badusb D:dolphin D:infrared @@ -241,10 +241,10 @@ F:33b8fde22f34ef556b64b77164bc19b0:578:dolphin/L3_Lab_research_128x54/frame_8.bm F:f267f0654781049ca323b11bb4375519:581:dolphin/L3_Lab_research_128x54/frame_9.bm F:41106c0cbc5144f151b2b2d3daaa0527:727:dolphin/L3_Lab_research_128x54/meta.txt D:infrared/assets -F:665b09ef2a1849306b56d1afb0fdd67a:118089:infrared/assets/ac.ir -F:da34b5968815387f1bcebcb3d8c4bf54:47410:infrared/assets/audio.ir -F:50718b2cfc6fae7b79a35eab5cccc6c0:78119:infrared/assets/fans.ir -F:88ac3e7ae8be5a0df84c1d7f81989cae:4170:infrared/assets/projectors.ir +F:13fe3def425723bccd05fe09c745a335:122232:infrared/assets/ac.ir +F:2f9395f655e75cbc362a9739de22412d:47494:infrared/assets/audio.ir +F:1703fea41cb6ef71553b91a1004dc936:82397:infrared/assets/fans.ir +F:08d864cf44e2557fb25aec8837740de5:6567:infrared/assets/projectors.ir F:77bc8314d113b8618942589f21a491fc:127350:infrared/assets/tv.ir F:a157a80f5a668700403d870c23b9567d:470:music_player/Marble_Machine.fmf D:nfc/assets @@ -258,7 +258,7 @@ F:50cf77ba8b935ee6cb3b6f111cf2d93d:286:subghz/assets/dangerous_settings F:111d2b8df83e27fd889fc5e270297865:3231:subghz/assets/keeloq_mfcodes F:bb48d7d7db4f6e849436d0e1a9b7a1a7:633:subghz/assets/keeloq_mfcodes_user_example F:653bd8d349055a41e1152e557d4a52d3:202:subghz/assets/nice_flor_s -F:9f7dea8ec70b2ce34eb57f009bd62033:2795:subghz/assets/setting_user +F:48eec96d1884c311a7b011c0ad5b2dde:2816:subghz/assets/setting_user D:u2f/assets F:7e11e688e39034bbb9d88410044795e1:365:u2f/assets/cert.der F:f60b88c20ed479ed9684e249f7134618:264:u2f/assets/cert_key.u2f diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index ee09035fbc..fa5d5a372b 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -1,6 +1,6 @@ Filetype: IR library file Version: 1 -# Last Updated 27th Aug, 2022 +# Last Updated 30th Aug, 2022 # name: TEMP+ type: raw @@ -104,6 +104,12 @@ protocol: NEC address: 81 00 00 00 command: 68 00 00 00 # +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 198 131341 3063 3026 3054 4297 600 1676 575 560 571 1691 571 697 568 568 573 1688 574 562 569 1824 573 563 599 1676 575 1686 576 1817 569 567 574 562 569 567 574 1819 567 569 572 563 599 1676 575 692 574 562 569 1693 569 567 574 1819 567 568 573 563 567 1694 599 682 573 563 568 568 573 1688 574 694 571 564 567 569 572 564 567 701 596 1679 572 1688 574 563 567 700 576 560 570 1690 572 565 576 691 574 561 601 549 571 565 576 691 574 561 569 567 574 1686 576 692 573 562 569 568 594 1681 570 697 568 567 574 562 568 567 574 694 571 564 567 569 572 564 598 707 569 1692 570 1691 571 566 575 716 570 1691 571 565 576 1686 576 1685 597 +# name: MODE type: parsed protocol: NEC @@ -920,3 +926,32 @@ frequency: 38000 duty_cycle: 0.330000 data: 552 17959 3004 8946 521 530 474 1490 519 477 517 505 499 497 497 498 496 500 494 501 493 503 501 1464 524 497 497 499 495 1470 518 504 500 495 499 1493 495 1496 492 1499 520 1472 516 1475 524 498 496 500 494 501 493 503 501 494 500 496 498 497 497 499 495 501 493 502 492 531 473 522 472 524 470 525 490 506 498 497 497 499 495 501 493 502 492 504 500 495 499 497 497 498 496 500 494 501 493 503 501 494 500 496 498 524 470 526 468 527 467 529 496 1469 519 1472 527 1465 523 1468 520 2979 2997 8954 523 1469 519 502 492 504 500 495 499 524 470 525 469 527 467 528 497 499 495 1470 518 503 501 495 499 1466 522 500 494 1471 528 1464 524 497 497 1468 520 1446 604 1440 496 525 469 1496 523 499 495 1470 518 1473 526 497 497 498 496 500 494 1471 528 1464 524 1467 521 501 493 529 465 531 473 522 472 524 491 1474 525 497 497 1469 519 502 492 1474 525 1466 522 500 494 1471 528 494 500 496 498 1494 494 528 466 529 475 521 494 502 492 503 491 1474 525 1467 521 1470 518 1474 525 # +name: TEMP+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3062 3028 3062 4288 599 1678 573 563 567 1694 568 700 576 560 570 1691 570 565 576 1817 569 1692 601 549 571 564 567 1826 570 566 575 1686 576 1686 576 692 574 562 568 568 594 1680 571 697 568 567 574 1687 575 561 570 1824 572 563 567 568 573 1689 593 687 568 568 573 563 567 1693 568 1825 571 564 566 570 571 565 576 692 594 1680 571 1689 572 564 566 701 575 561 570 1692 570 566 575 692 573 563 599 550 570 566 575 693 572 563 567 568 573 1687 574 693 572 564 567 569 603 1672 569 698 567 569 572 564 566 569 572 696 569 566 575 561 569 566 596 709 567 1694 567 1693 568 1693 568 1849 568 568 573 563 567 568 573 1689 593 +# +name: TEMP- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3055 3033 3056 4296 600 1676 575 560 570 1692 569 698 567 568 573 1689 572 564 566 1826 570 1691 601 548 572 564 577 691 574 561 569 1692 569 1692 569 1824 572 563 567 569 603 1672 568 699 577 559 623 1638 571 564 577 1817 569 566 575 561 569 1692 600 681 574 562 568 567 574 1688 573 1820 576 559 571 564 577 559 571 696 600 1675 576 1685 576 560 570 697 568 567 574 1688 573 562 568 699 577 559 603 547 573 562 568 700 576 560 570 565 576 1685 576 692 573 562 568 567 595 1681 570 697 568 568 573 562 568 568 573 694 571 565 576 560 570 565 597 708 568 1694 567 1694 567 1694 567 724 572 564 566 569 572 1690 571 564 598 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3054 3034 3055 4297 599 1677 574 562 568 1693 568 700 576 560 570 1690 571 565 576 1817 569 1693 599 550 570 566 575 693 572 564 566 569 572 1689 572 696 569 566 575 561 600 1674 577 691 574 562 568 567 574 562 568 700 576 560 570 565 576 560 601 680 575 560 570 566 575 561 569 698 567 568 573 563 567 568 573 695 601 1673 567 1693 568 568 573 695 570 566 575 1686 575 561 569 698 567 568 593 556 574 561 569 699 566 569 572 564 566 1695 566 701 575 561 569 567 594 554 576 691 574 562 568 567 574 562 568 699 577 560 570 565 576 560 601 704 572 1688 573 563 567 1694 567 1850 567 569 572 565 576 1685 576 1685 597 +# +name: SWING +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3055 3034 3056 4296 600 1676 575 561 569 1692 569 698 567 569 572 1690 571 564 566 1827 569 1692 600 549 571 565 576 692 573 1687 574 1687 574 562 568 1824 572 564 566 1695 597 1677 574 694 571 565 576 560 570 565 576 692 573 562 568 568 573 562 600 682 573 562 568 568 573 563 567 700 576 560 570 565 576 560 570 697 599 1675 576 1685 576 559 571 697 568 567 574 1687 574 562 568 699 566 569 603 547 573 563 567 700 576 560 570 565 576 1685 566 701 575 561 569 567 595 555 576 692 573 562 568 567 574 562 568 699 566 570 571 564 566 570 602 703 573 1687 574 1687 574 1687 574 1843 574 1687 574 1687 574 1687 574 562 599 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3063 3027 3062 4289 597 1680 571 565 576 1686 575 692 573 563 567 1694 567 569 572 1821 575 1686 596 554 566 569 572 696 569 567 574 562 568 568 573 694 571 565 576 560 601 1673 567 700 576 560 570 566 575 561 569 698 567 569 572 564 566 569 603 678 566 570 571 564 577 559 571 1821 575 562 568 567 574 562 568 700 596 1678 573 1688 573 563 567 700 576 561 569 1691 570 566 575 693 572 564 597 552 568 568 573 694 571 565 576 560 570 1690 571 697 568 567 574 563 598 551 569 698 567 569 572 564 566 569 572 696 569 567 574 562 568 567 594 710 576 1685 576 560 570 1691 570 1846 571 566 575 561 569 1692 569 567 594 diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index 955c113be4..995383fe08 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1220,3 +1220,9 @@ protocol: NEC address: 78 00 00 00 command: 1F 00 00 00 # +name: MUTE +type: parsed +protocol: RC5X +address: 0A 00 00 00 +command: 2F 00 00 00 +# diff --git a/assets/resources/infrared/assets/fans.ir b/assets/resources/infrared/assets/fans.ir index ca740821f3..76c25a3873 100644 --- a/assets/resources/infrared/assets/fans.ir +++ b/assets/resources/infrared/assets/fans.ir @@ -1,6 +1,6 @@ Filetype: IR library file Version: 1 -# Last Updated 27th Aug, 2022 +# Last Updated 29th Aug, 2022 # name: POWER type: parsed @@ -817,3 +817,38 @@ protocol: NECext address: 00 FC 00 00 command: 86 79 00 00 # +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1299 409 1271 412 433 1211 1293 416 1274 409 436 1207 462 1207 462 1208 461 1208 461 1209 460 1209 1296 7131 1300 410 1270 386 459 1210 1294 389 1301 382 463 1206 464 1206 463 1207 463 1208 462 1208 461 1209 1295 8208 1302 382 1298 385 460 1208 1297 387 1293 390 455 1213 456 1214 466 1205 465 1205 464 1206 463 1206 1298 7129 1302 382 1298 385 460 1208 1297 387 1293 390 455 1213 457 1213 467 1204 465 1205 464 1205 464 1206 1298 8207 1293 391 1299 383 452 1218 1297 386 1294 388 457 1213 456 1214 455 1215 454 1216 454 1216 453 1217 1298 7130 1290 415 1275 406 429 1219 1296 409 1271 411 434 1212 457 1213 456 1213 456 1214 455 1188 481 1215 1299 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1296 386 1294 414 431 1212 1292 416 1274 409 436 1206 463 1207 462 1207 463 1207 463 1208 1297 411 434 7953 1292 417 1273 408 437 1206 1298 411 1269 413 432 1210 459 1210 459 1211 458 1211 458 1211 1293 415 430 9123 1293 389 1301 407 438 1205 1299 410 1269 412 433 1209 460 1210 459 1210 459 1210 459 1210 1294 388 457 7957 1298 410 1270 413 432 1211 1293 389 1301 408 437 1205 464 1206 463 1206 463 1207 463 1207 1297 385 460 9120 1296 387 1293 416 429 1214 1301 381 1299 410 435 1208 461 1209 460 1209 460 1210 459 1210 1294 414 431 7958 1297 385 1295 414 431 1212 1303 380 1300 409 436 1207 462 1207 463 1207 462 1209 460 1208 1296 386 459 +# +name: SPEED- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1295 410 1270 411 434 1210 1294 412 1268 414 431 1238 431 1212 1302 405 429 1214 455 1266 1249 406 428 7959 1296 410 1270 412 433 1210 1294 413 1267 414 431 1213 456 1213 1301 405 429 1214 455 1266 1249 406 428 9065 1299 406 1274 408 437 1207 1297 409 1271 411 434 1236 433 1210 1294 412 433 1211 458 1264 1240 414 431 7958 1297 409 1271 411 434 1209 1295 412 1268 414 431 1238 431 1212 1302 405 429 1214 455 1267 1248 407 427 9067 1298 383 1297 410 435 1209 1295 412 1268 414 431 1238 431 1212 1292 415 430 1214 455 1266 1249 407 427 7962 1293 414 1276 406 428 1215 1300 408 1272 410 435 1235 434 1209 1295 411 434 1210 459 1262 1242 413 432 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1300 381 1299 410 435 1208 1296 413 1267 415 430 1213 456 1213 456 1214 455 1214 1301 408 437 1207 462 7950 1295 413 1267 416 429 1214 1301 381 1299 410 435 1208 461 1208 461 1208 461 1208 1296 386 459 1211 458 9008 1296 387 1293 415 430 1213 1301 407 1273 410 435 1208 461 1208 461 1208 461 1208 1296 386 459 1210 459 7952 1293 416 1274 408 437 1206 1298 384 1296 413 432 1211 458 1211 458 1211 458 1211 1304 405 429 1214 455 9013 1301 407 1273 410 435 1259 1245 412 1268 415 430 1264 405 1213 456 1213 456 1213 1301 407 438 1256 403 7958 1297 410 1270 413 432 1262 1253 405 1275 407 427 1267 402 1216 453 1216 453 1216 1298 409 436 1259 410 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1294 412 1268 415 430 1265 1250 408 1272 411 434 1260 409 1210 1294 413 432 1264 405 1213 456 1215 454 7959 1296 411 1269 415 430 1265 1250 408 1271 410 435 1260 409 1234 1270 413 432 1264 405 1238 431 1214 455 9016 1298 410 1270 414 431 1264 1251 407 1273 409 436 1260 409 1260 1244 413 432 1263 406 1237 433 1213 456 7959 1296 412 1268 415 430 1265 1250 407 1273 410 435 1260 409 1234 1270 414 431 1264 405 1214 455 1215 454 9017 1297 411 1269 414 431 1264 1251 407 1273 410 435 1260 409 1209 1295 387 458 1237 432 1213 456 1214 456 7959 1296 413 1267 416 429 1239 1276 409 1271 412 433 1235 434 1211 1304 379 455 1239 430 1215 454 1216 453 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1294 388 1291 390 455 1215 1289 392 1298 384 451 1220 460 1210 459 1210 1294 388 457 1212 457 1212 457 7954 1301 382 1298 384 461 1207 1297 387 1293 389 456 1212 457 1212 457 1213 1291 392 463 1205 465 1205 464 9263 1295 414 1266 417 428 1214 1301 409 1271 412 433 1209 460 1209 460 1210 1294 415 430 1213 456 1213 456 7959 1296 413 1267 415 430 1213 1302 408 1271 411 434 1208 461 1209 460 1209 1295 414 431 1212 457 1213 456 9272 1297 412 1268 415 430 1212 1292 417 1273 410 435 1207 462 1208 461 1208 1296 413 432 1211 458 1211 458 7956 1299 410 1270 413 432 1210 1294 390 1300 409 436 1206 463 1207 463 1207 1298 387 458 1210 459 1211 458 diff --git a/assets/resources/infrared/assets/projectors.ir b/assets/resources/infrared/assets/projectors.ir index 33f8e46c8f..b761a21b52 100644 --- a/assets/resources/infrared/assets/projectors.ir +++ b/assets/resources/infrared/assets/projectors.ir @@ -1,6 +1,6 @@ Filetype: IR library file Version: 1 -# Last Updated 27th Aug, 2022 +# Last Updated 29th Aug, 2022 # name: POWER type: parsed @@ -290,3 +290,27 @@ protocol: NECext address: 87 4E 00 00 command: 0D 00 00 00 # +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9032 4479 597 560 572 558 564 566 566 1666 589 1671 594 562 570 560 562 568 564 1669 596 560 562 568 564 1669 596 560 562 1671 594 1666 588 1671 594 562 570 560 562 568 564 1669 596 560 562 568 564 566 566 563 569 1664 591 1669 596 1664 590 565 567 1667 598 1661 593 1666 588 1671 594 562 570 560 562 568 564 565 567 563 569 560 562 568 564 565 567 1666 588 1671 594 1665 589 1670 595 1665 590 1669 596 1664 590 1668 597 13983 9029 2222 599 96237 9030 2221 589 96244 9034 2217 594 96244 9033 2218 592 96249 9038 2213 597 96239 9037 2214 596 96238 9028 2223 598 96221 9032 2215 595 +# +name: VOL+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9034 4482 593 563 569 561 571 559 563 1698 566 1694 570 559 563 568 564 566 566 1695 569 560 572 559 563 1671 593 563 569 1692 562 1671 593 1693 571 558 564 567 565 565 567 1693 571 532 590 567 565 1695 569 560 562 1698 566 1694 570 1663 591 539 593 1693 571 1688 566 564 568 1691 563 567 565 565 567 563 569 561 571 559 563 567 565 565 567 563 569 1690 564 1695 569 1691 563 1696 568 1691 563 1697 567 1692 562 1697 567 13988 9030 2223 597 96250 9035 2219 591 96245 9032 2221 589 96240 9038 2215 595 96235 9033 2220 590 +# +name: VOL- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9028 4482 593 563 569 561 571 558 564 1696 568 1690 564 566 566 563 569 561 571 1688 566 563 569 561 571 1688 566 563 569 1690 564 1695 569 1689 565 1668 596 560 562 568 564 1695 569 560 562 568 564 1695 569 560 562 568 564 1695 569 1690 564 566 566 1692 572 1687 567 563 569 1690 564 566 566 564 568 562 570 559 563 567 565 565 567 562 570 560 562 1696 568 1665 589 1670 594 1665 589 1670 594 1664 590 1669 647 1612 590 13987 9031 2220 590 96223 9033 2217 593 96223 9034 2218 592 96225 9032 2219 591 96221 9087 2164 595 +# +name: MUTE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9031 4479 596 560 572 558 564 566 566 1693 571 1688 566 563 569 561 571 559 563 1696 568 561 571 559 563 1697 567 562 570 1689 565 1694 570 1688 566 1693 571 1661 593 1693 571 558 564 566 566 564 568 1691 563 541 591 564 568 562 570 560 562 1697 567 1692 562 1696 568 562 570 1689 565 564 568 561 571 559 563 567 565 564 568 562 570 560 562 567 565 1694 570 1689 565 1694 570 1688 566 1693 571 1688 566 1693 571 1662 592 13987 9031 2220 590 96231 9034 2217 593 96234 9030 2222 588 96247 9037 2215 595 +# diff --git a/assets/resources/subghz/assets/setting_user b/assets/resources/subghz/assets/setting_user index 32051d45d3..de419485c1 100644 --- a/assets/resources/subghz/assets/setting_user +++ b/assets/resources/subghz/assets/setting_user @@ -19,6 +19,7 @@ Frequency: 309000000 Frequency: 310000000 Frequency: 312000000 Frequency: 312100000 +Frequency: 313000000 Frequency: 313850000 Frequency: 314000000 Frequency: 314350000 @@ -50,8 +51,8 @@ Frequency: 928000000 # Frequencies used for hopping mode (keep this list small or flipper will miss signal) - they added after default ones if enabled in Add_standard_frequencies Hopper_frequency: 310000000 Hopper_frequency: 315000000 +Hopper_frequency: 313000000 Hopper_frequency: 318000000 -Hopper_frequency: 345000000 Hopper_frequency: 390000000 Hopper_frequency: 433920000 Hopper_frequency: 434420000 From 4fcb90928c96dfa8c324fe7392b517954d7688cc Mon Sep 17 00:00:00 2001 From: Max Lapan Date: Tue, 30 Aug 2022 13:33:05 +0200 Subject: [PATCH 67/78] ST25TB type is not handled (#1679) We search for ST25TB type cards, but not handling them being found. As a result, such cards are detected as NFC-A with 8-byte UID, which lead to read error on emulation attempt. Co-authored-by: gornekich --- firmware/targets/f7/furi_hal/furi_hal_nfc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index 2d6db8fbf1..bd7fbc3fcc 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -124,7 +124,9 @@ bool furi_hal_nfc_detect(FuriHalNfcDevData* nfc_data, uint32_t timeout) { } nfc_data->cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) | (cuid_start[3]); - } else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCB) { + } else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCB || + dev_list[0].type == RFAL_NFC_LISTEN_TYPE_ST25TB) + { nfc_data->type = FuriHalNfcTypeB; } else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCF) { nfc_data->type = FuriHalNfcTypeF; From 23217f4a6ad0f58860c63949bdcd5927ed888881 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 30 Aug 2022 14:37:44 +0300 Subject: [PATCH 68/78] update audio manifest by @Amec0e --- assets/resources/Manifest | 4 ++-- assets/resources/infrared/assets/audio.ir | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/assets/resources/Manifest b/assets/resources/Manifest index b928457b35..7cfdd27d56 100644 --- a/assets/resources/Manifest +++ b/assets/resources/Manifest @@ -1,5 +1,5 @@ V:0 -T:1661854501 +T:1661859394 D:badusb D:dolphin D:infrared @@ -242,7 +242,7 @@ F:f267f0654781049ca323b11bb4375519:581:dolphin/L3_Lab_research_128x54/frame_9.bm F:41106c0cbc5144f151b2b2d3daaa0527:727:dolphin/L3_Lab_research_128x54/meta.txt D:infrared/assets F:13fe3def425723bccd05fe09c745a335:122232:infrared/assets/ac.ir -F:2f9395f655e75cbc362a9739de22412d:47494:infrared/assets/audio.ir +F:bbf2da1adc15aca3a2bb7f8a8800b81a:47577:infrared/assets/audio.ir F:1703fea41cb6ef71553b91a1004dc936:82397:infrared/assets/fans.ir F:08d864cf44e2557fb25aec8837740de5:6567:infrared/assets/projectors.ir F:77bc8314d113b8618942589f21a491fc:127350:infrared/assets/tv.ir diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index 995383fe08..db4f8ef1db 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1,6 +1,6 @@ Filetype: IR library file Version: 1 -# Last Updated 27th Aug, 2022 +# Last Updated 30th Aug, 2022 # name: POWER type: parsed @@ -1226,3 +1226,9 @@ protocol: RC5X address: 0A 00 00 00 command: 2F 00 00 00 # +name: VOL- +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 15 00 00 00 +# From e4c6158d65b93166eb4dc54857c30d3dff575001 Mon Sep 17 00:00:00 2001 From: Foul Date: Tue, 30 Aug 2022 14:15:14 +0200 Subject: [PATCH 69/78] Update comment in SConstruct (#1684) * Update SConstruct: fix Typo * Grammar in SConstruct Co-authored-by: Aleksandr Kutuzov --- SConstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SConstruct b/SConstruct index 52fe75a6a9..4462f2f300 100644 --- a/SConstruct +++ b/SConstruct @@ -1,5 +1,5 @@ # -# Main Fipper Build System entry point +# Main Flipper Build System entry point # # This file is evaluated by scons (the build system) every time fbt is invoked. # Scons constructs all referenced environments & their targets' dependency @@ -15,7 +15,7 @@ DefaultEnvironment(tools=[]) # Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15) -# This environment is created only for loading options & validating file/dir existance +# This environment is created only for loading options & validating file/dir existence fbt_variables = SConscript("site_scons/commandline.scons") cmd_environment = Environment(tools=[], variables=fbt_variables) Help(fbt_variables.GenerateHelpText(cmd_environment)) From b67aaad6d56fba6b37ab679c0fb12335a225c7cf Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 30 Aug 2022 15:33:51 +0300 Subject: [PATCH 70/78] fix text --- applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp b/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp index ea4f03dbb4..91e26d23a8 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp @@ -9,7 +9,7 @@ typedef enum { void LfRfidAppSceneExtraActions::on_enter(LfRfidApp* app, bool need_restore) { auto submenu = app->view_controller.get(); - submenu->add_item("Read ASK (Animal, Ordinary Card)", SubmenuASK, submenu_callback, app); + submenu->add_item("Read ASK (FDX,Regular)", SubmenuASK, submenu_callback, app); submenu->add_item("Read PSK (Indala)", SubmenuPSK, submenu_callback, app); if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { From 8e9043003f6d7462e1790d00bacc6f997c6f3dbc Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Tue, 30 Aug 2022 06:59:34 -0700 Subject: [PATCH 71/78] Picopass write (#1658) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [picopass] Prevent false success with non-standard key * UI for writing * worker function for write * Update write command value * Show card read failure message Co-authored-by: あく --- applications/picopass/picopass_worker.c | 114 +++++++++++++++++- applications/picopass/picopass_worker.h | 1 + applications/picopass/picopass_worker_i.h | 1 + .../picopass/scenes/picopass_scene_config.h | 2 + .../scenes/picopass_scene_read_card.c | 2 - .../scenes/picopass_scene_read_card_success.c | 77 +++++++----- .../scenes/picopass_scene_saved_menu.c | 5 + .../scenes/picopass_scene_write_card.c | 53 ++++++++ .../picopass_scene_write_card_success.c | 57 +++++++++ lib/ST25RFAL002/include/rfal_picopass.h | 2 +- lib/ST25RFAL002/source/rfal_picopass.c | 16 ++- 11 files changed, 286 insertions(+), 44 deletions(-) create mode 100644 applications/picopass/scenes/picopass_scene_write_card.c create mode 100644 applications/picopass/scenes/picopass_scene_write_card_success.c diff --git a/applications/picopass/picopass_worker.c b/applications/picopass/picopass_worker.c index 88df8d45b8..3ca56d0065 100644 --- a/applications/picopass/picopass_worker.c +++ b/applications/picopass/picopass_worker.c @@ -190,12 +190,87 @@ ReturnCode picopass_read_card(PicopassBlock* AA1) { return ERR_NONE; } +ReturnCode picopass_write_card(PicopassBlock* AA1) { + rfalPicoPassIdentifyRes idRes; + rfalPicoPassSelectRes selRes; + rfalPicoPassReadCheckRes rcRes; + rfalPicoPassCheckRes chkRes; + + ReturnCode err; + + uint8_t div_key[8] = {0}; + uint8_t mac[4] = {0}; + uint8_t ccnr[12] = {0}; + + err = rfalPicoPassPollerIdentify(&idRes); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerIdentify error %d", err); + return err; + } + + err = rfalPicoPassPollerSelect(idRes.CSN, &selRes); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerSelect error %d", err); + return err; + } + + err = rfalPicoPassPollerReadCheck(&rcRes); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err); + return err; + } + memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0 + + loclass_diversifyKey(selRes.CSN, picopass_iclass_key, div_key); + loclass_opt_doReaderMAC(ccnr, div_key, mac); + + err = rfalPicoPassPollerCheck(mac, &chkRes); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerCheck error %d", err); + return err; + } + + for(size_t i = 6; i < 10; i++) { + FURI_LOG_D(TAG, "rfalPicoPassPollerWriteBlock %d", i); + uint8_t data[9] = {0}; + data[0] = i; + memcpy(data + 1, AA1[i].data, RFAL_PICOPASS_MAX_BLOCK_LEN); + loclass_doMAC_N(data, sizeof(data), div_key, mac); + FURI_LOG_D( + TAG, + "loclass_doMAC_N %d %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x", + i, + data[1], + data[2], + data[3], + data[4], + data[5], + data[6], + data[7], + data[8], + mac[0], + mac[1], + mac[2], + mac[3]); + + err = rfalPicoPassPollerWriteBlock(i, AA1[i].data, mac); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerWriteBlock error %d", err); + return err; + } + } + + return ERR_NONE; +} + int32_t picopass_worker_task(void* context) { PicopassWorker* picopass_worker = context; picopass_worker_enable_field(); if(picopass_worker->state == PicopassWorkerStateDetect) { picopass_worker_detect(picopass_worker); + } else if(picopass_worker->state == PicopassWorkerStateWrite) { + picopass_worker_write(picopass_worker); } picopass_worker_disable_field(ERR_NONE); @@ -212,27 +287,60 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) { PicopassPacs* pacs = &dev_data->pacs; ReturnCode err; + PicopassWorkerEvent nextState = PicopassWorkerEventSuccess; + while(picopass_worker->state == PicopassWorkerStateDetect) { if(picopass_detect_card(1000) == ERR_NONE) { // Process first found device err = picopass_read_card(AA1); if(err != ERR_NONE) { FURI_LOG_E(TAG, "picopass_read_card error %d", err); + nextState = PicopassWorkerEventFail; } - err = picopass_device_parse_credential(AA1, pacs); + if(nextState == PicopassWorkerEventSuccess) { + err = picopass_device_parse_credential(AA1, pacs); + } if(err != ERR_NONE) { FURI_LOG_E(TAG, "picopass_device_parse_credential error %d", err); + nextState = PicopassWorkerEventFail; } - err = picopass_device_parse_wiegand(pacs->credential, &pacs->record); + if(nextState == PicopassWorkerEventSuccess) { + err = picopass_device_parse_wiegand(pacs->credential, &pacs->record); + } if(err != ERR_NONE) { FURI_LOG_E(TAG, "picopass_device_parse_wiegand error %d", err); + nextState = PicopassWorkerEventFail; + } + + // Notify caller and exit + if(picopass_worker->callback) { + picopass_worker->callback(nextState, picopass_worker->context); + } + break; + } + furi_delay_ms(100); + } +} + +void picopass_worker_write(PicopassWorker* picopass_worker) { + PicopassDeviceData* dev_data = picopass_worker->dev_data; + PicopassBlock* AA1 = dev_data->AA1; + ReturnCode err; + PicopassWorkerEvent nextState = PicopassWorkerEventSuccess; + + while(picopass_worker->state == PicopassWorkerStateWrite) { + if(picopass_detect_card(1000) == ERR_NONE) { + err = picopass_write_card(AA1); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "picopass_write_card error %d", err); + nextState = PicopassWorkerEventFail; } // Notify caller and exit if(picopass_worker->callback) { - picopass_worker->callback(PicopassWorkerEventSuccess, picopass_worker->context); + picopass_worker->callback(nextState, picopass_worker->context); } break; } diff --git a/applications/picopass/picopass_worker.h b/applications/picopass/picopass_worker.h index 9035f1c895..6ad7090583 100644 --- a/applications/picopass/picopass_worker.h +++ b/applications/picopass/picopass_worker.h @@ -11,6 +11,7 @@ typedef enum { PicopassWorkerStateReady, // Main worker states PicopassWorkerStateDetect, + PicopassWorkerStateWrite, // Transition PicopassWorkerStateStop, } PicopassWorkerState; diff --git a/applications/picopass/picopass_worker_i.h b/applications/picopass/picopass_worker_i.h index 789951900b..9b215fb743 100644 --- a/applications/picopass/picopass_worker_i.h +++ b/applications/picopass/picopass_worker_i.h @@ -31,3 +31,4 @@ void picopass_worker_change_state(PicopassWorker* picopass_worker, PicopassWorke int32_t picopass_worker_task(void* context); void picopass_worker_detect(PicopassWorker* picopass_worker); +void picopass_worker_write(PicopassWorker* picopass_worker); diff --git a/applications/picopass/scenes/picopass_scene_config.h b/applications/picopass/scenes/picopass_scene_config.h index 87745378b6..27d6bbcd77 100644 --- a/applications/picopass/scenes/picopass_scene_config.h +++ b/applications/picopass/scenes/picopass_scene_config.h @@ -9,3 +9,5 @@ ADD_SCENE(picopass, file_select, FileSelect) ADD_SCENE(picopass, device_info, DeviceInfo) ADD_SCENE(picopass, delete, Delete) ADD_SCENE(picopass, delete_success, DeleteSuccess) +ADD_SCENE(picopass, write_card, WriteCard) +ADD_SCENE(picopass, write_card_success, WriteCardSuccess) diff --git a/applications/picopass/scenes/picopass_scene_read_card.c b/applications/picopass/scenes/picopass_scene_read_card.c index 0867898a53..8188207a2a 100644 --- a/applications/picopass/scenes/picopass_scene_read_card.c +++ b/applications/picopass/scenes/picopass_scene_read_card.c @@ -37,8 +37,6 @@ bool picopass_scene_read_card_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCardSuccess); consumed = true; } - } else if(event.type == SceneManagerEventTypeTick) { - consumed = true; } return consumed; } diff --git a/applications/picopass/scenes/picopass_scene_read_card_success.c b/applications/picopass/scenes/picopass_scene_read_card_success.c index 3866d201c4..c281b32ca2 100644 --- a/applications/picopass/scenes/picopass_scene_read_card_success.c +++ b/applications/picopass/scenes/picopass_scene_read_card_success.c @@ -29,38 +29,57 @@ void picopass_scene_read_card_success_on_enter(void* context) { PicopassPacs* pacs = &picopass->dev->dev_data.pacs; Widget* widget = picopass->widget; - size_t bytesLength = 1 + pacs->record.bitLength / 8; - string_set_str(credential_str, ""); - for(uint8_t i = PICOPASS_BLOCK_LEN - bytesLength; i < PICOPASS_BLOCK_LEN; i++) { - string_cat_printf(credential_str, " %02X", pacs->credential[i]); - } - - if(pacs->record.valid) { - string_cat_printf( - wiegand_str, "FC: %u CN: %u", pacs->record.FacilityCode, pacs->record.CardNumber); + if(pacs->record.bitLength == 0) { + string_cat_printf(wiegand_str, "Read Failed"); + + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Retry", + picopass_scene_read_card_success_widget_callback, + picopass); + + widget_add_string_element( + widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str)); } else { - string_cat_printf(wiegand_str, "%d bits", pacs->record.bitLength); - } + size_t bytesLength = 1 + pacs->record.bitLength / 8; + string_set_str(credential_str, ""); + for(uint8_t i = PICOPASS_BLOCK_LEN - bytesLength; i < PICOPASS_BLOCK_LEN; i++) { + string_cat_printf(credential_str, " %02X", pacs->credential[i]); + } - widget_add_button_element( - widget, - GuiButtonTypeLeft, - "Retry", - picopass_scene_read_card_success_widget_callback, - picopass); - - widget_add_button_element( - widget, - GuiButtonTypeRight, - "More", - picopass_scene_read_card_success_widget_callback, - picopass); - - widget_add_string_element( - widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str)); - widget_add_string_element( - widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(credential_str)); + if(pacs->record.valid) { + string_cat_printf( + wiegand_str, "FC: %u CN: %u", pacs->record.FacilityCode, pacs->record.CardNumber); + } else { + string_cat_printf(wiegand_str, "%d bits", pacs->record.bitLength); + } + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Retry", + picopass_scene_read_card_success_widget_callback, + picopass); + + widget_add_button_element( + widget, + GuiButtonTypeRight, + "More", + picopass_scene_read_card_success_widget_callback, + picopass); + + widget_add_string_element( + widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str)); + widget_add_string_element( + widget, + 64, + 32, + AlignCenter, + AlignCenter, + FontSecondary, + string_get_cstr(credential_str)); + } string_clear(credential_str); string_clear(wiegand_str); diff --git a/applications/picopass/scenes/picopass_scene_saved_menu.c b/applications/picopass/scenes/picopass_scene_saved_menu.c index 8f0ce40bae..90a27ee816 100644 --- a/applications/picopass/scenes/picopass_scene_saved_menu.c +++ b/applications/picopass/scenes/picopass_scene_saved_menu.c @@ -24,6 +24,8 @@ void picopass_scene_saved_menu_on_enter(void* context) { picopass); submenu_add_item( submenu, "Info", SubmenuIndexInfo, picopass_scene_saved_menu_submenu_callback, picopass); + submenu_add_item( + submenu, "Write", SubmenuIndexWrite, picopass_scene_saved_menu_submenu_callback, picopass); submenu_set_selected_item( picopass->submenu, @@ -46,6 +48,9 @@ bool picopass_scene_saved_menu_on_event(void* context, SceneManagerEvent event) } else if(event.event == SubmenuIndexInfo) { scene_manager_next_scene(picopass->scene_manager, PicopassSceneDeviceInfo); consumed = true; + } else if(event.event == SubmenuIndexWrite) { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteCard); + consumed = true; } } diff --git a/applications/picopass/scenes/picopass_scene_write_card.c b/applications/picopass/scenes/picopass_scene_write_card.c new file mode 100644 index 0000000000..a905dca955 --- /dev/null +++ b/applications/picopass/scenes/picopass_scene_write_card.c @@ -0,0 +1,53 @@ +#include "../picopass_i.h" +#include + +void picopass_write_card_worker_callback(PicopassWorkerEvent event, void* context) { + UNUSED(event); + Picopass* picopass = context; + view_dispatcher_send_custom_event(picopass->view_dispatcher, PicopassCustomEventWorkerExit); +} + +void picopass_scene_write_card_on_enter(void* context) { + Picopass* picopass = context; + DOLPHIN_DEED(DolphinDeedNfcSave); + + // Setup view + Popup* popup = picopass->popup; + popup_set_header(popup, "Writing\npicopass\ncard", 68, 30, AlignLeft, AlignTop); + popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61); + + // Start worker + view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewPopup); + picopass_worker_start( + picopass->worker, + PicopassWorkerStateWrite, + &picopass->dev->dev_data, + picopass_write_card_worker_callback, + picopass); + + picopass_blink_start(picopass); +} + +bool picopass_scene_write_card_on_event(void* context, SceneManagerEvent event) { + Picopass* picopass = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == PicopassCustomEventWorkerExit) { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteCardSuccess); + consumed = true; + } + } + return consumed; +} + +void picopass_scene_write_card_on_exit(void* context) { + Picopass* picopass = context; + + // Stop worker + picopass_worker_stop(picopass->worker); + // Clear view + popup_reset(picopass->popup); + + picopass_blink_stop(picopass); +} diff --git a/applications/picopass/scenes/picopass_scene_write_card_success.c b/applications/picopass/scenes/picopass_scene_write_card_success.c new file mode 100644 index 0000000000..108e7d1cef --- /dev/null +++ b/applications/picopass/scenes/picopass_scene_write_card_success.c @@ -0,0 +1,57 @@ +#include "../picopass_i.h" +#include + +void picopass_scene_write_card_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + furi_assert(context); + Picopass* picopass = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(picopass->view_dispatcher, result); + } +} + +void picopass_scene_write_card_success_on_enter(void* context) { + Picopass* picopass = context; + Widget* widget = picopass->widget; + + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + + // Send notification + notification_message(picopass->notifications, &sequence_success); + + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Retry", + picopass_scene_write_card_success_widget_callback, + picopass); + + view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget); +} + +bool picopass_scene_write_card_success_on_event(void* context, SceneManagerEvent event) { + Picopass* picopass = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(picopass->scene_manager); + } else if(event.event == GuiButtonTypeRight) { + // Clear device name + picopass_device_set_name(picopass->dev, ""); + scene_manager_next_scene(picopass->scene_manager, PicopassSceneCardMenu); + consumed = true; + } + } + return consumed; +} + +void picopass_scene_write_card_success_on_exit(void* context) { + Picopass* picopass = context; + + // Clear view + widget_reset(picopass->widget); +} diff --git a/lib/ST25RFAL002/include/rfal_picopass.h b/lib/ST25RFAL002/include/rfal_picopass.h index 2baf96f375..e7fb272cee 100644 --- a/lib/ST25RFAL002/include/rfal_picopass.h +++ b/lib/ST25RFAL002/include/rfal_picopass.h @@ -26,7 +26,7 @@ enum { RFAL_PICOPASS_CMD_READCHECK = 0x88, RFAL_PICOPASS_CMD_CHECK = 0x05, RFAL_PICOPASS_CMD_READ = 0x0C, - RFAL_PICOPASS_CMD_WRITE = 0x0C, + RFAL_PICOPASS_CMD_WRITE = 0x87, }; typedef struct { diff --git a/lib/ST25RFAL002/source/rfal_picopass.c b/lib/ST25RFAL002/source/rfal_picopass.c index d4422e4123..f33fcdf8c1 100644 --- a/lib/ST25RFAL002/source/rfal_picopass.c +++ b/lib/ST25RFAL002/source/rfal_picopass.c @@ -2,6 +2,8 @@ #include "rfal_picopass.h" #include "utils.h" +#define TAG "RFAL_PICOPASS" + typedef struct { uint8_t CMD; uint8_t CSN[RFAL_PICOPASS_UID_LEN]; @@ -169,18 +171,14 @@ ReturnCode rfalPicoPassPollerWriteBlock(uint8_t blockNum, uint8_t data[8], uint8 uint16_t recvLen = 0; uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS; uint32_t fwt = rfalConvMsTo1fc(20); - rfalPicoPassReadBlockRes readRes; + rfalPicoPassReadBlockRes block; ret = rfalTransceiveBlockingTxRx( - txBuf, - sizeof(txBuf), - (uint8_t*)&readRes, - sizeof(rfalPicoPassReadBlockRes), - &recvLen, - flags, - fwt); + txBuf, sizeof(txBuf), (uint8_t*)&block, sizeof(block), &recvLen, flags, fwt); - // TODO: compare response + if(ret == ERR_NONE) { + // TODO: compare response + } return ret; } From e7a5d19f9c919c1bc5c49f53f93b6ac8bec03b2b Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Tue, 30 Aug 2022 19:22:24 +0400 Subject: [PATCH 72/78] [FL-2778] SubGhz: fix CLI "subghz tx" (#1681) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: fix CLI "subghz tx" * Fix qoutes in amap workflow * Github: fix step naming * fix quotes in PR name again Co-authored-by: あく Co-authored-by: DrunkBatya --- .github/workflows/amap_analyse.yml | 16 +++++++++++++--- applications/subghz/subghz_cli.c | 20 ++++++++++++-------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/.github/workflows/amap_analyse.yml b/.github/workflows/amap_analyse.yml index 11dac543ae..5efdb09e52 100644 --- a/.github/workflows/amap_analyse.yml +++ b/.github/workflows/amap_analyse.yml @@ -45,6 +45,19 @@ jobs: fetch-depth: 0 ref: ${{ github.event.pull_request.head.sha }} + - name: 'Escape pull request title' + if: github.event_name == 'pull_request' + run: | + import json + import os + import shlex + with open('${{ github.event_path }}') as fh: + event = json.load(fh) + escaped = shlex.quote(event['pull_request']['title']) + with open(os.environ['GITHUB_ENV'], 'a') as fh: + print(f'PULL_NAME={escaped}', file=fh) + shell: python3 {0} + - name: 'Generate prefixes by commit' id: names run: | @@ -58,7 +71,6 @@ jobs: SHA="$(cut -c -8 <<< "$COMMIT_HASH")" COMMIT_MSG="$(git log -1 --pretty=format:"%s")" PULL_ID="${{github.event.pull_request.number}}" - PULL_NAME="${{github.event.pull_request.title}}" fi BRANCH_NAME=${REF#refs/*/} SUFFIX=${BRANCH_NAME//\//_}-$(date +'%d%m%Y')-${SHA} @@ -78,7 +90,6 @@ jobs: mkdir artifacts - name: 'Download build artifacts' - if: ${{ !github.event.pull_request.head.repo.fork }} run: | echo "${{ secrets.RSYNC_DEPLOY_KEY }}" > deploy_key; chmod 600 ./deploy_key; @@ -112,7 +123,6 @@ jobs: export FREE_FLASH_SIZE="$(get_size ".free_flash")" if [[ ${{ github.event_name }} == 'pull_request' ]]; then export PULL_ID="${{steps.names.outputs.pull-id}}" - export PULL_NAME="${{steps.names.outputs.pull-name}}" fi python3 -m pip install mariadb python3 scripts/amap_mariadb_insert.py \ diff --git a/applications/subghz/subghz_cli.c b/applications/subghz/subghz_cli.c index 09dae0481f..cda50c79ca 100644 --- a/applications/subghz/subghz_cli.c +++ b/applications/subghz/subghz_cli.c @@ -114,19 +114,21 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) { uint32_t frequency = 433920000; uint32_t key = 0x0074BADE; uint32_t repeat = 10; + uint32_t te = 403; if(string_size(args)) { - int ret = sscanf(string_get_cstr(args), "%lx %lu %lu", &key, &frequency, &repeat); - if(ret != 3) { + int ret = sscanf(string_get_cstr(args), "%lx %lu %lu %lu", &key, &frequency, &te, &repeat); + if(ret != 4) { printf( - "sscanf returned %d, key: %lx, frequency: %lu, repeat: %lu\r\n", + "sscanf returned %d, key: %lx, frequency: %lu, te:%lu, repeat: %lu\r\n", ret, key, frequency, + te, repeat); cli_print_usage( "subghz tx", - "<3 Byte Key: in hex> ", + "<3 Byte Key: in hex> ", string_get_cstr(args)); return; } @@ -139,9 +141,10 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) { } printf( - "Transmitting at %lu, key %lx, repeat %lu. Press CTRL+C to stop\r\n", + "Transmitting at %lu, key %lx, te %lu, repeat %lu. Press CTRL+C to stop\r\n", frequency, key, + te, repeat); string_t flipper_format_string; @@ -149,12 +152,13 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) { flipper_format_string, "Protocol: Princeton\n" "Bit: 24\n" - "Key: 00 00 00 00 00 %X %X %X\n" - "TE: 403\n" + "Key: 00 00 00 00 00 %02X %02X %02X\n" + "TE: %d\n" "Repeat: %d\n", (uint8_t)((key >> 16) & 0xFF), (uint8_t)((key >> 8) & 0xFF), (uint8_t)(key & 0xFF), + te, repeat); FlipperFormat* flipper_format = flipper_format_string_alloc(); Stream* stream = flipper_format_get_raw_stream(flipper_format); @@ -425,7 +429,7 @@ static void subghz_cli_command_print_usage() { printf("\tchat \t - Chat with other Flippers\r\n"); printf( - "\ttx <3 byte Key: in hex> \t - Transmitting key\r\n"); + "\ttx <3 byte Key: in hex> \t - Transmitting key\r\n"); printf("\trx \t - Reception key\r\n"); printf("\tdecode_raw \t - Testing\r\n"); From 079cadaedaad9d3ccae04f6904079964db265370 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 30 Aug 2022 21:25:08 +0300 Subject: [PATCH 73/78] SubGhz: add protocol Prastel - OFW PR 1674 by Skorpionm --- lib/subghz/protocols/came.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/subghz/protocols/came.c b/lib/subghz/protocols/came.c index 726461d4d1..14c66b7fa9 100644 --- a/lib/subghz/protocols/came.c +++ b/lib/subghz/protocols/came.c @@ -13,6 +13,9 @@ */ #define TAG "SubGhzProtocolCAME" +#define CAME_24_COUNT_BIT 24 +#define PRASTEL_COUNT_BIT 25 +#define PRASTEL_NAME "Prastel" static const SubGhzBlockConst subghz_protocol_came_const = { .te_short = 320, @@ -114,9 +117,9 @@ static bool subghz_protocol_encoder_came_get_upload(SubGhzProtocolEncoderCame* i //Send header instance->encoder.upload[index++] = level_duration_make( false, - ((instance->generic.data_count_bit == subghz_protocol_came_const.min_count_bit_for_found) ? - (uint32_t)subghz_protocol_came_const.te_short * 39 : - (uint32_t)subghz_protocol_came_const.te_short * 76)); + ((instance->generic.data_count_bit == CAME_24_COUNT_BIT) ? + (uint32_t)subghz_protocol_came_const.te_short * 76 : + (uint32_t)subghz_protocol_came_const.te_short * 39)); //Send start bit instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)subghz_protocol_came_const.te_short); @@ -150,8 +153,8 @@ bool subghz_protocol_encoder_came_deserialize(void* context, FlipperFormat* flip } if((instance->generic.data_count_bit != subghz_protocol_came_const.min_count_bit_for_found) && - (instance->generic.data_count_bit != - 2 * subghz_protocol_came_const.min_count_bit_for_found)) { + (instance->generic.data_count_bit != CAME_24_COUNT_BIT) && + (instance->generic.data_count_bit != PRASTEL_COUNT_BIT)) { FURI_LOG_E(TAG, "Wrong number of bits in key"); break; } @@ -309,8 +312,8 @@ bool subghz_protocol_decoder_came_deserialize(void* context, FlipperFormat* flip } if((instance->generic.data_count_bit != subghz_protocol_came_const.min_count_bit_for_found) && - (instance->generic.data_count_bit != - 2 * subghz_protocol_came_const.min_count_bit_for_found)) { + (instance->generic.data_count_bit != CAME_24_COUNT_BIT) && + (instance->generic.data_count_bit != PRASTEL_COUNT_BIT)) { FURI_LOG_E(TAG, "Wrong number of bits in key"); break; } @@ -335,7 +338,8 @@ void subghz_protocol_decoder_came_get_string(void* context, string_t output) { "%s %dbit\r\n" "Key:0x%08lX\r\n" "Yek:0x%08lX\r\n", - instance->generic.protocol_name, + (instance->generic.data_count_bit == PRASTEL_COUNT_BIT ? PRASTEL_NAME : + instance->generic.protocol_name), instance->generic.data_count_bit, code_found_lo, code_found_reverse_lo); From 613c729025ee21922c33d4d66a0c96f6928e750f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 30 Aug 2022 21:29:13 +0300 Subject: [PATCH 74/78] Fix displaying LFRFID protocol names - OFW PR 1682 by Astrrra --- .../lfrfid/scene/lfrfid_app_scene_save_type.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp b/applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp index b017e7b057..760fda1620 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp @@ -4,11 +4,17 @@ void LfRfidAppSceneSaveType::on_enter(LfRfidApp* app, bool need_restore) { auto submenu = app->view_controller.get(); for(uint8_t i = 0; i < keys_count; i++) { - string_init_printf( - submenu_name[i], - "%s %s", - protocol_dict_get_manufacturer(app->dict, i), - protocol_dict_get_name(app->dict, i)); + if(strcmp( + protocol_dict_get_manufacturer(app->dict, i), + protocol_dict_get_name(app->dict, i))) { + string_init_printf( + submenu_name[i], + "%s %s", + protocol_dict_get_manufacturer(app->dict, i), + protocol_dict_get_name(app->dict, i)); + } else { + string_init_printf(submenu_name[i], "%s", protocol_dict_get_name(app->dict, i)); + } submenu->add_item(string_get_cstr(submenu_name[i]), i, submenu_callback, app); } From 4d388f4bdef88f70187561fddfa814c0435ac0f4 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 30 Aug 2022 21:55:25 +0300 Subject: [PATCH 75/78] SubGhz: add protocol Intertechno_V3 - OFW PR 1622 by Skorpionm --- applications/unit_tests/subghz/subghz_test.c | 20 +- assets/unit_tests/subghz/intertechno_v3.sub | 7 + .../unit_tests/subghz/intertechno_v3_raw.sub | 13 + lib/subghz/protocols/intertechno_v3.c | 472 ++++++++++++++++++ lib/subghz/protocols/intertechno_v3.h | 111 ++++ lib/subghz/protocols/magellen.c | 9 +- lib/subghz/protocols/registry.c | 2 +- lib/subghz/protocols/registry.h | 1 + 8 files changed, 628 insertions(+), 7 deletions(-) create mode 100644 assets/unit_tests/subghz/intertechno_v3.sub create mode 100644 assets/unit_tests/subghz/intertechno_v3_raw.sub create mode 100644 lib/subghz/protocols/intertechno_v3.c create mode 100644 lib/subghz/protocols/intertechno_v3.h diff --git a/applications/unit_tests/subghz/subghz_test.c b/applications/unit_tests/subghz/subghz_test.c index 04f442f6c4..6345b758fd 100644 --- a/applications/unit_tests/subghz/subghz_test.c +++ b/applications/unit_tests/subghz/subghz_test.c @@ -13,7 +13,7 @@ #define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo") #define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s") #define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub") -#define TEST_RANDOM_COUNT_PARSE 196 +#define TEST_RANDOM_COUNT_PARSE 208 #define TEST_TIMEOUT 10000 static SubGhzEnvironment* environment_handler; @@ -127,7 +127,7 @@ static bool subghz_decode_random_test(const char* path) { } subghz_file_encoder_worker_free(file_worker_encoder_handler); } - FURI_LOG_T(TAG, "\r\n Decoder count parse \033[0;33m%d\033[0m ", subghz_test_decoder_count); + FURI_LOG_D(TAG, "\r\n Decoder count parse \033[0;33m%d\033[0m ", subghz_test_decoder_count); if(furi_get_tick() - test_start > TEST_TIMEOUT * 10) { printf("\033[0;31mRandom test ERROR TimeOut\033[0m\r\n"); return false; @@ -419,6 +419,14 @@ MU_TEST(subghz_decoder_magellen_test) { "Test decoder " SUBGHZ_PROTOCOL_MAGELLEN_NAME " error\r\n"); } +MU_TEST(subghz_decoder_intertechno_v3_test) { + mu_assert( + subghz_decoder_test( + EXT_PATH("unit_tests/subghz/intertechno_v3_raw.sub"), + SUBGHZ_PROTOCOL_INTERTECHNO_V3_NAME), + "Test decoder " SUBGHZ_PROTOCOL_INTERTECHNO_V3_NAME " error\r\n"); +} + //test encoders MU_TEST(subghz_encoder_princeton_test) { mu_assert( @@ -528,6 +536,12 @@ MU_TEST(subghz_encoder_magellen_test) { "Test encoder " SUBGHZ_PROTOCOL_MAGELLEN_NAME " error\r\n"); } +MU_TEST(subghz_encoder_intertechno_v3_test) { + mu_assert( + subghz_encoder_test(EXT_PATH("unit_tests/subghz/intertechno_v3.sub")), + "Test encoder " SUBGHZ_PROTOCOL_INTERTECHNO_V3_NAME " error\r\n"); +} + MU_TEST(subghz_random_test) { mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n"); } @@ -566,6 +580,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_decoder_phoenix_v2_test); MU_RUN_TEST(subghz_decoder_honeywell_wdb_test); MU_RUN_TEST(subghz_decoder_magellen_test); + MU_RUN_TEST(subghz_decoder_intertechno_v3_test); MU_RUN_TEST(subghz_encoder_princeton_test); MU_RUN_TEST(subghz_encoder_came_test); @@ -585,6 +600,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_encoder_phoenix_v2_test); MU_RUN_TEST(subghz_encoder_honeywell_wdb_test); MU_RUN_TEST(subghz_encoder_magellen_test); + MU_RUN_TEST(subghz_encoder_intertechno_v3_test); MU_RUN_TEST(subghz_random_test); subghz_test_deinit(); diff --git a/assets/unit_tests/subghz/intertechno_v3.sub b/assets/unit_tests/subghz/intertechno_v3.sub new file mode 100644 index 0000000000..af68b74555 --- /dev/null +++ b/assets/unit_tests/subghz/intertechno_v3.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz Key File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: Intertechno_V3 +Bit: 32 +Key: 00 00 00 00 3F 86 C5 9F diff --git a/assets/unit_tests/subghz/intertechno_v3_raw.sub b/assets/unit_tests/subghz/intertechno_v3_raw.sub new file mode 100644 index 0000000000..2cfc79511c --- /dev/null +++ b/assets/unit_tests/subghz/intertechno_v3_raw.sub @@ -0,0 +1,13 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: RAW +RAW_Data: 15041 -66 15883 -66 12643 -66 12681 -66 3413 -68 2713 -68 33389 -66 1445 -66 1279 -68 1027 -66 6911 -98 25229 -66 3967 -100 3019 -100 6131 -66 955 -66 3605 -66 12411 -98 1419 -66 3593 -68 2753 -66 2457 -66 6007 -66 627 -100 1597 -66 3071 -98 22749 -66 333 -66 12829 -66 4313 -132 855 -66 44097 -64 20391 -98 29999 -66 3539 -98 557 -66 1489 -100 4081 -100 3857 -64 2895 -132 2261 -166 3089 -66 2429 -68 34467 -66 3585 -66 3087 -66 3329 -132 5287 -66 1063 -98 15259 -100 2535 -66 995 -66 13057 -100 24233 -68 531 -100 26415 -66 1761 -100 2717 -66 4071 -100 12191 -66 23367 -68 2323 -66 19809 -248 245 -1388 255 -242 275 -1358 273 -1370 277 -246 277 -1368 275 -246 275 -1362 275 -244 275 -1364 275 -244 275 -1362 275 -244 275 -1328 273 -278 273 -1358 275 -246 275 -238 263 -1384 275 -246 273 -1358 275 -244 273 -1358 275 -246 275 -1360 275 -1344 277 -246 275 -1358 275 -244 275 -234 263 -1382 277 -1344 277 -246 279 -1362 275 -246 271 -234 261 -1380 275 -246 273 -1360 275 -246 275 -1366 277 -1340 277 -248 279 -238 263 -1382 275 -1344 277 -246 279 -1364 277 -244 275 -234 263 -1382 277 -244 273 -1358 275 -1344 277 -248 279 -1368 275 -244 273 -1360 239 -280 271 -1358 275 -244 275 -1358 275 -174 269 -10298 289 -2660 267 -238 299 -1356 275 -244 275 -1356 275 -1344 277 -248 277 -1360 275 -246 275 -1328 309 -244 273 -1358 277 -244 275 -1356 275 -246 273 -1326 309 -244 275 -1356 275 -246 273 -234 263 -1380 277 -246 273 -1326 309 -244 273 -1356 277 -246 277 -1358 275 -1338 279 -248 279 -1364 275 -246 273 -234 261 -1380 277 -1344 279 -250 277 -1330 309 -244 273 -232 261 -1384 275 -246 273 -1356 275 -248 275 -1360 275 -1340 279 -248 277 -236 263 -1380 277 -1342 279 -248 279 -1366 275 -246 273 -234 263 -1380 275 -246 275 -1358 275 -1340 279 -248 281 -1336 309 -244 273 -1358 275 -246 273 -1360 275 -244 273 -1358 275 -176 267 -10306 257 -2646 299 -234 301 -1354 277 -246 275 -1356 277 -1340 279 -250 279 -1332 309 -244 275 -1358 275 -248 273 -1326 309 -246 273 -1326 309 -244 275 -1356 277 -248 275 -1328 309 -246 273 -234 261 -1382 277 -246 277 -1326 309 -244 275 -1358 277 -246 277 -1356 277 -1346 277 -250 277 -1358 277 -246 275 -234 263 -1382 279 -1346 279 -248 281 -1330 307 -246 273 -236 261 -1380 277 -246 277 -1360 277 -246 277 -1360 275 -1344 279 -248 279 -236 263 -1384 277 -1340 279 -250 281 -1338 307 -246 271 -234 261 -1384 277 -246 275 -1356 277 -1340 279 -250 283 -1336 309 -246 273 -1356 277 -246 273 -1360 277 -246 +RAW_Data: 275 -1328 309 -174 269 -10296 289 -2648 267 -238 299 -1356 277 -246 275 -1324 307 -1342 279 -250 277 -1330 309 -244 275 -1362 277 -244 275 -1356 275 -248 273 -1328 309 -244 273 -1328 309 -244 275 -1360 277 -246 275 -234 259 -1384 277 -246 275 -1360 275 -246 273 -1358 277 -248 277 -1362 275 -1344 277 -248 277 -1328 307 -246 273 -236 261 -1384 277 -1348 279 -248 279 -1360 277 -246 273 -234 263 -1388 275 -246 275 -1360 277 -248 279 -1368 277 -1344 279 -248 279 -240 265 -1386 275 -1342 279 -286 247 -1372 275 -248 275 -238 265 -1386 277 -248 275 -1360 275 -1344 277 -286 247 -1374 275 -246 275 -1362 277 -246 275 -1360 277 -248 275 -1326 307 -174 269 -10290 287 -2654 269 -236 301 -1352 275 -248 273 -1326 311 -1340 277 -248 277 -1328 309 -244 273 -1358 275 -244 275 -1326 309 -244 273 -1356 277 -244 273 -1356 275 -246 275 -1358 275 -244 275 -234 261 -1382 277 -246 273 -1358 275 -246 273 -1360 277 -246 273 -1324 309 -1340 277 -248 277 -1328 307 -246 271 -234 259 -1382 277 -1346 279 -248 277 -1330 309 -244 271 -232 259 -1382 277 -244 275 -1356 277 -248 273 -1354 277 -1342 277 -248 275 -236 261 -1380 277 -1344 277 -248 279 -1330 307 -246 273 -234 261 -1378 277 -246 273 -1356 277 -1342 277 -248 277 -1330 309 -244 273 -1322 307 -246 273 -1326 309 -244 273 -1322 309 -176 267 -10298 257 -2682 265 -236 299 -1324 309 -248 273 -1324 311 -1342 277 -246 279 -1360 277 -244 275 -1362 275 -244 275 -1358 275 -244 275 -1360 275 -246 273 -1360 275 -244 277 -1360 275 -246 273 -234 263 -1384 275 -246 273 -1358 275 -246 275 -1360 277 -246 277 -1356 277 -1342 279 -248 277 -1364 275 -244 275 -234 261 -1384 275 -1344 277 -250 279 -1366 275 -246 273 -236 263 -1384 277 -246 275 -1358 277 -246 277 -1362 277 -1342 279 -248 279 -236 265 -1382 277 -1346 277 -248 281 -1366 275 -246 275 -234 265 -1384 275 -246 273 -1358 277 -1344 279 -248 279 -1364 275 -244 275 -1324 309 -246 273 -1324 307 -246 273 -1326 309 -174 267 -118796 133 -100 131 -892 329 -166 199 -132 131 -166 99 -100 265 -264 4663 -134 4889 -100 365 -98 5921 -100 5903 -68 4877 -98 2953 -98 1645 -64 1687 -66 981 -98 10769 -66 18319 -66 4831 -66 13301 -66 893 -132 5967 -100 15949 -66 3749 -66 497 -100 625 -66 1147 -66 469 -66 1261 -66 3651 -100 265 -100 26741 -68 6873 -66 4485 -100 2667 -68 3159 -68 2857 -132 2655 -66 12903 -66 1277 -66 1711 -66 787 -100 1327 -198 727 -64 1677 -100 1187 -66 1019 -66 891 -66 4303 -100 11297 -66 3923 -254 253 -1380 247 -292 253 -1344 +RAW_Data: 277 -1346 277 -250 279 -1364 275 -244 275 -1362 275 -244 275 -1356 275 -246 273 -1358 241 -278 273 -1356 275 -246 273 -1360 275 -246 273 -234 263 -1382 275 -244 273 -1358 275 -246 273 -1360 275 -246 273 -1358 275 -1340 277 -248 277 -1362 275 -246 273 -234 261 -1380 277 -1344 277 -248 279 -1362 275 -244 273 -236 261 -1380 275 -244 275 -1360 275 -246 275 -1358 275 -1346 277 -246 275 -236 263 -1384 275 -1342 277 -248 277 -1364 277 -244 273 -234 261 -1378 277 -246 273 -1356 277 -1340 277 -248 281 -1334 307 -246 271 -1356 275 -246 273 -1358 275 -244 273 -1326 309 -174 267 -10296 257 -2650 297 -232 263 -1384 277 -244 273 -1358 275 -1340 279 -248 279 -1328 309 -244 275 -1328 307 -244 273 -1356 275 -244 275 -1358 275 -246 273 -1324 309 -244 275 -1328 307 -244 273 -234 261 -1382 275 -246 273 -1326 309 -244 273 -1358 275 -246 273 -1358 275 -1338 279 -248 279 -1330 309 -244 273 -232 261 -1380 277 -1344 279 -248 279 -1330 309 -244 271 -234 261 -1382 275 -246 273 -1358 277 -244 275 -1330 309 -1338 277 -246 277 -236 263 -1380 277 -1342 277 -248 279 -1364 275 -246 273 -232 261 -1380 275 -248 275 -1328 307 -1338 277 -248 279 -1334 309 -244 271 -1358 275 -244 275 -1324 307 -246 271 -1328 309 -174 265 -10270 291 -2640 297 -232 297 -1350 277 -248 275 -1326 309 -1340 277 -248 277 -1328 309 -244 273 -1358 275 -246 273 -1326 309 -244 273 -1354 275 -246 273 -1330 307 -244 273 -1358 275 -246 273 -234 263 -1380 275 -246 273 -1358 275 -246 273 -1360 275 -244 273 -1358 275 -1340 277 -248 279 -1364 275 -244 273 -232 261 -1380 277 -1342 279 -250 279 -1332 307 -244 271 -234 261 -1378 277 -246 273 -1358 275 -248 275 -1360 275 -1340 277 -248 275 -236 263 -1382 277 -1344 277 -246 277 -1364 275 -246 273 -234 259 -1380 275 -246 273 -1362 275 -1342 275 -248 277 -1334 309 -244 271 -1356 275 -244 275 -1326 307 -244 273 -1356 275 -176 267 -10290 289 -2644 267 -238 301 -1320 309 -246 273 -1324 309 -1340 277 -248 277 -1328 307 -246 273 -1326 307 -246 273 -1324 309 -246 273 -1322 309 -246 273 -1322 307 -246 275 -1326 309 -246 273 -234 259 -1382 275 -246 275 -1322 309 -246 273 -1326 309 -246 273 -1326 309 -1340 277 -248 275 -1326 309 -246 273 -232 261 -1380 279 -1346 277 -250 277 -1328 309 -244 271 -232 261 -1380 277 -246 273 -1358 275 -248 273 -1328 307 -1340 277 -248 277 -236 261 -1380 277 -1344 277 -248 279 -1328 309 -244 275 -232 261 -1378 277 -248 273 -1326 309 -1344 277 -248 277 -1358 277 -246 273 -1328 307 -244 271 -1324 309 -244 +RAW_Data: 273 -1324 309 -174 267 -10270 289 -2638 297 -234 297 -1352 275 -248 275 -1328 307 -1340 277 -248 275 -1330 309 -244 273 -1358 275 -244 275 -1326 309 -244 271 -1356 275 -244 275 -1326 307 -246 273 -1326 309 -244 273 -234 261 -1378 275 -248 275 -1326 309 -244 271 -1356 277 -248 273 -1328 309 -1338 277 -248 277 -1328 309 -244 271 -232 261 -1380 277 -1348 279 -248 277 -1328 307 -246 271 -234 259 -1384 275 -244 275 -1356 277 -246 275 -1326 309 -1344 275 -248 275 -236 261 -1378 277 -1342 277 -250 279 -1334 309 -244 271 -232 261 -1380 277 -246 273 -1326 307 -1344 277 -248 277 -1328 309 -246 273 -1326 309 -244 271 -1324 309 -244 273 -1324 307 -176 267 -10288 287 -2618 299 -236 299 -1354 277 -244 273 -1326 307 -1340 279 -248 275 -1328 309 -244 275 -1326 309 -246 273 -1324 307 -246 273 -1322 309 -244 273 -1322 309 -244 275 -1328 309 -246 273 -232 261 -1380 277 -246 275 -1324 309 -244 273 -1356 277 -246 275 -1324 309 -1340 279 -246 277 -1328 309 -244 273 -232 261 -1382 277 -1344 279 -250 277 -1324 309 -246 273 -234 261 -1380 277 -246 273 -1358 277 -246 273 -1328 309 -1340 277 -248 275 -236 261 -1380 275 -1344 279 -248 279 -1360 277 -244 273 -234 261 -1380 277 -246 275 -1354 277 -1344 277 -248 277 -1328 311 -246 273 -1324 307 -244 273 -1324 309 -244 273 -1320 309 -176 269 -118210 761 -168 267 -66 563 -132 99 -132 3543 -66 5345 -100 4355 -66 4617 -68 20503 -166 2379 -132 293 -98 4117 -66 1151 -98 3353 -66 3485 -66 2491 -66 6133 -66 233 -68 16307 -68 16959 -98 357 -66 5419 -134 799 -100 327 -100 791 -66 2481 -66 963 -100 3481 -98 1679 -134 2473 -100 227 -68 3087 -66 11527 -130 4305 -98 435 -66 563 -100 2887 -100 267 -66 1787 -66 9655 -66 4793 -100 2119 -66 359 -98 1313 -132 3393 -234 995 -66 2681 -98 99 -130 1379 -100 3757 -100 21695 -132 5135 -100 693 -98 4631 -100 2325 -68 4937 -66 10409 -98 897 -100 1287 -66 2565 -66 3753 -66 4055 -66 2023 -68 1961 -68 629 -66 431 -66 5039 -66 2155 -100 2673 -66 1163 -98 6539 -100 825 -66 1197 -100 3053 -66 13973 -68 15515 -100 1861 -66 1027 -66 797 -98 959 -98 787 -132 787 -64 3811 -132 1747 -66 6683 -66 1033 -68 24927 -66 1259 -100 1125 -68 663 -66 1687 -66 4357 -132 4567 -66 3969 -98 3317 -132 433 -134 6043 -66 3249 -100 431 -98 2367 -100 11265 -66 5085 -68 2355 -64 1815 -66 1395 -274 241 -1366 275 -244 275 -1362 275 -1338 277 -284 243 -1368 239 -278 275 -1362 275 -244 275 -1360 241 -278 273 -1356 275 -246 275 -1360 239 -280 275 -1360 +RAW_Data: 275 -244 275 -234 263 -1386 239 -280 273 -1356 275 -244 273 -1360 275 -244 277 -1364 275 -1336 277 -248 277 -1366 275 -244 273 -234 263 -1386 275 -1340 277 -248 279 -1364 275 -244 275 -234 263 -1384 273 -244 275 -1358 275 -244 275 -1364 275 -1342 275 -248 277 -236 265 -1384 275 -1340 277 -282 243 -1366 275 -246 273 -236 263 -1382 277 -244 275 -1358 275 -1342 277 -248 277 -1364 275 -246 275 -1360 239 -280 273 -1358 241 -278 275 -1356 275 -210 233 -10302 257 -2652 297 -232 297 -1354 277 -244 275 -1358 275 -1340 279 -248 279 -1360 275 -246 275 -1360 275 -246 273 -1360 275 -244 275 -1328 309 -242 273 -1324 309 -244 275 -1360 275 -246 273 -234 261 -1384 275 -246 273 -1358 275 -244 275 -1358 277 -248 273 -1358 275 -1340 279 -248 277 -1334 307 -242 273 -232 261 -1380 277 -1348 277 -250 277 -1364 275 -244 275 -234 261 -1380 277 -244 275 -1358 277 -246 277 -1360 277 -1342 275 -248 275 -236 263 -1380 277 -1344 277 -248 279 -1368 275 -244 275 -232 261 -1382 277 -244 275 -1356 275 -1344 277 -248 279 -1362 275 -246 275 -1360 275 -246 273 -1356 275 -246 273 -1356 275 -176 267 -10302 257 -2648 299 -234 297 -1352 277 -246 275 -1326 309 -1340 279 -248 277 -1330 309 -244 275 -1328 309 -244 273 -1324 309 -244 275 -1324 309 -246 273 -1324 307 -246 275 -1328 309 -244 273 -234 261 -1378 277 -248 275 -1328 309 -244 273 -1356 277 -248 275 -1326 309 -1344 277 -248 275 -1326 309 -246 273 -234 259 -1380 277 -1348 281 -248 279 -1328 307 -246 273 -234 259 -1382 277 -246 275 -1360 275 -248 275 -1324 309 -1340 279 -248 277 -238 261 -1382 277 -1344 277 -248 279 -1330 311 -244 273 -234 259 -1378 277 -248 275 -1326 309 -1340 279 -248 279 -1336 307 -246 271 -1324 309 -244 275 -1324 307 -246 273 -1326 309 -174 269 -10296 257 -2648 299 -234 297 -1352 277 -248 273 -1326 309 -1342 277 -248 277 -1328 309 -246 275 -1328 309 -244 273 -1326 309 -244 273 -1322 309 -244 273 -1328 307 -244 275 -1328 309 -246 273 -234 261 -1382 277 -246 275 -1326 309 -244 273 -1352 277 -248 275 -1330 309 -1340 277 -248 277 -1328 309 -244 275 -232 261 -1384 277 -1342 279 -250 279 -1328 309 -244 273 -234 263 -1380 277 -246 273 -1360 277 -246 275 -1326 309 -1340 277 -250 277 -236 263 -1382 277 -1342 277 -248 279 -1362 277 -246 273 -234 263 -1382 277 -244 275 -1356 277 -1340 279 -248 279 -1362 275 -246 275 -1328 307 -246 273 -1356 275 -246 273 -1356 275 -174 269 -10292 287 -2650 269 -236 301 -1354 275 -248 273 -1358 275 -1340 279 -248 277 -1332 307 -246 275 -1328 +RAW_Data: 309 -244 273 -1324 309 -244 273 -1356 275 -246 273 -1358 275 -244 277 -1330 309 -244 273 -234 261 -1382 277 -244 275 -1358 275 -246 273 -1356 277 -248 275 -1360 275 -1340 277 -248 277 -1360 275 -246 273 -236 261 -1382 279 -1344 279 -248 279 -1360 277 -244 273 -234 261 -1380 277 -246 275 -1360 277 -246 273 -1360 275 -1342 279 -248 275 -236 263 -1382 275 -1344 279 -248 279 -1362 277 -246 273 -234 263 -1380 277 -246 275 -1356 275 -1342 277 -248 281 -1336 307 -246 271 -1354 277 -246 275 -1328 307 -244 273 -1352 277 -176 269 -10300 257 -2650 299 -232 297 -1354 277 -246 275 -1356 277 -1342 277 -248 279 -1328 309 -244 275 -1360 275 -246 273 -1328 307 -246 273 -1356 277 -246 277 -1326 309 -244 277 -1360 277 -246 273 -234 263 -1384 277 -246 275 -1324 309 -246 275 -1358 277 -246 277 -1360 277 -1344 277 -248 277 -1326 309 -246 273 -236 261 -1382 277 -1348 279 -250 281 -1330 307 -246 273 -234 263 -1386 277 -244 275 -1356 277 -248 277 -1362 277 -1342 277 -250 277 -238 263 -1384 277 -1342 277 -250 281 -1332 309 -246 273 -234 263 -1380 277 -246 275 -1360 277 -1342 279 -248 281 -1334 307 -246 273 -1356 275 -248 275 -1328 309 -244 275 -1324 309 -176 269 -115034 163 -362 67 -894 529 -166 14663 -98 4135 -66 3681 -100 299 -68 9829 -66 3517 -64 21569 -66 3251 -66 2209 -64 23701 -66 3359 -68 1057 -66 723 -66 299 -134 765 -66 589 -98 1687 -134 2153 -66 3081 -68 10447 -66 11643 -66 2451 -66 2277 -66 2897 -66 755 -100 5539 -64 5117 -132 4867 -134 3931 -64 625 -66 1317 -98 11597 -66 2255 -66 1165 -66 1123 -66 6371 -100 699 -68 1811 -66 621 -68 2191 -64 1291 -134 3003 -66 2423 -64 1463 -66 663 -100 1127 -100 6169 -100 489 -100 6087 -100 2027 -66 1195 -66 13195 -66 557 -66 40423 -98 1919 -100 1061 -132 201 -66 2553 -132 12549 -66 1789 -100 921 -134 1067 -66 729 -66 10029 -66 3909 -100 265 -100 16017 -134 21177 -68 2461 -66 2215 -68 1197 -66 5911 -66 2645 -66 3419 -132 16275 -64 5091 -68 2123 -66 2677 -64 10305 -66 12381 -100 427 -166 25331 -66 2457 -66 11859 -248 279 -1368 275 -246 275 -1360 275 -1340 277 -246 279 -1364 239 -278 275 -1358 275 -244 275 -1362 239 -278 273 -1358 239 -280 271 -1360 241 -278 273 -1360 275 -244 275 -234 261 -1384 239 -280 273 -1356 275 -244 273 -1360 275 -244 275 -1358 275 -1344 277 -248 275 -1358 275 -244 273 -236 261 -1384 275 -1342 279 -246 279 -1360 275 -244 275 -234 263 -1384 239 -278 273 -1358 275 -244 275 -1362 275 -1342 275 -248 275 -238 263 -1382 275 -1344 275 -248 +RAW_Data: 277 -1364 275 -244 273 -234 263 -1380 275 -246 273 -1358 275 -1342 277 -246 279 -1366 275 -244 273 -1362 239 -278 239 -1386 275 -246 273 -1360 241 -208 269 -10290 257 -2686 265 -232 265 -1384 275 -246 275 -1358 275 -1344 277 -248 275 -1358 275 -246 275 -1360 277 -244 273 -1326 309 -244 271 -1354 275 -244 275 -1358 275 -246 273 -1358 275 -246 273 -234 263 -1378 275 -246 275 -1360 275 -244 273 -1356 275 -246 275 -1360 275 -1342 277 -246 277 -1360 275 -246 273 -232 261 -1382 277 -1342 279 -248 279 -1360 275 -244 275 -232 261 -1380 277 -244 275 -1356 277 -246 277 -1360 275 -1342 277 -246 275 -236 263 -1384 275 -1342 277 -248 277 -1362 275 -246 273 -234 261 -1378 277 -246 275 -1328 307 -1340 277 -246 279 -1366 275 -244 273 -1326 307 -244 273 -1324 309 -244 273 -1356 275 -174 267 -10304 255 -2648 297 -230 263 -1382 277 -244 275 -1330 307 -1338 277 -248 277 -1330 309 -244 273 -1356 275 -246 273 -1362 275 -244 273 -1356 275 -244 273 -1326 307 -244 273 -1360 273 -246 273 -236 261 -1380 275 -244 275 -1328 307 -244 273 -1358 275 -244 275 -1360 275 -1342 277 -246 277 -1364 275 -244 271 -232 261 -1384 277 -1340 279 -248 279 -1360 275 -246 273 -234 261 -1380 275 -244 275 -1360 277 -244 275 -1356 275 -1342 279 -246 277 -236 263 -1382 275 -1340 277 -248 279 -1366 275 -246 271 -234 261 -1382 277 -244 275 -1354 275 -1342 277 -248 277 -1364 273 -246 273 -1362 275 -244 271 -1360 275 -244 273 -1358 275 -174 267 -10272 289 -2646 265 -262 261 -1382 277 -244 275 -1356 275 -1342 277 -248 277 -1364 275 -244 275 -1360 275 -244 273 -1358 275 -244 273 -1358 275 -244 273 -1326 307 -244 275 -1358 275 -246 273 -234 261 -1382 275 -246 273 -1358 275 -244 273 -1358 275 -246 275 -1360 275 -1338 277 -248 277 -1362 277 -244 271 -234 261 -1380 277 -1344 279 -248 277 -1332 273 -278 271 -234 261 -1382 275 -244 275 -1356 277 -246 275 -1360 277 -1340 277 -246 277 -234 263 -1384 275 -1342 277 -248 277 -1366 275 -244 273 -234 261 -1380 275 -246 273 -1360 275 -1340 277 -246 279 -1334 307 -244 273 -1356 275 -246 273 -1360 275 -244 271 -1354 277 -174 269 -10300 257 -2648 297 -230 263 -1384 277 -244 273 -1356 277 -1342 277 -248 277 -1362 275 -244 275 -1330 307 -244 273 -1324 309 -244 273 -1324 307 -246 273 -1326 307 -244 273 -1358 275 -246 273 -234 261 -1380 277 -246 273 -1358 275 -244 275 -1354 277 -248 275 -1360 275 -1338 279 -246 277 -1360 275 -244 273 -234 261 -1378 279 -1344 279 -248 279 -1330 309 -244 271 -232 261 -1380 277 -246 273 -1360 +RAW_Data: 277 -244 275 -1360 275 -1340 277 -246 277 -236 261 -1380 275 -1346 277 -248 277 -1362 275 -246 273 -234 263 -1380 275 -244 275 -1358 275 -1340 277 -248 279 -1334 309 -244 273 -1324 307 -246 273 -1356 275 -244 273 -1356 275 -174 269 -10302 257 -2644 297 -232 263 -1384 277 -246 275 -1354 275 -1344 277 -248 275 -1360 275 -246 275 -1358 275 -246 273 -1326 307 -246 273 -1324 307 -244 273 -1328 307 -244 273 -1358 275 -244 273 -236 261 -1380 275 -246 273 -1358 275 -244 273 -1358 275 -246 273 -1360 275 -1344 275 -248 275 -1360 275 -244 273 -234 261 -1378 277 -1344 279 -248 277 -1362 275 -246 273 -234 261 -1378 275 -244 275 -1360 275 -246 275 -1358 275 -1344 277 -246 277 -234 263 -1380 275 -1338 279 -246 281 -1368 275 -244 271 -234 261 -1386 275 -244 271 -1358 275 -1342 277 -246 279 -1362 275 -244 275 -1326 273 -278 273 -1358 239 -278 273 -1358 275 -174 267 -127478 195 -964 2317 -66 763 -98 1455 -100 16109 -66 5683 -98 11469 -66 34413 -66 5443 -66 11613 -66 2737 -66 12191 -66 2951 -68 1851 -68 1895 -68 2643 diff --git a/lib/subghz/protocols/intertechno_v3.c b/lib/subghz/protocols/intertechno_v3.c new file mode 100644 index 0000000000..e70bb8c8b7 --- /dev/null +++ b/lib/subghz/protocols/intertechno_v3.c @@ -0,0 +1,472 @@ +#include "intertechno_v3.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocolIntertechnoV3" + +#define CH_PATTERN "%c%c%c%c" +#define CNT_TO_CH(ch) \ + (ch & 0x8 ? '1' : '0'), (ch & 0x4 ? '1' : '0'), (ch & 0x2 ? '1' : '0'), (ch & 0x1 ? '1' : '0') + +#define INTERTECHNO_V3_DIMMING_COUNT_BIT 36 + +static const SubGhzBlockConst subghz_protocol_intertechno_v3_const = { + .te_short = 275, + .te_long = 1375, + .te_delta = 150, + .min_count_bit_for_found = 32, +}; + +struct SubGhzProtocolDecoderIntertechno_V3 { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; +}; + +struct SubGhzProtocolEncoderIntertechno_V3 { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + IntertechnoV3DecoderStepReset = 0, + IntertechnoV3DecoderStepStartSync, + IntertechnoV3DecoderStepFoundSync, + IntertechnoV3DecoderStepStartDuration, + IntertechnoV3DecoderStepSaveDuration, + IntertechnoV3DecoderStepCheckDuration, + IntertechnoV3DecoderStepEndDuration, +} IntertechnoV3DecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_intertechno_v3_decoder = { + .alloc = subghz_protocol_decoder_intertechno_v3_alloc, + .free = subghz_protocol_decoder_intertechno_v3_free, + + .feed = subghz_protocol_decoder_intertechno_v3_feed, + .reset = subghz_protocol_decoder_intertechno_v3_reset, + + .get_hash_data = subghz_protocol_decoder_intertechno_v3_get_hash_data, + .serialize = subghz_protocol_decoder_intertechno_v3_serialize, + .deserialize = subghz_protocol_decoder_intertechno_v3_deserialize, + .get_string = subghz_protocol_decoder_intertechno_v3_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_intertechno_v3_encoder = { + .alloc = subghz_protocol_encoder_intertechno_v3_alloc, + .free = subghz_protocol_encoder_intertechno_v3_free, + + .deserialize = subghz_protocol_encoder_intertechno_v3_deserialize, + .stop = subghz_protocol_encoder_intertechno_v3_stop, + .yield = subghz_protocol_encoder_intertechno_v3_yield, +}; + +const SubGhzProtocol subghz_protocol_intertechno_v3 = { + .name = SUBGHZ_PROTOCOL_INTERTECHNO_V3_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 | + SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | + SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_intertechno_v3_decoder, + .encoder = &subghz_protocol_intertechno_v3_encoder, +}; + +void* subghz_protocol_encoder_intertechno_v3_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderIntertechno_V3* instance = + malloc(sizeof(SubGhzProtocolEncoderIntertechno_V3)); + + instance->base.protocol = &subghz_protocol_intertechno_v3; + 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_intertechno_v3_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderIntertechno_V3* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderIntertechno_V3 instance + * @return true On success + */ +static bool subghz_protocol_encoder_intertechno_v3_get_upload( + SubGhzProtocolEncoderIntertechno_V3* instance) { + furi_assert(instance); + size_t index = 0; + + //Send header + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_intertechno_v3_const.te_short * 38); + //Send sync + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_intertechno_v3_const.te_short * 10); + //Send key data + for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { + if((instance->generic.data_count_bit == INTERTECHNO_V3_DIMMING_COUNT_BIT) && (i == 9)) { + //send bit dimm + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + } else if(bit_read(instance->generic.data, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_intertechno_v3_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_intertechno_v3_const.te_long); + } + } + instance->encoder.size_upload = index; + return true; +} + +bool subghz_protocol_encoder_intertechno_v3_deserialize( + void* context, + FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderIntertechno_V3* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + if((instance->generic.data_count_bit != + subghz_protocol_intertechno_v3_const.min_count_bit_for_found) && + (instance->generic.data_count_bit != INTERTECHNO_V3_DIMMING_COUNT_BIT)) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_encoder_intertechno_v3_get_upload(instance); + instance->encoder.is_running = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_intertechno_v3_stop(void* context) { + SubGhzProtocolEncoderIntertechno_V3* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_intertechno_v3_yield(void* context) { + SubGhzProtocolEncoderIntertechno_V3* 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_intertechno_v3_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderIntertechno_V3* instance = + malloc(sizeof(SubGhzProtocolDecoderIntertechno_V3)); + instance->base.protocol = &subghz_protocol_intertechno_v3; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_intertechno_v3_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderIntertechno_V3* instance = context; + free(instance); +} + +void subghz_protocol_decoder_intertechno_v3_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderIntertechno_V3* instance = context; + instance->decoder.parser_step = IntertechnoV3DecoderStepReset; +} + +void subghz_protocol_decoder_intertechno_v3_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderIntertechno_V3* instance = context; + switch(instance->decoder.parser_step) { + case IntertechnoV3DecoderStepReset: + if((!level) && + (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short * 37) < + subghz_protocol_intertechno_v3_const.te_delta * 15)) { + instance->decoder.parser_step = IntertechnoV3DecoderStepStartSync; + } + break; + case IntertechnoV3DecoderStepStartSync: + if(level && (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short) < + subghz_protocol_intertechno_v3_const.te_delta)) { + instance->decoder.parser_step = IntertechnoV3DecoderStepFoundSync; + } else { + instance->decoder.parser_step = IntertechnoV3DecoderStepReset; + } + break; + + case IntertechnoV3DecoderStepFoundSync: + if(!level && (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short * 10) < + subghz_protocol_intertechno_v3_const.te_delta * 3)) { + instance->decoder.parser_step = IntertechnoV3DecoderStepStartDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } else { + instance->decoder.parser_step = IntertechnoV3DecoderStepReset; + } + break; + + case IntertechnoV3DecoderStepStartDuration: + if(level && (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short) < + subghz_protocol_intertechno_v3_const.te_delta)) { + instance->decoder.parser_step = IntertechnoV3DecoderStepSaveDuration; + } else { + instance->decoder.parser_step = IntertechnoV3DecoderStepReset; + } + break; + + case IntertechnoV3DecoderStepSaveDuration: + if(!level) { //save interval + if(duration >= (subghz_protocol_intertechno_v3_const.te_short * 11)) { + instance->decoder.parser_step = IntertechnoV3DecoderStepStartSync; + if((instance->decoder.decode_count_bit == + subghz_protocol_intertechno_v3_const.min_count_bit_for_found) || + (instance->decoder.decode_count_bit == INTERTECHNO_V3_DIMMING_COUNT_BIT)) { + 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); + } + break; + } + instance->decoder.te_last = duration; + instance->decoder.parser_step = IntertechnoV3DecoderStepCheckDuration; + } else { + instance->decoder.parser_step = IntertechnoV3DecoderStepReset; + } + break; + case IntertechnoV3DecoderStepCheckDuration: + if(level) { + //Add 0 bit + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_intertechno_v3_const.te_short) < + subghz_protocol_intertechno_v3_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short) < + subghz_protocol_intertechno_v3_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = IntertechnoV3DecoderStepEndDuration; + } else if( + //Add 1 bit + (DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_intertechno_v3_const.te_long) < + subghz_protocol_intertechno_v3_const.te_delta * 2) && + (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short) < + subghz_protocol_intertechno_v3_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = IntertechnoV3DecoderStepEndDuration; + + } else if( + //Add dimm_state + (DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_intertechno_v3_const.te_short) < + subghz_protocol_intertechno_v3_const.te_delta * 2) && + (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short) < + subghz_protocol_intertechno_v3_const.te_delta) && + (instance->decoder.decode_count_bit == 27)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = IntertechnoV3DecoderStepEndDuration; + + } else + instance->decoder.parser_step = IntertechnoV3DecoderStepReset; + } else { + instance->decoder.parser_step = IntertechnoV3DecoderStepReset; + } + break; + + case IntertechnoV3DecoderStepEndDuration: + if(!level && ((DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short) < + subghz_protocol_intertechno_v3_const.te_delta) || + (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_long) < + subghz_protocol_intertechno_v3_const.te_delta * 2))) { + instance->decoder.parser_step = IntertechnoV3DecoderStepStartDuration; + } else { + instance->decoder.parser_step = IntertechnoV3DecoderStepReset; + } + break; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_intertechno_v3_check_remote_controller(SubGhzBlockGeneric* instance) { + /* + * A frame is either 32 or 36 bits: + * + * _ + * start bit: | |__________ (T,10T) + * _ _ + * '0': | |_| |_____ (T,T,T,5T) + * _ _ + * '1': | |_____| |_ (T,5T,T,T) + * _ _ + * dimm: | |_| |_ (T,T,T,T) + * + * _ + * stop bit: | |____...____ (T,38T) + * + * if frame 32 bits + * SSSSSSSSSSSSSSSSSSSSSSSSSS all_ch on/off ~ch + * Key:0x3F86C59F => 00111111100001101100010110 0 1 1111 + * + * if frame 36 bits + * SSSSSSSSSSSSSSSSSSSSSSSSSS all_ch dimm ~ch dimm_level + * Key:0x42D2E8856 => 01000010110100101110100010 0 X 0101 0110 + * + */ + + if(instance->data_count_bit == subghz_protocol_intertechno_v3_const.min_count_bit_for_found) { + instance->serial = (instance->data >> 6) & 0x3FFFFFF; + if((instance->data >> 5) & 0x1) { + instance->cnt = 1 << 5; + } else { + instance->cnt = (~instance->data & 0xF); + } + instance->btn = (instance->data >> 4) & 0x1; + } else if(instance->data_count_bit == INTERTECHNO_V3_DIMMING_COUNT_BIT) { + instance->serial = (instance->data >> 10) & 0x3FFFFFF; + if((instance->data >> 9) & 0x1) { + instance->cnt = 1 << 5; + } else { + instance->cnt = (~(instance->data >> 4) & 0xF); + } + instance->btn = (instance->data) & 0xF; + } else { + instance->serial = 0; + instance->cnt = 0; + instance->btn = 0; + } +} + +uint8_t subghz_protocol_decoder_intertechno_v3_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderIntertechno_V3* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_intertechno_v3_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset) { + furi_assert(context); + SubGhzProtocolDecoderIntertechno_V3* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_intertechno_v3_deserialize( + void* context, + FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderIntertechno_V3* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if((instance->generic.data_count_bit != + subghz_protocol_intertechno_v3_const.min_count_bit_for_found) && + (instance->generic.data_count_bit != INTERTECHNO_V3_DIMMING_COUNT_BIT)) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void subghz_protocol_decoder_intertechno_v3_get_string(void* context, string_t output) { + furi_assert(context); + SubGhzProtocolDecoderIntertechno_V3* instance = context; + + subghz_protocol_intertechno_v3_check_remote_controller(&instance->generic); + + string_cat_printf( + output, + "%.11s %db\r\n" + "Key:0x%08llX\r\n" + "Sn:%07lX\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + instance->generic.data, + instance->generic.serial); + + if(instance->generic.data_count_bit == + subghz_protocol_intertechno_v3_const.min_count_bit_for_found) { + if(instance->generic.cnt >> 5) { + string_cat_printf( + output, "Ch: All Btn:%s\r\n", (instance->generic.btn ? "On" : "Off")); + } else { + string_cat_printf( + output, + "Ch:" CH_PATTERN " Btn:%s\r\n", + CNT_TO_CH(instance->generic.cnt), + (instance->generic.btn ? "On" : "Off")); + } + } else if(instance->generic.data_count_bit == INTERTECHNO_V3_DIMMING_COUNT_BIT) { + string_cat_printf( + output, + "Ch:" CH_PATTERN " Dimm:%d%%\r\n", + CNT_TO_CH(instance->generic.cnt), + (int)(6.67 * (float)instance->generic.btn)); + } +} diff --git a/lib/subghz/protocols/intertechno_v3.h b/lib/subghz/protocols/intertechno_v3.h new file mode 100644 index 0000000000..65d6f61d10 --- /dev/null +++ b/lib/subghz/protocols/intertechno_v3.h @@ -0,0 +1,111 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_INTERTECHNO_V3_NAME "Intertechno_V3" + +typedef struct SubGhzProtocolDecoderIntertechno_V3 SubGhzProtocolDecoderIntertechno_V3; +typedef struct SubGhzProtocolEncoderIntertechno_V3 SubGhzProtocolEncoderIntertechno_V3; + +extern const SubGhzProtocolDecoder subghz_protocol_intertechno_v3_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_intertechno_v3_encoder; +extern const SubGhzProtocol subghz_protocol_intertechno_v3; + +/** + * Allocate SubGhzProtocolEncoderIntertechno_V3. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderIntertechno_V3* pointer to a SubGhzProtocolEncoderIntertechno_V3 instance + */ +void* subghz_protocol_encoder_intertechno_v3_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderIntertechno_V3. + * @param context Pointer to a SubGhzProtocolEncoderIntertechno_V3 instance + */ +void subghz_protocol_encoder_intertechno_v3_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderIntertechno_V3 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_intertechno_v3_deserialize( + void* context, + FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderIntertechno_V3 instance + */ +void subghz_protocol_encoder_intertechno_v3_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderIntertechno_V3 instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_intertechno_v3_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderIntertechno_V3. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderIntertechno_V3* pointer to a SubGhzProtocolDecoderIntertechno_V3 instance + */ +void* subghz_protocol_decoder_intertechno_v3_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderIntertechno_V3. + * @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance + */ +void subghz_protocol_decoder_intertechno_v3_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderIntertechno_V3. + * @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance + */ +void subghz_protocol_decoder_intertechno_v3_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_intertechno_v3_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_intertechno_v3_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderIntertechno_V3. + * @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzPresetDefinition + * @return true On success + */ +bool subghz_protocol_decoder_intertechno_v3_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset); + +/** + * Deserialize data SubGhzProtocolDecoderIntertechno_V3. + * @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_intertechno_v3_deserialize( + void* context, + FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance + * @param output Resulting text + */ +void subghz_protocol_decoder_intertechno_v3_get_string(void* context, string_t output); diff --git a/lib/subghz/protocols/magellen.c b/lib/subghz/protocols/magellen.c index 859f803519..bb0600a745 100644 --- a/lib/subghz/protocols/magellen.c +++ b/lib/subghz/protocols/magellen.c @@ -360,11 +360,11 @@ static void subghz_protocol_magellen_check_remote_controller(SubGhzBlockGeneric* * 0x1275EC => 0x12-event codes, 0x75EC-serial (dec 117236) * * event codes -* bit_0: 1-alarm, 0-close +* bit_0: 1-Open/Motion, 0-close/ok * bit_1: 1-Tamper On (alarm), 0-Tamper Off (ok) * bit_2: ? * bit_3: 1-power on -* bit_4: model type - door alarm +* bit_4: model type - wireless reed * bit_5: model type - motion sensor * bit_6: ? * bit_7: ? @@ -379,11 +379,12 @@ static void subghz_protocol_magellen_get_event_serialize(uint8_t event, string_t string_cat_printf( output, "%s%s%s%s%s%s%s%s", - (event & 0x1 ? " Alarm" : "Ok"), + ((event >> 4) & 0x1 ? (event & 0x1 ? " Open" : " Close") : + (event & 0x1 ? " Motion" : " Ok")), ((event >> 1) & 0x1 ? ", Tamper On (Alarm)" : ""), ((event >> 2) & 0x1 ? ", ?" : ""), ((event >> 3) & 0x1 ? ", Power On" : ""), - ((event >> 4) & 0x1 ? ", MT:Door_Alarm" : ""), + ((event >> 4) & 0x1 ? ", MT:Wireless_Reed" : ""), ((event >> 5) & 0x1 ? ", MT:Motion_Sensor" : ""), ((event >> 6) & 0x1 ? ", ?" : ""), ((event >> 7) & 0x1 ? ", ?" : "")); diff --git a/lib/subghz/protocols/registry.c b/lib/subghz/protocols/registry.c index b72278788c..6c113cbf86 100644 --- a/lib/subghz/protocols/registry.c +++ b/lib/subghz/protocols/registry.c @@ -11,7 +11,7 @@ const SubGhzProtocol* subghz_protocol_registry[] = { &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_magellen, + &subghz_protocol_honeywell_wdb, &subghz_protocol_magellen, &subghz_protocol_intertechno_v3, }; diff --git a/lib/subghz/protocols/registry.h b/lib/subghz/protocols/registry.h index 36a560765a..342bf6d2bb 100644 --- a/lib/subghz/protocols/registry.h +++ b/lib/subghz/protocols/registry.h @@ -34,6 +34,7 @@ #include "phoenix_v2.h" #include "honeywell_wdb.h" #include "magellen.h" +#include "intertechno_v3.h" /** * Registration by name SubGhzProtocol. From 6c7611c57eb12ca1ae8c2c53f20dd3ca1d7d5e10 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 30 Aug 2022 21:56:59 +0300 Subject: [PATCH 76/78] Fix (LF RFID -> Add manually) names again remove N/A for PAC (and future protocols with N/A manufacturer) --- applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp b/applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp index 760fda1620..8e7af48fb6 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp @@ -6,7 +6,8 @@ void LfRfidAppSceneSaveType::on_enter(LfRfidApp* app, bool need_restore) { for(uint8_t i = 0; i < keys_count; i++) { if(strcmp( protocol_dict_get_manufacturer(app->dict, i), - protocol_dict_get_name(app->dict, i))) { + protocol_dict_get_name(app->dict, i)) && + strcmp(protocol_dict_get_manufacturer(app->dict, i), "N/A")) { string_init_printf( submenu_name[i], "%s %s", From f14874b0e079c216f6b59c5708df7de1e76f8f23 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 30 Aug 2022 23:14:43 +0300 Subject: [PATCH 77/78] update docs and fix led in subghz decode scene --- CHANGELOG.md | 26 +++++++++++-------- ReadMe.md | 21 +++++++-------- .../subghz/scenes/subghz_scene_decode_raw.c | 1 + .../scenes/subghz_scene_receiver_info.c | 25 +++++++++++------- applications/subghz/subghz.c | 2 ++ applications/subghz/subghz_i.h | 2 ++ documentation/AppManifests.md | 16 +++++++++++- documentation/SubGHzRemotePlugin.md | 16 ++++-------- 8 files changed, 64 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 822e6466ef..f25923c152 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,21 @@ ### New changes -* UniRF (Sub-GHz Remote) - All protocols support, long button press support (by @darmiel & @xMasterX) (PR #47) -* Universal remote for Fans, new buttons for universal AC remote, icons by @Svaarich -* Bugfix for universal remotes (by @darmiel) (PR #50) -* Frequency Analyzer feedback modes (by @darmiel) (PR #49) -* RFID EM4100 Fuzzer plugin (by @Ganapati & some fixes by @xMasterX) (PR #48) +* NRF24 sniffer - tweak sniff parameters for more speed and reliability (by @mothball187) (PR #51) +* Fixed text in LF RFID -> Extra Actions * Updated universal remote assets (by @Amec0e) -* New UniRF Animated icon & New Spectrum Analyzer icon (by @Svaarich) -* Fixed Keeloq seed display -* OFW: nfc: Change furi_assert to furi_crash for default switch cases -* OFW: SubGhz: fix CAME, Chamberlain protocol -* OFW: LFRFID RC fixes +* OFW PR: SubGHz decode raw gui (by @qistoph) (PR 1667) / xMasterX: Replaced custom image with default one & Fixed Led don't stop blink after pressing Send from decoder scene +* WAV Player plugin excluded from releases to save space, you can enable it in `applications\meta` for your builds +* OFW PR: SubGhz: add protocol Intertechno_V3 - OFW PR 1622 +* OFW PR: SubGhz: add protocol Prastel - OFW PR 1674 +* OFW PR: Fix displaying LFRFID protocol names - OFW PR 1682 / xMasterX: Fixed display for N/A manufacturer +* OFW: LF RFID - PAC/Stanley, Paradox, Jablotron, Viking, Pyramid protocols support +* OFW: Picopass write (PR 1658) +* OFW: SubGhz: fix CLI "subghz tx" +* OFW: IR: Fix crash after cancelling Learn New Remote +* OFW: SubGhz: output debug data to external pin +* OFW: Speedup SD card & enlarge your RAM +* OFW: Other small changes -**Note: Prefer installing using web updater or by self update package, all needed assets will be installed** +**Note: To avoid issues prefer installing using web updater or by self update package, all needed assets will be installed** Self-update package (update from microSD) - `flipper-z-f7-update-(version).zip` or `.tgz` for iOS mobile app diff --git a/ReadMe.md b/ReadMe.md index b9cc9e257d..0575144a5d 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -4,10 +4,10 @@ -Welcome to Flipper Zero's Custom Firmware repo! +### Welcome to Flipper Zero Unleashed Firmware repo! Our goal is to make any features possible in this device without any limitations! -Please help us implement emulation for all subghz dynamic (rolling code) protocols and static code brute-force app! +Please help us implement emulation for all subghz dynamic (rolling code) protocols and static code brute-force plugin!
@@ -31,21 +31,20 @@ Our Discord Community: * Extra SubGHz frequencies + extra Mifare Classic keys * Picopass/iClass plugin included in releases * Recompiled IR TV Universal Remote for ALL buttons -* Universal A/C and Audio(soundbars, etc.) remote -* Universal remote for Projectors +* Universal remote for Projectors, Fans, A/Cs and Audio(soundbars, etc.) * BadUSB keyboard layouts * Customizable Flipper name * Other small fixes and changes throughout See changelog in releases for latest updates! -### Current modified and new SubGhz protocols list: +### Current modified and new SubGHz protocols list: - HCS101 - An-Motors - CAME Atomo -- FAAC SLH (Spa) [if cloning existing remote - external seed calculation required] -- BFT Mitto [if cloning existing remote - external seed calculation required] -- Keeloq (+ proper manufacturer codes selection) [Not ALL systems supported yet!] +- FAAC SLH (Spa) [External seed calculation required] +- BFT Mitto [External seed calculation required] +- Keeloq [Not ALL systems supported yet!] - Nice Flor S - Security+ v1 & v2 - Star Line @@ -56,20 +55,18 @@ See changelog in releases for latest updates! * DOGE: `D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv` * LTC: `ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9` -**Big thanks to all sponsors!** - ### Community apps included: - ESP8266 Deauther plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-Wifi-ESP8266-Deauther-Module) - WiFi Scanner plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module) - MultiConverter plugin [(by theisolinearchip)](https://github.com/theisolinearchip/flipperzero_stuff) -- WAV player plugin (fixed) [(OFW: DrZlo13)](https://github.com/flipperdevices/flipperzero-firmware/tree/zlo/wav-player) +- `Excluded from releases` - WAV player plugin (fixed) [(OFW: DrZlo13)](https://github.com/flipperdevices/flipperzero-firmware/tree/zlo/wav-player) - UPC-A Barcode generator plugin [(by McAzzaMan)](https://github.com/McAzzaMan/flipperzero-firmware/tree/UPC-A_Barcode_Generator/applications/barcode_generator) - GPIO: Sentry Safe plugin [(by H4ckd4ddy)](https://github.com/H4ckd4ddy/flipperzero-sentry-safe-plugin) - ESP32: WiFi Marauder companion plugin [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion) - NRF24: Sniffer & MouseJacker (with changes) [(by mothball187)](https://github.com/mothball187/flipperzero-nrf24/tree/main/mousejacker) - Simple Clock (fixed) !! New version WIP, wait for updates !! [(Original by CompaqDisc)](https://gist.github.com/CompaqDisc/4e329c501bd03c1e801849b81f48ea61) -- UniversalRF Remix (with changes)(only RAW subghz files) [(by ESurge)(Original UniversalRF by jimilinuxguy)](https://github.com/ESurge/flipperzero-firmware-unirfremix) +- UniversalRF Remix / Sub-GHz Remote [(by ESurge)](https://github.com/ESurge/flipperzero-firmware-unirfremix)[(updated and all protocol support added by darmiel & xMasterX)](https://github.com/darmiel/flipper-playlist/tree/feat/unirf-protocols) - Tetris (with fixes) [(by jeffplang)](https://github.com/jeffplang/flipperzero-firmware/tree/tetris_game/applications/tetris_game) - Spectrum Analyzer (with changes) [(by jolcese)](https://github.com/jolcese/flipperzero-firmware/tree/spectrum/applications/spectrum_analyzer) - [Ultra Narrow mode & scan channels non-consecutively](https://github.com/theY4Kman/flipperzero-firmware/commits?author=theY4Kman) - Arkanoid (with fixes) [(by gotnull)](https://github.com/gotnull/flipperzero-firmware-wPlugins) diff --git a/applications/subghz/scenes/subghz_scene_decode_raw.c b/applications/subghz/scenes/subghz_scene_decode_raw.c index ae77194372..4f532b0fd0 100644 --- a/applications/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/subghz/scenes/subghz_scene_decode_raw.c @@ -225,6 +225,7 @@ bool subghz_scene_decode_raw_on_event(void* context, SceneManagerEvent event) { subghz->txrx->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); subghz->state_notifications = SubGhzNotificationStateIDLE; + subghz->in_decoder_scene = true; scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); consumed = true; break; diff --git a/applications/subghz/scenes/subghz_scene_receiver_info.c b/applications/subghz/scenes/subghz_scene_receiver_info.c index c25d6ef8bf..47b4110e21 100644 --- a/applications/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/subghz/scenes/subghz_scene_receiver_info.c @@ -152,17 +152,19 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { subghz_tx_stop(subghz); } - if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } - if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { - subghz->txrx->hopper_state = SubGhzHopperStateRunnig; + if(!subghz->in_decoder_scene) { + if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { + subghz_begin( + subghz, + subghz_setting_get_preset_data_by_name( + subghz->setting, string_get_cstr(subghz->txrx->preset->name))); + subghz_rx(subghz, subghz->txrx->preset->frequency); + } + if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { + subghz->txrx->hopper_state = SubGhzHopperStateRunnig; + } + subghz->state_notifications = SubGhzNotificationStateRx; } - subghz->state_notifications = SubGhzNotificationStateRx; return true; } else if(event.event == SubGhzCustomEventSceneReceiverInfoSave) { //CC1101 Stop RX -> Save @@ -209,6 +211,9 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) void subghz_scene_receiver_info_on_exit(void* context) { SubGhz* subghz = context; + if(subghz->in_decoder_scene) { + subghz->in_decoder_scene = false; + } widget_reset(subghz->widget); keeloq_reset_mfname(); keeloq_reset_kl_type(); diff --git a/applications/subghz/subghz.c b/applications/subghz/subghz.c index fab68fb4d4..97c8232e67 100644 --- a/applications/subghz/subghz.c +++ b/applications/subghz/subghz.c @@ -68,6 +68,8 @@ SubGhz* subghz_alloc() { // GUI subghz->gui = furi_record_open(RECORD_GUI); + subghz->in_decoder_scene = false; + // View Dispatcher subghz->view_dispatcher = view_dispatcher_alloc(); view_dispatcher_enable_queue(subghz->view_dispatcher); diff --git a/applications/subghz/subghz_i.h b/applications/subghz/subghz_i.h index 894c7984b9..03e049900a 100644 --- a/applications/subghz/subghz_i.h +++ b/applications/subghz/subghz_i.h @@ -102,6 +102,8 @@ struct SubGhz { SubGhzSetting* setting; SubGhzLock lock; + bool in_decoder_scene; + void* rpc_ctx; }; diff --git a/documentation/AppManifests.md b/documentation/AppManifests.md index 7b11778900..d17c11c0e4 100644 --- a/documentation/AppManifests.md +++ b/documentation/AppManifests.md @@ -1,3 +1,17 @@ # Flipper Application Manifests (.fam) -TBD \ No newline at end of file +``` +App( + appid="example_app", => App id, used in fbt app lists only, like applications\meta + name="My Plugin", => App name in menu + apptype=FlipperAppType.PLUGIN, => App type APP / PLUGIN / GAME (or service) + entry_point="my_example_app", => App entry point / main function + cdefines=["APP_MYEXAMPLE"], => C style define that will be used in generated file + requires=[ + "gui", + "dialogs", + ], => Requirements (other app id's that required for this app) + stack_size=2 * 1024, => Memory stack size + order=60, => App order in menu +) +``` \ No newline at end of file diff --git a/documentation/SubGHzRemotePlugin.md b/documentation/SubGHzRemotePlugin.md index 82885be56d..615c8ba093 100644 --- a/documentation/SubGHzRemotePlugin.md +++ b/documentation/SubGHzRemotePlugin.md @@ -1,4 +1,4 @@ -# UniRF Remix +# UniRF Remix / Sub-GHz Remote ### The UniRF Tool *requires* the creation of custom user map with `.txt` extension in the `unirf` folder on the sdcard. @@ -6,19 +6,16 @@ ## You can add as many `.txt` map files as you want, file name doesn't matter! -### App currenty works only with RAW subghz files - ## Incorrect or unconfigured file error If the `.txt` file has not been properly configured, the following error will be thrown when trying to run the UniRF Remix app: ``` -Invalid map file! +Config is incorrect. -Please reconfigure -your map file. +Please configure map -Hold Back to Exit +Press Back to Exit ``` @@ -60,10 +57,7 @@ OKLABEL: Garage CLOSE ## Notes * ##### App Usage - Press a button to send the assigned capture file. - - Press Back button to set how many repeats the app should send. Capped at 5 repeats. - - Hold Back button to exit app. - - Only RAW SubGhz captures are supported currently. - - No skip function. + - Press Back button to exit app. * ##### Universal RF Map - File path should not have any spaces or special characters (- and _ excluded). From 9ff35c9fc32cade9e3e7bfcb37845690d1c12ffc Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 31 Aug 2022 01:37:01 +0300 Subject: [PATCH 78/78] update audio asset, fix some things audio asset by @Amec0e --- applications/nrfsniff/nrfsniff.c | 19 ++++++++------- .../spectrum_analyzer/spectrum_analyzer.c | 4 ++++ assets/resources/Manifest | 4 ++-- assets/resources/infrared/assets/audio.ir | 24 +++++++++++++++++++ 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/applications/nrfsniff/nrfsniff.c b/applications/nrfsniff/nrfsniff.c index a9be614a9b..c56ee9fde2 100644 --- a/applications/nrfsniff/nrfsniff.c +++ b/applications/nrfsniff/nrfsniff.c @@ -86,8 +86,7 @@ static int get_highest_idx() { // if array is full, start over from beginning static void insert_addr(uint8_t* addr, uint8_t addr_size) { - if(candidate_idx >= MAX_ADDRS) - candidate_idx = 0; + if(candidate_idx >= MAX_ADDRS) candidate_idx = 0; memcpy(candidates[candidate_idx], addr, addr_size); counts[candidate_idx] = 1; @@ -243,10 +242,10 @@ void alt_address(uint8_t* addr, uint8_t* altaddr) { for(int i = 0; i < 5; i++) altaddr[i] = tmpaddr[4 - i]; } -static bool previously_confirmed(uint8_t *addr){ +static bool previously_confirmed(uint8_t* addr) { bool found = false; - for(int i = 0; i < MAX_CONFIRMED; i++){ - if(!memcmp(confirmed[i], addr, 5)){ + for(int i = 0; i < MAX_CONFIRMED; i++) { + if(!memcmp(confirmed[i], addr, 5)) { found = true; break; } @@ -290,14 +289,13 @@ static void wrap_up(Storage* storage, NotificationApp* notification) { hexlify(addr, 5, top_address); save_addr_to_file(storage, addr, 5, notification); found_count++; - if(confirmed_idx < MAX_CONFIRMED) - memcpy(confirmed[confirmed_idx++], addr, 5); + if(confirmed_idx < MAX_CONFIRMED) memcpy(confirmed[confirmed_idx++], addr, 5); break; } } } -static void clear_cache(){ +static void clear_cache() { found_count = 0; confirmed_idx = 0; candidate_idx = 0; @@ -410,7 +408,7 @@ int32_t nrfsniff_app(void* p) { if(nrf24_sniff_address(nrf24_HANDLE, 5, address)) { int idx; uint8_t* top_addr; - if(!previously_confirmed(address)){ + if(!previously_confirmed(address)) { idx = get_addr_index(address, 5); if(idx == -1) insert_addr(address, 5); @@ -439,6 +437,9 @@ int32_t nrfsniff_app(void* p) { } clear_cache(); + sample_time = DEFAULT_SAMPLE_TIME; + target_rate = 8; // rate can be either 8 (2Mbps) or 0 (1Mbps) + sniffing_state = false; furi_hal_spi_release(nrf24_HANDLE); view_port_enabled_set(view_port, false); gui_remove_view_port(gui, view_port); diff --git a/applications/spectrum_analyzer/spectrum_analyzer.c b/applications/spectrum_analyzer/spectrum_analyzer.c index 503870ed83..5bc5634511 100644 --- a/applications/spectrum_analyzer/spectrum_analyzer.c +++ b/applications/spectrum_analyzer/spectrum_analyzer.c @@ -400,6 +400,8 @@ int32_t spectrum_analyzer_app(void* p) { SpectrumAnalyzer* spectrum_analyzer = spectrum_analyzer_alloc(); InputEvent input; + furi_hal_power_suppress_charge_enter(); + FURI_LOG_D("Spectrum", "Main Loop - Starting worker"); furi_delay_ms(50); @@ -503,6 +505,8 @@ int32_t spectrum_analyzer_app(void* p) { spectrum_analyzer_worker_stop(spectrum_analyzer->worker); + furi_hal_power_suppress_charge_exit(); + spectrum_analyzer_free(spectrum_analyzer); return 0; diff --git a/assets/resources/Manifest b/assets/resources/Manifest index 7cfdd27d56..4fbac9f549 100644 --- a/assets/resources/Manifest +++ b/assets/resources/Manifest @@ -1,5 +1,5 @@ V:0 -T:1661859394 +T:1661895856 D:badusb D:dolphin D:infrared @@ -242,7 +242,7 @@ F:f267f0654781049ca323b11bb4375519:581:dolphin/L3_Lab_research_128x54/frame_9.bm F:41106c0cbc5144f151b2b2d3daaa0527:727:dolphin/L3_Lab_research_128x54/meta.txt D:infrared/assets F:13fe3def425723bccd05fe09c745a335:122232:infrared/assets/ac.ir -F:bbf2da1adc15aca3a2bb7f8a8800b81a:47577:infrared/assets/audio.ir +F:a3dad0916846fef907c93a65dd8e331d:52540:infrared/assets/audio.ir F:1703fea41cb6ef71553b91a1004dc936:82397:infrared/assets/fans.ir F:08d864cf44e2557fb25aec8837740de5:6567:infrared/assets/projectors.ir F:77bc8314d113b8618942589f21a491fc:127350:infrared/assets/tv.ir diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index db4f8ef1db..0fe001247a 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1232,3 +1232,27 @@ protocol: NEC address: 00 00 00 00 command: 15 00 00 00 # +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8437 4188 538 1565 539 1565 539 513 544 508 538 513 544 1559 545 507 539 1564 540 1564 540 1563 541 1563 541 511 546 1557 547 505 542 511 546 505 542 20497 597 1507 545 1559 545 507 539 512 545 507 539 1564 540 512 545 1558 546 1558 546 1558 546 1557 547 505 542 1562 542 510 547 505 542 510 547 20492 540 1564 540 1564 540 512 545 506 540 511 546 1558 546 505 542 1562 542 1562 542 1562 542 1561 543 509 548 1555 538 514 543 509 537 514 543 20495 547 1558 546 1557 547 505 541 511 546 505 542 1562 542 510 547 1556 548 1556 548 1556 548 1556 537 514 543 1560 544 508 538 514 543 508 538 20501 541 1562 542 1562 542 510 547 505 541 510 547 1556 548 504 543 1561 543 1561 543 1560 544 1560 544 508 538 1565 539 513 544 507 539 513 544 20494 548 1556 548 1556 548 504 543 509 548 504 543 1560 544 508 539 1565 539 1565 539 1564 540 1564 540 512 545 1559 545 506 540 512 545 506 540 20499 543 1560 544 1560 544 508 539 513 544 508 538 1564 540 512 545 1559 545 1558 546 1558 546 1558 546 506 541 1563 541 510 547 505 542 510 547 +# +name: VOL+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8430 4194 542 1562 542 1562 542 510 547 505 541 510 547 1556 548 504 542 1561 543 509 548 1556 548 1556 548 1556 548 1556 548 504 542 509 537 514 543 20496 545 1559 545 1559 545 507 539 512 545 507 539 1564 540 512 545 1559 545 507 539 1564 540 1564 540 1563 541 1563 541 511 546 506 540 511 546 20494 546 1557 547 1557 547 505 541 510 547 505 541 1562 542 510 547 1556 548 505 541 1562 542 1562 542 1561 543 1561 543 509 548 504 542 509 537 20501 540 1565 539 1565 539 512 545 507 539 512 545 1559 545 507 539 1564 540 512 545 1559 545 1558 546 1558 546 1558 546 506 540 511 546 506 540 20498 543 1562 542 1562 542 510 547 505 541 510 547 1557 547 505 541 1562 542 509 548 1556 548 1556 548 1556 548 1556 548 504 542 509 548 504 542 20497 543 1560 544 1560 544 508 538 513 544 508 538 1565 539 513 544 1560 544 508 538 1565 539 1565 539 1565 539 1564 540 513 544 507 539 512 545 20495 545 1558 546 1558 546 506 540 511 546 506 540 1563 541 511 546 1558 546 506 540 1563 541 1563 541 1563 541 1562 542 510 547 505 541 510 547 20493 548 1556 548 1556 548 504 542 509 548 504 542 1561 543 509 537 1566 538 514 543 1560 544 1560 544 1560 544 1560 544 508 538 513 544 508 538 20501 539 1564 540 1564 540 512 545 507 539 512 545 1559 545 507 539 1564 540 512 545 1559 545 1558 546 1558 546 1558 546 506 540 511 546 506 540 +# +name: VOL- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8434 4191 545 1559 545 1559 545 534 512 513 544 507 539 1564 540 538 519 1559 545 1558 546 1558 546 1558 546 1558 546 1558 546 533 513 511 546 506 540 19446 547 1557 547 1557 547 532 514 511 546 532 514 1562 593 459 546 1557 547 1557 547 1557 547 1557 547 1557 547 1557 547 531 515 510 547 505 541 19446 548 1556 548 1556 548 530 516 509 548 504 543 1561 543 535 512 1566 538 1565 539 1565 539 1565 539 1565 539 1565 539 540 517 509 537 514 543 19444 539 1565 539 1565 539 513 544 508 538 513 544 1559 545 534 512 1564 540 1564 540 1564 540 1564 540 1564 540 1564 540 539 518 507 539 513 544 19442 541 1563 541 1563 541 538 519 507 539 512 545 1558 546 506 540 1563 541 1563 541 1563 541 1563 541 1563 541 1562 542 537 520 505 541 511 546 19440 595 1509 543 1561 543 536 521 504 542 509 548 1555 538 540 517 1560 544 1560 544 1560 544 1560 544 1560 544 1560 544 534 512 513 544 508 538 19448 546 1559 545 1559 545 533 513 512 545 507 539 1563 541 538 519 1558 546 1558 546 1558 546 1557 547 1558 546 1558 546 533 513 512 545 506 540 19447 546 1557 547 1557 547 532 514 511 546 506 540 1562 542 537 520 1557 547 1557 547 1557 547 1557 547 1557 547 1557 547 505 542 510 547 505 541 19445 548 1556 548 1556 548 531 515 510 547 504 542 1561 543 536 521 1555 538 1566 538 1566 538 1566 538 1566 538 1565 539 514 543 509 537 514 543 +# +name: MUTE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8435 4189 547 1557 547 1557 547 505 541 510 547 505 541 1562 542 510 547 1557 547 505 541 510 547 1557 546 1557 547 1557 547 505 541 510 547 505 541 21550 547 1558 545 1558 546 506 540 511 546 506 540 1563 541 511 546 1558 545 506 540 511 546 1558 546 1558 546 1558 546 506 540 511 546 506 540 21551 546 1558 546 1558 546 506 540 512 545 506 540 1563 540 512 545 1558 546 506 540 512 545 1558 546 1558 546 1558 546 506 540 512 545 506 540 21551 546 1559 545 1559 545 507 539 512 545 507 539 1564 539 512 545 1559 545 507 539 512 545 1559 545 1559 545 1559 545 507 539 512 545 507 539 21552 545 1559 545 1559 545 507 539 513 544 507 539 1564 540 512 545 1559 545 507 539 512 545 1559 545 1559 545 1559 545 507 539 512 545 507 539 21552 545 1559 545 1559 545 507 539 513 544 507 539 1565 538 513 544 1559 545 507 539 513 544 1559 545 1559 544 1559 545 534 512 513 544 507 539 21553 544 1560 544 1560 544 534 512 513 544 508 538 1565 539 539 518 1560 544 534 512 513 544 1560 544 1560 544 1560 544 534 512 513 544 508 538 +#