diff --git a/.drone.yml b/.drone.yml index 15c5dfce1..9bcb35546 100644 --- a/.drone.yml +++ b/.drone.yml @@ -36,6 +36,7 @@ steps: - mkdir -p sd-card/nfc/assets - mkdir -p sd-card/infrared/assets - mkdir -p sd-card/unirf + - mkdir -p sd-card/rfidfuzzer - mkdir -p sd-card/badusb/layouts - cp assets/resources/badusb/layouts/* sd-card/badusb/layouts/ - cp assets/resources/subghz/assets/dangerous_settings sd-card/subghz/assets/dangerous_settings @@ -44,9 +45,11 @@ 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 + - cp assets/resources/rfidfuzzer/example_uids.txt sd-card/rfidfuzzer/example_uids.txt - cp assets/resources/Manifest sd-card/Manifest - zip -r artifacts-default/sd-card-${DRONE_TAG}.zip sd-card - rm -rf sd-card @@ -115,9 +118,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/CHANGELOG.md b/CHANGELOG.md index 64ed851a2..6c404d929 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,24 +1,10 @@ ### New changes -* 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 +* Actually fix universal tv remote +* bt and lfrfid tune debug apps excluded from releases -**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** -**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/ReadMe.md b/ReadMe.md index b9cc9e257..c555e734c 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!
@@ -27,25 +27,26 @@ Our Discord Community: * SubGHz frequecy range can be extended in settings file (Warning: It can damage flipper's hardware) * Many rolling code protocols now have the ability to save & send captured signals * FAAC SLH (Spa) & BFT Mitto (secure with seed) manual creation +* Sub-GHz static code brute-force plugin +* LFRFID Fuzzer plugin * Custom community plugins and games added * 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,10 +57,10 @@ See changelog in releases for latest updates! * DOGE: `D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv` * LTC: `ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9` -**Big thanks to all sponsors!** - ### Community apps included: +- RFID Fuzzer plugin [(by Ganapati)](https://github.com/Eng1n33r/flipperzero-firmware/pull/54) with some changes by xMasterX +- Sub-GHz bruteforce plugin [(by Ganapati & xMasterX)](https://github.com/Eng1n33r/flipperzero-firmware/pull/57) - 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) @@ -68,8 +69,8 @@ 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) -- 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) +- Simple Clock (fixed) [(Original by CompaqDisc)](https://gist.github.com/CompaqDisc/4e329c501bd03c1e801849b81f48ea61) +- 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/SConstruct b/SConstruct index 52fe75a6a..4462f2f30 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)) 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/application.fam b/applications/bt/application.fam index 248386ff3..1d276d019 100644 --- a/applications/bt/application.fam +++ b/applications/bt/application.fam @@ -11,7 +11,7 @@ App( provides=[ "bt_start", "bt_settings", - "bt_debug", + #"bt_debug", ], stack_size=1 * 1024, order=20, 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_commands.c b/applications/cli/cli_commands.c index 177a274a1..a6dd672fc 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/cli/cli_i.h b/applications/cli/cli_i.h old mode 100755 new mode 100644 diff --git a/applications/debug_tools/application.fam b/applications/debug_tools/application.fam index 8cb495b0c..701115241 100644 --- a/applications/debug_tools/application.fam +++ b/applications/debug_tools/application.fam @@ -15,6 +15,16 @@ App( ], ) +App( + appid="debug_apps_lite", + name="Basic debug apps bundle", + apptype=FlipperAppType.METAPACKAGE, + provides=[ + "usb_mouse", + "uart_echo", + ], +) + App( appid="blink_test", name="Blink Test", diff --git a/applications/desktop/desktop_settings/desktop_settings.h b/applications/desktop/desktop_settings/desktop_settings.h index 800847d56..c33aadb76 100644 --- a/applications/desktop/desktop_settings/desktop_settings.h +++ b/applications/desktop/desktop_settings/desktop_settings.h @@ -46,4 +46,5 @@ typedef struct { PinCode pin_code; uint8_t is_locked; uint32_t auto_lock_delay_ms; + uint8_t displayBatteryPercentage; } DesktopSettings; diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c index aaaf2e779..d3c3aa072 100644 --- a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c @@ -8,6 +8,7 @@ #define SCENE_EVENT_SELECT_FAVORITE_SECONDARY 1 #define SCENE_EVENT_SELECT_PIN_SETUP 2 #define SCENE_EVENT_SELECT_AUTO_LOCK_DELAY 3 +#define SCENE_EVENT_SELECT_BATTERY_DISPLAY 4 #define AUTO_LOCK_DELAY_COUNT 9 const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = { @@ -25,11 +26,31 @@ const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = { const uint32_t auto_lock_delay_value[AUTO_LOCK_DELAY_COUNT] = {0, 10000, 15000, 30000, 60000, 90000, 120000, 300000, 600000}; +#define BATTERY_VIEW_COUNT 5 + +const char* const battery_view_count_text[BATTERY_VIEW_COUNT] = { + "Bar", + "%", + "Inv. %", + "Retro 3", + "Retro 5", +}; + +const uint32_t displayBatteryPercentage_value[BATTERY_VIEW_COUNT] = {0, 1, 2, 3, 4}; + static void desktop_settings_scene_start_var_list_enter_callback(void* context, uint32_t index) { DesktopSettingsApp* app = context; view_dispatcher_send_custom_event(app->view_dispatcher, index); } +static void desktop_settings_scene_start_battery_view_changed(VariableItem* item) { + DesktopSettingsApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, battery_view_count_text[index]); + app->settings.displayBatteryPercentage = index; +} + static void desktop_settings_scene_start_auto_lock_delay_changed(VariableItem* item) { DesktopSettingsApp* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -65,6 +86,20 @@ void desktop_settings_scene_start_on_enter(void* context) { variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, auto_lock_delay_text[value_index]); + item = variable_item_list_add( + variable_item_list, + "Battery View", + BATTERY_VIEW_COUNT, + desktop_settings_scene_start_battery_view_changed, + app); + + value_index = value_index_uint32( + app->settings.displayBatteryPercentage, + displayBatteryPercentage_value, + BATTERY_VIEW_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, battery_view_count_text[value_index]); + view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewVarItemList); } @@ -91,6 +126,9 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even case SCENE_EVENT_SELECT_AUTO_LOCK_DELAY: consumed = true; break; + case SCENE_EVENT_SELECT_BATTERY_DISPLAY: + consumed = true; + break; } } return consumed; diff --git a/applications/desktop/views/desktop_view_main.c b/applications/desktop/views/desktop_view_main.c index a3aa63707..397011a43 100644 --- a/applications/desktop/views/desktop_view_main.c +++ b/applications/desktop/views/desktop_view_main.c @@ -16,7 +16,7 @@ struct DesktopMainView { TimerHandle_t poweroff_timer; }; -#define DESKTOP_MAIN_VIEW_POWEROFF_TIMEOUT 3000 +#define DESKTOP_MAIN_VIEW_POWEROFF_TIMEOUT 2000 static void desktop_main_poweroff_timer_callback(TimerHandle_t timer) { DesktopMainView* main_view = pvTimerGetTimerID(timer); diff --git a/applications/flipfrid/LICENSE.md b/applications/flipfrid/LICENSE.md new file mode 100644 index 000000000..a856581c9 --- /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 000000000..51ed2fa67 --- /dev/null +++ b/applications/flipfrid/README.md @@ -0,0 +1,21 @@ +# Flipfrid + +Basic EM4100 Fuzzer + +## Why + +Flipfrid is a simple Rfid fuzzer using EM4100 protocol (125khz). +Objective is to provide a simple to use fuzzer to test readers by emulating various cards. + +EM4100 cards use a 1 byte customer id and 4 bytes card id. + +## How + +There is 4 modes : +- Default key loop over 16 factory/default keys and emulate each one after one ; +- BF customer id. just an iteration from 0X00 to 0XFF on the first byte ; +- Load Dump file : Load an existing EM4100 dump generated by Flipperzero, select an index and bruteforce from 0X00 to 0XFF; +- Uids list: loop over a text file (one uid per line) + +TODO : +- blank screen on back press diff --git a/applications/flipfrid/application.fam b/applications/flipfrid/application.fam new file mode 100644 index 000000000..4bcb38139 --- /dev/null +++ b/applications/flipfrid/application.fam @@ -0,0 +1,10 @@ +App( + appid="flipfrid", + name="RFID Fuzzer", + apptype=FlipperAppType.PLUGIN, + entry_point="flipfrid_start", + cdefines=["APP_FLIP_FRID"], + requires=["gui"], + stack_size=1 * 1024, + order=13, +) diff --git a/applications/flipfrid/flipfrid.c b/applications/flipfrid/flipfrid.c new file mode 100644 index 000000000..1dab3cae1 --- /dev/null +++ b/applications/flipfrid/flipfrid.c @@ -0,0 +1,258 @@ +#include "flipfrid.h" + +#include "scene/flipfrid_scene_entrypoint.h" +#include "scene/flipfrid_scene_load_file.h" +#include "scene/flipfrid_scene_select_field.h" +#include "scene/flipfrid_scene_run_attack.h" +#include "scene/flipfrid_scene_load_custom_uids.h" + +#define RFIDFUZZER_APP_FOLDER "/ext/rfidfuzzer" + +static void flipfrid_draw_callback(Canvas* const canvas, void* ctx) { + FlipFridState* flipfrid_state = (FlipFridState*)acquire_mutex((ValueMutex*)ctx, 100); + + if(flipfrid_state == NULL) { + return; + } + + // Draw correct Canvas + switch(flipfrid_state->current_scene) { + case NoneScene: + case SceneEntryPoint: + flipfrid_scene_entrypoint_on_draw(canvas, flipfrid_state); + break; + case SceneSelectFile: + flipfrid_scene_load_file_on_draw(canvas, flipfrid_state); + break; + case SceneSelectField: + flipfrid_scene_select_field_on_draw(canvas, flipfrid_state); + break; + case SceneAttack: + flipfrid_scene_run_attack_on_draw(canvas, flipfrid_state); + break; + case SceneLoadCustomUids: + flipfrid_scene_load_custom_uids_on_draw(canvas, flipfrid_state); + break; + } + + 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); +} + +FlipFridState* flipfrid_alloc() { + FlipFridState* flipfrid = malloc(sizeof(FlipFridState)); + string_init(flipfrid->notification_msg); + string_init(flipfrid->attack_name); + + flipfrid->previous_scene = NoneScene; + flipfrid->current_scene = SceneEntryPoint; + flipfrid->is_running = true; + flipfrid->is_attacking = false; + flipfrid->key_index = 0; + flipfrid->menu_index = 0; + + flipfrid->attack = FlipFridAttackDefaultValues; + flipfrid->notify = furi_record_open(RECORD_NOTIFICATION); + + flipfrid->data[0] = 0x00; + flipfrid->data[1] = 0x00; + flipfrid->data[2] = 0x00; + flipfrid->data[3] = 0x00; + flipfrid->data[4] = 0x00; + + flipfrid->payload[0] = 0x00; + flipfrid->payload[1] = 0x00; + flipfrid->payload[2] = 0x00; + flipfrid->payload[3] = 0x00; + flipfrid->payload[4] = 0x00; + + //Dialog + flipfrid->dialogs = furi_record_open(RECORD_DIALOGS); + + return flipfrid; +} + +void flipfrid_free(FlipFridState* flipfrid) { + //Dialog + furi_record_close(RECORD_DIALOGS); + notification_message(flipfrid->notify, &sequence_blink_stop); + + // Strings + string_clear(flipfrid->notification_msg); + string_clear(flipfrid->attack_name); + + free(flipfrid->data); + free(flipfrid->payload); + + // The rest + free(flipfrid); +} + +// ENTRYPOINT +int32_t flipfrid_start(void* p) { + UNUSED(p); + // Input + FURI_LOG_I(TAG, "Initializing input"); + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(FlipFridEvent)); + FlipFridState* flipfrid_state = flipfrid_alloc(); + ValueMutex flipfrid_state_mutex; + + // Mutex + FURI_LOG_I(TAG, "Initializing flipfrid mutex"); + if(!init_mutex(&flipfrid_state_mutex, flipfrid_state, sizeof(FlipFridState))) { + FURI_LOG_E(TAG, "cannot create mutex\r\n"); + furi_message_queue_free(event_queue); + furi_record_close(RECORD_NOTIFICATION); + furi_record_close(RECORD_DIALOGS); + free(flipfrid_state); + return 255; + } + + Storage* storage = furi_record_open(RECORD_STORAGE); + if(!storage_simply_mkdir(storage, RFIDFUZZER_APP_FOLDER)) { + FURI_LOG_E(TAG, "Could not create folder %s", RFIDFUZZER_APP_FOLDER); + } + furi_record_close(RECORD_STORAGE); + + // Configure view port + FURI_LOG_I(TAG, "Initializing viewport"); + 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 + FURI_LOG_I(TAG, "Initializing timer"); + FuriTimer* timer = + furi_timer_alloc(flipfrid_timer_callback, FuriTimerTypePeriodic, event_queue); + furi_timer_start(timer, furi_kernel_get_tick_frequency() / 10); // 10 times per second + + // Register view port in GUI + FURI_LOG_I(TAG, "Initializing gui"); + Gui* gui = (Gui*)furi_record_open(RECORD_GUI); + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + + // Init values + FlipFridEvent event; + while(flipfrid_state->is_running) { + // Get next event + FuriStatus event_status = furi_message_queue_get(event_queue, &event, 25); + if(event_status == FuriStatusOk) { + if(event.evt_type == EventTypeKey) { + //Handle event key + switch(flipfrid_state->current_scene) { + case NoneScene: + case SceneEntryPoint: + flipfrid_scene_entrypoint_on_event(event, flipfrid_state); + break; + case SceneSelectFile: + flipfrid_scene_load_file_on_event(event, flipfrid_state); + break; + case SceneSelectField: + flipfrid_scene_select_field_on_event(event, flipfrid_state); + break; + case SceneAttack: + flipfrid_scene_run_attack_on_event(event, flipfrid_state); + break; + case SceneLoadCustomUids: + flipfrid_scene_load_custom_uids_on_event(event, flipfrid_state); + break; + } + + } else if(event.evt_type == EventTypeTick) { + //Handle event tick + if(flipfrid_state->current_scene != flipfrid_state->previous_scene) { + // Trigger Exit Scene + switch(flipfrid_state->previous_scene) { + case SceneEntryPoint: + flipfrid_scene_entrypoint_on_exit(flipfrid_state); + break; + case SceneSelectFile: + flipfrid_scene_load_file_on_exit(flipfrid_state); + break; + case SceneSelectField: + flipfrid_scene_select_field_on_exit(flipfrid_state); + break; + case SceneAttack: + flipfrid_scene_run_attack_on_exit(flipfrid_state); + break; + case SceneLoadCustomUids: + flipfrid_scene_load_custom_uids_on_exit(flipfrid_state); + break; + case NoneScene: + break; + } + + // Trigger Entry Scene + switch(flipfrid_state->current_scene) { + case NoneScene: + case SceneEntryPoint: + flipfrid_scene_entrypoint_on_enter(flipfrid_state); + break; + case SceneSelectFile: + flipfrid_scene_load_file_on_enter(flipfrid_state); + break; + case SceneSelectField: + flipfrid_scene_select_field_on_enter(flipfrid_state); + break; + case SceneAttack: + flipfrid_scene_run_attack_on_enter(flipfrid_state); + break; + case SceneLoadCustomUids: + flipfrid_scene_load_custom_uids_on_enter(flipfrid_state); + break; + } + flipfrid_state->previous_scene = flipfrid_state->current_scene; + } + + // Trigger Tick Scene + switch(flipfrid_state->current_scene) { + case NoneScene: + case SceneEntryPoint: + flipfrid_scene_entrypoint_on_tick(flipfrid_state); + break; + case SceneSelectFile: + flipfrid_scene_load_file_on_tick(flipfrid_state); + break; + case SceneSelectField: + flipfrid_scene_select_field_on_tick(flipfrid_state); + break; + case SceneAttack: + flipfrid_scene_run_attack_on_tick(flipfrid_state); + break; + case SceneLoadCustomUids: + flipfrid_scene_load_custom_uids_on_tick(flipfrid_state); + break; + } + view_port_update(view_port); + } + } + } + + // Cleanup + furi_timer_stop(timer); + furi_timer_free(timer); + + FURI_LOG_I(TAG, "Cleaning up"); + gui_remove_view_port(gui, view_port); + view_port_free(view_port); + furi_message_queue_free(event_queue); + furi_record_close(RECORD_GUI); + furi_record_close(RECORD_NOTIFICATION); + flipfrid_free(flipfrid_state); + + 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 000000000..95bb2121d --- /dev/null +++ b/applications/flipfrid/flipfrid.h @@ -0,0 +1,76 @@ +#pragma once +#include +#include +#include +#include +#include +#include "m-string.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define TAG "FlipFrid" + +typedef enum { + FlipFridAttackDefaultValues, + FlipFridAttackBfCustomerId, + FlipFridAttackLoadFile, + FlipFridAttackLoadFileCustomUids, +} FlipFridAttacks; + +typedef enum { + NoneScene, + SceneEntryPoint, + SceneSelectFile, + SceneSelectField, + SceneAttack, + SceneLoadCustomUids, +} FlipFridScene; + +typedef enum { + EventTypeTick, + EventTypeKey, +} EventType; + +typedef struct { + EventType evt_type; + InputKey key; + InputType input_type; +} FlipFridEvent; + +// STRUCTS +typedef struct { + bool is_running; + bool is_attacking; + FlipFridScene current_scene; + FlipFridScene previous_scene; + NotificationApp* notify; + u_int8_t menu_index; + + string_t data_str; + uint8_t data[5]; + uint8_t payload[5]; + uint8_t attack_step; + FlipFridAttacks attack; + string_t attack_name; + + DialogsApp* dialogs; + string_t notification_msg; + uint8_t key_index; + LFRFIDWorker* worker; + ProtocolDict* dict; + ProtocolId protocol; + + // Used for custom dictionnary + Stream* uids_stream; +} FlipFridState; \ No newline at end of file diff --git a/applications/flipfrid/scene/flipfrid_scene_entrypoint.c b/applications/flipfrid/scene/flipfrid_scene_entrypoint.c new file mode 100644 index 000000000..f30bb8e1d --- /dev/null +++ b/applications/flipfrid/scene/flipfrid_scene_entrypoint.c @@ -0,0 +1,123 @@ +#include "flipfrid_scene_entrypoint.h" + +string_t menu_items[4]; + +void flipfrid_scene_entrypoint_menu_callback(FlipFridState* context, uint32_t index) { + switch(index) { + case FlipFridAttackDefaultValues: + context->attack = FlipFridAttackDefaultValues; + context->current_scene = SceneAttack; + string_set_str(context->attack_name, "Default Values"); + break; + case FlipFridAttackBfCustomerId: + context->attack = FlipFridAttackBfCustomerId; + context->current_scene = SceneAttack; + string_set_str(context->attack_name, "Bad Customer ID"); + break; + case FlipFridAttackLoadFile: + context->attack = FlipFridAttackLoadFile; + context->current_scene = SceneSelectFile; + string_set_str(context->attack_name, "Load File"); + break; + case FlipFridAttackLoadFileCustomUids: + context->attack = FlipFridAttackLoadFileCustomUids; + context->current_scene = SceneLoadCustomUids; + string_set_str(context->attack_name, "Load Custom UIDs"); + break; + default: + break; + } +} + +void flipfrid_scene_entrypoint_on_enter(FlipFridState* context) { + // Clear the previous payload + context->payload[0] = 0x00; + context->payload[1] = 0x00; + context->payload[2] = 0x00; + context->payload[3] = 0x00; + context->payload[4] = 0x00; + + context->menu_index = 0; + for(uint32_t i = 0; i < 4; i++) { + string_init(menu_items[i]); + } + + string_set(menu_items[0], "Default Values"); + string_set(menu_items[1], "BF Customer ID"); + string_set(menu_items[2], "Load File"); + string_set(menu_items[3], "Load uids from file"); +} + +void flipfrid_scene_entrypoint_on_exit(FlipFridState* context) { + UNUSED(context); + for(uint32_t i = 0; i < 4; i++) { + string_clear(menu_items[i]); + } +} + +void flipfrid_scene_entrypoint_on_tick(FlipFridState* context) { + UNUSED(context); +} + +void flipfrid_scene_entrypoint_on_event(FlipFridEvent event, FlipFridState* context) { + if(event.evt_type == EventTypeKey) { + if(event.input_type == InputTypeShort) { + switch(event.key) { + case InputKeyDown: + if(context->menu_index < FlipFridAttackLoadFileCustomUids) { + context->menu_index++; + } + break; + case InputKeyUp: + if(context->menu_index > FlipFridAttackDefaultValues) { + context->menu_index--; + } + break; + case InputKeyLeft: + case InputKeyRight: + break; + case InputKeyOk: + flipfrid_scene_entrypoint_menu_callback(context, context->menu_index); + break; + case InputKeyBack: + context->is_running = false; + break; + } + } + } +} + +void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context) { + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + + // Title + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 64, 6, AlignCenter, AlignTop, "RFID Fuzzer"); + + if(context->menu_index > FlipFridAttackDefaultValues) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, + 64, + 24, + AlignCenter, + AlignTop, + string_get_cstr(menu_items[context->menu_index - 1])); + } + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned( + canvas, 64, 36, AlignCenter, AlignTop, string_get_cstr(menu_items[context->menu_index])); + + if(context->menu_index < FlipFridAttackLoadFileCustomUids) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, + 64, + 48, + AlignCenter, + AlignTop, + string_get_cstr(menu_items[context->menu_index + 1])); + } +} \ No newline at end of file diff --git a/applications/flipfrid/scene/flipfrid_scene_entrypoint.h b/applications/flipfrid/scene/flipfrid_scene_entrypoint.h new file mode 100644 index 000000000..29ca5bdfa --- /dev/null +++ b/applications/flipfrid/scene/flipfrid_scene_entrypoint.h @@ -0,0 +1,8 @@ +#pragma once +#include "../flipfrid.h" + +void flipfrid_scene_entrypoint_on_enter(FlipFridState* context); +void flipfrid_scene_entrypoint_on_exit(FlipFridState* context); +void flipfrid_scene_entrypoint_on_tick(FlipFridState* context); +void flipfrid_scene_entrypoint_on_event(FlipFridEvent event, FlipFridState* context); +void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context); \ No newline at end of file diff --git a/applications/flipfrid/scene/flipfrid_scene_load_custom_uids.c b/applications/flipfrid/scene/flipfrid_scene_load_custom_uids.c new file mode 100644 index 000000000..bb3cf37d7 --- /dev/null +++ b/applications/flipfrid/scene/flipfrid_scene_load_custom_uids.c @@ -0,0 +1,79 @@ +#include "flipfrid_scene_load_custom_uids.h" +#include "flipfrid_scene_run_attack.h" +#include "flipfrid_scene_entrypoint.h" + +#define LFRFID_UIDS_EXTENSION ".txt" +#define RFIDFUZZER_APP_PATH_FOLDER "/ext/rfidfuzzer" + +bool flipfrid_load_uids(FlipFridState* context, const char* file_path) { + bool result = false; + Storage* storage = furi_record_open(RECORD_STORAGE); + context->uids_stream = buffered_file_stream_alloc(storage); + result = + buffered_file_stream_open(context->uids_stream, file_path, FSAM_READ, FSOM_OPEN_EXISTING); + // Close if loading fails + if(!result) { + buffered_file_stream_close(context->uids_stream); + return false; + } + return result; +} + +bool flipfrid_load_custom_uids_from_file(FlipFridState* context) { + // Input events and views are managed by file_select + string_t uid_path; + string_init(uid_path); + string_set_str(uid_path, RFIDFUZZER_APP_PATH_FOLDER); + + bool res = dialog_file_browser_show( + context->dialogs, uid_path, uid_path, LFRFID_UIDS_EXTENSION, true, &I_125_10px, false); + + if(res) { + res = flipfrid_load_uids(context, string_get_cstr(uid_path)); + } + + string_clear(uid_path); + + return res; +} + +void flipfrid_scene_load_custom_uids_on_enter(FlipFridState* context) { + if(flipfrid_load_custom_uids_from_file(context)) { + // Force context loading + flipfrid_scene_run_attack_on_enter(context); + context->current_scene = SceneAttack; + } else { + flipfrid_scene_entrypoint_on_enter(context); + context->current_scene = SceneEntryPoint; + } +} + +void flipfrid_scene_load_custom_uids_on_exit(FlipFridState* context) { + UNUSED(context); +} + +void flipfrid_scene_load_custom_uids_on_tick(FlipFridState* context) { + UNUSED(context); +} + +void flipfrid_scene_load_custom_uids_on_event(FlipFridEvent event, FlipFridState* context) { + if(event.evt_type == EventTypeKey) { + if(event.input_type == InputTypeShort) { + switch(event.key) { + case InputKeyDown: + case InputKeyUp: + case InputKeyLeft: + case InputKeyRight: + case InputKeyOk: + case InputKeyBack: + context->current_scene = SceneEntryPoint; + break; + } + } + } +} + +void flipfrid_scene_load_custom_uids_on_draw(Canvas* canvas, FlipFridState* context) { + UNUSED(context); + UNUSED(canvas); +} diff --git a/applications/flipfrid/scene/flipfrid_scene_load_custom_uids.h b/applications/flipfrid/scene/flipfrid_scene_load_custom_uids.h new file mode 100644 index 000000000..a8ed982b6 --- /dev/null +++ b/applications/flipfrid/scene/flipfrid_scene_load_custom_uids.h @@ -0,0 +1,9 @@ +#pragma once +#include "../flipfrid.h" + +void flipfrid_scene_load_custom_uids_on_enter(FlipFridState* context); +void flipfrid_scene_load_custom_uids_on_exit(FlipFridState* context); +void flipfrid_scene_load_custom_uids_on_tick(FlipFridState* context); +void flipfrid_scene_load_custom_uids_on_event(FlipFridEvent event, FlipFridState* context); +void flipfrid_scene_load_custom_uids_on_draw(Canvas* canvas, FlipFridState* context); +bool flipfrid_load_custom_uids_from_file(FlipFridState* context); \ No newline at end of file diff --git a/applications/flipfrid/scene/flipfrid_scene_load_file.c b/applications/flipfrid/scene/flipfrid_scene_load_file.c new file mode 100644 index 000000000..c4b1321d6 --- /dev/null +++ b/applications/flipfrid/scene/flipfrid_scene_load_file.c @@ -0,0 +1,146 @@ +#include "flipfrid_scene_load_file.h" +#include "flipfrid_scene_entrypoint.h" + +#define LFRFID_APP_EXTENSION ".rfid" +#define LFRFID_APP_PATH_FOLDER "/ext/lfrfid" + +bool flipfrid_load(FlipFridState* context, const char* file_path) { + bool result = false; + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); + string_t temp_str; + string_init(temp_str); + do { + if(!flipper_format_file_open_existing(fff_data_file, file_path)) { + FURI_LOG_E(TAG, "Error open file %s", file_path); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Error open file"); + break; + } + + // FileType + if(!flipper_format_read_string(fff_data_file, "Filetype", temp_str)) { + FURI_LOG_E(TAG, "Missing or incorrect Filetype"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Missing or incorrect Filetypes"); + break; + } else { + FURI_LOG_I(TAG, "Filetype: %s", string_get_cstr(temp_str)); + } + + // Key type + if(!flipper_format_read_string(fff_data_file, "Key type", temp_str)) { + FURI_LOG_E(TAG, "Missing or incorrect Key type"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Missing or incorrect Key type"); + break; + } else { + FURI_LOG_I(TAG, "Key type: %s", string_get_cstr(temp_str)); + if(strcmp(string_get_cstr(temp_str), "EM4100") != 0) { + FURI_LOG_E(TAG, "Unsupported Key type"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Unsupported Key type"); + break; + } + } + + // Data + if(!flipper_format_read_string(fff_data_file, "Data", context->data_str)) { + FURI_LOG_E(TAG, "Missing or incorrect Data"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Missing or incorrect Key"); + break; + } else { + FURI_LOG_I(TAG, "Key: %s", string_get_cstr(context->data_str)); + + // Check data size + if(string_size(context->data_str) != 14) { + FURI_LOG_E(TAG, "Incorrect Key length"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Incorrect Key length"); + break; + } + // String to uint8_t + for(uint8_t i = 0; i < 5; i++) { + char temp_str2[3]; + temp_str2[0] = string_get_cstr(context->data_str)[i * 3]; + temp_str2[1] = string_get_cstr(context->data_str)[i * 3 + 1]; + temp_str2[2] = '\0'; + context->data[i] = (uint8_t)strtol(temp_str2, NULL, 16); + } + } + + result = true; + } while(0); + string_clear(temp_str); + flipper_format_free(fff_data_file); + if(result) { + FURI_LOG_I(TAG, "Loaded successfully"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Source loaded."); + } + return result; +} + +void flipfrid_scene_load_file_on_enter(FlipFridState* context) { + if(flipfrid_load_protocol_from_file(context)) { + context->current_scene = SceneSelectField; + } else { + flipfrid_scene_entrypoint_on_enter(context); + context->current_scene = SceneEntryPoint; + } +} + +void flipfrid_scene_load_file_on_exit(FlipFridState* context) { + UNUSED(context); +} + +void flipfrid_scene_load_file_on_tick(FlipFridState* context) { + UNUSED(context); +} + +void flipfrid_scene_load_file_on_event(FlipFridEvent event, FlipFridState* context) { + if(event.evt_type == EventTypeKey) { + if(event.input_type == InputTypeShort) { + switch(event.key) { + case InputKeyDown: + case InputKeyUp: + case InputKeyLeft: + case InputKeyRight: + case InputKeyOk: + case InputKeyBack: + context->current_scene = SceneEntryPoint; + break; + } + } + } +} + +void flipfrid_scene_load_file_on_draw(Canvas* canvas, FlipFridState* context) { + UNUSED(context); + UNUSED(canvas); +} + +bool flipfrid_load_protocol_from_file(FlipFridState* context) { + string_t user_file_path; + string_init(user_file_path); + string_set_str(user_file_path, LFRFID_APP_PATH_FOLDER); + + // Input events and views are managed by file_select + bool res = dialog_file_browser_show( + context->dialogs, + user_file_path, + user_file_path, + LFRFID_APP_EXTENSION, + true, + &I_125_10px, + true); + + if(res) { + res = flipfrid_load(context, string_get_cstr(user_file_path)); + } + + string_clear(user_file_path); + + return res; +} \ No newline at end of file diff --git a/applications/flipfrid/scene/flipfrid_scene_load_file.h b/applications/flipfrid/scene/flipfrid_scene_load_file.h new file mode 100644 index 000000000..ca82daab4 --- /dev/null +++ b/applications/flipfrid/scene/flipfrid_scene_load_file.h @@ -0,0 +1,9 @@ +#pragma once +#include "../flipfrid.h" + +void flipfrid_scene_load_file_on_enter(FlipFridState* context); +void flipfrid_scene_load_file_on_exit(FlipFridState* context); +void flipfrid_scene_load_file_on_tick(FlipFridState* context); +void flipfrid_scene_load_file_on_event(FlipFridEvent event, FlipFridState* context); +void flipfrid_scene_load_file_on_draw(Canvas* canvas, FlipFridState* context); +bool flipfrid_load_protocol_from_file(FlipFridState* context); \ No newline at end of file diff --git a/applications/flipfrid/scene/flipfrid_scene_run_attack.c b/applications/flipfrid/scene/flipfrid_scene_run_attack.c new file mode 100644 index 000000000..e34cb8986 --- /dev/null +++ b/applications/flipfrid/scene/flipfrid_scene_run_attack.c @@ -0,0 +1,214 @@ +#include "flipfrid_scene_run_attack.h" +#include + +uint8_t counter = 0; +#define TIME_BETWEEN_CARDS 5 +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 +}; + +void flipfrid_scene_run_attack_on_enter(FlipFridState* context) { + context->attack_step = 0; + context->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); + context->worker = lfrfid_worker_alloc(context->dict); + context->protocol = protocol_dict_get_protocol_by_name(context->dict, "EM4100"); +} + +void flipfrid_scene_run_attack_on_exit(FlipFridState* context) { + lfrfid_worker_stop(context->worker); + lfrfid_worker_stop_thread(context->worker); + lfrfid_worker_free(context->worker); + protocol_dict_free(context->dict); + notification_message(context->notify, &sequence_blink_stop); +} + +void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { + if(context->is_attacking) { + if(1 == counter) { + protocol_dict_set_data(context->dict, context->protocol, context->payload, 5); + lfrfid_worker_free(context->worker); + context->worker = lfrfid_worker_alloc(context->dict); + lfrfid_worker_start_thread(context->worker); + lfrfid_worker_emulate_start(context->worker, context->protocol); + } else if(0 == counter) { + lfrfid_worker_stop(context->worker); + lfrfid_worker_stop_thread(context->worker); + switch(context->attack) { + case FlipFridAttackDefaultValues: + context->payload[0] = id_list[context->attack_step][0]; + context->payload[1] = id_list[context->attack_step][1]; + context->payload[2] = id_list[context->attack_step][2]; + context->payload[3] = id_list[context->attack_step][3]; + context->payload[4] = id_list[context->attack_step][4]; + + if(context->attack_step == 15) { + context->attack_step = 0; + counter = 0; + context->is_attacking = false; + notification_message(context->notify, &sequence_blink_stop); + notification_message(context->notify, &sequence_single_vibro); + + } else { + context->attack_step++; + } + break; + + case FlipFridAttackBfCustomerId: + context->payload[0] = context->attack_step; + context->payload[1] = 0x00; + context->payload[2] = 0x00; + context->payload[3] = 0x00; + context->payload[4] = 0x00; + + if(context->attack_step == 255) { + context->attack_step = 0; + counter = 0; + context->is_attacking = false; + notification_message(context->notify, &sequence_blink_stop); + notification_message(context->notify, &sequence_single_vibro); + } else { + context->attack_step++; + } + break; + case FlipFridAttackLoadFile: + context->payload[0] = context->data[0]; + context->payload[1] = context->data[1]; + context->payload[2] = context->data[2]; + context->payload[3] = context->data[3]; + context->payload[4] = context->data[4]; + + context->payload[context->key_index] = context->attack_step; + + if(context->attack_step == 255) { + context->attack_step = 0; + counter = 0; + context->is_attacking = false; + notification_message(context->notify, &sequence_blink_stop); + notification_message(context->notify, &sequence_single_vibro); + break; + } else { + context->attack_step++; + } + break; + case FlipFridAttackLoadFileCustomUids: + while(true) { + string_reset(context->data_str); + if(!stream_read_line(context->uids_stream, context->data_str)) { + context->attack_step = 0; + counter = 0; + context->is_attacking = false; + notification_message(context->notify, &sequence_blink_stop); + notification_message(context->notify, &sequence_single_vibro); + break; + }; + if(string_get_char(context->data_str, 0) == '#') continue; + if(string_size(context->data_str) != 11) continue; + break; + } + FURI_LOG_D(TAG, string_get_cstr(context->data_str)); + + // string is valid, parse it in context->payload + for(uint8_t i = 0; i < 5; i++) { + char temp_str[3]; + temp_str[0] = string_get_cstr(context->data_str)[i * 2]; + temp_str[1] = string_get_cstr(context->data_str)[i * 2 + 1]; + temp_str[2] = '\0'; + context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16); + } + break; + } + } + + if(counter > TIME_BETWEEN_CARDS) { + counter = 0; + } else { + counter++; + } + } +} + +void flipfrid_scene_run_attack_on_event(FlipFridEvent event, FlipFridState* context) { + if(event.evt_type == EventTypeKey) { + if(event.input_type == InputTypeShort) { + switch(event.key) { + case InputKeyDown: + case InputKeyUp: + case InputKeyLeft: + case InputKeyRight: + break; + case InputKeyOk: + counter = 0; + if(!context->is_attacking) { + notification_message(context->notify, &sequence_blink_start_blue); + context->is_attacking = true; + } else { + context->is_attacking = false; + notification_message(context->notify, &sequence_blink_stop); + notification_message(context->notify, &sequence_single_vibro); + } + break; + case InputKeyBack: + if(context->attack == FlipFridAttackLoadFileCustomUids) { + buffered_file_stream_close(context->uids_stream); + } + + context->attack_step = 0; + context->is_attacking = false; + string_reset(context->notification_msg); + context->current_scene = SceneEntryPoint; + notification_message(context->notify, &sequence_blink_stop); + break; + } + } + } +} + +void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context) { + 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, string_get_cstr(context->attack_name)); + + char uid[16]; + snprintf( + uid, + sizeof(uid), + "%02X:%02X:%02X:%02X:%02X", + context->payload[0], + context->payload[1], + context->payload[2], + context->payload[3], + context->payload[4]); + canvas_draw_str_aligned(canvas, 64, 24, AlignCenter, AlignTop, uid); + + canvas_set_font(canvas, FontSecondary); + //char start_stop_msg[20]; + if(context->is_attacking) { + elements_button_center(canvas, "Stop"); + //snprintf(start_stop_msg, sizeof(start_stop_msg), " Press OK to stop "); + } else { + elements_button_center(canvas, "Start"); + } + //canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignTop, start_stop_msg); +} diff --git a/applications/flipfrid/scene/flipfrid_scene_run_attack.h b/applications/flipfrid/scene/flipfrid_scene_run_attack.h new file mode 100644 index 000000000..ae56d35e7 --- /dev/null +++ b/applications/flipfrid/scene/flipfrid_scene_run_attack.h @@ -0,0 +1,8 @@ +#pragma once +#include "../flipfrid.h" + +void flipfrid_scene_run_attack_on_enter(FlipFridState* context); +void flipfrid_scene_run_attack_on_exit(FlipFridState* context); +void flipfrid_scene_run_attack_on_tick(FlipFridState* context); +void flipfrid_scene_run_attack_on_event(FlipFridEvent event, FlipFridState* context); +void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context); diff --git a/applications/flipfrid/scene/flipfrid_scene_select_field.c b/applications/flipfrid/scene/flipfrid_scene_select_field.c new file mode 100644 index 000000000..03411b2f4 --- /dev/null +++ b/applications/flipfrid/scene/flipfrid_scene_select_field.c @@ -0,0 +1,121 @@ +#include "flipfrid_scene_select_field.h" + +void flipfrid_center_displayed_key(FlipFridState* context, uint8_t index) { + const char* key_cstr = string_get_cstr(context->data_str); + uint8_t str_index = (index * 3); + + char display_menu[17] = { + 'X', 'X', ' ', 'X', 'X', ' ', '<', 'X', 'X', '>', ' ', 'X', 'X', ' ', 'X', 'X', '\0'}; + + if(index > 1) { + display_menu[0] = key_cstr[str_index - 6]; + display_menu[1] = key_cstr[str_index - 5]; + } else { + display_menu[0] = ' '; + display_menu[1] = ' '; + } + + if(index > 0) { + display_menu[3] = key_cstr[str_index - 3]; + display_menu[4] = key_cstr[str_index - 2]; + } else { + display_menu[3] = ' '; + display_menu[4] = ' '; + } + + display_menu[7] = key_cstr[str_index]; + display_menu[8] = key_cstr[str_index + 1]; + + if((str_index + 4) <= (uint8_t)strlen(key_cstr)) { + display_menu[11] = key_cstr[str_index + 3]; + display_menu[12] = key_cstr[str_index + 4]; + } else { + display_menu[11] = ' '; + display_menu[12] = ' '; + } + + if((str_index + 8) <= (uint8_t)strlen(key_cstr)) { + display_menu[14] = key_cstr[str_index + 6]; + display_menu[15] = key_cstr[str_index + 7]; + } else { + display_menu[14] = ' '; + display_menu[15] = ' '; + } + + string_reset(context->notification_msg); + string_set_str(context->notification_msg, display_menu); +} + +void flipfrid_scene_select_field_on_enter(FlipFridState* context) { + string_clear(context->notification_msg); +} + +void flipfrid_scene_select_field_on_exit(FlipFridState* context) { + UNUSED(context); +} + +void flipfrid_scene_select_field_on_tick(FlipFridState* context) { + UNUSED(context); +} + +void flipfrid_scene_select_field_on_event(FlipFridEvent event, FlipFridState* context) { + if(event.evt_type == EventTypeKey) { + if(event.input_type == InputTypeShort) { + const char* key_cstr = string_get_cstr(context->data_str); + + // don't look, it's ugly but I'm a python dev so... + uint8_t nb_bytes = 0; + for(uint8_t i = 0; i < strlen(key_cstr); i++) { + if(' ' == key_cstr[i]) { + nb_bytes++; + } + } + + switch(event.key) { + case InputKeyDown: + case InputKeyUp: + break; + case InputKeyLeft: + if(context->key_index > 0) { + context->key_index = context->key_index - 1; + } + break; + case InputKeyRight: + if(context->key_index < nb_bytes) { + context->key_index = context->key_index + 1; + } + break; + case InputKeyOk: + string_reset(context->notification_msg); + context->current_scene = SceneAttack; + break; + case InputKeyBack: + string_reset(context->notification_msg); + context->current_scene = SceneSelectFile; + break; + } + FURI_LOG_D(TAG, "Position: %d/%d", context->key_index, nb_bytes); + } + } +} + +void flipfrid_scene_select_field_on_draw(Canvas* canvas, FlipFridState* context) { + 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, 10, AlignCenter, AlignTop, "Use < > to select byte."); + + char msg_index[18]; + snprintf(msg_index, sizeof(msg_index), "Field index : %d", context->key_index); + canvas_draw_str_aligned(canvas, 64, 26, AlignCenter, AlignTop, msg_index); + + flipfrid_center_displayed_key(context, context->key_index); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, 64, 40, AlignCenter, AlignTop, string_get_cstr(context->notification_msg)); +} diff --git a/applications/flipfrid/scene/flipfrid_scene_select_field.h b/applications/flipfrid/scene/flipfrid_scene_select_field.h new file mode 100644 index 000000000..5533e321c --- /dev/null +++ b/applications/flipfrid/scene/flipfrid_scene_select_field.h @@ -0,0 +1,9 @@ +#pragma once +#include "../flipfrid.h" + +void flipfrid_scene_select_field_on_enter(FlipFridState* context); +void flipfrid_scene_select_field_on_exit(FlipFridState* context); +void flipfrid_scene_select_field_on_tick(FlipFridState* context); +void flipfrid_scene_select_field_on_event(FlipFridEvent event, FlipFridState* context); +void flipfrid_scene_select_field_on_draw(Canvas* canvas, FlipFridState* context); +void center_displayed_key(FlipFridState* context, uint8_t index); \ No newline at end of file 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.c b/applications/gui/canvas.c index 1e275aafb..562f2e183 100644 --- a/applications/gui/canvas.c +++ b/applications/gui/canvas.c @@ -12,6 +12,7 @@ const CanvasFontParameters canvas_font_params[FontTotalNumber] = { [FontSecondary] = {.leading_default = 11, .leading_min = 9, .height = 7, .descender = 2}, [FontKeyboard] = {.leading_default = 11, .leading_min = 9, .height = 7, .descender = 2}, [FontBigNumbers] = {.leading_default = 18, .leading_min = 16, .height = 15, .descender = 0}, + [FontBatteryPercent] = {.leading_default = 11, .leading_min = 9, .height = 6, .descender = 0}, }; Canvas* canvas_init() { @@ -132,6 +133,8 @@ void canvas_set_font(Canvas* canvas, Font font) { u8g2_SetFont(&canvas->fb, u8g2_font_profont11_mr); } else if(font == FontBigNumbers) { u8g2_SetFont(&canvas->fb, u8g2_font_profont22_tn); + } else if(font == FontBatteryPercent) { + u8g2_SetFont(&canvas->fb, u8g2_font_5x7_tf); //u8g2_font_micro_tr); } else { furi_crash(NULL); } diff --git a/applications/gui/canvas.h b/applications/gui/canvas.h old mode 100755 new mode 100644 index 4923e2e66..edde10a01 --- a/applications/gui/canvas.h +++ b/applications/gui/canvas.h @@ -25,6 +25,7 @@ typedef enum { FontSecondary, FontKeyboard, FontBigNumbers, + FontBatteryPercent, // Keep last for fonts number calculation FontTotalNumber, diff --git a/applications/gui/modules/button_panel.c b/applications/gui/modules/button_panel.c index e3ae59a36..ff52ebd8c 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 0c17e3a7c..9c944ca46 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/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/text_input.c b/applications/gui/modules/text_input.c index 26f74e7ac..b8098a3b9 100644 --- a/applications/gui/modules/text_input.c +++ b/applications/gui/modules/text_input.c @@ -463,8 +463,6 @@ void text_input_free(TextInput* text_input) { // Send stop command furi_timer_stop(text_input->timer); - // Wait till timer stop - while(furi_timer_is_running(text_input->timer)) furi_delay_tick(1); // Release allocated memory furi_timer_free(text_input->timer); diff --git a/applications/gui/modules/validators.c b/applications/gui/modules/validators.c index ac293f8cb..52f9946ca 100644 --- a/applications/gui/modules/validators.c +++ b/applications/gui/modules/validators.c @@ -42,7 +42,9 @@ ValidatorIsFile* validator_is_file_alloc_init( instance->app_path_folder = strdup(app_path_folder); instance->app_extension = app_extension; - instance->current_name = strdup(current_name); + if(current_name != NULL) { + instance->current_name = strdup(current_name); + } return instance; } 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/infrared/infrared_brute_force.c b/applications/infrared/infrared_brute_force.c index 8dbc23012..89272de7e 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 acf0d7b6e..fff472e79 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/infrared_cli.c b/applications/infrared/infrared_cli.c index aae02e8fd..693e191ee 100644 --- a/applications/infrared/infrared_cli.c +++ b/applications/infrared/infrared_cli.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include "infrared_signal.h" @@ -10,6 +12,7 @@ static void infrared_cli_start_ir_rx(Cli* cli, string_t args); static void infrared_cli_start_ir_tx(Cli* cli, string_t args); +static void infrared_cli_process_decode(Cli* cli, string_t args); static const struct { const char* cmd; @@ -17,6 +20,7 @@ static const struct { } infrared_cli_commands[] = { {.cmd = "rx", .process_function = infrared_cli_start_ir_rx}, {.cmd = "tx", .process_function = infrared_cli_start_ir_tx}, + {.cmd = "decode", .process_function = infrared_cli_process_decode}, }; static void signal_received_callback(void* context, InfraredWorkerSignal* received_signal) { @@ -86,6 +90,7 @@ static void infrared_cli_print_usage(void) { "\tFrequency (%d - %d), Duty cycle (0 - 100), max 512 samples\r\n", INFRARED_MIN_FREQUENCY, INFRARED_MAX_FREQUENCY); + printf("\tir decode []\r\n"); } static bool infrared_cli_parse_message(const char* str, InfraredSignal* signal) { @@ -162,6 +167,160 @@ static void infrared_cli_start_ir_tx(Cli* cli, string_t args) { infrared_signal_free(signal); } +static bool + infrared_cli_save_signal(InfraredSignal* signal, FlipperFormat* file, const char* name) { + bool ret = infrared_signal_save(signal, file, name); + if(!ret) { + printf("Failed to save signal: \"%s\"\r\n", name); + } + return ret; +} + +static bool infrared_cli_decode_raw_signal( + InfraredRawSignal* raw_signal, + InfraredDecoderHandler* decoder, + FlipperFormat* output_file, + const char* signal_name) { + InfraredSignal* signal = infrared_signal_alloc(); + bool ret = false, level = true, is_decoded = false; + + size_t i; + for(i = 0; i < raw_signal->timings_size; ++i) { + // TODO: Any infrared_check_decoder_ready() magic? + const InfraredMessage* message = infrared_decode(decoder, level, raw_signal->timings[i]); + + if(message) { + is_decoded = true; + printf( + "Protocol: %s address: 0x%lX command: 0x%lX %s\r\n", + infrared_get_protocol_name(message->protocol), + message->address, + message->command, + (message->repeat ? "R" : "")); + if(output_file && !message->repeat) { + infrared_signal_set_message(signal, message); + if(!infrared_cli_save_signal(signal, output_file, signal_name)) break; + } + } + + level = !level; + } + + if(i == raw_signal->timings_size) { + if(!is_decoded && output_file) { + infrared_signal_set_raw_signal( + signal, + raw_signal->timings, + raw_signal->timings_size, + raw_signal->frequency, + raw_signal->duty_cycle); + ret = infrared_cli_save_signal(signal, output_file, signal_name); + } else { + ret = true; + } + } + + infrared_reset_decoder(decoder); + infrared_signal_free(signal); + return ret; +} + +static bool infrared_cli_decode_file(FlipperFormat* input_file, FlipperFormat* output_file) { + bool ret = false; + + InfraredSignal* signal = infrared_signal_alloc(); + InfraredDecoderHandler* decoder = infrared_alloc_decoder(); + + string_t tmp; + string_init(tmp); + + while(infrared_signal_read(signal, input_file, tmp)) { + ret = false; + if(!infrared_signal_is_valid(signal)) { + printf("Invalid signal\r\n"); + break; + } + if(!infrared_signal_is_raw(signal)) { + if(output_file && + !infrared_cli_save_signal(signal, output_file, string_get_cstr(tmp))) { + break; + } else { + printf("Skipping decoded signal\r\n"); + continue; + } + } + InfraredRawSignal* raw_signal = infrared_signal_get_raw_signal(signal); + printf("Raw signal: %s, %u samples\r\n", string_get_cstr(tmp), raw_signal->timings_size); + if(!infrared_cli_decode_raw_signal(raw_signal, decoder, output_file, string_get_cstr(tmp))) + break; + ret = true; + } + + infrared_free_decoder(decoder); + infrared_signal_free(signal); + string_clear(tmp); + + return ret; +} + +static void infrared_cli_process_decode(Cli* cli, string_t args) { + UNUSED(cli); + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* input_file = flipper_format_buffered_file_alloc(storage); + FlipperFormat* output_file = NULL; + + uint32_t version; + string_t tmp, header, input_path, output_path; + string_init(tmp); + string_init(header); + string_init(input_path); + string_init(output_path); + + do { + if(!args_read_probably_quoted_string_and_trim(args, input_path)) { + printf("Wrong arguments.\r\n"); + infrared_cli_print_usage(); + break; + } + args_read_probably_quoted_string_and_trim(args, output_path); + if(!flipper_format_buffered_file_open_existing(input_file, string_get_cstr(input_path))) { + printf("Failed to open file for reading: \"%s\"\r\n", string_get_cstr(input_path)); + break; + } + if(!flipper_format_read_header(input_file, header, &version) || + (!string_start_with_str_p(header, "IR")) || version != 1) { + printf("Invalid or corrupted input file: \"%s\"\r\n", string_get_cstr(input_path)); + break; + } + if(!string_empty_p(output_path)) { + printf("Writing output to file: \"%s\"\r\n", string_get_cstr(output_path)); + output_file = flipper_format_file_alloc(storage); + } + if(output_file && + !flipper_format_file_open_always(output_file, string_get_cstr(output_path))) { + printf("Failed to open file for writing: \"%s\"\r\n", string_get_cstr(output_path)); + break; + } + if(output_file && !flipper_format_write_header(output_file, header, version)) { + printf("Failed to write to the output file: \"%s\"\r\n", string_get_cstr(output_path)); + break; + } + if(!infrared_cli_decode_file(input_file, output_file)) { + break; + } + printf("File successfully decoded.\r\n"); + } while(false); + + string_clear(tmp); + string_clear(header); + string_clear(input_path); + string_clear(output_path); + + flipper_format_free(input_file); + if(output_file) flipper_format_free(output_file); + furi_record_close(RECORD_STORAGE); +} + static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) { UNUSED(context); if(furi_hal_infrared_is_busy()) { @@ -169,18 +328,15 @@ static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) { return; } + string_t command; + string_init(command); + args_read_string_and_trim(args, command); + size_t i = 0; for(; i < COUNT_OF(infrared_cli_commands); ++i) { - size_t size = strlen(infrared_cli_commands[i].cmd); - bool cmd_found = !strncmp(string_get_cstr(args), infrared_cli_commands[i].cmd, size); - if(cmd_found) { - if(string_size(args) == size) { - break; - } - if(string_get_cstr(args)[size] == ' ') { - string_right(args, size + 1); - break; - } + size_t cmd_len = strlen(infrared_cli_commands[i].cmd); + if(!strncmp(string_get_cstr(command), infrared_cli_commands[i].cmd, cmd_len)) { + break; } } @@ -189,6 +345,8 @@ static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) { } else { infrared_cli_print_usage(); } + + string_clear(command); } void infrared_on_system_start() { #ifdef SRV_CLI diff --git a/applications/infrared/scenes/common/infrared_scene_universal_common.c b/applications/infrared/scenes/common/infrared_scene_universal_common.c index 57ac81168..1072549ff 100644 --- a/applications/infrared/scenes/common/infrared_scene_universal_common.c +++ b/applications/infrared/scenes/common/infrared_scene_universal_common.c @@ -33,6 +33,8 @@ 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)); } diff --git a/applications/infrared/scenes/infrared_scene_config.h b/applications/infrared/scenes/infrared_scene_config.h index 27eabe225..551485295 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_learn.c b/applications/infrared/scenes/infrared_scene_learn.c index 0edb74ca2..37f9b3e05 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); diff --git a/applications/infrared/scenes/infrared_scene_universal.c b/applications/infrared/scenes/infrared_scene_universal.c index 36c7d86e1..b70ffbd5c 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 9e98a671e..68a6ea942 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 000000000..37657ac3c --- /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/applications/lfrfid/application.fam b/applications/lfrfid/application.fam index 8722bb4f8..425804a55 100644 --- a/applications/lfrfid/application.fam +++ b/applications/lfrfid/application.fam @@ -10,7 +10,7 @@ App( ], provides=[ "lfrfid_start", - "lfrfid_debug", + #"lfrfid_debug", ], icon="A_125khz_14", stack_size=2 * 1024, diff --git a/applications/lfrfid/lfrfid.c b/applications/lfrfid/lfrfid.c new file mode 100644 index 000000000..87332b1ac --- /dev/null +++ b/applications/lfrfid/lfrfid.c @@ -0,0 +1,316 @@ +#include "lfrfid_i.h" + +static bool lfrfid_debug_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + LfRfid* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +static bool lfrfid_debug_back_event_callback(void* context) { + furi_assert(context); + LfRfid* app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) { + furi_assert(context); + LfRfid* app = (LfRfid*)context; + + if(rpc_event == RpcAppEventSessionClose) { + view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventRpcSessionClose); + // Detach RPC + rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL); + app->rpc_ctx = NULL; + } else if(rpc_event == RpcAppEventAppExit) { + view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventExit); + } else if(rpc_event == RpcAppEventLoadFile) { + view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventRpcLoadFile); + } else { + rpc_system_app_confirm(app->rpc_ctx, rpc_event, false); + } +} + +static LfRfid* lfrfid_alloc() { + LfRfid* lfrfid = malloc(sizeof(LfRfid)); + + lfrfid->storage = furi_record_open(RECORD_STORAGE); + lfrfid->dialogs = furi_record_open(RECORD_DIALOGS); + + string_init(lfrfid->file_name); + string_init(lfrfid->raw_file_name); + string_init_set_str(lfrfid->file_path, LFRFID_APP_FOLDER); + + lfrfid->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); + + size_t size = protocol_dict_get_max_data_size(lfrfid->dict); + lfrfid->new_key_data = (uint8_t*)malloc(size); + lfrfid->old_key_data = (uint8_t*)malloc(size); + + lfrfid->lfworker = lfrfid_worker_alloc(lfrfid->dict); + + lfrfid->view_dispatcher = view_dispatcher_alloc(); + lfrfid->scene_manager = scene_manager_alloc(&lfrfid_scene_handlers, lfrfid); + view_dispatcher_enable_queue(lfrfid->view_dispatcher); + view_dispatcher_set_event_callback_context(lfrfid->view_dispatcher, lfrfid); + view_dispatcher_set_custom_event_callback( + lfrfid->view_dispatcher, lfrfid_debug_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + lfrfid->view_dispatcher, lfrfid_debug_back_event_callback); + + // Open GUI record + lfrfid->gui = furi_record_open(RECORD_GUI); + + // Open Notification record + lfrfid->notifications = furi_record_open(RECORD_NOTIFICATION); + + // Submenu + lfrfid->submenu = submenu_alloc(); + view_dispatcher_add_view( + lfrfid->view_dispatcher, LfRfidViewSubmenu, submenu_get_view(lfrfid->submenu)); + + // Dialog + lfrfid->dialog_ex = dialog_ex_alloc(); + view_dispatcher_add_view( + lfrfid->view_dispatcher, LfRfidViewDialogEx, dialog_ex_get_view(lfrfid->dialog_ex)); + + // Popup + lfrfid->popup = popup_alloc(); + view_dispatcher_add_view( + lfrfid->view_dispatcher, LfRfidViewPopup, popup_get_view(lfrfid->popup)); + + // Widget + lfrfid->widget = widget_alloc(); + view_dispatcher_add_view( + lfrfid->view_dispatcher, LfRfidViewWidget, widget_get_view(lfrfid->widget)); + + // Text Input + lfrfid->text_input = text_input_alloc(); + view_dispatcher_add_view( + lfrfid->view_dispatcher, LfRfidViewTextInput, text_input_get_view(lfrfid->text_input)); + + // Byte Input + lfrfid->byte_input = byte_input_alloc(); + view_dispatcher_add_view( + lfrfid->view_dispatcher, LfRfidViewByteInput, byte_input_get_view(lfrfid->byte_input)); + + // Read custom view + lfrfid->read_view = lfrfid_view_read_alloc(); + view_dispatcher_add_view( + lfrfid->view_dispatcher, LfRfidViewRead, lfrfid_view_read_get_view(lfrfid->read_view)); + + return lfrfid; +} + +static void lfrfid_free(LfRfid* lfrfid) { + furi_assert(lfrfid); + + string_clear(lfrfid->raw_file_name); + string_clear(lfrfid->file_name); + string_clear(lfrfid->file_path); + protocol_dict_free(lfrfid->dict); + + lfrfid_worker_free(lfrfid->lfworker); + + if(lfrfid->rpc_ctx) { + rpc_system_app_set_callback(lfrfid->rpc_ctx, NULL, NULL); + rpc_system_app_send_exited(lfrfid->rpc_ctx); + } + + free(lfrfid->new_key_data); + free(lfrfid->old_key_data); + + // Submenu + view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewSubmenu); + submenu_free(lfrfid->submenu); + + // DialogEx + view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewDialogEx); + dialog_ex_free(lfrfid->dialog_ex); + + // Popup + view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewPopup); + popup_free(lfrfid->popup); + + // Widget + view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewWidget); + widget_free(lfrfid->widget); + + // TextInput + view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewTextInput); + text_input_free(lfrfid->text_input); + + // ByteInput + view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewByteInput); + byte_input_free(lfrfid->byte_input); + + // Read custom view + view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewRead); + lfrfid_view_read_free(lfrfid->read_view); + + // View Dispatcher + view_dispatcher_free(lfrfid->view_dispatcher); + + // Scene Manager + scene_manager_free(lfrfid->scene_manager); + + // GUI + furi_record_close(RECORD_GUI); + lfrfid->gui = NULL; + + // Notifications + furi_record_close(RECORD_NOTIFICATION); + lfrfid->notifications = NULL; + + furi_record_close(RECORD_STORAGE); + furi_record_close(RECORD_DIALOGS); + + free(lfrfid); +} + +int32_t lfrfid_app(void* p) { + LfRfid* app = lfrfid_alloc(); + char* args = p; + + lfrfid_make_app_folder(app); + + if(args && strlen(args)) { + uint32_t rpc_ctx_ptr = 0; + if(sscanf(args, "RPC %lX", &rpc_ctx_ptr) == 1) { + app->rpc_ctx = (RpcAppSystem*)rpc_ctx_ptr; + rpc_system_app_set_callback(app->rpc_ctx, rpc_command_callback, app); + rpc_system_app_send_started(app->rpc_ctx); + view_dispatcher_attach_to_gui( + app->view_dispatcher, app->gui, ViewDispatcherTypeDesktop); + scene_manager_next_scene(app->scene_manager, LfRfidSceneRpc); + } else { + string_set_str(app->file_path, args); + lfrfid_load_key_data(app, app->file_path, true); + view_dispatcher_attach_to_gui( + app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); + } + + } else { + view_dispatcher_attach_to_gui( + app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + scene_manager_next_scene(app->scene_manager, LfRfidSceneStart); + } + + view_dispatcher_run(app->view_dispatcher); + + lfrfid_free(app); + + return 0; +} + +bool lfrfid_save_key(LfRfid* app) { + furi_assert(app); + + bool result = false; + + lfrfid_make_app_folder(app); + + if(string_end_with_str_p(app->file_path, LFRFID_APP_EXTENSION)) { + size_t filename_start = string_search_rchar(app->file_path, '/'); + string_left(app->file_path, filename_start); + } + + string_cat_printf( + app->file_path, "/%s%s", string_get_cstr(app->file_name), LFRFID_APP_EXTENSION); + + result = lfrfid_save_key_data(app, app->file_path); + return result; +} + +bool lfrfid_load_key_from_file_select(LfRfid* app) { + furi_assert(app); + + bool result = dialog_file_browser_show( + app->dialogs, + app->file_path, + app->file_path, + LFRFID_APP_EXTENSION, + true, + &I_125_10px, + true); + + if(result) { + result = lfrfid_load_key_data(app, app->file_path, true); + } + + return result; +} + +bool lfrfid_delete_key(LfRfid* app) { + furi_assert(app); + + return storage_simply_remove(app->storage, string_get_cstr(app->file_path)); +} + +bool lfrfid_load_key_data(LfRfid* app, string_t path, bool show_dialog) { + bool result = false; + + do { + app->protocol_id = lfrfid_dict_file_load(app->dict, string_get_cstr(path)); + if(app->protocol_id == PROTOCOL_NO) break; + + path_extract_filename(path, app->file_name, true); + result = true; + } while(0); + + if((!result) && (show_dialog)) { + dialog_message_show_storage_error(app->dialogs, "Cannot load\nkey file"); + } + + return result; +} + +bool lfrfid_save_key_data(LfRfid* app, string_t path) { + bool result = lfrfid_dict_file_save(app->dict, app->protocol_id, string_get_cstr(path)); + + if(!result) { + dialog_message_show_storage_error(app->dialogs, "Cannot save\nkey file"); + } + + return result; +} + +void lfrfid_make_app_folder(LfRfid* app) { + furi_assert(app); + + if(!storage_simply_mkdir(app->storage, LFRFID_APP_FOLDER)) { + dialog_message_show_storage_error(app->dialogs, "Cannot create\napp folder"); + } +} + +void lfrfid_text_store_set(LfRfid* app, const char* text, ...) { + furi_assert(app); + va_list args; + va_start(args, text); + + vsnprintf(app->text_store, LFRFID_TEXT_STORE_SIZE, text, args); + + va_end(args); +} + +void lfrfid_text_store_clear(LfRfid* app) { + furi_assert(app); + memset(app->text_store, 0, sizeof(app->text_store)); +} + +void lfrfid_popup_timeout_callback(void* context) { + LfRfid* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventPopupClosed); +} + +void lfrfid_widget_callback(GuiButtonType result, InputType type, void* context) { + LfRfid* app = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(app->view_dispatcher, result); + } +} + +void lfrfid_text_input_callback(void* context) { + LfRfid* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventNext); +} \ No newline at end of file diff --git a/applications/lfrfid/lfrfid_app.cpp b/applications/lfrfid/lfrfid_app.cpp deleted file mode 100644 index 9373ca8c7..000000000 --- a/applications/lfrfid/lfrfid_app.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include "lfrfid_app.h" -#include "assets_icons.h" -#include -#include "m-string.h" -#include "scene/lfrfid_app_scene_start.h" -#include "scene/lfrfid_app_scene_read.h" -#include "scene/lfrfid_app_scene_read_success.h" -#include "scene/lfrfid_app_scene_retry_confirm.h" -#include "scene/lfrfid_app_scene_exit_confirm.h" -#include "scene/lfrfid_app_scene_read_menu.h" -#include "scene/lfrfid_app_scene_write.h" -#include "scene/lfrfid_app_scene_write_success.h" -#include "scene/lfrfid_app_scene_emulate.h" -#include "scene/lfrfid_app_scene_save_name.h" -#include "scene/lfrfid_app_scene_save_success.h" -#include "scene/lfrfid_app_scene_select_key.h" -#include "scene/lfrfid_app_scene_saved_key_menu.h" -#include "scene/lfrfid_app_scene_save_data.h" -#include "scene/lfrfid_app_scene_save_type.h" -#include "scene/lfrfid_app_scene_saved_info.h" -#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 - -#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{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) { - furi_assert(context); - LfRfidApp* app = static_cast(context); - - if(rpc_event == RpcAppEventSessionClose) { - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::RpcSessionClose; - app->view_controller.send_event(&event); - // Detach RPC - rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL); - app->rpc_ctx = NULL; - } else if(rpc_event == RpcAppEventAppExit) { - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Exit; - app->view_controller.send_event(&event); - } else if(rpc_event == RpcAppEventLoadFile) { - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::RpcLoadFile; - app->view_controller.send_event(&event); - } else { - rpc_system_app_confirm(app->rpc_ctx, rpc_event, false); - } -} - -void LfRfidApp::run(void* _args) { - const char* args = reinterpret_cast(_args); - - make_app_folder(); - - if(args && strlen(args)) { - uint32_t rpc_ctx_ptr = 0; - if(sscanf(args, "RPC %lX", &rpc_ctx_ptr) == 1) { - rpc_ctx = (RpcAppSystem*)rpc_ctx_ptr; - rpc_system_app_set_callback(rpc_ctx, rpc_command_callback, this); - rpc_system_app_send_started(rpc_ctx); - view_controller.attach_to_gui(ViewDispatcherTypeDesktop); - scene_controller.add_scene(SceneType::Rpc, new LfRfidAppSceneRpc()); - scene_controller.process(100, SceneType::Rpc); - } else { - string_set_str(file_path, args); - 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); - } - - } else { - view_controller.attach_to_gui(ViewDispatcherTypeFullscreen); - scene_controller.add_scene(SceneType::Start, new LfRfidAppSceneStart()); - scene_controller.add_scene(SceneType::Read, new LfRfidAppSceneRead()); - scene_controller.add_scene(SceneType::RetryConfirm, new LfRfidAppSceneRetryConfirm()); - scene_controller.add_scene(SceneType::ExitConfirm, new LfRfidAppSceneExitConfirm()); - scene_controller.add_scene(SceneType::ReadSuccess, new LfRfidAppSceneReadSuccess()); - scene_controller.add_scene(SceneType::ReadKeyMenu, new LfRfidAppSceneReadKeyMenu()); - scene_controller.add_scene(SceneType::Write, new LfRfidAppSceneWrite()); - scene_controller.add_scene(SceneType::WriteSuccess, new LfRfidAppSceneWriteSuccess()); - scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate()); - scene_controller.add_scene(SceneType::SaveName, new LfRfidAppSceneSaveName()); - scene_controller.add_scene(SceneType::SaveSuccess, new LfRfidAppSceneSaveSuccess()); - scene_controller.add_scene(SceneType::SelectKey, new LfRfidAppSceneSelectKey()); - scene_controller.add_scene(SceneType::SavedKeyMenu, new LfRfidAppSceneSavedKeyMenu()); - scene_controller.add_scene(SceneType::SaveData, new LfRfidAppSceneSaveData()); - scene_controller.add_scene(SceneType::SaveType, new LfRfidAppSceneSaveType()); - 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() { - bool result = false; - - make_app_folder(); - - if(string_end_with_str_p(file_path, app_extension)) { - size_t filename_start = string_search_rchar(file_path, '/'); - string_left(file_path, filename_start); - } - - string_cat_printf(file_path, "/%s%s", string_get_cstr(file_name), app_extension); - - result = save_key_data(file_path); - return result; -} - -bool LfRfidApp::load_key_from_file_select(bool need_restore) { - if(!need_restore) { - string_set_str(file_path, app_folder); - } - - bool result = dialog_file_browser_show( - dialogs, file_path, file_path, app_extension, true, &I_125_10px, true); - - if(result) { - result = load_key_data(file_path, true); - } - - return result; -} - -bool LfRfidApp::delete_key() { - return storage_simply_remove(storage, string_get_cstr(file_path)); -} - -bool LfRfidApp::load_key_data(string_t path, bool show_dialog) { - bool result = false; - - do { - protocol_id = lfrfid_dict_file_load(dict, string_get_cstr(path)); - if(protocol_id == PROTOCOL_NO) break; - - path_extract_filename(path, file_name, true); - result = true; - } while(0); - - if((!result) && (show_dialog)) { - dialog_message_show_storage_error(dialogs, "Cannot load\nkey file"); - } - - return result; -} - -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"); - } - - return result; -} - -void LfRfidApp::make_app_folder() { - if(!storage_simply_mkdir(storage, app_folder)) { - dialog_message_show_storage_error(dialogs, "Cannot create\napp folder"); - } -} diff --git a/applications/lfrfid/lfrfid_app.h b/applications/lfrfid/lfrfid_app.h deleted file mode 100644 index 153218dbd..000000000 --- a/applications/lfrfid/lfrfid_app.h +++ /dev/null @@ -1,137 +0,0 @@ -#pragma once -#include "m-string.h" -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include "view/container_vm.h" - -#include -#include -#include - -#include "rpc/rpc_app.h" - -#include -#include -#include -#include - -#define LFRFID_KEY_NAME_SIZE 22 - -class LfRfidApp { -public: - enum class EventType : uint8_t { - GENERIC_EVENT_ENUM_VALUES, - Next, - MenuSelected, - Stay, - Retry, - Exit, - ReadEventSenseStart, - ReadEventSenseEnd, - ReadEventSenseCardStart, - ReadEventSenseCardEnd, - ReadEventStartASK, - ReadEventStartPSK, - ReadEventDone, - ReadEventOverrun, - ReadEventError, - WriteEventOK, - WriteEventProtocolCannotBeWritten, - WriteEventFobCannotBeWritten, - WriteEventTooLongToWrite, - RpcLoadFile, - RpcSessionClose, - }; - - enum class SceneType : uint8_t { - GENERIC_SCENE_ENUM_VALUES, - Read, - ReadSuccess, - RetryConfirm, - ExitConfirm, - ReadKeyMenu, - Write, - WriteSuccess, - Emulate, - SaveName, - SaveSuccess, - SelectKey, - SavedKeyMenu, - SaveData, - SaveType, - SavedInfo, - DeleteConfirm, - DeleteSuccess, - Rpc, - ExtraActions, - RawInfo, - RawName, - RawRead, - RawSuccess, - }; - - class Event { - public: - union { - int32_t signed_int; - } payload; - - EventType type; - }; - - SceneController, LfRfidApp> scene_controller; - ViewController - view_controller; - - ~LfRfidApp(); - LfRfidApp(); - - RecordController notification; - RecordController storage; - RecordController dialogs; - - TextStore text_store; - - string_t file_path; - - RpcAppSystem* rpc_ctx; - - 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(); - bool load_key_from_file_select(bool need_restore); - bool delete_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_app_launcher.cpp b/applications/lfrfid/lfrfid_app_launcher.cpp deleted file mode 100644 index 2855850f5..000000000 --- a/applications/lfrfid/lfrfid_app_launcher.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "lfrfid_app.h" - -// app enter function -extern "C" int32_t lfrfid_app(void* args) { - LfRfidApp* app = new LfRfidApp(); - app->run(args); - delete app; - - return 0; -} diff --git a/applications/lfrfid/lfrfid_cli.c b/applications/lfrfid/lfrfid_cli.c index 9a6930a67..281a0e963 100644 --- a/applications/lfrfid/lfrfid_cli.c +++ b/applications/lfrfid/lfrfid_cli.c @@ -114,7 +114,7 @@ static void lfrfid_cli_read(Cli* cli, string_t args) { string_t info; string_init(info); protocol_dict_render_data(dict, info, context.protocol); - if(string_size(info) > 0) { + if(!string_empty_p(info)) { printf("%s\r\n", string_get_cstr(info)); } string_clear(info); diff --git a/applications/lfrfid/lfrfid_i.h b/applications/lfrfid/lfrfid_i.h new file mode 100644 index 000000000..77e872527 --- /dev/null +++ b/applications/lfrfid/lfrfid_i.h @@ -0,0 +1,145 @@ +#pragma once + +#include "m-string.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#define LFRFID_KEY_NAME_SIZE 22 +#define LFRFID_TEXT_STORE_SIZE 40 + +#define LFRFID_APP_FOLDER ANY_PATH("lfrfid") +#define LFRFID_SD_FOLDER EXT_PATH("lfrfid") +#define LFRFID_APP_EXTENSION ".rfid" +#define LFRFID_APP_SHADOW_EXTENSION ".shd" + +#define LFRFID_APP_RAW_ASK_EXTENSION ".ask.raw" +#define LFRFID_APP_RAW_PSK_EXTENSION ".psk.raw" + +enum LfRfidCustomEvent { + LfRfidEventNext = 100, + LfRfidEventExit, + LfRfidEventPopupClosed, + LfRfidEventReadSenseStart, + LfRfidEventReadSenseEnd, + LfRfidEventReadSenseCardStart, + LfRfidEventReadSenseCardEnd, + LfRfidEventReadStartASK, + LfRfidEventReadStartPSK, + LfRfidEventReadDone, + LfRfidEventReadOverrun, + LfRfidEventReadError, + LfRfidEventWriteOK, + LfRfidEventWriteProtocolCannotBeWritten, + LfRfidEventWriteFobCannotBeWritten, + LfRfidEventWriteTooLongToWrite, + LfRfidEventRpcLoadFile, + LfRfidEventRpcSessionClose, +}; + +typedef enum { + LfRfidRpcStateIdle, + LfRfidRpcStateEmulating, +} LfRfidRpcState; + +typedef struct LfRfid LfRfid; + +struct LfRfid { + LFRFIDWorker* lfworker; + ViewDispatcher* view_dispatcher; + Gui* gui; + NotificationApp* notifications; + SceneManager* scene_manager; + Storage* storage; + DialogsApp* dialogs; + Widget* widget; + + char text_store[LFRFID_TEXT_STORE_SIZE + 1]; + string_t file_path; + string_t file_name; + string_t raw_file_name; + + ProtocolDict* dict; + ProtocolId protocol_id; + ProtocolId protocol_id_next; + LFRFIDWorkerReadType read_type; + + uint8_t* old_key_data; + uint8_t* new_key_data; + + RpcAppSystem* rpc_ctx; + LfRfidRpcState rpc_state; + + // Common Views + Submenu* submenu; + DialogEx* dialog_ex; + Popup* popup; + TextInput* text_input; + ByteInput* byte_input; + + // Custom views + LfRfidReadView* read_view; +}; + +typedef enum { + LfRfidViewSubmenu, + LfRfidViewDialogEx, + LfRfidViewPopup, + LfRfidViewWidget, + LfRfidViewTextInput, + LfRfidViewByteInput, + LfRfidViewRead, +} LfRfidView; + +bool lfrfid_save_key(LfRfid* app); + +bool lfrfid_load_key_from_file_select(LfRfid* app); + +bool lfrfid_delete_key(LfRfid* app); + +bool lfrfid_load_key_data(LfRfid* app, string_t path, bool show_dialog); + +bool lfrfid_save_key_data(LfRfid* app, string_t path); + +void lfrfid_make_app_folder(LfRfid* app); + +void lfrfid_text_store_set(LfRfid* app, const char* text, ...); + +void lfrfid_text_store_clear(LfRfid* app); + +void lfrfid_popup_timeout_callback(void* context); + +void lfrfid_widget_callback(GuiButtonType result, InputType type, void* context); + +void lfrfid_text_input_callback(void* context); diff --git a/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp b/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp deleted file mode 100644 index 58ff4dcdf..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "lfrfid_app_scene_delete_confirm.h" -#include "../view/elements/button_element.h" -#include "../view/elements/icon_element.h" -#include "../view/elements/string_element.h" - -void LfRfidAppSceneDeleteConfirm::on_enter(LfRfidApp* app, bool /* need_restore */) { - string_init(string_data); - string_init(string_header); - - auto container = app->view_controller.get(); - - auto button = container->add(); - button->set_type(ButtonElement::Type::Left, "Back"); - button->set_callback(app, LfRfidAppSceneDeleteConfirm::back_callback); - - button = container->add(); - button->set_type(ButtonElement::Type::Right, "Delete"); - button->set_callback(app, LfRfidAppSceneDeleteConfirm::delete_callback); - - auto line_1 = container->add(); - auto line_2 = container->add(); - auto line_3 = container->add(); - - 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?", string_get_cstr(app->file_name)); - line_1->set_text( - string_get_cstr(string_header), 64, 0, 128 - 2, AlignCenter, AlignTop, FontPrimary); - line_2->set_text( - string_get_cstr(string_data), 64, 19, 0, AlignCenter, AlignTop, FontSecondary); - line_3->set_text( - protocol_dict_get_name(app->dict, app->protocol_id), - 64, - 49, - 0, - AlignCenter, - AlignBottom, - FontSecondary); - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneDeleteConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Next) { - app->delete_key(); - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::DeleteSuccess); - consumed = true; - } else if(event->type == LfRfidApp::EventType::Stay) { - app->scene_controller.switch_to_previous_scene(); - consumed = true; - } else if(event->type == LfRfidApp::EventType::Back) { - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneDeleteConfirm::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); - string_clear(string_data); - string_clear(string_header); -} - -void LfRfidAppSceneDeleteConfirm::back_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Stay; - app->view_controller.send_event(&event); -} - -void LfRfidAppSceneDeleteConfirm::delete_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_delete_confirm.h b/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.h deleted file mode 100644 index f9daed543..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneDeleteConfirm : 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 back_callback(void* context); - static void delete_callback(void* context); - - string_t string_header; - string_t string_data; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_delete_success.cpp b/applications/lfrfid/scene/lfrfid_app_scene_delete_success.cpp deleted file mode 100644 index 9820338d1..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_delete_success.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "lfrfid_app_scene_delete_success.h" - -void LfRfidAppSceneDeleteSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) { - auto popup = app->view_controller.get(); - - popup->set_icon(0, 2, &I_DolphinMafia_115x62); - popup->set_header("Deleted", 83, 19, AlignLeft, AlignBottom); - popup->set_context(app); - popup->set_callback(LfRfidAppSceneDeleteSuccess::timeout_callback); - popup->set_timeout(1500); - popup->enable_timeout(); - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneDeleteSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Back) { - app->scene_controller.search_and_switch_to_previous_scene( - {LfRfidApp::SceneType::SelectKey}); - - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneDeleteSuccess::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneDeleteSuccess::timeout_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Back; - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_delete_success.h b/applications/lfrfid/scene/lfrfid_app_scene_delete_success.h deleted file mode 100644 index 009b9f25d..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_delete_success.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneDeleteSuccess : 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 timeout_callback(void* context); -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_emulate.cpp b/applications/lfrfid/scene/lfrfid_app_scene_emulate.cpp deleted file mode 100644 index 02cb011d1..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_emulate.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "lfrfid_app_scene_emulate.h" -#include -#include - -void LfRfidAppSceneEmulate::on_enter(LfRfidApp* app, bool /* need_restore */) { - DOLPHIN_DEED(DolphinDeedRfidEmulate); - auto popup = app->view_controller.get(); - - popup->set_header("Emulating", 89, 30, 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( - 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(); - lfrfid_worker_start_thread(app->lfworker); - lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id); - notification_message(app->notification, &sequence_blink_start_magenta); -} - -bool LfRfidAppSceneEmulate::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - UNUSED(app); - UNUSED(event); - bool consumed = false; - return consumed; -} - -void LfRfidAppSceneEmulate::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); - 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 deleted file mode 100644 index 13d2b857d..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_emulate.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneEmulate : 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; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.cpp b/applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.cpp deleted file mode 100644 index be070b40e..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "lfrfid_app_scene_exit_confirm.h" -#include "../view/elements/button_element.h" -#include "../view/elements/icon_element.h" -#include "../view/elements/string_element.h" - -void LfRfidAppSceneExitConfirm::on_enter(LfRfidApp* app, bool /* need_restore */) { - auto container = app->view_controller.get(); - - auto button = container->add(); - button->set_type(ButtonElement::Type::Left, "Exit"); - button->set_callback(app, LfRfidAppSceneExitConfirm::exit_callback); - - button = container->add(); - button->set_type(ButtonElement::Type::Right, "Stay"); - button->set_callback(app, LfRfidAppSceneExitConfirm::stay_callback); - - auto line_1 = container->add(); - auto line_2 = container->add(); - - line_1->set_text("Exit to RFID Menu?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary); - line_2->set_text( - "All unsaved data will be lost!", 64, 31, 0, AlignCenter, AlignBottom, FontSecondary); - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneExitConfirm::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::Start}); - consumed = true; - } else if(event->type == LfRfidApp::EventType::Stay) { - app->scene_controller.switch_to_previous_scene(); - consumed = true; - } else if(event->type == LfRfidApp::EventType::Back) { - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneExitConfirm::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneExitConfirm::exit_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Next; - app->view_controller.send_event(&event); -} - -void LfRfidAppSceneExitConfirm::stay_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Stay; - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.h b/applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.h deleted file mode 100644 index a0a102325..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneExitConfirm : 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 exit_callback(void* context); - static void stay_callback(void* context); -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp b/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp deleted file mode 100644 index ea4f03dbb..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#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 deleted file mode 100644 index dcd746146..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_extra_actions.h +++ /dev/null @@ -1,13 +0,0 @@ -#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 deleted file mode 100644 index ce3634b2a..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_raw_info.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#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 deleted file mode 100644 index eecca1436..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_raw_info.h +++ /dev/null @@ -1,12 +0,0 @@ -#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 deleted file mode 100644 index 0ad346198..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_raw_name.cpp +++ /dev/null @@ -1,46 +0,0 @@ - -#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 deleted file mode 100644 index 225d135e5..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_raw_name.h +++ /dev/null @@ -1,12 +0,0 @@ -#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 deleted file mode 100644 index 0d04e6bc7..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_raw_read.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#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 deleted file mode 100644 index 09ef74639..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_raw_read.h +++ /dev/null @@ -1,15 +0,0 @@ -#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 deleted file mode 100644 index 227ab580a..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_raw_success.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#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 deleted file mode 100644 index 0a0b0116b..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_raw_success.h +++ /dev/null @@ -1,13 +0,0 @@ -#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 deleted file mode 100644 index 120eb1a07..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_read.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#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); - 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(); - 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 = 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(); - lfrfid_worker_stop(app->lfworker); - lfrfid_worker_stop_thread(app->lfworker); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_read.h b/applications/lfrfid/scene/lfrfid_app_scene_read.h deleted file mode 100644 index b5035b72a..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_read.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneRead : 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; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_read_menu.cpp b/applications/lfrfid/scene/lfrfid_app_scene_read_menu.cpp deleted file mode 100644 index aa3b3f1fb..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_read_menu.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "lfrfid_app_scene_read_menu.h" - -typedef enum { - SubmenuSave, - SubmenuEmulate, - SubmenuWrite, -} SubmenuIndex; - -void LfRfidAppSceneReadKeyMenu::on_enter(LfRfidApp* app, bool need_restore) { - auto submenu = app->view_controller.get(); - - submenu->add_item("Save", SubmenuSave, submenu_callback, app); - submenu->add_item("Emulate", SubmenuEmulate, submenu_callback, app); - submenu->add_item("Write", SubmenuWrite, submenu_callback, app); - - if(need_restore) { - submenu->set_selected_item(submenu_item_selected); - } - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneReadKeyMenu::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 SubmenuWrite: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Write); - break; - case SubmenuSave: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveName); - break; - case SubmenuEmulate: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Emulate); - break; - } - consumed = true; - } else if(event->type == LfRfidApp::EventType::Back) { - app->scene_controller.switch_to_previous_scene(); - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneReadKeyMenu::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneReadKeyMenu::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_read_menu.h b/applications/lfrfid/scene/lfrfid_app_scene_read_menu.h deleted file mode 100644 index 2b50b96f9..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_read_menu.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneReadKeyMenu : 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_read_success.cpp b/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp deleted file mode 100644 index 277b43a3e..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "lfrfid_app_scene_read_success.h" -#include "../view/elements/button_element.h" -#include "../view/elements/icon_element.h" -#include "../view/elements/string_element.h" - -void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) { - 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(); - - auto button = container->add(); - button->set_type(ButtonElement::Type::Left, "Retry"); - button->set_callback(app, LfRfidAppSceneReadSuccess::back_callback); - - button = container->add(); - button->set_type(ButtonElement::Type::Right, "More"); - button->set_callback(app, LfRfidAppSceneReadSuccess::more_callback); - - auto header = container->add(); - header->set_text(string_get_cstr(string_header), 0, 2, 0, AlignLeft, AlignTop, FontPrimary); - - auto text = container->add(); - text->set_text(string_get_cstr(string_info), 0, 16, 0, AlignLeft, AlignTop, FontSecondary); - - app->view_controller.switch_to(); - - notification_message_block(app->notification, &sequence_set_green_255); -} - -bool LfRfidAppSceneReadSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Next) { - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadKeyMenu); - consumed = true; - } else if(event->type == LfRfidApp::EventType::Retry) { - app->scene_controller.switch_to_next_scene({LfRfidApp::SceneType::RetryConfirm}); - consumed = true; - } else if(event->type == LfRfidApp::EventType::Back) { - app->scene_controller.switch_to_next_scene({LfRfidApp::SceneType::ExitConfirm}); - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneReadSuccess::on_exit(LfRfidApp* app) { - notification_message_block(app->notification, &sequence_reset_green); - app->view_controller.get()->clean(); - string_clear(string_info); - string_clear(string_header); -} - -void LfRfidAppSceneReadSuccess::back_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Retry; - app->view_controller.send_event(&event); -} - -void LfRfidAppSceneReadSuccess::more_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_read_success.h b/applications/lfrfid/scene/lfrfid_app_scene_read_success.h deleted file mode 100644 index 6d90f6310..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_read_success.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneReadSuccess : 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 back_callback(void* context); - static void more_callback(void* context); - - string_t string_header; - string_t string_info; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.cpp b/applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.cpp deleted file mode 100644 index c18122323..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "lfrfid_app_scene_retry_confirm.h" -#include "../view/elements/button_element.h" -#include "../view/elements/icon_element.h" -#include "../view/elements/string_element.h" - -void LfRfidAppSceneRetryConfirm::on_enter(LfRfidApp* app, bool /* need_restore */) { - auto container = app->view_controller.get(); - - auto button = container->add(); - button->set_type(ButtonElement::Type::Left, "Exit"); - button->set_callback(app, LfRfidAppSceneRetryConfirm::exit_callback); - - button = container->add(); - button->set_type(ButtonElement::Type::Right, "Stay"); - button->set_callback(app, LfRfidAppSceneRetryConfirm::stay_callback); - - auto line_1 = container->add(); - auto line_2 = container->add(); - - line_1->set_text("Return to Reading?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary); - line_2->set_text( - "All unsaved data will be lost!", 64, 29, 0, AlignCenter, AlignBottom, FontSecondary); - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneRetryConfirm::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::Read}); - consumed = true; - } else if(event->type == LfRfidApp::EventType::Stay) { - app->scene_controller.switch_to_previous_scene(); - consumed = true; - } else if(event->type == LfRfidApp::EventType::Back) { - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneRetryConfirm::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneRetryConfirm::exit_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Next; - app->view_controller.send_event(&event); -} - -void LfRfidAppSceneRetryConfirm::stay_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Stay; - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.h b/applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.h deleted file mode 100644 index 01b7329c9..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneRetryConfirm : 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 exit_callback(void* context); - static void stay_callback(void* context); -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp b/applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp deleted file mode 100644 index c2e5ec2a6..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "lfrfid_app_scene_rpc.h" -#include -#include -#include - -void LfRfidAppSceneRpc::on_enter(LfRfidApp* app, bool /* need_restore */) { - auto popup = app->view_controller.get(); - - popup->set_header("LF RFID", 89, 42, AlignCenter, AlignBottom); - popup->set_text("RPC mode", 89, 44, AlignCenter, AlignTop); - popup->set_icon(0, 12, &I_RFIDDolphinSend_97x61); - - app->view_controller.switch_to(); - - notification_message(app->notification, &sequence_display_backlight_on); -} - -bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - UNUSED(app); - UNUSED(event); - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Exit) { - consumed = true; - LfRfidApp::Event view_event; - view_event.type = LfRfidApp::EventType::Back; - app->view_controller.send_event(&view_event); - rpc_system_app_confirm(app->rpc_ctx, RpcAppEventAppExit, true); - } else if(event->type == LfRfidApp::EventType::RpcSessionClose) { - consumed = true; - LfRfidApp::Event view_event; - view_event.type = LfRfidApp::EventType::Back; - app->view_controller.send_event(&view_event); - } else if(event->type == LfRfidApp::EventType::RpcLoadFile) { - const char* arg = rpc_system_app_get_data(app->rpc_ctx); - consumed = true; - bool result = false; - if(arg && !emulating) { - string_set_str(app->file_path, arg); - 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", 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); - result = true; - } - } - rpc_system_app_confirm(app->rpc_ctx, RpcAppEventLoadFile, result); - } - - return consumed; -} - -void LfRfidAppSceneRpc::on_exit(LfRfidApp* app) { - if(emulating) { - 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_rpc.h b/applications/lfrfid/scene/lfrfid_app_scene_rpc.h deleted file mode 100644 index f630dfd35..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_rpc.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneRpc : 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: - bool emulating = false; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_data.cpp b/applications/lfrfid/scene/lfrfid_app_scene_save_data.cpp deleted file mode 100644 index c506cd729..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_data.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "lfrfid_app_scene_save_data.h" -#include - -void LfRfidAppSceneSaveData::on_enter(LfRfidApp* app, bool need_restore) { - auto byte_input = app->view_controller.get(); - size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); - - if(need_restore) { - protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size); - } else { - protocol_dict_get_data(app->dict, app->protocol_id, app->old_key_data, size); - } - - 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, app->new_key_data, size); - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneSaveData::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Next) { - 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); - } - - return consumed; -} - -void LfRfidAppSceneSaveData::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneSaveData::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_save_data.h b/applications/lfrfid/scene/lfrfid_app_scene_save_data.h deleted file mode 100644 index d03cae125..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_data.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneSaveData : 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_save_name.cpp b/applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp deleted file mode 100644 index ed58b6453..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "lfrfid_app_scene_save_name.h" -#include "m-string.h" -#include -#include - -void LfRfidAppSceneSaveName::on_enter(LfRfidApp* app, bool /* need_restore */) { - const char* key_name = string_get_cstr(app->file_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); - } else { - app->text_store.set("%s", key_name); - } - - auto text_input = app->view_controller.get(); - text_input->set_header_text("Name the card"); - - text_input->set_result_callback( - save_callback, app, app->text_store.text, LFRFID_KEY_NAME_SIZE, key_name_empty); - - string_t folder_path; - string_init(folder_path); - - path_extract_dirname(string_get_cstr(app->file_path), folder_path); - - ValidatorIsFile* validator_is_file = - validator_is_file_alloc_init(string_get_cstr(folder_path), app->app_extension, key_name); - text_input->set_validator(validator_is_file_callback, validator_is_file); - - string_clear(folder_path); - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneSaveName::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Next) { - if(string_size(app->file_name) > 0) { - app->delete_key(); - } - - string_set_str(app->file_name, app->text_store.text); - - if(app->save_key()) { - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveSuccess); - } else { - app->scene_controller.search_and_switch_to_previous_scene( - {LfRfidApp::SceneType::ReadKeyMenu}); - } - } - - return consumed; -} - -void LfRfidAppSceneSaveName::on_exit(LfRfidApp* app) { - void* validator_context = - app->view_controller.get()->get_validator_callback_context(); - app->view_controller.get()->set_validator(NULL, NULL); - validator_is_file_free((ValidatorIsFile*)validator_context); - - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneSaveName::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_save_name.h b/applications/lfrfid/scene/lfrfid_app_scene_save_name.h deleted file mode 100644 index ced42cc0e..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_name.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneSaveName : 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_save_success.cpp b/applications/lfrfid/scene/lfrfid_app_scene_save_success.cpp deleted file mode 100644 index 64efafa73..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_success.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "lfrfid_app_scene_save_success.h" -#include -#include -#include - -void LfRfidAppSceneSaveSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) { - auto popup = app->view_controller.get(); - - DOLPHIN_DEED(DolphinDeedRfidSave); - popup->set_icon(32, 5, &I_DolphinNice_96x59); - popup->set_header("Saved!", 5, 7, AlignLeft, AlignTop); - popup->set_context(app); - popup->set_callback(LfRfidAppSceneSaveSuccess::timeout_callback); - popup->set_timeout(1500); - popup->enable_timeout(); - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneSaveSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Back) { - bool result = app->scene_controller.has_previous_scene( - {LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey}); - - if(result) { - app->scene_controller.search_and_switch_to_previous_scene( - {LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey}); - } else { - app->scene_controller.search_and_switch_to_another_scene( - {LfRfidApp::SceneType::SaveType}, LfRfidApp::SceneType::SelectKey); - } - - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneSaveSuccess::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneSaveSuccess::timeout_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Back; - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_success.h b/applications/lfrfid/scene/lfrfid_app_scene_save_success.h deleted file mode 100644 index 62273a76b..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_success.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneSaveSuccess : 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 timeout_callback(void* context); -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp b/applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp deleted file mode 100644 index b017e7b05..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "lfrfid_app_scene_save_type.h" - -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)); - submenu->add_item(string_get_cstr(submenu_name[i]), i, submenu_callback, app); - } - - if(need_restore) { - submenu->set_selected_item(submenu_item_selected); - } - - app->view_controller.switch_to(); - - // clear key 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.signed_int; - app->protocol_id = event->payload.signed_int; - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveData); - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneSaveType::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); - for(uint8_t i = 0; i < keys_count; i++) { - string_clear(submenu_name[i]); - } -} - -void LfRfidAppSceneSaveType::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_save_type.h b/applications/lfrfid/scene/lfrfid_app_scene_save_type.h deleted file mode 100644 index e4c1be3e6..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_type.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneSaveType : 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; - 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 deleted file mode 100644 index 614dd505c..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_saved_info.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "lfrfid_app_scene_saved_info.h" -#include "../view/elements/button_element.h" -#include "../view/elements/icon_element.h" -#include "../view/elements/string_element.h" - -void LfRfidAppSceneSavedInfo::on_enter(LfRfidApp* app, bool /* need_restore */) { - 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_info, " "); - } - - string_cat_printf(string_info, "%02X", data[i]); - } - free(data); - - 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); - - auto container = app->view_controller.get(); - - 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(); -} - -bool LfRfidAppSceneSavedInfo::on_event(LfRfidApp* /* app */, LfRfidApp::Event* /* event */) { - return false; -} - -void LfRfidAppSceneSavedInfo::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); - 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 deleted file mode 100644 index b0b588bcb..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_saved_info.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneSavedInfo : 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_saved_key_menu.cpp b/applications/lfrfid/scene/lfrfid_app_scene_saved_key_menu.cpp deleted file mode 100644 index e7a38d8ad..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_saved_key_menu.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "lfrfid_app_scene_saved_key_menu.h" - -typedef enum { - SubmenuEmulate, - SubmenuWrite, - SubmenuEdit, - SubmenuDelete, - SubmenuInfo, -} SubmenuIndex; - -void LfRfidAppSceneSavedKeyMenu::on_enter(LfRfidApp* app, bool need_restore) { - auto submenu = app->view_controller.get(); - - submenu->add_item("Emulate", SubmenuEmulate, submenu_callback, app); - submenu->add_item("Write", SubmenuWrite, submenu_callback, app); - submenu->add_item("Edit", SubmenuEdit, submenu_callback, app); - submenu->add_item("Delete", SubmenuDelete, submenu_callback, app); - submenu->add_item("Info", SubmenuInfo, submenu_callback, app); - - if(need_restore) { - submenu->set_selected_item(submenu_item_selected); - } - - app->view_controller.switch_to(); -} - -bool LfRfidAppSceneSavedKeyMenu::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 SubmenuEmulate: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Emulate); - break; - case SubmenuWrite: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Write); - break; - case SubmenuEdit: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveData); - break; - case SubmenuDelete: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::DeleteConfirm); - break; - case SubmenuInfo: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SavedInfo); - break; - } - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneSavedKeyMenu::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneSavedKeyMenu::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_saved_key_menu.h b/applications/lfrfid/scene/lfrfid_app_scene_saved_key_menu.h deleted file mode 100644 index 69a6e5e58..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_saved_key_menu.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneSavedKeyMenu : 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_select_key.cpp b/applications/lfrfid/scene/lfrfid_app_scene_select_key.cpp deleted file mode 100644 index 6d5df73cb..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_select_key.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "lfrfid_app_scene_select_key.h" - -void LfRfidAppSceneSelectKey::on_enter(LfRfidApp* app, bool need_restore) { - if(app->load_key_from_file_select(need_restore)) { - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SavedKeyMenu); - } else { - app->scene_controller.switch_to_previous_scene(); - } -} - -bool LfRfidAppSceneSelectKey::on_event(LfRfidApp* /* app */, LfRfidApp::Event* /* event */) { - return false; -} - -void LfRfidAppSceneSelectKey::on_exit(LfRfidApp* /* app */) { -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_select_key.h b/applications/lfrfid/scene/lfrfid_app_scene_select_key.h deleted file mode 100644 index be565a91c..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_select_key.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneSelectKey : 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; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_start.cpp b/applications/lfrfid/scene/lfrfid_app_scene_start.cpp deleted file mode 100644 index 5005c9afb..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_start.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "lfrfid_app_scene_start.h" - -typedef enum { - SubmenuRead, - SubmenuSaved, - SubmenuAddManually, - SubmenuExtraActions, -} SubmenuIndex; - -void LfRfidAppSceneStart::on_enter(LfRfidApp* app, bool need_restore) { - auto submenu = app->view_controller.get(); - - 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); - } - - app->view_controller.switch_to(); - - // clear key - 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.signed_int; - switch(event->payload.signed_int) { - case SubmenuRead: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read); - break; - case SubmenuSaved: - app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SelectKey); - break; - 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; - } - - return consumed; -} - -void LfRfidAppSceneStart::on_exit(LfRfidApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneStart::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_start.h b/applications/lfrfid/scene/lfrfid_app_scene_start.h deleted file mode 100644 index 255590d6a..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_start.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneStart : 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_write.cpp b/applications/lfrfid/scene/lfrfid_app_scene_write.cpp deleted file mode 100644 index 8e04d8e8d..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_write.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "lfrfid_app_scene_write.h" - -static void lfrfid_write_callback(LFRFIDWorkerWriteResult result, void* ctx) { - LfRfidApp* app = static_cast(ctx); - LfRfidApp::Event event; - - 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(string_size(app->file_name)) { - popup->set_text(string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); - } else { - 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(); - 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 = true; - auto popup = app->view_controller.get(); - - 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(); - 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 deleted file mode 100644 index 7564eff9d..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_write.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneWrite : 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; -}; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_write_success.cpp b/applications/lfrfid/scene/lfrfid_app_scene_write_success.cpp deleted file mode 100644 index 3cf00183d..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_write_success.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "lfrfid_app_scene_write_success.h" - -void LfRfidAppSceneWriteSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) { - auto popup = app->view_controller.get(); - popup->set_header("Successfully\nwritten!", 94, 3, AlignCenter, AlignTop); - popup->set_icon(0, 6, &I_RFIDDolphinSuccess_108x57); - popup->set_context(app); - popup->set_callback(LfRfidAppSceneWriteSuccess::timeout_callback); - popup->set_timeout(1500); - popup->enable_timeout(); - - app->view_controller.switch_to(); - notification_message_block(app->notification, &sequence_set_green_255); -} - -bool LfRfidAppSceneWriteSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidApp::EventType::Back) { - app->scene_controller.search_and_switch_to_previous_scene( - {LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey}); - consumed = true; - } - - return consumed; -} - -void LfRfidAppSceneWriteSuccess::on_exit(LfRfidApp* app) { - notification_message_block(app->notification, &sequence_reset_green); - app->view_controller.get()->clean(); -} - -void LfRfidAppSceneWriteSuccess::timeout_callback(void* context) { - LfRfidApp* app = static_cast(context); - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::Back; - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_write_success.h b/applications/lfrfid/scene/lfrfid_app_scene_write_success.h deleted file mode 100644 index 4ac9f0892..000000000 --- a/applications/lfrfid/scene/lfrfid_app_scene_write_success.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "../lfrfid_app.h" - -class LfRfidAppSceneWriteSuccess : 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 timeout_callback(void* context); -}; diff --git a/applications/lfrfid/scenes/lfrfid_scene.c b/applications/lfrfid/scenes/lfrfid_scene.c new file mode 100644 index 000000000..0de5ec36b --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene.c @@ -0,0 +1,30 @@ +#include "lfrfid_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const lfrfid_on_enter_handlers[])(void*) = { +#include "lfrfid_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const lfrfid_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "lfrfid_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const lfrfid_on_exit_handlers[])(void* context) = { +#include "lfrfid_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers lfrfid_scene_handlers = { + .on_enter_handlers = lfrfid_on_enter_handlers, + .on_event_handlers = lfrfid_on_event_handlers, + .on_exit_handlers = lfrfid_on_exit_handlers, + .scene_num = LfRfidSceneNum, +}; diff --git a/applications/lfrfid/scenes/lfrfid_scene.h b/applications/lfrfid/scenes/lfrfid_scene.h new file mode 100644 index 000000000..8ce7da09c --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) LfRfidScene##id, +typedef enum { +#include "lfrfid_scene_config.h" + LfRfidSceneNum, +} LfRfidScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers lfrfid_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "lfrfid_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "lfrfid_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "lfrfid_scene_config.h" +#undef ADD_SCENE diff --git a/applications/lfrfid/scenes/lfrfid_scene_config.h b/applications/lfrfid/scenes/lfrfid_scene_config.h new file mode 100644 index 000000000..b77ade82f --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_config.h @@ -0,0 +1,24 @@ +ADD_SCENE(lfrfid, start, Start) +ADD_SCENE(lfrfid, read, Read) +ADD_SCENE(lfrfid, read_success, ReadSuccess) +ADD_SCENE(lfrfid, retry_confirm, RetryConfirm) +ADD_SCENE(lfrfid, exit_confirm, ExitConfirm) +ADD_SCENE(lfrfid, delete_confirm, DeleteConfirm) +ADD_SCENE(lfrfid, read_key_menu, ReadKeyMenu) +ADD_SCENE(lfrfid, write, Write) +ADD_SCENE(lfrfid, write_success, WriteSuccess) +ADD_SCENE(lfrfid, emulate, Emulate) +ADD_SCENE(lfrfid, save_name, SaveName) +ADD_SCENE(lfrfid, save_success, SaveSuccess) +ADD_SCENE(lfrfid, select_key, SelectKey) +ADD_SCENE(lfrfid, saved_key_menu, SavedKeyMenu) +ADD_SCENE(lfrfid, save_data, SaveData) +ADD_SCENE(lfrfid, save_type, SaveType) +ADD_SCENE(lfrfid, saved_info, SavedInfo) +ADD_SCENE(lfrfid, delete_success, DeleteSuccess) +ADD_SCENE(lfrfid, extra_actions, ExtraActions) +ADD_SCENE(lfrfid, raw_info, RawInfo) +ADD_SCENE(lfrfid, raw_name, RawName) +ADD_SCENE(lfrfid, raw_read, RawRead) +ADD_SCENE(lfrfid, raw_success, RawSuccess) +ADD_SCENE(lfrfid, rpc, Rpc) diff --git a/applications/lfrfid/scenes/lfrfid_scene_delete_confirm.c b/applications/lfrfid/scenes/lfrfid_scene_delete_confirm.c new file mode 100644 index 000000000..dc1c3df26 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_delete_confirm.c @@ -0,0 +1,68 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_delete_confirm_on_enter(void* context) { + LfRfid* app = context; + Widget* widget = app->widget; + + string_t tmp_string; + string_init(tmp_string); + + widget_add_button_element(widget, GuiButtonTypeLeft, "Back", lfrfid_widget_callback, app); + widget_add_button_element(widget, GuiButtonTypeRight, "Delete", lfrfid_widget_callback, app); + + string_printf(tmp_string, "Delete %s?", string_get_cstr(app->file_name)); + widget_add_string_element( + widget, 64, 0, AlignCenter, AlignTop, FontPrimary, string_get_cstr(tmp_string)); + + string_reset(tmp_string); + 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(tmp_string, " "); + } + + string_cat_printf(tmp_string, "%02X", data[i]); + } + free(data); + + widget_add_string_element( + widget, 64, 19, AlignCenter, AlignTop, FontSecondary, string_get_cstr(tmp_string)); + widget_add_string_element( + widget, + 64, + 49, + AlignCenter, + AlignBottom, + FontSecondary, + protocol_dict_get_name(app->dict, app->protocol_id)); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); + string_clear(tmp_string); +} + +bool lfrfid_scene_delete_confirm_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + SceneManager* scene_manager = app->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + consumed = true; // Ignore Back button presses + } else if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == GuiButtonTypeLeft) { + scene_manager_previous_scene(scene_manager); + } else if(event.event == GuiButtonTypeRight) { + lfrfid_delete_key(app); + scene_manager_next_scene(scene_manager, LfRfidSceneDeleteSuccess); + } + } + + return consumed; +} + +void lfrfid_scene_delete_confirm_on_exit(void* context) { + LfRfid* app = context; + widget_reset(app->widget); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_delete_success.c b/applications/lfrfid/scenes/lfrfid_scene_delete_success.c new file mode 100644 index 000000000..f940b9bd4 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_delete_success.c @@ -0,0 +1,35 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_delete_success_on_enter(void* context) { + LfRfid* app = context; + Popup* popup = app->popup; + + popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); + popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); + popup_set_context(popup, app); + popup_set_callback(popup, lfrfid_popup_timeout_callback); + popup_set_timeout(popup, 1500); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); +} + +bool lfrfid_scene_delete_success_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + bool consumed = false; + + if((event.type == SceneManagerEventTypeBack) || + ((event.type == SceneManagerEventTypeCustom) && (event.event == LfRfidEventPopupClosed))) { + scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, LfRfidSceneSelectKey); + consumed = true; + } + + return consumed; +} + +void lfrfid_scene_delete_success_on_exit(void* context) { + LfRfid* app = context; + + popup_reset(app->popup); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_emulate.c b/applications/lfrfid/scenes/lfrfid_scene_emulate.c new file mode 100644 index 000000000..70cc2418c --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_emulate.c @@ -0,0 +1,44 @@ +#include "../lfrfid_i.h" +#include + +void lfrfid_scene_emulate_on_enter(void* context) { + LfRfid* app = context; + Popup* popup = app->popup; + + DOLPHIN_DEED(DolphinDeedRfidEmulate); + + popup_set_header(popup, "Emulating", 89, 30, AlignCenter, AlignTop); + if(!string_empty_p(app->file_name)) { + popup_set_text(popup, string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); + } else { + popup_set_text( + popup, + protocol_dict_get_name(app->dict, app->protocol_id), + 89, + 43, + AlignCenter, + AlignTop); + } + popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61); + + lfrfid_worker_start_thread(app->lfworker); + lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id); + notification_message(app->notifications, &sequence_blink_start_magenta); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); +} + +bool lfrfid_scene_emulate_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + bool consumed = false; + return consumed; +} + +void lfrfid_scene_emulate_on_exit(void* context) { + LfRfid* app = context; + notification_message(app->notifications, &sequence_blink_stop); + popup_reset(app->popup); + lfrfid_worker_stop(app->lfworker); + lfrfid_worker_stop_thread(app->lfworker); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_exit_confirm.c b/applications/lfrfid/scenes/lfrfid_scene_exit_confirm.c new file mode 100644 index 000000000..e8ab481c6 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_exit_confirm.c @@ -0,0 +1,39 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_exit_confirm_on_enter(void* context) { + LfRfid* app = context; + Widget* widget = app->widget; + + widget_add_button_element(widget, GuiButtonTypeLeft, "Exit", lfrfid_widget_callback, app); + widget_add_button_element(widget, GuiButtonTypeRight, "Stay", lfrfid_widget_callback, app); + widget_add_string_element( + widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to RFID Menu?"); + widget_add_string_element( + widget, 64, 31, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!"); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); +} + +bool lfrfid_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + SceneManager* scene_manager = app->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + consumed = true; // Ignore Back button presses + } else if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene(scene_manager, LfRfidSceneStart); + } else if(event.event == GuiButtonTypeRight) { + scene_manager_previous_scene(scene_manager); + } + } + + return consumed; +} + +void lfrfid_scene_exit_confirm_on_exit(void* context) { + LfRfid* app = context; + widget_reset(app->widget); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_extra_actions.c b/applications/lfrfid/scenes/lfrfid_scene_extra_actions.c new file mode 100644 index 000000000..58082cf10 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_extra_actions.c @@ -0,0 +1,79 @@ +#include "../lfrfid_i.h" + +typedef enum { + SubmenuIndexASK, + SubmenuIndexPSK, + SubmenuIndexRAW, +} SubmenuIndex; + +static void lfrfid_scene_extra_actions_submenu_callback(void* context, uint32_t index) { + LfRfid* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void lfrfid_scene_extra_actions_on_enter(void* context) { + LfRfid* app = context; + Submenu* submenu = app->submenu; + + submenu_add_item( + submenu, + "Read ASK (FDX,Regular)", + SubmenuIndexASK, + lfrfid_scene_extra_actions_submenu_callback, + app); + submenu_add_item( + submenu, + "Read PSK (Indala)", + SubmenuIndexPSK, + lfrfid_scene_extra_actions_submenu_callback, + app); + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + submenu_add_item( + submenu, + "Read RAW RFID data", + SubmenuIndexRAW, + lfrfid_scene_extra_actions_submenu_callback, + app); + } + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneExtraActions)); + + // clear key + string_reset(app->file_name); + app->protocol_id = PROTOCOL_NO; + app->read_type = LFRFIDWorkerReadTypeAuto; + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu); +} + +bool lfrfid_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexASK) { + app->read_type = LFRFIDWorkerReadTypeASKOnly; + scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); + consumed = true; + } else if(event.event == SubmenuIndexPSK) { + app->read_type = LFRFIDWorkerReadTypePSKOnly; + scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); + consumed = true; + } else if(event.event == SubmenuIndexRAW) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneRawName); + consumed = true; + } + scene_manager_set_scene_state(app->scene_manager, LfRfidSceneExtraActions, event.event); + } + + return consumed; +} + +void lfrfid_scene_extra_actions_on_exit(void* context) { + LfRfid* app = context; + + submenu_reset(app->submenu); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_raw_info.c b/applications/lfrfid/scenes/lfrfid_scene_raw_info.c new file mode 100644 index 000000000..f60dd6243 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_raw_info.c @@ -0,0 +1,64 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_raw_info_on_enter(void* context) { + LfRfid* app = context; + Widget* widget = app->widget; + + // string_t tmp_string; + // string_init(tmp_string); + + bool sd_exist = storage_sd_status(app->storage) == FSE_OK; + if(!sd_exist) { + widget_add_icon_element(widget, 0, 0, &I_SDQuestion_35x43); + widget_add_string_multiline_element( + widget, + 81, + 4, + AlignCenter, + AlignTop, + FontSecondary, + "No SD card found.\nThis function will not\nwork without\nSD card."); + + widget_add_button_element(widget, GuiButtonTypeLeft, "Back", lfrfid_widget_callback, app); + } else { + widget_add_string_multiline_element( + widget, + 0, + 1, + AlignLeft, + AlignTop, + FontSecondary, + "RAW RFID data reader\n1) Put the Flipper on your card\n2) Press OK\n3) Wait until data is read"); + + widget_add_button_element(widget, GuiButtonTypeCenter, "OK", lfrfid_widget_callback, app); + } + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); + //string_clear(tmp_string); +} + +bool lfrfid_scene_raw_info_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + SceneManager* scene_manager = app->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + consumed = true; + scene_manager_search_and_switch_to_previous_scene(scene_manager, LfRfidSceneExtraActions); + } else if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == GuiButtonTypeCenter) { + scene_manager_next_scene(scene_manager, LfRfidSceneRawRead); + } else if(event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene( + scene_manager, LfRfidSceneExtraActions); + } + } + + return consumed; +} + +void lfrfid_scene_raw_info_on_exit(void* context) { + LfRfid* app = context; + widget_reset(app->widget); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_raw_name.c b/applications/lfrfid/scenes/lfrfid_scene_raw_name.c new file mode 100644 index 000000000..512f9ee4c --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_raw_name.c @@ -0,0 +1,58 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_raw_name_on_enter(void* context) { + LfRfid* app = context; + TextInput* text_input = app->text_input; + + const char* key_name = string_get_cstr(app->raw_file_name); + + bool key_name_is_empty = string_empty_p(app->file_name); + if(key_name_is_empty) { + lfrfid_text_store_set(app, "RfidRecord"); + } else { + lfrfid_text_store_set(app, "%s", key_name); + } + + text_input_set_header_text(text_input, "Name the raw file"); + + text_input_set_result_callback( + text_input, + lfrfid_text_input_callback, + app, + app->text_store, + LFRFID_KEY_NAME_SIZE, + key_name_is_empty); + + ValidatorIsFile* validator_is_file = + validator_is_file_alloc_init(LFRFID_SD_FOLDER, LFRFID_APP_RAW_ASK_EXTENSION, NULL); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewTextInput); +} + +bool lfrfid_scene_raw_name_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + SceneManager* scene_manager = app->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == LfRfidEventNext) { + consumed = true; + string_set_str(app->raw_file_name, app->text_store); + scene_manager_next_scene(scene_manager, LfRfidSceneRawInfo); + } + } + + return consumed; +} + +void lfrfid_scene_raw_name_on_exit(void* context) { + LfRfid* app = context; + TextInput* text_input = app->text_input; + + void* validator_context = text_input_get_validator_callback_context(text_input); + text_input_set_validator(text_input, NULL, NULL); + validator_is_file_free((ValidatorIsFile*)validator_context); + + text_input_reset(text_input); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_raw_read.c b/applications/lfrfid/scenes/lfrfid_scene_raw_read.c new file mode 100644 index 000000000..d0c03ffa9 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_raw_read.c @@ -0,0 +1,126 @@ +#include "../lfrfid_i.h" + +#define RAW_READ_TIME 5000 + +typedef struct { + string_t string_file_name; + FuriTimer* timer; + bool is_psk; + bool error; +} LfRfidReadRawState; + +static void lfrfid_read_callback(LFRFIDWorkerReadRawResult result, void* context) { + LfRfid* app = context; + + if(result == LFRFIDWorkerReadRawFileError) { + view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventReadError); + } else if(result == LFRFIDWorkerReadRawOverrun) { + view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventReadOverrun); + } +} + +static void timer_callback(void* context) { + LfRfid* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventReadDone); +} + +void lfrfid_scene_raw_read_on_enter(void* context) { + LfRfid* app = context; + Popup* popup = app->popup; + + LfRfidReadRawState* state = malloc(sizeof(LfRfidReadRawState)); + scene_manager_set_scene_state(app->scene_manager, LfRfidSceneRawRead, (uint32_t)state); + string_init(state->string_file_name); + + popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); + lfrfid_worker_start_thread(app->lfworker); + lfrfid_make_app_folder(app); + + state->timer = furi_timer_alloc(timer_callback, FuriTimerTypeOnce, app); + furi_timer_start(state->timer, RAW_READ_TIME); + string_printf( + state->string_file_name, + "%s/%s%s", + LFRFID_SD_FOLDER, + string_get_cstr(app->raw_file_name), + LFRFID_APP_RAW_ASK_EXTENSION); + popup_set_header(popup, "Reading\nRAW RFID\nASK", 89, 30, AlignCenter, AlignTop); + lfrfid_worker_read_raw_start( + app->lfworker, + string_get_cstr(state->string_file_name), + LFRFIDWorkerReadTypeASKOnly, + lfrfid_read_callback, + app); + + notification_message(app->notifications, &sequence_blink_start_cyan); + + state->is_psk = false; + state->error = false; +} + +bool lfrfid_scene_raw_read_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + Popup* popup = app->popup; + LfRfidReadRawState* state = + (LfRfidReadRawState*)scene_manager_get_scene_state(app->scene_manager, LfRfidSceneRawRead); + bool consumed = false; + + furi_assert(state); + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == LfRfidEventReadError) { + consumed = true; + state->error = true; + popup_set_header( + popup, "Reading\nRAW RFID\nFile error", 89, 30, AlignCenter, AlignTop); + notification_message(app->notifications, &sequence_blink_start_red); + furi_timer_stop(state->timer); + } else if(event.event == LfRfidEventReadDone) { + consumed = true; + if(!state->error) { + if(state->is_psk) { + notification_message(app->notifications, &sequence_success); + scene_manager_next_scene(app->scene_manager, LfRfidSceneRawSuccess); + } else { + popup_set_header( + popup, "Reading\nRAW RFID\nPSK", 89, 30, AlignCenter, AlignTop); + notification_message(app->notifications, &sequence_blink_start_yellow); + lfrfid_worker_stop(app->lfworker); + string_printf( + state->string_file_name, + "%s/%s%s", + LFRFID_SD_FOLDER, + string_get_cstr(app->raw_file_name), + LFRFID_APP_RAW_PSK_EXTENSION); + lfrfid_worker_read_raw_start( + app->lfworker, + string_get_cstr(state->string_file_name), + LFRFIDWorkerReadTypePSKOnly, + lfrfid_read_callback, + app); + furi_timer_start(state->timer, RAW_READ_TIME); + state->is_psk = true; + } + } + } + } + + return consumed; +} + +void lfrfid_scene_raw_read_on_exit(void* context) { + LfRfid* app = context; + LfRfidReadRawState* state = + (LfRfidReadRawState*)scene_manager_get_scene_state(app->scene_manager, LfRfidSceneRawRead); + + notification_message(app->notifications, &sequence_blink_stop); + popup_reset(app->popup); + lfrfid_worker_stop(app->lfworker); + lfrfid_worker_stop_thread(app->lfworker); + furi_timer_free(state->timer); + + string_clear(state->string_file_name); + free(state); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_raw_success.c b/applications/lfrfid/scenes/lfrfid_scene_raw_success.c new file mode 100644 index 000000000..09a005298 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_raw_success.c @@ -0,0 +1,39 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_raw_success_on_enter(void* context) { + LfRfid* app = context; + Widget* widget = app->widget; + + widget_add_button_element(widget, GuiButtonTypeCenter, "OK", lfrfid_widget_callback, app); + + widget_add_string_multiline_element( + widget, + 0, + 1, + AlignLeft, + AlignTop, + FontSecondary, + "RAW RFID read success!\nNow you can analyze files\nOr send them to developers"); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); +} + +bool lfrfid_scene_raw_success_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + SceneManager* scene_manager = app->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == GuiButtonTypeCenter) { + scene_manager_search_and_switch_to_previous_scene( + scene_manager, LfRfidSceneExtraActions); + } + } + return consumed; +} + +void lfrfid_scene_raw_success_on_exit(void* context) { + LfRfid* app = context; + widget_reset(app->widget); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_read.c b/applications/lfrfid/scenes/lfrfid_scene_read.c new file mode 100644 index 000000000..661680381 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_read.c @@ -0,0 +1,109 @@ +#include "../lfrfid_i.h" +#include + +static const NotificationSequence sequence_blink_set_yellow = { + &message_blink_set_color_yellow, + NULL, +}; + +static const NotificationSequence sequence_blink_set_green = { + &message_blink_set_color_green, + NULL, +}; + +static const NotificationSequence sequence_blink_set_cyan = { + &message_blink_set_color_cyan, + NULL, +}; + +static void + lfrfid_read_callback(LFRFIDWorkerReadResult result, ProtocolId protocol, void* context) { + LfRfid* app = context; + uint32_t event = 0; + + if(result == LFRFIDWorkerReadSenseStart) { + event = LfRfidEventReadSenseStart; + } else if(result == LFRFIDWorkerReadSenseEnd) { + event = LfRfidEventReadSenseEnd; + } else if(result == LFRFIDWorkerReadSenseCardStart) { + event = LfRfidEventReadSenseCardStart; + } else if(result == LFRFIDWorkerReadSenseCardEnd) { + event = LfRfidEventReadSenseCardEnd; + } else if(result == LFRFIDWorkerReadDone) { + event = LfRfidEventReadDone; + app->protocol_id_next = protocol; + } else if(result == LFRFIDWorkerReadStartASK) { + event = LfRfidEventReadStartASK; + } else if(result == LFRFIDWorkerReadStartPSK) { + event = LfRfidEventReadStartPSK; + } else { + return; + } + + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void lfrfid_scene_read_on_enter(void* context) { + LfRfid* app = context; + + DOLPHIN_DEED(DolphinDeedRfidRead); + if(app->read_type == LFRFIDWorkerReadTypePSKOnly) { + lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadPskOnly); + } else if(app->read_type == LFRFIDWorkerReadTypeASKOnly) { + lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadAskOnly); + } + + lfrfid_worker_start_thread(app->lfworker); + lfrfid_worker_read_start(app->lfworker, app->read_type, lfrfid_read_callback, app); + + notification_message(app->notifications, &sequence_blink_start_cyan); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewRead); +} + +bool lfrfid_scene_read_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == LfRfidEventReadSenseStart) { + notification_message(app->notifications, &sequence_blink_set_yellow); + consumed = true; + } else if(event.event == LfRfidEventReadSenseCardStart) { + notification_message(app->notifications, &sequence_blink_set_green); + consumed = true; + } else if( + (event.event == LfRfidEventReadSenseEnd) || + (event.event == LfRfidEventReadSenseCardEnd)) { + notification_message(app->notifications, &sequence_blink_set_cyan); + consumed = true; + } else if(event.event == LfRfidEventReadDone) { + app->protocol_id = app->protocol_id_next; + DOLPHIN_DEED(DolphinDeedRfidReadSuccess); + notification_message(app->notifications, &sequence_success); + string_reset(app->file_name); + scene_manager_next_scene(app->scene_manager, LfRfidSceneReadSuccess); + consumed = true; + } else if(event.event == LfRfidEventReadStartPSK) { + if(app->read_type == LFRFIDWorkerReadTypeAuto) { + lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadPsk); + } + consumed = true; + } else if(event.event == LfRfidEventReadStartASK) { + if(app->read_type == LFRFIDWorkerReadTypeAuto) { + lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadAsk); + } + consumed = true; + } + } + + return consumed; +} + +void lfrfid_scene_read_on_exit(void* context) { + LfRfid* app = context; + notification_message(app->notifications, &sequence_blink_stop); + popup_reset(app->popup); + lfrfid_worker_stop(app->lfworker); + lfrfid_worker_stop_thread(app->lfworker); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_read_key_menu.c b/applications/lfrfid/scenes/lfrfid_scene_read_key_menu.c new file mode 100644 index 000000000..221cc0084 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_read_key_menu.c @@ -0,0 +1,58 @@ +#include "../lfrfid_i.h" + +typedef enum { + SubmenuIndexSave, + SubmenuIndexEmulate, + SubmenuIndexWrite, +} SubmenuIndex; + +void lfrfid_scene_read_key_menu_submenu_callback(void* context, uint32_t index) { + LfRfid* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void lfrfid_scene_read_key_menu_on_enter(void* context) { + LfRfid* app = context; + Submenu* submenu = app->submenu; + + submenu_add_item( + submenu, "Save", SubmenuIndexSave, lfrfid_scene_read_key_menu_submenu_callback, app); + submenu_add_item( + submenu, "Emulate", SubmenuIndexEmulate, lfrfid_scene_read_key_menu_submenu_callback, app); + submenu_add_item( + submenu, "Write", SubmenuIndexWrite, lfrfid_scene_read_key_menu_submenu_callback, app); + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneReadKeyMenu)); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu); +} + +bool lfrfid_scene_read_key_menu_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexWrite) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite); + consumed = true; + } else if(event.event == SubmenuIndexSave) { + string_reset(app->file_name); + scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveName); + consumed = true; + } else if(event.event == SubmenuIndexEmulate) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); + consumed = true; + } + scene_manager_set_scene_state(app->scene_manager, LfRfidSceneReadKeyMenu, event.event); + } + + return consumed; +} + +void lfrfid_scene_read_key_menu_on_exit(void* context) { + LfRfid* app = context; + + submenu_reset(app->submenu); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_read_success.c b/applications/lfrfid/scenes/lfrfid_scene_read_success.c new file mode 100644 index 000000000..c250fe4ea --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_read_success.c @@ -0,0 +1,80 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_read_success_on_enter(void* context) { + LfRfid* app = context; + Widget* widget = app->widget; + + string_t tmp_string; + string_init(tmp_string); + + widget_add_button_element(widget, GuiButtonTypeLeft, "Retry", lfrfid_widget_callback, app); + widget_add_button_element(widget, GuiButtonTypeRight, "More", lfrfid_widget_callback, app); + + string_printf( + tmp_string, + "%s[%s]", + protocol_dict_get_name(app->dict, app->protocol_id), + protocol_dict_get_manufacturer(app->dict, app->protocol_id)); + + widget_add_string_element( + widget, 16, 3, AlignLeft, AlignTop, FontPrimary, string_get_cstr(tmp_string)); + + string_reset(tmp_string); + 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 >= 9) { + string_cat_printf(tmp_string, ".."); + break; + } else { + if(i != 0) { + string_cat_printf(tmp_string, ":"); + } + string_cat_printf(tmp_string, "%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(tmp_string, "\r\n%s", string_get_cstr(render_data)); + string_clear(render_data); + + widget_add_string_multiline_element( + widget, 0, 16, AlignLeft, AlignTop, FontSecondary, string_get_cstr(tmp_string)); + + widget_add_icon_element(app->widget, 0, 0, &I_RFIDSmallChip_14x14); + + notification_message_block(app->notifications, &sequence_set_green_255); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); + string_clear(tmp_string); +} + +bool lfrfid_scene_read_success_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + SceneManager* scene_manager = app->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(scene_manager, LfRfidSceneExitConfirm); + consumed = true; + } else if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == GuiButtonTypeLeft) { + scene_manager_next_scene(scene_manager, LfRfidSceneRetryConfirm); + } else if(event.event == GuiButtonTypeRight) { + scene_manager_next_scene(scene_manager, LfRfidSceneReadKeyMenu); + } + } + + return consumed; +} + +void lfrfid_scene_read_success_on_exit(void* context) { + LfRfid* app = context; + notification_message_block(app->notifications, &sequence_reset_green); + widget_reset(app->widget); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_retry_confirm.c b/applications/lfrfid/scenes/lfrfid_scene_retry_confirm.c new file mode 100644 index 000000000..f639f0ae1 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_retry_confirm.c @@ -0,0 +1,39 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_retry_confirm_on_enter(void* context) { + LfRfid* app = context; + Widget* widget = app->widget; + + widget_add_button_element(widget, GuiButtonTypeLeft, "Exit", lfrfid_widget_callback, app); + widget_add_button_element(widget, GuiButtonTypeRight, "Stay", lfrfid_widget_callback, app); + widget_add_string_element( + widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Return to reading?"); + widget_add_string_element( + widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!"); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); +} + +bool lfrfid_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + SceneManager* scene_manager = app->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + consumed = true; // Ignore Back button presses + } else if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene(scene_manager, LfRfidSceneRead); + } else if(event.event == GuiButtonTypeRight) { + scene_manager_previous_scene(scene_manager); + } + } + + return consumed; +} + +void lfrfid_scene_retry_confirm_on_exit(void* context) { + LfRfid* app = context; + widget_reset(app->widget); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_rpc.c b/applications/lfrfid/scenes/lfrfid_scene_rpc.c new file mode 100644 index 000000000..a69d6453a --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_rpc.c @@ -0,0 +1,67 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_rpc_on_enter(void* context) { + LfRfid* app = context; + Popup* popup = app->popup; + + popup_set_header(popup, "LF RFID", 89, 42, AlignCenter, AlignBottom); + popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); + + notification_message(app->notifications, &sequence_display_backlight_on); + + app->rpc_state = LfRfidRpcStateIdle; +} + +bool lfrfid_scene_rpc_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + Popup* popup = app->popup; + UNUSED(event); + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == LfRfidEventExit) { + rpc_system_app_confirm(app->rpc_ctx, RpcAppEventAppExit, true); + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + } else if(event.event == LfRfidEventRpcSessionClose) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + } else if(event.event == LfRfidEventRpcLoadFile) { + const char* arg = rpc_system_app_get_data(app->rpc_ctx); + bool result = false; + if(arg && (app->rpc_state == LfRfidRpcStateIdle)) { + string_set_str(app->file_path, arg); + if(lfrfid_load_key_data(app, app->file_path, false)) { + lfrfid_worker_start_thread(app->lfworker); + lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id); + app->rpc_state = LfRfidRpcStateEmulating; + + lfrfid_text_store_set(app, "emulating\n%s", string_get_cstr(app->file_name)); + popup_set_text(popup, app->text_store, 89, 44, AlignCenter, AlignTop); + + notification_message(app->notifications, &sequence_blink_start_magenta); + result = true; + } + } + rpc_system_app_confirm(app->rpc_ctx, RpcAppEventLoadFile, result); + } + } + return consumed; +} + +void lfrfid_scene_rpc_on_exit(void* context) { + LfRfid* app = context; + Popup* popup = app->popup; + + if(app->rpc_state == LfRfidRpcStateEmulating) { + lfrfid_worker_stop(app->lfworker); + lfrfid_worker_stop_thread(app->lfworker); + notification_message(app->notifications, &sequence_blink_stop); + } + + popup_reset(popup); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_save_data.c b/applications/lfrfid/scenes/lfrfid_scene_save_data.c new file mode 100644 index 000000000..2ca1bb433 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_save_data.c @@ -0,0 +1,51 @@ +#include "../lfrfid_i.h" +#include + +void lfrfid_scene_save_data_on_enter(void* context) { + LfRfid* app = context; + ByteInput* byte_input = app->byte_input; + + size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); + + bool need_restore = scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveData); + + if(need_restore) { + protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size); + } else { + protocol_dict_get_data(app->dict, app->protocol_id, app->old_key_data, size); + } + + protocol_dict_get_data(app->dict, app->protocol_id, app->new_key_data, size); + + byte_input_set_header_text(byte_input, "Enter the data in hex"); + + byte_input_set_result_callback( + byte_input, lfrfid_text_input_callback, NULL, app, app->new_key_data, size); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewByteInput); +} + +bool lfrfid_scene_save_data_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + SceneManager* scene_manager = app->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == LfRfidEventNext) { + consumed = true; + 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); + scene_manager_next_scene(scene_manager, LfRfidSceneSaveName); + scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 1); + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 0); + } + + return consumed; +} + +void lfrfid_scene_save_data_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_save_name.c b/applications/lfrfid/scenes/lfrfid_scene_save_name.c new file mode 100644 index 000000000..febf30a41 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_save_name.c @@ -0,0 +1,76 @@ +#include "m-string.h" +#include +#include "../lfrfid_i.h" + +void lfrfid_scene_save_name_on_enter(void* context) { + LfRfid* app = context; + TextInput* text_input = app->text_input; + string_t folder_path; + string_init(folder_path); + + bool key_name_is_empty = string_empty_p(app->file_name); + if(key_name_is_empty) { + string_set_str(app->file_path, LFRFID_APP_FOLDER); + set_random_name(app->text_store, LFRFID_TEXT_STORE_SIZE); + string_set_str(folder_path, LFRFID_APP_FOLDER); + } else { + lfrfid_text_store_set(app, "%s", string_get_cstr(app->file_name)); + path_extract_dirname(string_get_cstr(app->file_path), folder_path); + } + + text_input_set_header_text(text_input, "Name the card"); + text_input_set_result_callback( + text_input, + lfrfid_text_input_callback, + app, + app->text_store, + LFRFID_KEY_NAME_SIZE, + key_name_is_empty); + + FURI_LOG_I("", "%s %s", string_get_cstr(folder_path), app->text_store); + + ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( + string_get_cstr(folder_path), LFRFID_APP_EXTENSION, string_get_cstr(app->file_name)); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + + string_clear(folder_path); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewTextInput); +} + +bool lfrfid_scene_save_name_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + SceneManager* scene_manager = app->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == LfRfidEventNext) { + consumed = true; + if(!string_empty_p(app->file_name)) { + lfrfid_delete_key(app); + } + + string_set_str(app->file_name, app->text_store); + + if(lfrfid_save_key(app)) { + scene_manager_next_scene(scene_manager, LfRfidSceneSaveSuccess); + } else { + scene_manager_search_and_switch_to_previous_scene( + scene_manager, LfRfidSceneReadKeyMenu); + } + } + } + + return consumed; +} + +void lfrfid_scene_save_name_on_exit(void* context) { + LfRfid* app = context; + TextInput* text_input = app->text_input; + + void* validator_context = text_input_get_validator_callback_context(text_input); + text_input_set_validator(text_input, NULL, NULL); + validator_is_file_free((ValidatorIsFile*)validator_context); + + text_input_reset(text_input); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_save_success.c b/applications/lfrfid/scenes/lfrfid_scene_save_success.c new file mode 100644 index 000000000..830ef3368 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_save_success.c @@ -0,0 +1,43 @@ +#include "../lfrfid_i.h" +#include + +void lfrfid_scene_save_success_on_enter(void* context) { + LfRfid* app = context; + Popup* popup = app->popup; + + DOLPHIN_DEED(DolphinDeedRfidSave); + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); + popup_set_context(popup, app); + popup_set_callback(popup, lfrfid_popup_timeout_callback); + popup_set_timeout(popup, 1500); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); +} + +bool lfrfid_scene_save_success_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + bool consumed = false; + + const uint32_t prev_scenes[] = {LfRfidSceneReadKeyMenu, LfRfidSceneSelectKey}; + + if((event.type == SceneManagerEventTypeBack) || + ((event.type == SceneManagerEventTypeCustom) && (event.event == LfRfidEventPopupClosed))) { + bool result = scene_manager_search_and_switch_to_previous_scene_one_of( + app->scene_manager, prev_scenes, COUNT_OF(prev_scenes)); + if(!result) { + scene_manager_search_and_switch_to_another_scene( + app->scene_manager, LfRfidSceneSelectKey); + } + consumed = true; + } + + return consumed; +} + +void lfrfid_scene_save_success_on_exit(void* context) { + LfRfid* app = context; + + popup_reset(app->popup); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_save_type.c b/applications/lfrfid/scenes/lfrfid_scene_save_type.c new file mode 100644 index 000000000..827e6d151 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_save_type.c @@ -0,0 +1,87 @@ +#include "../lfrfid_i.h" + +typedef struct { + string_t menu_item_name[LFRFIDProtocolMax]; + uint32_t line_sel; +} SaveTypeCtx; + +static void lfrfid_scene_save_type_submenu_callback(void* context, uint32_t index) { + LfRfid* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void lfrfid_scene_save_type_on_enter(void* context) { + LfRfid* app = context; + Submenu* submenu = app->submenu; + + SaveTypeCtx* state = malloc(sizeof(SaveTypeCtx)); + for(uint8_t i = 0; i < LFRFIDProtocolMax; i++) { + if((strcmp( + protocol_dict_get_manufacturer(app->dict, i), + protocol_dict_get_name(app->dict, i)) != 0) && + (strcmp(protocol_dict_get_manufacturer(app->dict, i), "N/A") != 0)) { + string_init_printf( + state->menu_item_name[i], + "%s %s", + protocol_dict_get_manufacturer(app->dict, i), + protocol_dict_get_name(app->dict, i)); + } else { + string_init_printf( + state->menu_item_name[i], "%s", protocol_dict_get_name(app->dict, i)); + } + submenu_add_item( + submenu, + string_get_cstr(state->menu_item_name[i]), + i, + lfrfid_scene_save_type_submenu_callback, + app); + } + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveType)); + + scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSaveType, (uint32_t)state); + + // clear key name + string_reset(app->file_name); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu); +} + +bool lfrfid_scene_save_type_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + bool consumed = false; + + SaveTypeCtx* state = + (SaveTypeCtx*)scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveType); + furi_check(state); + + if(event.type == SceneManagerEventTypeCustom) { + app->protocol_id = event.event; + state->line_sel = event.event; + scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveData); + consumed = true; + } + + return consumed; +} + +void lfrfid_scene_save_type_on_exit(void* context) { + LfRfid* app = context; + SaveTypeCtx* state = + (SaveTypeCtx*)scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveType); + furi_check(state); + + submenu_reset(app->submenu); + + for(uint8_t i = 0; i < LFRFIDProtocolMax; i++) { + string_clear(state->menu_item_name[i]); + } + + uint32_t line_sel = state->line_sel; + + free(state); + + scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSaveType, line_sel); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_saved_info.c b/applications/lfrfid/scenes/lfrfid_scene_saved_info.c new file mode 100644 index 000000000..7e376ca01 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_saved_info.c @@ -0,0 +1,51 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_saved_info_on_enter(void* context) { + LfRfid* app = context; + Widget* widget = app->widget; + + string_t tmp_string; + string_init(tmp_string); + + string_printf( + tmp_string, + "%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(tmp_string, ":"); + } + + string_cat_printf(tmp_string, "%02X", data[i]); + } + free(data); + + string_t render_data; + string_init(render_data); + protocol_dict_render_data(app->dict, render_data, app->protocol_id); + string_cat_printf(tmp_string, "\r\n%s", string_get_cstr(render_data)); + string_clear(render_data); + + widget_add_string_multiline_element( + widget, 0, 1, AlignLeft, AlignTop, FontSecondary, string_get_cstr(tmp_string)); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget); + string_clear(tmp_string); +} + +bool lfrfid_scene_saved_info_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + bool consumed = false; + return consumed; +} + +void lfrfid_scene_saved_info_on_exit(void* context) { + LfRfid* app = context; + widget_reset(app->widget); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_saved_key_menu.c b/applications/lfrfid/scenes/lfrfid_scene_saved_key_menu.c new file mode 100644 index 000000000..040b31f10 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_saved_key_menu.c @@ -0,0 +1,69 @@ +#include "../lfrfid_i.h" + +typedef enum { + SubmenuIndexEmulate, + SubmenuIndexWrite, + SubmenuIndexEdit, + SubmenuIndexDelete, + SubmenuIndexInfo, +} SubmenuIndex; + +static void lfrfid_scene_saved_key_menu_submenu_callback(void* context, uint32_t index) { + LfRfid* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void lfrfid_scene_saved_key_menu_on_enter(void* context) { + LfRfid* app = context; + Submenu* submenu = app->submenu; + + submenu_add_item( + submenu, "Emulate", SubmenuIndexEmulate, lfrfid_scene_saved_key_menu_submenu_callback, app); + submenu_add_item( + submenu, "Write", SubmenuIndexWrite, lfrfid_scene_saved_key_menu_submenu_callback, app); + submenu_add_item( + submenu, "Edit", SubmenuIndexEdit, lfrfid_scene_saved_key_menu_submenu_callback, app); + submenu_add_item( + submenu, "Delete", SubmenuIndexDelete, lfrfid_scene_saved_key_menu_submenu_callback, app); + submenu_add_item( + submenu, "Info", SubmenuIndexInfo, lfrfid_scene_saved_key_menu_submenu_callback, app); + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSavedKeyMenu)); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu); +} + +bool lfrfid_scene_saved_key_menu_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexEmulate) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); + consumed = true; + } else if(event.event == SubmenuIndexWrite) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite); + consumed = true; + } else if(event.event == SubmenuIndexEdit) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveData); + consumed = true; + } else if(event.event == SubmenuIndexDelete) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneDeleteConfirm); + consumed = true; + } else if(event.event == SubmenuIndexInfo) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneSavedInfo); + consumed = true; + } + scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSavedKeyMenu, event.event); + } + + return consumed; +} + +void lfrfid_scene_saved_key_menu_on_exit(void* context) { + LfRfid* app = context; + + submenu_reset(app->submenu); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_select_key.c b/applications/lfrfid/scenes/lfrfid_scene_select_key.c new file mode 100644 index 000000000..2a9cc1c63 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_select_key.c @@ -0,0 +1,22 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_select_key_on_enter(void* context) { + LfRfid* app = context; + + if(lfrfid_load_key_from_file_select(app)) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneSavedKeyMenu); + } else { + scene_manager_previous_scene(app->scene_manager); + } +} + +bool lfrfid_scene_select_key_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + bool consumed = false; + return consumed; +} + +void lfrfid_scene_select_key_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_start.c b/applications/lfrfid/scenes/lfrfid_scene_start.c new file mode 100644 index 000000000..9074e859b --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_start.c @@ -0,0 +1,72 @@ +#include "../lfrfid_i.h" + +typedef enum { + SubmenuIndexRead, + SubmenuIndexSaved, + SubmenuIndexAddManually, + SubmenuIndexExtraActions, +} SubmenuIndex; + +static void lfrfid_scene_start_submenu_callback(void* context, uint32_t index) { + LfRfid* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void lfrfid_scene_start_on_enter(void* context) { + LfRfid* app = context; + Submenu* submenu = app->submenu; + + submenu_add_item(submenu, "Read", SubmenuIndexRead, lfrfid_scene_start_submenu_callback, app); + submenu_add_item( + submenu, "Saved", SubmenuIndexSaved, lfrfid_scene_start_submenu_callback, app); + submenu_add_item( + submenu, "Add Manually", SubmenuIndexAddManually, lfrfid_scene_start_submenu_callback, app); + submenu_add_item( + submenu, + "Extra Actions", + SubmenuIndexExtraActions, + lfrfid_scene_start_submenu_callback, + app); + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneStart)); + + // clear key + string_reset(app->file_name); + app->protocol_id = PROTOCOL_NO; + app->read_type = LFRFIDWorkerReadTypeAuto; + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu); +} + +bool lfrfid_scene_start_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexRead) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); + consumed = true; + } else if(event.event == SubmenuIndexSaved) { + string_set_str(app->file_path, LFRFID_APP_FOLDER); + scene_manager_next_scene(app->scene_manager, LfRfidSceneSelectKey); + consumed = true; + } else if(event.event == SubmenuIndexAddManually) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveType); + consumed = true; + } else if(event.event == SubmenuIndexExtraActions) { + scene_manager_next_scene(app->scene_manager, LfRfidSceneExtraActions); + consumed = true; + } + scene_manager_set_scene_state(app->scene_manager, LfRfidSceneStart, event.event); + } + + return consumed; +} + +void lfrfid_scene_start_on_exit(void* context) { + LfRfid* app = context; + + submenu_reset(app->submenu); +} diff --git a/applications/lfrfid/scenes/lfrfid_scene_write.c b/applications/lfrfid/scenes/lfrfid_scene_write.c new file mode 100644 index 000000000..4b03bac15 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_write.c @@ -0,0 +1,96 @@ +#include "../lfrfid_i.h" + +static void lfrfid_write_callback(LFRFIDWorkerWriteResult result, void* context) { + LfRfid* app = context; + uint32_t event = 0; + + if(result == LFRFIDWorkerWriteOK) { + event = LfRfidEventWriteOK; + } else if(result == LFRFIDWorkerWriteProtocolCannotBeWritten) { + event = LfRfidEventWriteProtocolCannotBeWritten; + } else if(result == LFRFIDWorkerWriteFobCannotBeWritten) { + event = LfRfidEventWriteFobCannotBeWritten; + } else if(result == LFRFIDWorkerWriteTooLongToWrite) { + event = LfRfidEventWriteTooLongToWrite; + } + + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void lfrfid_scene_write_on_enter(void* context) { + LfRfid* app = context; + Popup* popup = app->popup; + + popup_set_header(popup, "Writing", 89, 30, AlignCenter, AlignTop); + if(!string_empty_p(app->file_name)) { + popup_set_text(popup, string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); + } else { + popup_set_text( + popup, + protocol_dict_get_name(app->dict, app->protocol_id), + 89, + 43, + AlignCenter, + AlignTop); + } + popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); + + 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); + notification_message(app->notifications, &sequence_blink_start_magenta); +} + +bool lfrfid_scene_write_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + Popup* popup = app->popup; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == LfRfidEventWriteOK) { + notification_message(app->notifications, &sequence_success); + scene_manager_next_scene(app->scene_manager, LfRfidSceneWriteSuccess); + consumed = true; + } else if(event.event == LfRfidEventWriteProtocolCannotBeWritten) { + popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48); + popup_set_header(popup, "Error", 64, 3, AlignCenter, AlignTop); + popup_set_text(popup, "This protocol\ncannot be written", 3, 17, AlignLeft, AlignTop); + notification_message(app->notifications, &sequence_blink_start_red); + consumed = true; + } else if( + (event.event == LfRfidEventWriteFobCannotBeWritten) || + (event.event == LfRfidEventWriteTooLongToWrite)) { + popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48); + popup_set_header(popup, "Still trying to write...", 64, 3, AlignCenter, AlignTop); + popup_set_text( + popup, + "Make sure this\ncard is writable\nand not\nprotected.", + 3, + 17, + AlignLeft, + AlignTop); + notification_message(app->notifications, &sequence_blink_start_yellow); + consumed = true; + } + } + + return consumed; +} + +void lfrfid_scene_write_on_exit(void* context) { + LfRfid* app = context; + notification_message(app->notifications, &sequence_blink_stop); + popup_reset(app->popup); + 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/applications/lfrfid/scenes/lfrfid_scene_write_success.c b/applications/lfrfid/scenes/lfrfid_scene_write_success.c new file mode 100644 index 000000000..52e30d6b6 --- /dev/null +++ b/applications/lfrfid/scenes/lfrfid_scene_write_success.c @@ -0,0 +1,38 @@ +#include "../lfrfid_i.h" + +void lfrfid_scene_write_success_on_enter(void* context) { + LfRfid* app = context; + Popup* popup = app->popup; + + popup_set_header(popup, "Successfully\nwritten!", 94, 3, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 6, &I_RFIDDolphinSuccess_108x57); + popup_set_context(popup, app); + popup_set_callback(popup, lfrfid_popup_timeout_callback); + popup_set_timeout(popup, 1500); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); + notification_message_block(app->notifications, &sequence_set_green_255); +} + +bool lfrfid_scene_write_success_on_event(void* context, SceneManagerEvent event) { + LfRfid* app = context; + bool consumed = false; + + const uint32_t prev_scenes[] = {LfRfidSceneReadKeyMenu, LfRfidSceneSelectKey}; + + if((event.type == SceneManagerEventTypeBack) || + ((event.type == SceneManagerEventTypeCustom) && (event.event == LfRfidEventPopupClosed))) { + scene_manager_search_and_switch_to_previous_scene_one_of( + app->scene_manager, prev_scenes, COUNT_OF(prev_scenes)); + consumed = true; + } + + return consumed; +} + +void lfrfid_scene_write_success_on_exit(void* context) { + LfRfid* app = context; + notification_message_block(app->notifications, &sequence_reset_green); + popup_reset(app->popup); +} diff --git a/applications/lfrfid/view/container_vm.cpp b/applications/lfrfid/view/container_vm.cpp deleted file mode 100644 index 3c01ba304..000000000 --- a/applications/lfrfid/view/container_vm.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "container_vm.h" -#include "elements/generic_element.h" -#include "elements/string_element.h" -#include "elements/icon_element.h" -#include "elements/button_element.h" -#include - -class ContainerVMData { -public: - ContainerVMData(){}; - - ~ContainerVMData() { - for(auto& it : elements) delete it; - }; - - std::list elements; - - template T add(const T element, View* view) { - elements.push_back(element); - element->set_parent_view(view); - return element; - } - - void clean() { - for(auto& it : elements) delete it; - elements.clear(); - } -}; - -struct ContainerVMModel { - ContainerVMData* data; -}; - -ContainerVM::ContainerVM() { - view = view_alloc(); - view_set_context(view, this); - view_allocate_model(view, ViewModelTypeLocking, sizeof(ContainerVMModel)); - - with_view_model_cpp(view, ContainerVMModel, model, { - model->data = new ContainerVMData(); - return true; - }); - - view_set_draw_callback(view, view_draw_callback); - view_set_input_callback(view, view_input_callback); -} - -ContainerVM::~ContainerVM() { - with_view_model_cpp(view, ContainerVMModel, model, { - delete model->data; - model->data = NULL; - return false; - }); - - view_free(view); -} - -View* ContainerVM::get_view() { - return view; -} - -void ContainerVM::clean() { - with_view_model_cpp(view, ContainerVMModel, model, { - model->data->clean(); - return true; - }); -} - -template T* ContainerVM::add() { - T* element = new T(); - - with_view_model_cpp(view, ContainerVMModel, model, { - model->data->add(element, view); - return true; - }); - - return element; -} - -void ContainerVM::view_draw_callback(Canvas* canvas, void* model) { - ContainerVMData* data = static_cast(model)->data; - - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontPrimary); - - for(const auto& element : data->elements) { - element->draw(canvas); - } -} - -bool ContainerVM::view_input_callback(InputEvent* event, void* context) { - bool consumed = false; - View* view = static_cast(context)->view; - - with_view_model_cpp(view, ContainerVMModel, model, { - for(const auto& element : model->data->elements) { - if(element->input(event)) { - consumed = true; - } - - if(consumed) { - break; - } - } - - return consumed; - }); - - return consumed; -} - -template StringElement* ContainerVM::add(); -template IconElement* ContainerVM::add(); -template ButtonElement* ContainerVM::add(); diff --git a/applications/lfrfid/view/container_vm.h b/applications/lfrfid/view/container_vm.h deleted file mode 100644 index 011baa2e9..000000000 --- a/applications/lfrfid/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/lfrfid/view/elements/button_element.cpp b/applications/lfrfid/view/elements/button_element.cpp deleted file mode 100644 index 58e1ac3e1..000000000 --- a/applications/lfrfid/view/elements/button_element.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "button_element.h" -#include - -ButtonElement::ButtonElement() { -} - -ButtonElement::~ButtonElement() { -} - -void ButtonElement::draw(Canvas* canvas) { - if(text != nullptr) { - canvas_set_font(canvas, FontSecondary); - switch(type) { - case Type::Left: - elements_button_left(canvas, text); - break; - case Type::Center: - elements_button_center(canvas, text); - break; - case Type::Right: - elements_button_right(canvas, text); - break; - } - } -} - -bool ButtonElement::input(InputEvent* event) { - bool consumed = false; - if(event->type == InputTypeShort && callback != nullptr) { - switch(type) { - case Type::Left: - if(event->key == InputKeyLeft) { - callback(context); - consumed = true; - } - break; - case Type::Center: - if(event->key == InputKeyOk) { - callback(context); - consumed = true; - } - break; - case Type::Right: - if(event->key == InputKeyRight) { - callback(context); - consumed = true; - } - break; - } - } - - return consumed; -} - -void ButtonElement::set_type(Type _type, const char* _text) { - lock_model(); - type = _type; - text = _text; - unlock_model(true); -} - -void ButtonElement::set_callback(void* _context, ButtonElementCallback _callback) { - context = _context; - callback = _callback; -} diff --git a/applications/lfrfid/view/elements/button_element.h b/applications/lfrfid/view/elements/button_element.h deleted file mode 100644 index eb9644277..000000000 --- a/applications/lfrfid/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/lfrfid/view/elements/generic_element.cpp b/applications/lfrfid/view/elements/generic_element.cpp deleted file mode 100644 index e0f08d15c..000000000 --- a/applications/lfrfid/view/elements/generic_element.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "generic_element.h" - -void GenericElement::lock_model() { - furi_assert(view != nullptr); - view_get_model(view); -} - -void GenericElement::unlock_model(bool need_redraw) { - furi_assert(view != nullptr); - view_commit_model(view, need_redraw); -} - -void GenericElement::set_parent_view(View* _view) { - view = _view; -} diff --git a/applications/lfrfid/view/elements/generic_element.h b/applications/lfrfid/view/elements/generic_element.h deleted file mode 100644 index f5a58b2d9..000000000 --- a/applications/lfrfid/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/lfrfid/view/elements/icon_element.cpp b/applications/lfrfid/view/elements/icon_element.cpp deleted file mode 100644 index 0b6fba7da..000000000 --- a/applications/lfrfid/view/elements/icon_element.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "icon_element.h" - -IconElement::IconElement() { -} - -IconElement::~IconElement() { -} - -void IconElement::draw(Canvas* canvas) { - if(icon != NULL) { - canvas_draw_icon(canvas, x, y, icon); - } -} - -bool IconElement::input(InputEvent* /* event */) { - return false; -} - -void IconElement::set_icon(uint8_t _x, uint8_t _y, const Icon* _icon) { - lock_model(); - icon = _icon; - x = _x; - y = _y; - unlock_model(true); -} diff --git a/applications/lfrfid/view/elements/icon_element.h b/applications/lfrfid/view/elements/icon_element.h deleted file mode 100644 index a08202741..000000000 --- a/applications/lfrfid/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/lfrfid/view/elements/string_element.cpp b/applications/lfrfid/view/elements/string_element.cpp deleted file mode 100644 index 44c11e01a..000000000 --- a/applications/lfrfid/view/elements/string_element.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "string_element.h" -#include - -StringElement::StringElement() { -} - -StringElement::~StringElement() { -} - -void StringElement::draw(Canvas* canvas) { - if(text) { - string_t line; - string_init(line); - string_set_str(line, text); - - canvas_set_font(canvas, font); - if(fit_width != 0) { - elements_string_fit_width(canvas, line, fit_width); - } - elements_multiline_text_aligned(canvas, x, y, horizontal, vertical, string_get_cstr(line)); - - string_clear(line); - } -} - -bool StringElement::input(InputEvent* /* event */) { - return false; -} - -void StringElement::set_text( - const char* _text, - uint8_t _x, - uint8_t _y, - uint8_t _fit_w, - Align _horizontal, - Align _vertical, - Font _font) { - lock_model(); - text = _text; - x = _x; - y = _y; - fit_width = _fit_w; - horizontal = _horizontal; - vertical = _vertical; - font = _font; - unlock_model(true); -} diff --git a/applications/lfrfid/view/elements/string_element.h b/applications/lfrfid/view/elements/string_element.h deleted file mode 100644 index 173fdd601..000000000 --- a/applications/lfrfid/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/lfrfid/views/lfrfid_view_read.c b/applications/lfrfid/views/lfrfid_view_read.c new file mode 100644 index 000000000..2b63175da --- /dev/null +++ b/applications/lfrfid/views/lfrfid_view_read.c @@ -0,0 +1,117 @@ +#include "lfrfid_view_read.h" +#include + +#define TEMP_STR_LEN 128 + +struct LfRfidReadView { + View* view; +}; + +typedef struct { + IconAnimation* icon; + LfRfidReadViewMode read_mode; +} LfRfidReadViewModel; + +static void lfrfid_view_read_draw_callback(Canvas* canvas, void* _model) { + LfRfidReadViewModel* model = _model; + canvas_set_color(canvas, ColorBlack); + + canvas_draw_icon(canvas, 0, 8, &I_NFC_manual); + + canvas_set_font(canvas, FontPrimary); + + if(model->read_mode == LfRfidReadAsk) { + canvas_draw_str(canvas, 70, 16, "Reading 1/2"); + + canvas_draw_str(canvas, 77, 29, "ASK"); + canvas_draw_icon(canvas, 70, 22, &I_ButtonRight_4x7); + canvas_draw_icon_animation(canvas, 102, 21, model->icon); + + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 77, 43, "PSK"); + } else if(model->read_mode == LfRfidReadPsk) { + canvas_draw_str(canvas, 70, 16, "Reading 2/2"); + + canvas_draw_str(canvas, 77, 43, "PSK"); + canvas_draw_icon(canvas, 70, 36, &I_ButtonRight_4x7); + canvas_draw_icon_animation(canvas, 102, 35, model->icon); + + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 77, 29, "ASK"); + } else { + canvas_draw_str(canvas, 72, 16, "Reading"); + + if(model->read_mode == LfRfidReadAskOnly) { + canvas_draw_str(canvas, 77, 35, "ASK"); + } else { + canvas_draw_str(canvas, 77, 35, "PSK"); + } + canvas_draw_icon_animation(canvas, 102, 27, model->icon); + } + + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 61, 56, "Don't move card"); +} + +void lfrfid_view_read_enter(void* context) { + LfRfidReadView* read_view = context; + with_view_model( + read_view->view, (LfRfidReadViewModel * model) { + icon_animation_start(model->icon); + return true; + }); +} + +void lfrfid_view_read_exit(void* context) { + LfRfidReadView* read_view = context; + with_view_model( + read_view->view, (LfRfidReadViewModel * model) { + icon_animation_stop(model->icon); + return false; + }); +} + +LfRfidReadView* lfrfid_view_read_alloc() { + LfRfidReadView* read_view = malloc(sizeof(LfRfidReadView)); + read_view->view = view_alloc(); + view_set_context(read_view->view, read_view); + view_allocate_model(read_view->view, ViewModelTypeLocking, sizeof(LfRfidReadViewModel)); + + with_view_model( + read_view->view, (LfRfidReadViewModel * model) { + model->icon = icon_animation_alloc(&A_Round_loader_8x8); + view_tie_icon_animation(read_view->view, model->icon); + return false; + }); + + view_set_draw_callback(read_view->view, lfrfid_view_read_draw_callback); + view_set_enter_callback(read_view->view, lfrfid_view_read_enter); + view_set_exit_callback(read_view->view, lfrfid_view_read_exit); + + return read_view; +} + +void lfrfid_view_read_free(LfRfidReadView* read_view) { + with_view_model( + read_view->view, (LfRfidReadViewModel * model) { + icon_animation_free(model->icon); + return false; + }); + + view_free(read_view->view); + free(read_view); +} + +View* lfrfid_view_read_get_view(LfRfidReadView* read_view) { + return read_view->view; +} + +void lfrfid_view_read_set_read_mode(LfRfidReadView* read_view, LfRfidReadViewMode mode) { + with_view_model( + read_view->view, (LfRfidReadViewModel * model) { + icon_animation_stop(model->icon); + icon_animation_start(model->icon); + model->read_mode = mode; + return true; + }); +} diff --git a/applications/lfrfid/views/lfrfid_view_read.h b/applications/lfrfid/views/lfrfid_view_read.h new file mode 100644 index 000000000..55bb1f230 --- /dev/null +++ b/applications/lfrfid/views/lfrfid_view_read.h @@ -0,0 +1,19 @@ +#pragma once +#include + +typedef enum { + LfRfidReadAsk, + LfRfidReadPsk, + LfRfidReadAskOnly, + LfRfidReadPskOnly +} LfRfidReadViewMode; + +typedef struct LfRfidReadView LfRfidReadView; + +LfRfidReadView* lfrfid_view_read_alloc(); + +void lfrfid_view_read_free(LfRfidReadView* read_view); + +View* lfrfid_view_read_get_view(LfRfidReadView* read_view); + +void lfrfid_view_read_set_read_mode(LfRfidReadView* read_view, LfRfidReadViewMode mode); diff --git a/applications/lfrfid_debug/lfrfid_debug.c b/applications/lfrfid_debug/lfrfid_debug.c new file mode 100644 index 000000000..63d66b68b --- /dev/null +++ b/applications/lfrfid_debug/lfrfid_debug.c @@ -0,0 +1,81 @@ +#include "lfrfid_debug_i.h" + +static bool lfrfid_debug_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + LfRfidDebug* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +static bool lfrfid_debug_back_event_callback(void* context) { + furi_assert(context); + LfRfidDebug* app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +static LfRfidDebug* lfrfid_debug_alloc() { + LfRfidDebug* app = malloc(sizeof(LfRfidDebug)); + + app->view_dispatcher = view_dispatcher_alloc(); + app->scene_manager = scene_manager_alloc(&lfrfid_debug_scene_handlers, app); + view_dispatcher_enable_queue(app->view_dispatcher); + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + view_dispatcher_set_custom_event_callback( + app->view_dispatcher, lfrfid_debug_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, lfrfid_debug_back_event_callback); + + // Open GUI record + app->gui = furi_record_open(RECORD_GUI); + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + + // Submenu + app->submenu = submenu_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, LfRfidDebugViewSubmenu, submenu_get_view(app->submenu)); + + // Tune view + app->tune_view = lfrfid_debug_view_tune_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + LfRfidDebugViewTune, + lfrfid_debug_view_tune_get_view(app->tune_view)); + + return app; +} + +static void lfrfid_debug_free(LfRfidDebug* app) { + furi_assert(app); + + // Submenu + view_dispatcher_remove_view(app->view_dispatcher, LfRfidDebugViewSubmenu); + submenu_free(app->submenu); + + // Tune view + view_dispatcher_remove_view(app->view_dispatcher, LfRfidDebugViewTune); + lfrfid_debug_view_tune_free(app->tune_view); + + // View Dispatcher + view_dispatcher_free(app->view_dispatcher); + + // Scene Manager + scene_manager_free(app->scene_manager); + + // GUI + furi_record_close(RECORD_GUI); + app->gui = NULL; + + free(app); +} + +int32_t lfrfid_debug_app(void* p) { + UNUSED(p); + LfRfidDebug* app = lfrfid_debug_alloc(); + + scene_manager_next_scene(app->scene_manager, LfRfidDebugSceneStart); + + view_dispatcher_run(app->view_dispatcher); + + lfrfid_debug_free(app); + + return 0; +} \ No newline at end of file diff --git a/applications/lfrfid_debug/lfrfid_debug_app.cpp b/applications/lfrfid_debug/lfrfid_debug_app.cpp deleted file mode 100644 index ef970e361..000000000 --- a/applications/lfrfid_debug/lfrfid_debug_app.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "lfrfid_debug_app.h" -#include "scene/lfrfid_debug_app_scene_start.h" -#include "scene/lfrfid_debug_app_scene_tune.h" - -LfRfidDebugApp::LfRfidDebugApp() - : scene_controller{this} { -} - -LfRfidDebugApp::~LfRfidDebugApp() { -} - -void LfRfidDebugApp::run() { - view_controller.attach_to_gui(ViewDispatcherTypeFullscreen); - scene_controller.add_scene(SceneType::Start, new LfRfidDebugAppSceneStart()); - scene_controller.add_scene(SceneType::TuneScene, new LfRfidDebugAppSceneTune()); - scene_controller.process(100); -} diff --git a/applications/lfrfid_debug/lfrfid_debug_app.h b/applications/lfrfid_debug/lfrfid_debug_app.h deleted file mode 100644 index fee183aec..000000000 --- a/applications/lfrfid_debug/lfrfid_debug_app.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include -#include - -#include -#include -#include - -#include -#include "view_modules/lfrfid_view_tune_vm.h" - -class LfRfidDebugApp { -public: - enum class EventType : uint8_t { - GENERIC_EVENT_ENUM_VALUES, - MenuSelected, - }; - - enum class SceneType : uint8_t { - GENERIC_SCENE_ENUM_VALUES, - TuneScene, - }; - - class Event { - public: - union { - int32_t menu_index; - } payload; - - EventType type; - }; - - SceneController, LfRfidDebugApp> scene_controller; - ViewController view_controller; - - ~LfRfidDebugApp(); - LfRfidDebugApp(); - - void run(); -}; diff --git a/applications/lfrfid_debug/lfrfid_debug_app_launcher.cpp b/applications/lfrfid_debug/lfrfid_debug_app_launcher.cpp deleted file mode 100644 index 4551a17cb..000000000 --- a/applications/lfrfid_debug/lfrfid_debug_app_launcher.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "lfrfid_debug_app.h" - -// app enter function -extern "C" int32_t lfrfid_debug_app(void* p) { - UNUSED(p); - LfRfidDebugApp* app = new LfRfidDebugApp(); - app->run(); - delete app; - - return 0; -} diff --git a/applications/lfrfid_debug/lfrfid_debug_i.h b/applications/lfrfid_debug/lfrfid_debug_i.h new file mode 100644 index 000000000..368f1f158 --- /dev/null +++ b/applications/lfrfid_debug/lfrfid_debug_i.h @@ -0,0 +1,31 @@ +#pragma once +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include + +typedef struct LfRfidDebug LfRfidDebug; + +struct LfRfidDebug { + Gui* gui; + ViewDispatcher* view_dispatcher; + SceneManager* scene_manager; + + // Common Views + Submenu* submenu; + LfRfidTuneView* tune_view; +}; + +typedef enum { + LfRfidDebugViewSubmenu, + LfRfidDebugViewTune, +} LfRfidDebugView; diff --git a/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_start.cpp b/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_start.cpp deleted file mode 100644 index 873e152a1..000000000 --- a/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_start.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "lfrfid_debug_app_scene_start.h" - -typedef enum { - SubmenuTune, -} SubmenuIndex; - -void LfRfidDebugAppSceneStart::on_enter(LfRfidDebugApp* app, bool need_restore) { - auto submenu = app->view_controller.get(); - auto callback = cbc::obtain_connector(this, &LfRfidDebugAppSceneStart::submenu_callback); - - submenu->add_item("Tune", SubmenuTune, callback, app); - - if(need_restore) { - submenu->set_selected_item(submenu_item_selected); - } - app->view_controller.switch_to(); -} - -bool LfRfidDebugAppSceneStart::on_event(LfRfidDebugApp* app, LfRfidDebugApp::Event* event) { - bool consumed = false; - - if(event->type == LfRfidDebugApp::EventType::MenuSelected) { - submenu_item_selected = event->payload.menu_index; - switch(event->payload.menu_index) { - case SubmenuTune: - app->scene_controller.switch_to_next_scene(LfRfidDebugApp::SceneType::TuneScene); - break; - } - consumed = true; - } - - return consumed; -} - -void LfRfidDebugAppSceneStart::on_exit(LfRfidDebugApp* app) { - app->view_controller.get()->clean(); -} - -void LfRfidDebugAppSceneStart::submenu_callback(void* context, uint32_t index) { - LfRfidDebugApp* app = static_cast(context); - LfRfidDebugApp::Event event; - - event.type = LfRfidDebugApp::EventType::MenuSelected; - event.payload.menu_index = index; - - app->view_controller.send_event(&event); -} diff --git a/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_start.h b/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_start.h deleted file mode 100644 index 7fc0b07d9..000000000 --- a/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_start.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "../lfrfid_debug_app.h" - -class LfRfidDebugAppSceneStart : public GenericScene { -public: - void on_enter(LfRfidDebugApp* app, bool need_restore) final; - bool on_event(LfRfidDebugApp* app, LfRfidDebugApp::Event* event) final; - void on_exit(LfRfidDebugApp* app) final; - -private: - void submenu_callback(void* context, uint32_t index); - uint32_t submenu_item_selected = 0; -}; diff --git a/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_tune.h b/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_tune.h deleted file mode 100644 index 53399efc9..000000000 --- a/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_tune.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "../lfrfid_debug_app.h" - -class LfRfidDebugAppSceneTune : public GenericScene { -public: - void on_enter(LfRfidDebugApp* app, bool need_restore) final; - bool on_event(LfRfidDebugApp* app, LfRfidDebugApp::Event* event) final; - void on_exit(LfRfidDebugApp* app) final; -}; diff --git a/applications/lfrfid_debug/scenes/lfrfid_debug_app_scene_start.c b/applications/lfrfid_debug/scenes/lfrfid_debug_app_scene_start.c new file mode 100644 index 000000000..2fc6706e3 --- /dev/null +++ b/applications/lfrfid_debug/scenes/lfrfid_debug_app_scene_start.c @@ -0,0 +1,44 @@ +#include "../lfrfid_debug_i.h" + +typedef enum { + SubmenuIndexTune, +} SubmenuIndex; + +static void lfrfid_debug_scene_start_submenu_callback(void* context, uint32_t index) { + LfRfidDebug* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void lfrfid_debug_scene_start_on_enter(void* context) { + LfRfidDebug* app = context; + Submenu* submenu = app->submenu; + + submenu_add_item( + submenu, "Tune", SubmenuIndexTune, lfrfid_debug_scene_start_submenu_callback, app); + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidDebugSceneStart)); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidDebugViewSubmenu); +} + +bool lfrfid_debug_scene_start_on_event(void* context, SceneManagerEvent event) { + LfRfidDebug* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexTune) { + scene_manager_next_scene(app->scene_manager, LfRfidDebugSceneTune); + consumed = true; + } + } + + return consumed; +} + +void lfrfid_debug_scene_start_on_exit(void* context) { + LfRfidDebug* app = context; + + submenu_reset(app->submenu); +} diff --git a/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_tune.cpp b/applications/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c similarity index 53% rename from applications/lfrfid_debug/scene/lfrfid_debug_app_scene_tune.cpp rename to applications/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c index 4b6276497..c7f3bf24f 100644 --- a/applications/lfrfid_debug/scene/lfrfid_debug_app_scene_tune.cpp +++ b/applications/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c @@ -1,4 +1,4 @@ -#include "lfrfid_debug_app_scene_tune.h" +#include "../lfrfid_debug_i.h" #include static void comparator_trigger_callback(bool level, void* comp_ctx) { @@ -6,32 +6,38 @@ static void comparator_trigger_callback(bool level, void* comp_ctx) { furi_hal_gpio_write(&gpio_ext_pa7, !level); } -void LfRfidDebugAppSceneTune::on_enter(LfRfidDebugApp* app, bool /* need_restore */) { - app->view_controller.switch_to(); +void lfrfid_debug_scene_tune_on_enter(void* context) { + LfRfidDebug* app = context; + furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeOutputPushPull); - furi_hal_rfid_comp_set_callback(comparator_trigger_callback, this); + furi_hal_rfid_comp_set_callback(comparator_trigger_callback, app); furi_hal_rfid_comp_start(); furi_hal_rfid_pins_read(); furi_hal_rfid_tim_read(125000, 0.5); furi_hal_rfid_tim_read_start(); + + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidDebugViewTune); } -bool LfRfidDebugAppSceneTune::on_event(LfRfidDebugApp* app, LfRfidDebugApp::Event* /* event */) { +bool lfrfid_debug_scene_tune_on_event(void* context, SceneManagerEvent event) { + UNUSED(event); + + LfRfidDebug* app = context; bool consumed = false; - LfRfidViewTuneVM* tune = app->view_controller; - - if(tune->is_dirty()) { - furi_hal_rfid_set_read_period(tune->get_ARR()); - furi_hal_rfid_set_read_pulse(tune->get_CCR()); + if(lfrfid_debug_view_tune_is_dirty(app->tune_view)) { + furi_hal_rfid_set_read_period(lfrfid_debug_view_tune_get_arr(app->tune_view)); + furi_hal_rfid_set_read_pulse(lfrfid_debug_view_tune_get_ccr(app->tune_view)); } return consumed; } -void LfRfidDebugAppSceneTune::on_exit(LfRfidDebugApp* /* app */) { +void lfrfid_debug_scene_tune_on_exit(void* context) { + UNUSED(context); + furi_hal_rfid_comp_stop(); furi_hal_rfid_comp_set_callback(NULL, NULL); diff --git a/applications/lfrfid_debug/scenes/lfrfid_debug_scene.c b/applications/lfrfid_debug/scenes/lfrfid_debug_scene.c new file mode 100644 index 000000000..e6288e923 --- /dev/null +++ b/applications/lfrfid_debug/scenes/lfrfid_debug_scene.c @@ -0,0 +1,30 @@ +#include "lfrfid_debug_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const lfrfid_debug_on_enter_handlers[])(void*) = { +#include "lfrfid_debug_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const lfrfid_debug_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "lfrfid_debug_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const lfrfid_debug_on_exit_handlers[])(void* context) = { +#include "lfrfid_debug_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers lfrfid_debug_scene_handlers = { + .on_enter_handlers = lfrfid_debug_on_enter_handlers, + .on_event_handlers = lfrfid_debug_on_event_handlers, + .on_exit_handlers = lfrfid_debug_on_exit_handlers, + .scene_num = LfRfidDebugSceneNum, +}; diff --git a/applications/lfrfid_debug/scenes/lfrfid_debug_scene.h b/applications/lfrfid_debug/scenes/lfrfid_debug_scene.h new file mode 100644 index 000000000..8fc74f724 --- /dev/null +++ b/applications/lfrfid_debug/scenes/lfrfid_debug_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) LfRfidDebugScene##id, +typedef enum { +#include "lfrfid_debug_scene_config.h" + LfRfidDebugSceneNum, +} LfRfidDebugScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers lfrfid_debug_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "lfrfid_debug_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "lfrfid_debug_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "lfrfid_debug_scene_config.h" +#undef ADD_SCENE diff --git a/applications/lfrfid_debug/scenes/lfrfid_debug_scene_config.h b/applications/lfrfid_debug/scenes/lfrfid_debug_scene_config.h new file mode 100644 index 000000000..f3cca47b8 --- /dev/null +++ b/applications/lfrfid_debug/scenes/lfrfid_debug_scene_config.h @@ -0,0 +1,2 @@ +ADD_SCENE(lfrfid_debug, start, Start) +ADD_SCENE(lfrfid_debug, tune, Tune) diff --git a/applications/lfrfid_debug/view_modules/lfrfid_view_tune_vm.cpp b/applications/lfrfid_debug/view_modules/lfrfid_view_tune_vm.cpp deleted file mode 100644 index 5c244b92c..000000000 --- a/applications/lfrfid_debug/view_modules/lfrfid_view_tune_vm.cpp +++ /dev/null @@ -1,214 +0,0 @@ -#include "lfrfid_view_tune_vm.h" -#include -#include - -struct LfRfidViewTuneVMModel { - bool dirty; - bool fine; - uint32_t ARR; - uint32_t CCR; - int pos; -}; - -void LfRfidViewTuneVM::view_draw_callback(Canvas* canvas, void* _model) { - LfRfidViewTuneVMModel* model = reinterpret_cast(_model); - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - - if(model->fine) { - canvas_draw_box( - canvas, - 128 - canvas_string_width(canvas, "Fine") - 4, - 0, - canvas_string_width(canvas, "Fine") + 4, - canvas_current_font_height(canvas) + 1); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_str_aligned(canvas, 128 - 2, 2, AlignRight, AlignTop, "Fine"); - canvas_set_color(canvas, ColorBlack); - - constexpr uint8_t buffer_size = 128; - char buffer[buffer_size + 1]; - double freq = ((float)SystemCoreClock / ((float)model->ARR + 1)); - double duty = ((float)model->CCR + 1) / ((float)model->ARR + 1) * 100.0f; - snprintf( - buffer, - buffer_size, - "%sARR: %lu\n" - "freq = %.4f\n" - "%sCCR: %lu\n" - "duty = %.4f", - model->pos == 0 ? ">" : "", - model->ARR, - freq, - model->pos == 1 ? ">" : "", - model->CCR, - duty); - elements_multiline_text_aligned(canvas, 2, 2, AlignLeft, AlignTop, buffer); -} - -bool LfRfidViewTuneVM::view_input_callback(InputEvent* event, void* context) { - LfRfidViewTuneVM* _this = reinterpret_cast(context); - bool consumed = false; - - // Process key presses only - if(event->type == InputTypeShort || event->type == InputTypeRepeat) { - consumed = true; - - switch(event->key) { - case InputKeyLeft: - _this->button_left(); - break; - case InputKeyRight: - _this->button_right(); - break; - case InputKeyUp: - _this->button_up(); - break; - case InputKeyDown: - _this->button_down(); - break; - case InputKeyOk: - _this->button_ok(); - break; - default: - consumed = false; - break; - } - } - - return consumed; -} - -void LfRfidViewTuneVM::button_up() { - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - if(model->pos > 0) model->pos--; - return true; - }); -} - -void LfRfidViewTuneVM::button_down() { - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - if(model->pos < 1) model->pos++; - return true; - }); -} - -void LfRfidViewTuneVM::button_left() { - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - if(model->pos == 0) { - if(model->fine) { - model->ARR -= 1; - } else { - model->ARR -= 10; - } - } else if(model->pos == 1) { - if(model->fine) { - model->CCR -= 1; - } else { - model->CCR -= 10; - } - } - - model->dirty = true; - return true; - }); -} - -void LfRfidViewTuneVM::button_right() { - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - if(model->pos == 0) { - if(model->fine) { - model->ARR += 1; - } else { - model->ARR += 10; - } - } else if(model->pos == 1) { - if(model->fine) { - model->CCR += 1; - } else { - model->CCR += 10; - } - } - - model->dirty = true; - return true; - }); -} - -void LfRfidViewTuneVM::button_ok() { - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - model->fine = !model->fine; - return true; - }); -} - -LfRfidViewTuneVM::LfRfidViewTuneVM() { - view = view_alloc(); - view_set_context(view, this); - view_allocate_model(view, ViewModelTypeLocking, sizeof(LfRfidViewTuneVMModel)); - - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - model->dirty = true; - model->fine = false; - model->ARR = 511; - model->CCR = 255; - model->pos = 0; - return true; - }); - - view_set_draw_callback( - view, cbc::obtain_connector(this, &LfRfidViewTuneVM::view_draw_callback)); - view_set_input_callback( - view, cbc::obtain_connector(this, &LfRfidViewTuneVM::view_input_callback)); -} - -LfRfidViewTuneVM::~LfRfidViewTuneVM() { - view_free(view); -} - -View* LfRfidViewTuneVM::get_view() { - return view; -} - -void LfRfidViewTuneVM::clean() { - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - model->dirty = true; - model->fine = false; - model->ARR = 511; - model->CCR = 255; - model->pos = 0; - return true; - }); -} - -bool LfRfidViewTuneVM::is_dirty() { - bool result; - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - result = model->dirty; - model->dirty = false; - return false; - }); - - return result; -} - -uint32_t LfRfidViewTuneVM::get_ARR() { - uint32_t result; - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - result = model->ARR; - return false; - }); - - return result; -} - -uint32_t LfRfidViewTuneVM::get_CCR() { - uint32_t result; - with_view_model_cpp(view, LfRfidViewTuneVMModel, model, { - result = model->CCR; - return false; - }); - - return result; -} diff --git a/applications/lfrfid_debug/view_modules/lfrfid_view_tune_vm.h b/applications/lfrfid_debug/view_modules/lfrfid_view_tune_vm.h deleted file mode 100644 index 7fb185654..000000000 --- a/applications/lfrfid_debug/view_modules/lfrfid_view_tune_vm.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include -#include - -class LfRfidViewTuneVM : public GenericViewModule { -public: - LfRfidViewTuneVM(); - ~LfRfidViewTuneVM() final; - View* get_view() final; - void clean() final; - - bool is_dirty(); - uint32_t get_ARR(); - uint32_t get_CCR(); - -private: - View* view; - void view_draw_callback(Canvas* canvas, void* _model); - bool view_input_callback(InputEvent* event, void* context); - - void button_up(); - void button_down(); - void button_left(); - void button_right(); - void button_ok(); -}; diff --git a/applications/lfrfid_debug/views/lfrfid_debug_view_tune.c b/applications/lfrfid_debug/views/lfrfid_debug_view_tune.c new file mode 100644 index 000000000..38fe36036 --- /dev/null +++ b/applications/lfrfid_debug/views/lfrfid_debug_view_tune.c @@ -0,0 +1,229 @@ +#include "lfrfid_debug_view_tune.h" +#include + +#define TEMP_STR_LEN 128 + +struct LfRfidTuneView { + View* view; +}; + +typedef struct { + bool dirty; + bool fine; + uint32_t ARR; + uint32_t CCR; + int pos; +} LfRfidTuneViewModel; + +static void lfrfid_debug_view_tune_draw_callback(Canvas* canvas, void* _model) { + LfRfidTuneViewModel* model = _model; + canvas_set_color(canvas, ColorBlack); + + if(model->fine) { + canvas_draw_box( + canvas, + 128 - canvas_string_width(canvas, "Fine") - 4, + 0, + canvas_string_width(canvas, "Fine") + 4, + canvas_current_font_height(canvas) + 1); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_str_aligned(canvas, 128 - 2, 2, AlignRight, AlignTop, "Fine"); + canvas_set_color(canvas, ColorBlack); + + char buffer[TEMP_STR_LEN + 1]; + double freq = ((float)SystemCoreClock / ((float)model->ARR + 1)); + double duty = ((float)model->CCR + 1) / ((float)model->ARR + 1) * 100.0f; + snprintf( + buffer, + TEMP_STR_LEN, + "%sARR: %lu\n" + "freq = %.4f\n" + "%sCCR: %lu\n" + "duty = %.4f", + model->pos == 0 ? ">" : "", + model->ARR, + freq, + model->pos == 1 ? ">" : "", + model->CCR, + duty); + elements_multiline_text_aligned(canvas, 2, 2, AlignLeft, AlignTop, buffer); +} + +static void lfrfid_debug_view_tune_button_up(LfRfidTuneView* tune_view) { + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + if(model->pos > 0) model->pos--; + return true; + }); +} + +static void lfrfid_debug_view_tune_button_down(LfRfidTuneView* tune_view) { + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + if(model->pos < 1) model->pos++; + return true; + }); +} + +static void lfrfid_debug_view_tune_button_left(LfRfidTuneView* tune_view) { + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + if(model->pos == 0) { + if(model->fine) { + model->ARR -= 1; + } else { + model->ARR -= 10; + } + } else if(model->pos == 1) { + if(model->fine) { + model->CCR -= 1; + } else { + model->CCR -= 10; + } + } + + model->dirty = true; + return true; + }); +} + +static void lfrfid_debug_view_tune_button_right(LfRfidTuneView* tune_view) { + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + if(model->pos == 0) { + if(model->fine) { + model->ARR += 1; + } else { + model->ARR += 10; + } + } else if(model->pos == 1) { + if(model->fine) { + model->CCR += 1; + } else { + model->CCR += 10; + } + } + + model->dirty = true; + return true; + }); +} + +static void lfrfid_debug_view_tune_button_ok(LfRfidTuneView* tune_view) { + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + model->fine = !model->fine; + return true; + }); +} + +static bool lfrfid_debug_view_tune_input_callback(InputEvent* event, void* context) { + LfRfidTuneView* tune_view = context; + bool consumed = false; + + // Process key presses only + if(event->type == InputTypeShort || event->type == InputTypeRepeat) { + consumed = true; + + switch(event->key) { + case InputKeyLeft: + lfrfid_debug_view_tune_button_left(tune_view); + break; + case InputKeyRight: + lfrfid_debug_view_tune_button_right(tune_view); + break; + case InputKeyUp: + lfrfid_debug_view_tune_button_up(tune_view); + break; + case InputKeyDown: + lfrfid_debug_view_tune_button_down(tune_view); + break; + case InputKeyOk: + lfrfid_debug_view_tune_button_ok(tune_view); + break; + default: + consumed = false; + break; + } + } + + return consumed; +} + +LfRfidTuneView* lfrfid_debug_view_tune_alloc() { + LfRfidTuneView* tune_view = malloc(sizeof(LfRfidTuneView)); + tune_view->view = view_alloc(); + view_set_context(tune_view->view, tune_view); + view_allocate_model(tune_view->view, ViewModelTypeLocking, sizeof(LfRfidTuneViewModel)); + + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + model->dirty = true; + model->fine = false; + model->ARR = 511; + model->CCR = 255; + model->pos = 0; + return true; + }); + + view_set_draw_callback(tune_view->view, lfrfid_debug_view_tune_draw_callback); + view_set_input_callback(tune_view->view, lfrfid_debug_view_tune_input_callback); + + return tune_view; +} + +void lfrfid_debug_view_tune_free(LfRfidTuneView* tune_view) { + view_free(tune_view->view); + free(tune_view); +} + +View* lfrfid_debug_view_tune_get_view(LfRfidTuneView* tune_view) { + return tune_view->view; +} + +void lfrfid_debug_view_tune_clean(LfRfidTuneView* tune_view) { + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + model->dirty = true; + model->fine = false; + model->ARR = 511; + model->CCR = 255; + model->pos = 0; + return true; + }); +} + +bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view) { + bool result = false; + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + result = model->dirty; + model->dirty = false; + return false; + }); + + return result; +} + +uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view) { + uint32_t result = false; + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + result = model->ARR; + return false; + }); + + return result; +} + +uint32_t lfrfid_debug_view_tune_get_ccr(LfRfidTuneView* tune_view) { + uint32_t result = false; + with_view_model( + tune_view->view, (LfRfidTuneViewModel * model) { + result = model->CCR; + return false; + }); + + return result; +} diff --git a/applications/lfrfid_debug/views/lfrfid_debug_view_tune.h b/applications/lfrfid_debug/views/lfrfid_debug_view_tune.h new file mode 100644 index 000000000..fd6d0b1fe --- /dev/null +++ b/applications/lfrfid_debug/views/lfrfid_debug_view_tune.h @@ -0,0 +1,18 @@ +#pragma once +#include + +typedef struct LfRfidTuneView LfRfidTuneView; + +LfRfidTuneView* lfrfid_debug_view_tune_alloc(); + +void lfrfid_debug_view_tune_free(LfRfidTuneView* tune_view); + +View* lfrfid_debug_view_tune_get_view(LfRfidTuneView* tune_view); + +void lfrfid_debug_view_tune_clean(LfRfidTuneView* tune_view); + +bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view); + +uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view); + +uint32_t lfrfid_debug_view_tune_get_ccr(LfRfidTuneView* tune_view); diff --git a/applications/meta/application.fam b/applications/meta/application.fam index 6e8194f6a..36bd9fa92 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", @@ -48,6 +48,7 @@ App( "tetris_game", "arkanoid_game", "tictactoe_game", + "wav_player", ], ) @@ -75,7 +76,9 @@ App( "wifi_marauder", "esp8266_deauth", "wifi_scanner", - "wav_player", + "multi_converter", + "flipfrid", + "subbrute", "sub_playlist", ], ) \ No newline at end of file diff --git a/applications/multi_converter/multi_converter.c b/applications/multi_converter/multi_converter.c index 69b3c71f6..590730357 100644 --- a/applications/multi_converter/multi_converter.c +++ b/applications/multi_converter/multi_converter.c @@ -8,152 +8,158 @@ #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; + } - 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); + } - 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); + release_mutex((ValueMutex*)ctx, multi_converter_state); } -static void multi_converter_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); +static void + multi_converter_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { + furi_assert(event_queue); - MultiConverterEvent event = {.type = EventTypeKey, .input = *input_event}; + 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 + // 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->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->unit_type_orig = UnitTypeDec; + multi_converter_state->unit_type_dest = UnitTypeHex; - multi_converter_state->keyboard_lock = 0; + multi_converter_state->keyboard_lock = 0; - // init the display view - multi_converter_mode_display_reset(multi_converter_state); + // init the display view + multi_converter_mode_display_reset(multi_converter_state); - // init the select view - multi_converter_mode_select_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; + // 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)); + // get event queue + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(MultiConverterEvent)); - // allocate state - MultiConverterState* multi_converter_state = malloc(sizeof(MultiConverterState)); + // 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; - } + // 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"); + furi_message_queue_free(event_queue); + 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); + // 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); + // 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); + 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); + // 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_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.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 (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); + } - 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); + } 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); - } + 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); - } + 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_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close("gui"); - view_port_free(view_port); + 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); diff --git a/applications/multi_converter/multi_converter_definitions.h b/applications/multi_converter/multi_converter_definitions.h index fe904342d..3bed192a0 100644 --- a/applications/multi_converter/multi_converter_definitions.h +++ b/applications/multi_converter/multi_converter_definitions.h @@ -1,82 +1,82 @@ #pragma once -#define MULTI_CONVERTER_NUMBER_DIGITS 9 +#define MULTI_CONVERTER_NUMBER_DIGITS 9 typedef enum { - EventTypeKey, + EventTypeKey, } EventType; typedef struct { - InputEvent input; - EventType type; + InputEvent input; + EventType type; } MultiConverterEvent; typedef enum { - ModeDisplay, - ModeSelector, + ModeDisplay, + ModeSelector, } MultiConverterMode; typedef enum { - None, - Reset, - Convert, + 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, + UnitTypeDec, + UnitTypeHex, + UnitTypeBin, - UnitTypeCelsius, - UnitTypeFahernheit, - UnitTypeKelvin, + UnitTypeCelsius, + UnitTypeFahernheit, + UnitTypeKelvin, - UnitTypeKilometers, - UnitTypeMeters, - UnitTypeCentimeters, - UnitTypeMiles, - UnitTypeFeet, - UnitTypeInches, + UnitTypeKilometers, + UnitTypeMeters, + UnitTypeCentimeters, + UnitTypeMiles, + UnitTypeFeet, + UnitTypeInches, - UnitTypeDegree, - UnitTypeRadian, + UnitTypeDegree, + UnitTypeRadian, } MultiConverterUnitType; typedef struct { - MultiConverterUnitType selected_unit_type_orig; - MultiConverterUnitType selected_unit_type_dest; - uint8_t select_orig; + 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? + 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); + 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!) + 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 index 2462cf60c..c72a954f7 100644 --- a/applications/multi_converter/multi_converter_mode_display.c +++ b/applications/multi_converter/multi_converter_mode_display.c @@ -1,284 +1,326 @@ #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_KEYS 18 // [0] to [F] + [BACK] + [SELECT] -#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_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_KEY_FRAME_MARGIN 3 -#define MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT 8 +#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 - // 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; - } + 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; + // 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); + // 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); +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); + // 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); + 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); + // 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); + 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); + // SEPARATOR_LINE + canvas_draw_line(canvas, 2, 25, 128 - 3, 25); - // KEYBOARD - uint8_t _x = 5; - uint8_t _y = 25 + 15; // line + 10 + // KEYBOARD + uint8_t _x = 5; + uint8_t _y = 25 + 15; // line + 10 - for (int i = 0; i < MULTI_CONVERTER_DISPLAY_KEYS; i++) { + 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; - 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); + 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; - } + 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 - ); - } + // 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); + // 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 - ); - } + // 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; - } - } + // 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) { +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; - // first move to keyboard position, then check if the ORIGIN allows that specific key, if not jump to the "closest one" - switch (key) { + 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; - default: - break; + case InputKeyLeft: + case InputKeyRight: - 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; + (multi_converter_state->display).key += (key == InputKeyLeft ? -1 : 1); - case InputKeyLeft: - case InputKeyRight: + 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; + } - (multi_converter_state->display).key += (key == InputKeyLeft ? -1 : 1); + // 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..." - 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; - } + 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; + } - // 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; + // 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; +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; + // 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->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--; - } + (multi_converter_state->display).cursor--; + } - // toggle flag - (multi_converter_state->display).negative ^= 1; - } + // 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 + 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; + // 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++; + 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 > + 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'; - } + 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++; + (multi_converter_state->display).cursor++; } -MultiConverterModeTrigger multi_converter_mode_display_ok(uint8_t long_press, MultiConverterState* const multi_converter_state) { +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 - 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); + } - // long press on 0 toggle NEGATIVE if allowed, on 1 adds COMMA if allowed - if (long_press) { + } else { + // regular keys + multi_converter_mode_display_add_number(multi_converter_state); + } - 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); - } + multi_converter_mode_display_convert(multi_converter_state); - } else { - // regular keys - multi_converter_mode_display_add_number(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--; - multi_converter_mode_display_convert(multi_converter_state); + 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; - } else if ((multi_converter_state->display).key == MULTI_CONVERTER_DISPLAY_KEY_DEL) { - if ((multi_converter_state->display).cursor > 0) (multi_converter_state->display).cursor--; + multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] = + MULTI_CONVERTER_DISPLAY_CHAR_BLANK; - 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_mode_display_convert(multi_converter_state); - 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; + } 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 index 7c23e230b..cae929d35 100644 --- a/applications/multi_converter/multi_converter_mode_display.h +++ b/applications/multi_converter/multi_converter_mode_display.h @@ -16,12 +16,16 @@ void multi_converter_mode_display_convert(MultiConverterState* const multi_conve // // 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); +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); +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; @@ -52,4 +56,6 @@ void multi_converter_mode_display_add_number(MultiConverterState* const multi_co // 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 +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 index c30a361e5..a56ccd58c 100644 --- a/applications/multi_converter/multi_converter_mode_select.c +++ b/applications/multi_converter/multi_converter_mode_select.c @@ -1,160 +1,210 @@ #include "multi_converter_mode_select.h" -#define MULTI_CONVERTER_LIST_ENTRIES_COUNT 3 +#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" +#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_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_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) { +void multi_converter_mode_select_draw( + Canvas* const canvas, + const MultiConverterState* multi_converter_state) { + int y = 10; + int x = 10; - int y = 10; - int x = 10; + canvas_set_color(canvas, ColorBlack); - canvas_set_color(canvas, ColorBlack); + // FROM + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, x, y, MULTI_CONVERTER_INFO_STRING_FROM); - // FROM - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, x, y, MULTI_CONVERTER_INFO_STRING_FROM); + canvas_set_font(canvas, FontSecondary); - canvas_set_font(canvas, FontSecondary); + // offset -1 + y += 12; - // 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); - 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; - // current selected element - y += 12; + multi_converter_mode_select_draw_selected_unit( + x, y, (multi_converter_state->select).selected_unit_type_orig, canvas); - 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, ">"); - if ((multi_converter_state->select).select_orig) canvas_draw_str(canvas, x - 6, y, ">"); + // offset +1 + y += 12; - // 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); - 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; - // 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, FontPrimary); - canvas_draw_str(canvas, x, y, MULTI_CONVERTER_INFO_STRING_TO); - - canvas_set_font(canvas, FontSecondary); + 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; + // 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); + multi_converter_mode_select_draw_destination_offset(x, y, -1, canvas, multi_converter_state); - // current selected element - y += 12; + // current selected element + y += 12; - multi_converter_mode_select_draw_selected_unit(x, y, (multi_converter_state->select).selected_unit_type_dest, canvas); + 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, ">"); + if(!(multi_converter_state->select).select_orig) canvas_draw_str(canvas, x - 6, y, ">"); - // offset +1: same but on the opposite direction - y += 12; + // offset +1: same but on the opposite direction + y += 12; - multi_converter_mode_select_draw_destination_offset(x, y, 1, canvas, multi_converter_state); + multi_converter_mode_select_draw_destination_offset(x, y, 1, canvas, multi_converter_state); - // OK / CANCEL + // 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, 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); + 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; - // 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; + (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) { +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; - 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 - 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 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 Reset; - } - - } - - return None; + return None; } void multi_converter_mode_select_switch(MultiConverterState* const multi_converter_state) { - (multi_converter_state->select).select_orig ^= 1; + (multi_converter_state->select).select_orig ^= 1; } -void multi_converter_mode_select_change_unit(int8_t direction, MultiConverterState* const multi_converter_state) { +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; + } - 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++; - } + // 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 index 2e4a9ec85..c10ab8e01 100644 --- a/applications/multi_converter/multi_converter_mode_select.h +++ b/applications/multi_converter/multi_converter_mode_select.h @@ -10,14 +10,25 @@ // // 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_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); +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); +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 @@ -33,11 +44,13 @@ void multi_converter_mode_select_reset(MultiConverterState* const multi_converte // 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) +// 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); +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 @@ -48,11 +61,13 @@ void multi_converter_mode_select_switch(MultiConverterState* const multi_convert // // 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); +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 index 281284923..4381f0e6e 100644 --- a/applications/multi_converter/multi_converter_units.c +++ b/applications/multi_converter/multi_converter_units.c @@ -1,124 +1,126 @@ #include "multi_converter_units.h" -#define MULTI_CONVERTER_CHAR_OVERFLOW '#' -#define MULTI_CONVERTER_MAX_SUPORTED_INT 999999999 +#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; +#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]; - char dest[MULTI_CONVERTER_NUMBER_DIGITS]; + int i = 0; + uint8_t overflow = 0; - int i = 0; - uint8_t overflow = 0; - - int a = 0; - int r = 0; - uint8_t f = 1; + 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); + 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 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; + case UnitTypeBin: + a = strtol(multi_converter_state->buffer_orig, NULL, 2); + f = (multi_converter_state->unit_type_dest == UnitTypeDec ? 10 : 16); - break; - } + 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] = ' '; - } - } + 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); + 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; - 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); + } - 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 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; - 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; + } - 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); - } + 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); + return ( + unit_type == UnitTypeCelsius || unit_type == UnitTypeFahernheit || + unit_type == UnitTypeKelvin); } // @@ -126,73 +128,102 @@ uint8_t multi_converter_unit_temperature_allowed(MultiConverterUnitType unit_typ // void multi_converter_unit_distance_convert(MultiConverterState* const multi_converter_state) { - double a = strtof(multi_converter_state->buffer_orig, NULL); - uint8_t overflow = 0; + 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; + 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; + 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 (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); - } + 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 - ); + return ( + unit_type == UnitTypeKilometers || unit_type == UnitTypeMeters || + unit_type == UnitTypeCentimeters || unit_type == UnitTypeMiles || + unit_type == UnitTypeFeet || unit_type == UnitTypeInches); } // @@ -200,31 +231,31 @@ uint8_t multi_converter_unit_distance_allowed(MultiConverterUnitType unit_type) // void multi_converter_unit_angle_convert(MultiConverterState* const multi_converter_state) { - double a = strtof(multi_converter_state->buffer_orig, NULL); - uint8_t overflow = 0; + 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; + 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; - } + 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 { + 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); - 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); - } + 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); + 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 index da281627e..6d3b477bb 100644 --- a/applications/multi_converter/multi_converter_units.h +++ b/applications/multi_converter/multi_converter_units.h @@ -8,7 +8,9 @@ #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) +#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 @@ -31,41 +33,139 @@ 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_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_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_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 }; +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, + [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, + [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, + [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, + [UnitTypeDegree] = multi_converter_unit_deg, + [UnitTypeRadian] = multi_converter_unit_rad, }; \ No newline at end of file diff --git a/applications/music_player/application.fam b/applications/music_player/application.fam index 70e297432..9b57028ac 100644 --- a/applications/music_player/application.fam +++ b/applications/music_player/application.fam @@ -1,7 +1,7 @@ App( appid="music_player", name="Music Player", - apptype=FlipperAppType.PLUGIN, + apptype=FlipperAppType.GAME, entry_point="music_player_app", cdefines=["APP_MUSIC_PLAYER"], requires=[ @@ -10,7 +10,7 @@ App( ], provides=["music_player_start"], stack_size=2 * 1024, - order=20, + order=45, ) App( 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/helpers/nfc_generators.c b/applications/nfc/helpers/nfc_generators.c index b94adbd7b..11083b9f0 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/applications/nfc/nfc.c b/applications/nfc/nfc.c index 3422e91af..57e25f81e 100644 --- a/applications/nfc/nfc.c +++ b/applications/nfc/nfc.c @@ -94,6 +94,11 @@ Nfc* nfc_alloc() { view_dispatcher_add_view( nfc->view_dispatcher, NfcViewDictAttack, dict_attack_get_view(nfc->dict_attack)); + // Detect Reader + nfc->detect_reader = detect_reader_alloc(); + view_dispatcher_add_view( + nfc->view_dispatcher, NfcViewDetectReader, detect_reader_get_view(nfc->detect_reader)); + // Generator nfc->generator = NULL; @@ -158,6 +163,10 @@ void nfc_free(Nfc* nfc) { view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDictAttack); dict_attack_free(nfc->dict_attack); + // Detect Reader + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDetectReader); + detect_reader_free(nfc->detect_reader); + // Worker nfc_worker_stop(nfc->worker); nfc_worker_free(nfc->worker); 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/nfc_i.h b/applications/nfc/nfc_i.h index bcfe4a219..c9ba7fff7 100644 --- a/applications/nfc/nfc_i.h +++ b/applications/nfc/nfc_i.h @@ -28,6 +28,7 @@ #include #include "views/dict_attack.h" +#include "views/detect_reader.h" #include #include @@ -71,6 +72,7 @@ struct Nfc { TextBox* text_box; Widget* widget; DictAttack* dict_attack; + DetectReader* detect_reader; const NfcGenerator* generator; }; @@ -85,6 +87,7 @@ typedef enum { NfcViewTextBox, NfcViewWidget, NfcViewDictAttack, + NfcViewDetectReader, } NfcView; Nfc* nfc_alloc(); 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 index ff34a11d8..540fe1098 --- a/applications/nfc/scenes/nfc_scene_config.h +++ b/applications/nfc/scenes/nfc_scene_config.h @@ -48,4 +48,6 @@ ADD_SCENE(nfc, rpc, Rpc) ADD_SCENE(nfc, exit_confirm, ExitConfirm) ADD_SCENE(nfc, retry_confirm, RetryConfirm) ADD_SCENE(nfc, detect_reader, DetectReader) +ADD_SCENE(nfc, mfkey_nonces_info, MfkeyNoncesInfo) +ADD_SCENE(nfc, mfkey_complete, MfkeyComplete) ADD_SCENE(nfc, nfc_data_info, NfcDataInfo) 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_detect_reader.c b/applications/nfc/scenes/nfc_scene_detect_reader.c index f734f04cb..8945febaf 100644 --- a/applications/nfc/scenes/nfc_scene_detect_reader.c +++ b/applications/nfc/scenes/nfc_scene_detect_reader.c @@ -1,126 +1,48 @@ #include "../nfc_i.h" #include -#define NFC_SCENE_DETECT_READER_LOG_SIZE_MAX (200) - -enum { - NfcSceneDetectReaderStateWidget, - NfcSceneDetectReaderStateTextBox, -}; - bool nfc_detect_reader_worker_callback(NfcWorkerEvent event, void* context) { UNUSED(event); furi_assert(context); Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); + view_dispatcher_send_custom_event(nfc->view_dispatcher, event); return true; } -void nfc_scene_detect_reader_widget_callback(GuiButtonType result, InputType type, void* context) { - furi_assert(context); - Nfc* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_detect_reader_textbox_callback(void* context) { +void nfc_scene_detect_reader_callback(void* context) { furi_assert(context); Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } -// Add widget with device name or inform that data received -static void nfc_scene_detect_reader_widget_config(Nfc* nfc, bool data_received) { - Widget* widget = nfc->widget; - widget_reset(widget); - - widget_add_icon_element(widget, 0, 14, &I_Reader_detect); - widget_add_string_element( - widget, 64, 3, AlignCenter, AlignTop, FontSecondary, "Hold Near Reader"); - widget_add_string_element(widget, 55, 22, AlignLeft, AlignTop, FontPrimary, "Emulating..."); - - if(data_received) { - widget_add_button_element( - widget, GuiButtonTypeCenter, "Log", nfc_scene_detect_reader_widget_callback, nfc); - } -} - void nfc_scene_detect_reader_on_enter(void* context) { Nfc* nfc = context; DOLPHIN_DEED(DolphinDeedNfcEmulate); - FuriHalNfcDevData nfc_params = { - .uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34}, - .uid_len = 7, - .atqa = {0x44, 0x00}, - .sak = 0x08, - .type = FuriHalNfcTypeA, - }; - nfc->dev->dev_data.nfc_data = nfc_params; - // Setup Widget - nfc_scene_detect_reader_widget_config(nfc, false); - // Setup TextBox - TextBox* text_box = nfc->text_box; - text_box_set_font(text_box, TextBoxFontHex); - text_box_set_focus(text_box, TextBoxFocusEnd); - string_reset(nfc->text_box_store); - - // Set Widget state and view - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateWidget); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - // Start worker - memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData)); + detect_reader_set_callback(nfc->detect_reader, nfc_scene_detect_reader_callback, nfc); nfc_worker_start( nfc->worker, - NfcWorkerStateUidEmulate, + NfcWorkerStateAnalyzeReader, &nfc->dev->dev_data, nfc_detect_reader_worker_callback, nfc); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDetectReader); + nfc_blink_start(nfc); } bool nfc_scene_detect_reader_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; - NfcReaderRequestData* reader_data = &nfc->dev->dev_data.reader_data; - uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDetectReader); bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventWorkerExit) { - // Add data button to widget if data is received for the first time - if(!string_size(nfc->text_box_store)) { - nfc_scene_detect_reader_widget_config(nfc, true); - } - // Update TextBox data - if(string_size(nfc->text_box_store) < NFC_SCENE_DETECT_READER_LOG_SIZE_MAX) { - string_cat_printf(nfc->text_box_store, "R:"); - for(uint16_t i = 0; i < reader_data->size; i++) { - string_cat_printf(nfc->text_box_store, " %02X", reader_data->data[i]); - } - string_push_back(nfc->text_box_store, '\n'); - text_box_set_text(nfc->text_box, string_get_cstr(nfc->text_box_store)); - } - memset(reader_data, 0, sizeof(NfcReaderRequestData)); + if(event.event == NfcCustomEventViewExit) { + nfc_worker_stop(nfc->worker); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfkeyNoncesInfo); consumed = true; - } else if(event.event == GuiButtonTypeCenter && state == NfcSceneDetectReaderStateWidget) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateTextBox); - consumed = true; - } else if(event.event == NfcCustomEventViewExit && state == NfcSceneDetectReaderStateTextBox) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateWidget); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - if(state == NfcSceneDetectReaderStateTextBox) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateWidget); + } else if(event.event == NfcWorkerEventDetectReaderMfkeyCollected) { + detect_reader_inc_nonce_cnt(nfc->detect_reader); consumed = true; } } @@ -135,9 +57,7 @@ void nfc_scene_detect_reader_on_exit(void* context) { nfc_worker_stop(nfc->worker); // Clear view - widget_reset(nfc->widget); - text_box_reset(nfc->text_box); - string_reset(nfc->text_box_store); + detect_reader_reset(nfc->detect_reader); nfc_blink_stop(nfc); } 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_mfkey_complete.c b/applications/nfc/scenes/nfc_scene_mfkey_complete.c new file mode 100644 index 000000000..3c4f9dba1 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_mfkey_complete.c @@ -0,0 +1,49 @@ +#include "../nfc_i.h" + +void nfc_scene_mfkey_complete_callback(GuiButtonType result, InputType type, void* context) { + Nfc* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mfkey_complete_on_enter(void* context) { + Nfc* nfc = context; + + widget_add_string_element(nfc->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Complete!"); + widget_add_string_multiline_element( + nfc->widget, + 64, + 32, + AlignCenter, + AlignCenter, + FontSecondary, + "Now use mfkey32v2\nto extract keys"); + widget_add_button_element( + nfc->widget, GuiButtonTypeCenter, "OK", nfc_scene_mfkey_complete_callback, nfc); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mfkey_complete_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); + } + } else if(event.event == SceneManagerEventTypeBack) { + consumed = + scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); + } + + return consumed; +} + +void nfc_scene_mfkey_complete_on_exit(void* context) { + Nfc* nfc = context; + + widget_reset(nfc->widget); +} \ No newline at end of file diff --git a/applications/nfc/scenes/nfc_scene_mfkey_nonces_info.c b/applications/nfc/scenes/nfc_scene_mfkey_nonces_info.c new file mode 100644 index 000000000..b45b690d3 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_mfkey_nonces_info.c @@ -0,0 +1,55 @@ +#include "../nfc_i.h" +#include + +void nfc_scene_mfkey_nonces_info_callback(GuiButtonType result, InputType type, void* context) { + Nfc* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mfkey_nonces_info_on_enter(void* context) { + Nfc* nfc = context; + + string_t temp_str; + string_init(temp_str); + + uint16_t nonces_saved = mfkey32_get_auth_sectors(temp_str); + widget_add_text_scroll_element(nfc->widget, 0, 22, 128, 42, string_get_cstr(temp_str)); + string_printf(temp_str, "Nonces saved %d", nonces_saved); + widget_add_string_element( + nfc->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, string_get_cstr(temp_str)); + widget_add_string_element( + nfc->widget, 0, 12, AlignLeft, AlignTop, FontSecondary, "Authenticated sectors:"); + + widget_add_button_element( + nfc->widget, GuiButtonTypeRight, "Next", nfc_scene_mfkey_nonces_info_callback, nfc); + + string_clear(temp_str); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mfkey_nonces_info_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeRight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfkeyComplete); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = + scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); + } + + return consumed; +} + +void nfc_scene_mfkey_nonces_info_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + widget_reset(nfc->widget); +} 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/nfc/scenes/nfc_scene_start.c b/applications/nfc/scenes/nfc_scene_start.c index 01ffb46b8..1a9051dfd 100644 --- a/applications/nfc/scenes/nfc_scene_start.c +++ b/applications/nfc/scenes/nfc_scene_start.c @@ -49,7 +49,12 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); consumed = true; } else if(event.event == SubmenuIndexDetectReader) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); + bool sd_exist = storage_sd_status(nfc->dev->storage) == FSE_OK; + if(sd_exist) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); + } consumed = true; } else if(event.event == SubmenuIndexSaved) { scene_manager_next_scene(nfc->scene_manager, NfcSceneFileSelect); @@ -61,7 +66,6 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType); consumed = true; } else if(event.event == SubmenuIndexDebug) { - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexDebug); scene_manager_next_scene(nfc->scene_manager, NfcSceneDebug); consumed = true; } diff --git a/applications/nfc/views/detect_reader.c b/applications/nfc/views/detect_reader.c new file mode 100644 index 000000000..177c13f75 --- /dev/null +++ b/applications/nfc/views/detect_reader.c @@ -0,0 +1,115 @@ +#include "detect_reader.h" + +#include + +struct DetectReader { + View* view; + DetectReaderDoneCallback callback; + void* context; +}; + +typedef struct { + uint16_t nonces; +} DetectReaderViewModel; + +static void detect_reader_draw_callback(Canvas* canvas, void* model) { + DetectReaderViewModel* m = model; + char text[32] = {}; + + snprintf(text, sizeof(text), "Tap the reader several times"); + canvas_draw_str_aligned(canvas, 64, 0, AlignCenter, AlignTop, "Tap the reader several times"); + + if(m->nonces == 0) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 52, 22, AlignLeft, AlignTop, "Emulating..."); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 52, 35, AlignLeft, AlignTop, "MIFARE Classic"); + canvas_draw_icon(canvas, 0, 13, &I_Tap_reader_36x38); + } else { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 54, 22, AlignLeft, AlignTop, "Collecting..."); + canvas_set_font(canvas, FontSecondary); + snprintf(text, sizeof(text), "Nonces: %d", m->nonces); + canvas_draw_str_aligned(canvas, 54, 35, AlignLeft, AlignTop, text); + elements_button_right(canvas, "Next"); + canvas_draw_icon(canvas, 6, 15, &I_ArrowC_1_36x36); + } +} + +static bool detect_reader_input_callback(InputEvent* event, void* context) { + DetectReader* detect_reader = context; + furi_assert(detect_reader->callback); + bool consumed = false; + + uint8_t nonces = 0; + with_view_model( + detect_reader->view, (DetectReaderViewModel * model) { + nonces = model->nonces; + return false; + }); + + if(event->type == InputTypeShort) { + if(event->key == InputKeyRight) { + if(nonces > 0) { + detect_reader->callback(detect_reader->context); + consumed = true; + } + } + } + + return consumed; +} + +DetectReader* detect_reader_alloc() { + DetectReader* detect_reader = malloc(sizeof(DetectReader)); + detect_reader->view = view_alloc(); + view_allocate_model(detect_reader->view, ViewModelTypeLocking, sizeof(DetectReaderViewModel)); + view_set_draw_callback(detect_reader->view, detect_reader_draw_callback); + view_set_input_callback(detect_reader->view, detect_reader_input_callback); + view_set_context(detect_reader->view, detect_reader); + + return detect_reader; +} + +void detect_reader_free(DetectReader* detect_reader) { + furi_assert(detect_reader); + + view_free(detect_reader->view); + free(detect_reader); +} + +void detect_reader_reset(DetectReader* detect_reader) { + furi_assert(detect_reader); + + with_view_model( + detect_reader->view, (DetectReaderViewModel * model) { + model->nonces = 0; + return false; + }); +} + +View* detect_reader_get_view(DetectReader* detect_reader) { + furi_assert(detect_reader); + + return detect_reader->view; +} + +void detect_reader_set_callback( + DetectReader* detect_reader, + DetectReaderDoneCallback callback, + void* context) { + furi_assert(detect_reader); + furi_assert(callback); + + detect_reader->callback = callback; + detect_reader->context = context; +} + +void detect_reader_inc_nonce_cnt(DetectReader* detect_reader) { + furi_assert(detect_reader); + with_view_model( + detect_reader->view, (DetectReaderViewModel * model) { + model->nonces++; + return false; + }); +} diff --git a/applications/nfc/views/detect_reader.h b/applications/nfc/views/detect_reader.h new file mode 100644 index 000000000..12cd03db4 --- /dev/null +++ b/applications/nfc/views/detect_reader.h @@ -0,0 +1,23 @@ +#pragma once +#include +#include +#include + +typedef struct DetectReader DetectReader; + +typedef void (*DetectReaderDoneCallback)(void* context); + +DetectReader* detect_reader_alloc(); + +void detect_reader_free(DetectReader* detect_reader); + +void detect_reader_reset(DetectReader* detect_reader); + +View* detect_reader_get_view(DetectReader* detect_reader); + +void detect_reader_set_callback( + DetectReader* detect_reader, + DetectReaderDoneCallback callback, + void* context); + +void detect_reader_inc_nonce_cnt(DetectReader* detect_reader); diff --git a/applications/nrfsniff/nrfsniff.c b/applications/nrfsniff/nrfsniff.c index e8dee30ac..ab074f87f 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,37 @@ typedef struct { } PluginState; char rate_text_fmt[] = "Transfer rate: %dMbps"; -char channel_text_fmt[] = "Channel: %d"; +char sample_text_fmt[] = "Sample Time: %d ms"; +char channel_text_fmt[] = "Channel: %d Sniffing: %s"; char preamble_text_fmt[] = "Preamble: %02X"; -char sniff_text_fmt[] = "Sniffing: %s Found: %d"; +char sniff_text_fmt[] = "Found: %d Unique: %u"; char addresses_header_text[] = "Address,rate"; char sniffed_address_fmt[] = "%s,%d"; char rate_text[46]; -char channel_text[42]; +char channel_text[38]; +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 unique_saved_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 +72,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 +85,14 @@ 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) { @@ -127,14 +112,16 @@ static void render_callback(Canvas* const canvas, void* ctx) { if(!sniffing_state) strcpy(sniffing, "No"); 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(sniff_text, sizeof(sniff_text), sniff_text_fmt, sniffing, found_count); + snprintf(channel_text, sizeof(channel_text), channel_text_fmt, (int)target_channel, sniffing); + 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, found_count, unique_saved_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); @@ -217,6 +204,7 @@ static bool save_addr_to_file( notification_message(notification, &sequence_success); stream_free(stream); + unique_saved_count++; return true; } } @@ -256,12 +244,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; @@ -289,16 +289,27 @@ static void wrap_up(Storage* storage, NotificationApp* notification) { if(ch <= LOGITECH_MAX_CHANNEL) { hexlify(addr, 5, top_address); - save_addr_to_file(storage, addr, 5, notification); found_count++; + save_addr_to_file(storage, addr, 5, notification); + if(confirmed_idx < MAX_CONFIRMED) memcpy(confirmed[confirmed_idx++], addr, 5); break; } } } -static void start_sniffing() { +static void clear_cache() { + found_count = 0; + unique_saved_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 +322,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 +377,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 +411,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]++; + 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); + 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 +439,10 @@ int32_t nrfsniff_app(void* p) { release_mutex(&state_mutex, plugin_state); } + 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); @@ -432,4 +453,4 @@ int32_t nrfsniff_app(void* p) { furi_message_queue_free(event_queue); return 0; -} \ No newline at end of file +} diff --git a/applications/picopass/picopass_worker.c b/applications/picopass/picopass_worker.c index 560548a18..359f19495 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(PicopassWorkerEventSuccess, picopass_worker->context); + 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(nextState, picopass_worker->context); } break; } diff --git a/applications/picopass/picopass_worker.h b/applications/picopass/picopass_worker.h old mode 100755 new mode 100644 index 9035f1c89..6ad709058 --- 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 789951900..9b215fb74 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.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 index 87745378b..27d6bbcd7 --- 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_delete_success.c b/applications/picopass/scenes/picopass_scene_delete_success.c old mode 100755 new mode 100644 diff --git a/applications/picopass/scenes/picopass_scene_read_card.c b/applications/picopass/scenes/picopass_scene_read_card.c index 0867898a5..8188207a2 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 3866d201c..c281b32ca 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.bitLength == 0) { + string_cat_printf(wiegand_str, "Read Failed"); - if(pacs->record.valid) { - string_cat_printf( - wiegand_str, "FC: %u CN: %u", pacs->record.FacilityCode, pacs->record.CardNumber); + 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]); + } + + 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)); } - - 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 8f0ce40ba..90a27ee81 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 000000000..a905dca95 --- /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 000000000..108e7d1ce --- /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/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.c b/applications/power/power_service/power.c index 3a2c6cf3b..a47a4e926 100644 --- a/applications/power/power_service/power.c +++ b/applications/power/power_service/power.c @@ -1,5 +1,6 @@ #include "power_i.h" #include "views/power_off.h" +#include "desktop/desktop_settings/desktop_settings.h" #include #include @@ -14,7 +15,59 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { canvas_draw_icon(canvas, 0, 0, &I_Battery_26x8); if(power->info.gauge_is_ok) { - canvas_draw_box(canvas, 2, 2, (power->info.charge + 4) / 5, 4); + char batteryPercentile[5]; + snprintf(batteryPercentile, sizeof(batteryPercentile), "%d", power->info.charge); + strcat(batteryPercentile, "%"); + + if((power->displayBatteryPercentage == 1) && + (power->state != + PowerStateCharging)) { //if display battery percentage, black background white text + canvas_set_font(canvas, FontBatteryPercent); + canvas_set_color(canvas, ColorBlack); + canvas_draw_box(canvas, 1, 1, 22, 6); + canvas_set_color(canvas, ColorWhite); + canvas_draw_str_aligned(canvas, 12, 4, AlignCenter, AlignCenter, batteryPercentile); + } else if( + (power->displayBatteryPercentage == 2) && + (power->state != + PowerStateCharging)) { //if display inverted percentage, white background black text + canvas_set_font(canvas, FontBatteryPercent); + canvas_set_color(canvas, ColorBlack); + canvas_draw_str_aligned(canvas, 12, 4, AlignCenter, AlignCenter, batteryPercentile); + } else if( + (power->displayBatteryPercentage == 3) && + (power->state != PowerStateCharging)) { //Retro style segmented display, 3 parts + if(power->info.charge > 25) { + canvas_draw_box(canvas, 2, 2, 6, 4); + } + if(power->info.charge > 50) { + canvas_draw_box(canvas, 9, 2, 6, 4); + } + if(power->info.charge > 75) { + canvas_draw_box(canvas, 16, 2, 6, 4); + } + } else if( + (power->displayBatteryPercentage == 4) && + (power->state != PowerStateCharging)) { //Retro style segmented display, 5 parts + if(power->info.charge > 10) { + canvas_draw_box(canvas, 2, 2, 3, 4); + } + if(power->info.charge > 30) { + canvas_draw_box(canvas, 6, 2, 3, 4); + } + if(power->info.charge > 50) { + canvas_draw_box(canvas, 10, 2, 3, 4); + } + if(power->info.charge > 70) { + canvas_draw_box(canvas, 14, 2, 3, 4); + } + if(power->info.charge > 90) { + canvas_draw_box(canvas, 18, 2, 3, 4); + } + } else { //default bar display, added here to serve as fallback/default behaviour. + canvas_draw_box(canvas, 2, 2, (power->info.charge + 4) / 5, 4); + } + if(power->state == PowerStateCharging) { canvas_set_bitmap_mode(canvas, 1); canvas_set_color(canvas, ColorWhite); @@ -207,6 +260,11 @@ int32_t power_srv(void* p) { power_update_info(power); furi_record_create(RECORD_POWER, power); + DesktopSettings* settings = malloc(sizeof(DesktopSettings)); + LOAD_DESKTOP_SETTINGS(settings); + power->displayBatteryPercentage = settings->displayBatteryPercentage; + free(settings); + while(1) { // Update data from gauge and charger bool need_refresh = power_update_info(power); @@ -221,7 +279,13 @@ int32_t power_srv(void* p) { power_check_battery_level_change(power); // Update battery view port - if(need_refresh) view_port_update(power->battery_view_port); + if(need_refresh) { + DesktopSettings* settings = malloc(sizeof(DesktopSettings)); + LOAD_DESKTOP_SETTINGS(settings); + power->displayBatteryPercentage = settings->displayBatteryPercentage; + free(settings); + view_port_update(power->battery_view_port); + } // Check OTG status and disable it in case of fault if(furi_hal_power_is_otg_enabled()) { diff --git a/applications/power/power_service/power_i.h b/applications/power/power_service/power_i.h old mode 100755 new mode 100644 index 66ced885b..434472896 --- a/applications/power/power_service/power_i.h +++ b/applications/power/power_service/power_i.h @@ -36,6 +36,7 @@ struct Power { bool battery_low; bool show_low_bat_level_message; + uint8_t displayBatteryPercentage; uint8_t battery_level; uint8_t power_off_timeout; 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/rpc/application.fam b/applications/rpc/application.fam index 683396e32..3a139cb3b 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 d767a928d..abba6ea42 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/applications/spectrum_analyzer/spectrum_analyzer.c b/applications/spectrum_analyzer/spectrum_analyzer.c index 503870ed8..5bc563451 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/applications/storage/storages/storage_int.c b/applications/storage/storages/storage_int.c index 0765a92dc..cae61f16e 100644 --- a/applications/storage/storages/storage_int.c +++ b/applications/storage/storages/storage_int.c @@ -9,7 +9,7 @@ /* When less than LFS_RESERVED_PAGES_COUNT are left free, creation & * modification of non-dot files is restricted */ -#define LFS_RESERVED_PAGES_COUNT 5 +#define LFS_RESERVED_PAGES_COUNT 3 typedef struct { const size_t start_address; 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/subbrute/LICENSE.md b/applications/subbrute/LICENSE.md new file mode 100644 index 000000000..a856581c9 --- /dev/null +++ b/applications/subbrute/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/subbrute/README.md b/applications/subbrute/README.md new file mode 100644 index 000000000..04a0c975d --- /dev/null +++ b/applications/subbrute/README.md @@ -0,0 +1,4 @@ +# FlipFrid + +SubGhz Fuzzer +select your base message, the field to fuzz and let's get fuzzy ! \ No newline at end of file diff --git a/applications/subbrute/application.fam b/applications/subbrute/application.fam new file mode 100644 index 000000000..2608cba8f --- /dev/null +++ b/applications/subbrute/application.fam @@ -0,0 +1,10 @@ +App( + appid="subbrute", + name="SubGHz Bruteforcer", + apptype=FlipperAppType.PLUGIN, + entry_point="subbrute_start", + cdefines=["APP_SUB_BRUTE"], + requires=["gui","dialogs"], + stack_size=2 * 1024, + order=11, +) diff --git a/applications/subbrute/scene/subbrute_scene_entrypoint.c b/applications/subbrute/scene/subbrute_scene_entrypoint.c new file mode 100644 index 000000000..a568ec152 --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_entrypoint.c @@ -0,0 +1,198 @@ +#include "subbrute_scene_entrypoint.h" +#include "../subbrute_utils.h" + +string_t subbrute_menu_items[9]; + +void subbrute_scene_entrypoint_menu_callback(SubBruteState* context, uint32_t index) { + string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async"); + string_set_str(context->protocol, "RAW"); + context->repeat = 5; + context->te = 0; + context->attack = index; + switch(index) { + case SubBruteAttackLoadFile: + context->current_scene = SceneSelectFile; + break; + case SubBruteAttackCAME12bit433: + context->frequency = 433920000; + context->bit = 12; + string_set_str(context->protocol, "CAME"); + string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async"); + if(!subbrute_is_frequency_allowed(context)) { + return; + } + context->current_scene = SceneAttack; + break; + case SubBruteAttackCAME12bit868: + context->frequency = 868350000; + context->bit = 12; + string_set_str(context->protocol, "CAME"); + string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async"); + if(!subbrute_is_frequency_allowed(context)) { + return; + } + context->current_scene = SceneAttack; + break; + case SubBruteAttackChamberlain9bit315: + context->frequency = 315000000; + context->bit = 9; + string_set_str(context->protocol, "Cham_Code"); + string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async"); + + if(!subbrute_is_frequency_allowed(context)) { + return; + } + context->current_scene = SceneAttack; + break; + case SubBruteAttackChamberlain9bit390: + context->frequency = 390000000; + context->bit = 9; + string_set_str(context->protocol, "Cham_Code"); + string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async"); + + if(!subbrute_is_frequency_allowed(context)) { + return; + } + context->current_scene = SceneAttack; + break; + case SubBruteAttackLinear10bit300: + context->frequency = 300000000; + context->bit = 10; + string_set_str(context->protocol, "Linear"); + string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async"); + if(!subbrute_is_frequency_allowed(context)) { + return; + } + context->current_scene = SceneAttack; + break; + case SubBruteAttackLinear10bit310: + context->frequency = 310000000; + context->bit = 10; + string_set_str(context->protocol, "Linear"); + string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async"); + if(!subbrute_is_frequency_allowed(context)) { + return; + } + context->current_scene = SceneAttack; + break; + case SubBruteAttackNICE12bit433: + context->frequency = 433920000; + context->bit = 12; + string_set_str(context->protocol, "Nice FLO"); + string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async"); + if(!subbrute_is_frequency_allowed(context)) { + return; + } + context->current_scene = SceneAttack; + break; + case SubBruteAttackNICE12bit868: + context->frequency = 868350000; + context->bit = 12; + string_set_str(context->protocol, "Nice FLO"); + string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async"); + if(!subbrute_is_frequency_allowed(context)) { + return; + } + context->current_scene = SceneAttack; + break; + default: + break; + } +} + +void subbrute_scene_entrypoint_on_enter(SubBruteState* context) { + // Clear the previous payload + context->menu_index = 0; + for(uint32_t i = 0; i < 9; i++) { + string_init(subbrute_menu_items[i]); + } + + string_set(subbrute_menu_items[0], "BF existing dump"); + string_set(subbrute_menu_items[1], "CAME 12bit 433mhz"); + string_set(subbrute_menu_items[2], "CAME 12bit 868mhz"); + string_set(subbrute_menu_items[3], "Chamberlain 9bit 315mhz"); + string_set(subbrute_menu_items[4], "Chamberlain 9bit 390mhz"); + string_set(subbrute_menu_items[5], "Linear 10bit 300mhz"); + string_set(subbrute_menu_items[6], "Linear 10bit 310mhz"); + string_set(subbrute_menu_items[7], "NICE 12bit 433mhz"); + string_set(subbrute_menu_items[8], "NICE 12bit 868mhz"); +} + +void subbrute_scene_entrypoint_on_exit(SubBruteState* context) { + UNUSED(context); + for(uint32_t i = 0; i < 9; i++) { + string_clear(subbrute_menu_items[i]); + } +} + +void subbrute_scene_entrypoint_on_tick(SubBruteState* context) { + UNUSED(context); +} + +void subbrute_scene_entrypoint_on_event(SubBruteEvent event, SubBruteState* context) { + if(event.evt_type == EventTypeKey) { + if(event.input_type == InputTypeShort) { + switch(event.key) { + case InputKeyDown: + if(context->menu_index < SubBruteAttackNICE12bit868) { + context->menu_index++; + } + break; + case InputKeyUp: + if(context->menu_index > SubBruteAttackLoadFile) { + context->menu_index--; + } + break; + case InputKeyLeft: + case InputKeyRight: + break; + case InputKeyOk: + subbrute_scene_entrypoint_menu_callback(context, context->menu_index); + break; + case InputKeyBack: + context->is_running = false; + break; + } + } + } +} + +void subbrute_scene_entrypoint_on_draw(Canvas* canvas, SubBruteState* context) { + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + + // Title + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 64, 6, AlignCenter, AlignTop, "SubGHz Fuzzer"); + + if(context->menu_index > SubBruteAttackLoadFile) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, + 64, + 24, + AlignCenter, + AlignTop, + string_get_cstr(subbrute_menu_items[context->menu_index - 1])); + } + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned( + canvas, + 64, + 36, + AlignCenter, + AlignTop, + string_get_cstr(subbrute_menu_items[context->menu_index])); + + if(context->menu_index < SubBruteAttackNICE12bit868) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, + 64, + 48, + AlignCenter, + AlignTop, + string_get_cstr(subbrute_menu_items[context->menu_index + 1])); + } +} \ No newline at end of file diff --git a/applications/subbrute/scene/subbrute_scene_entrypoint.h b/applications/subbrute/scene/subbrute_scene_entrypoint.h new file mode 100644 index 000000000..af6b3bc49 --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_entrypoint.h @@ -0,0 +1,8 @@ +#pragma once +#include "../subbrute.h" + +void subbrute_scene_entrypoint_on_enter(SubBruteState* context); +void subbrute_scene_entrypoint_on_exit(SubBruteState* context); +void subbrute_scene_entrypoint_on_tick(SubBruteState* context); +void subbrute_scene_entrypoint_on_event(SubBruteEvent event, SubBruteState* context); +void subbrute_scene_entrypoint_on_draw(Canvas* canvas, SubBruteState* context); \ No newline at end of file diff --git a/applications/subbrute/scene/subbrute_scene_load_file.c b/applications/subbrute/scene/subbrute_scene_load_file.c new file mode 100644 index 000000000..0f6d953f7 --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_load_file.c @@ -0,0 +1,212 @@ +#include "subbrute_scene_load_file.h" +#include "subbrute_scene_entrypoint.h" +#include "../subbrute_utils.h" +#include + +#define SUBGHZ_APP_PATH_FOLDER "/ext/subghz" + +bool subbrute_load(SubBruteState* context, const char* file_path) { + bool result = false; + + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); + + string_t temp_str; + string_init(temp_str); + uint32_t temp_data32; + + do { + if(!flipper_format_file_open_existing(fff_data_file, file_path)) { + FURI_LOG_E(TAG, "Error open file %s", file_path); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Error open file"); + break; + } + if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) { + FURI_LOG_E(TAG, "Missing or incorrect header"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Missing or incorrect header"); + break; + } + // Frequency + if(flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { + FURI_LOG_I(TAG, "Frequency: %d", temp_data32); + context->frequency = temp_data32; + if(!subbrute_is_frequency_allowed(context)) { + break; + } + } else { + FURI_LOG_E(TAG, "Missing or incorrect Frequency"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Missing or incorrect Frequency"); + break; + } + // Preset + if(!flipper_format_read_string(fff_data_file, "Preset", context->preset)) { + FURI_LOG_E(TAG, "Preset FAIL"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Preset FAIL"); + } + // Protocol + if(!flipper_format_read_string(fff_data_file, "Protocol", context->protocol)) { + FURI_LOG_E(TAG, "Missing Protocol"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Missing Protocol"); + break; + } else { + FURI_LOG_I(TAG, "Protocol: %s", string_get_cstr(context->protocol)); + } + + if(strcmp(string_get_cstr(context->protocol), "RAW") == 0) { + FURI_LOG_E(TAG, "RAW unsupported"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "RAW unsupported"); + break; + } + + const SubGhzProtocol* registry = + subghz_protocol_registry_get_by_name(string_get_cstr(context->protocol)); + + if(registry && registry->type == SubGhzProtocolTypeDynamic) { + FURI_LOG_D(TAG, "Protocol is dynamic - not supported"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Dynamic protocol unsupported"); + break; + } + + context->decoder_result = subghz_receiver_search_decoder_base_by_name( + context->receiver, string_get_cstr(context->protocol)); + + if(context->decoder_result) { + FURI_LOG_I(TAG, "Found decoder"); + } else { + FURI_LOG_E(TAG, "Protocol not found"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Protocol not found"); + break; + } + + // Bit + if(!flipper_format_read_uint32(fff_data_file, "Bit", &temp_data32, 1)) { + FURI_LOG_E(TAG, "Missing or incorrect Bit"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Missing or incorrect Bit"); + break; + } else { + FURI_LOG_I(TAG, "Bit: %d", temp_data32); + context->bit = temp_data32; + } + + // Key + if(!flipper_format_read_string(fff_data_file, "Key", temp_str)) { + FURI_LOG_E(TAG, "Missing or incorrect Key"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Missing or incorrect Key"); + break; + } else { + FURI_LOG_I(TAG, "Key: %s", string_get_cstr(temp_str)); + string_set(context->key, string_get_cstr(temp_str)); + } + + // TE + if(!flipper_format_read_uint32(fff_data_file, "TE", &temp_data32, 1)) { + FURI_LOG_E(TAG, "Missing or incorrect TE"); + //string_reset(context->notification_msg); + //string_set_str(context->notification_msg, "Missing or incorrect TE"); + //break; + } else { + FURI_LOG_I(TAG, "TE: %d", temp_data32); + context->te = temp_data32; + } + + // Repeat + if(flipper_format_read_uint32(fff_data_file, "Repeat", &temp_data32, 1)) { + FURI_LOG_I(TAG, "Repeat: %d", temp_data32); + context->repeat = temp_data32; + } else { + FURI_LOG_I(TAG, "Repeat: 3 (default)"); + context->repeat = 3; + } + + result = true; + } while(0); + + string_clear(temp_str); + flipper_format_file_close(fff_data_file); + flipper_format_free(fff_data_file); + if(result) { + FURI_LOG_I(TAG, "Loaded successfully"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "File looks ok."); + } + + return result; +} + +void subbrute_scene_load_file_on_enter(SubBruteState* context) { + if(subbrute_load_protocol_from_file(context)) { + context->current_scene = SceneSelectField; + } else { + subbrute_scene_entrypoint_on_enter(context); + context->current_scene = SceneEntryPoint; + } +} + +void subbrute_scene_load_file_on_exit(SubBruteState* context) { + UNUSED(context); +} + +void subbrute_scene_load_file_on_tick(SubBruteState* context) { + UNUSED(context); +} + +void subbrute_scene_load_file_on_event(SubBruteEvent event, SubBruteState* context) { + UNUSED(context); + if(event.evt_type == EventTypeKey) { + if(event.input_type == InputTypeShort) { + switch(event.key) { + case InputKeyDown: + case InputKeyUp: + case InputKeyLeft: + case InputKeyRight: + case InputKeyOk: + break; + case InputKeyBack: + context->current_scene = SceneEntryPoint; + break; + } + } + } +} + +void subbrute_scene_load_file_on_draw(Canvas* canvas, SubBruteState* context) { + UNUSED(context); + 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, 16, AlignCenter, AlignTop, "SubGHz Fuzzer"); + canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignTop, "Error: Press back"); +} + +bool subbrute_load_protocol_from_file(SubBruteState* context) { + string_t file_path; + string_init(file_path); + string_set_str(file_path, SUBGHZ_APP_PATH_FOLDER); + + // Input events and views are managed by file_select + bool res = dialog_file_browser_show( + context->dialogs, file_path, file_path, SUBGHZ_APP_EXTENSION, true, &I_sub1_10px, true); + + if(res) { + res = subbrute_load(context, string_get_cstr(file_path)); + } + + string_clear(file_path); + + return res; +} \ No newline at end of file diff --git a/applications/subbrute/scene/subbrute_scene_load_file.h b/applications/subbrute/scene/subbrute_scene_load_file.h new file mode 100644 index 000000000..9e186b1c9 --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_load_file.h @@ -0,0 +1,8 @@ +#include "../subbrute.h" + +void subbrute_scene_load_file_on_enter(SubBruteState* context); +void subbrute_scene_load_file_on_exit(SubBruteState* context); +void subbrute_scene_load_file_on_tick(SubBruteState* context); +void subbrute_scene_load_file_on_event(SubBruteEvent event, SubBruteState* context); +void subbrute_scene_load_file_on_draw(Canvas* canvas, SubBruteState* context); +bool subbrute_load_protocol_from_file(SubBruteState* context); \ No newline at end of file diff --git a/applications/subbrute/scene/subbrute_scene_run_attack.c b/applications/subbrute/scene/subbrute_scene_run_attack.c new file mode 100644 index 000000000..89d8c291c --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_run_attack.c @@ -0,0 +1,366 @@ +#include "subbrute_scene_run_attack.h" +#include +#include + +uint64_t subbrute_counter = 0; +uint64_t max_value; +bool locked = false; +bool toSave = false; +char subbrute_payload_byte[4]; +#define SUBBRUTE_DELAY 1 + +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; +} + +void subbrute_emit(SubBruteState* context) { + //FURI_LOG_D(TAG, string_get_cstr(context->flipper_format_string)); + + context->transmitter = + subghz_transmitter_alloc_init(context->environment, string_get_cstr(context->protocol)); + + subghz_transmitter_deserialize(context->transmitter, context->flipper_format); + furi_hal_subghz_reset(); + furi_hal_subghz_load_preset(str_to_preset(context->preset)); + + context->frequency_cal = furi_hal_subghz_set_frequency_and_path(context->frequency); + + furi_hal_subghz_start_async_tx(subghz_transmitter_yield, context->transmitter); + while(!(furi_hal_subghz_is_async_tx_complete())) { + furi_delay_ms(1); + } + + furi_hal_subghz_stop_async_tx(); + subghz_transmitter_stop(context->transmitter); + furi_hal_subghz_idle(); + subghz_transmitter_free(context->transmitter); +} + +void prepare_emit(SubBruteState* context) { + UNUSED(context); + + furi_hal_subghz_init(); +} + +void clear_emit(SubBruteState* context) { + UNUSED(context); + + furi_hal_subghz_stop_async_tx(); + furi_hal_subghz_idle(); + furi_hal_subghz_sleep(); +} +/* +void subbrute_send_raw_packet(SubBruteState* context) { + string_reset(context->candidate); + + // Payload to padded binary string + int* binaryNum = (int*)malloc(sizeof(int) * context->bit); + uint32_t i = 0; + for(i = 0; i < context->bit; i++) { + binaryNum[i] = 0; + } + i = 0; + uint64_t counter = context->payload; + while(counter > 0) { + binaryNum[i] = counter % 2; + counter = counter / 2; + i++; + } + + // printing binary array in reverse order and build raw payload + for(uint32_t loop = 0; loop < context->repeat; loop++) { + for(int j = (int)context->bit - 1; j >= 0; j--) { + if(binaryNum[j] == 1) { + string_cat(context->candidate, context->subbrute_raw_one); + } else { + string_cat(context->candidate, context->subbrute_raw_zero); + } + } + string_cat(context->candidate, context->subbrute_raw_stop); + } + + free(binaryNum); + + string_init_printf( + context->flipper_format_string, + "Filetype: Flipper SubGhz RAW File\n" + "Version: 1\n" + "Frequency: %d\n" + "Preset: %s\n" + "Protocol: RAW\n" + "RAW_Data: %s", + context->frequency, + string_get_cstr(context->preset), + string_get_cstr(context->candidate)); + + subbrute_emit(context); +} +*/ +void subbrute_send_packet_parsed(SubBruteState* context) { + if(context->attack == SubBruteAttackLoadFile) { + snprintf(subbrute_payload_byte, 4, "%02X ", (uint8_t)context->payload); + string_replace_at(context->candidate, context->str_index, 3, subbrute_payload_byte); + } else { + string_t buffer; + string_init(buffer); + string_init_printf(buffer, "%16X", context->payload); + int j = 0; + string_set_str(context->candidate, " "); + for(uint8_t i = 0; i < 16; i++) { + if(string_get_char(buffer, i) != ' ') { + string_set_char(context->candidate, i + j, string_get_char(buffer, i)); + } else { + string_set_char(context->candidate, i + j, '0'); + } + if(i % 2 != 0) { + j++; + } + } + string_clear(buffer); + } + if(strcmp(string_get_cstr(context->protocol), "Princeton") == 0) { + string_init_printf( + context->flipper_format_string, + "Filetype: Flipper SubGhz Key File\n" + "Version: 1\n" + "Frequency: %u\n" + "Preset: %s\n" + "Protocol: %s\n" + "Bit: %d\n" + "Key: %s\n" + "TE: %d\n", + context->frequency, + string_get_cstr(context->preset), + string_get_cstr(context->protocol), + context->bit, + string_get_cstr(context->candidate), + context->te); + } else { + string_init_printf( + context->flipper_format_string, + "Filetype: Flipper SubGhz Key File\n" + "Version: 1\n" + "Frequency: %u\n" + "Preset: %s\n" + "Protocol: %s\n" + "Bit: %d\n" + "Key: %s\n", + context->frequency, + string_get_cstr(context->preset), + string_get_cstr(context->protocol), + context->bit, + string_get_cstr(context->candidate)); + } + + stream_clean(context->stream); + stream_write_string(context->stream, context->flipper_format_string); + + subbrute_emit(context); +} + +void subbrute_send_packet(SubBruteState* context) { + ///if(string_cmp_str(context->protocol, "RAW") == 0) { + // subbrute_send_raw_packet(context); + //} else { + subbrute_send_packet_parsed(context); + //} + string_clear(context->flipper_format_string); +} + +void subbrute_scene_run_attack_on_exit(SubBruteState* context) { + if(!toSave) { + clear_emit(context); + furi_thread_free(context->bruthread); + } +} + +void subbrute_scene_run_attack_on_tick(SubBruteState* context) { + if(!context->is_attacking || locked) { + return; + } + //if(0 != subbrute_counter) { + locked = true; + subbrute_send_packet(context); + + if(context->payload == max_value) { + context->payload = 0x00; + subbrute_counter = 0; + context->is_attacking = false; + notification_message(context->notify, &sequence_blink_stop); + notification_message(context->notify, &sequence_single_vibro); + } else { + context->payload++; + } + locked = false; + //} + /*if(subbrute_counter > SUBBRUTE_DELAY) { + subbrute_counter = 0; + } else { + subbrute_counter++; + }*/ +} +void subbrute_run_timer(SubBruteState* context) { + while(true) { + if(context->close_thread_please) { + context->is_thread_running = false; + break; + } + //furi_delay_ms(10); + subbrute_scene_run_attack_on_tick(context); + } +} + +// entrypoint for worker +static int32_t subbrute_worker_thread(void* ctx) { + SubBruteState* app = ctx; + subbrute_run_timer(app); + return 0; +} + +void start_bruthread(SubBruteState* app) { + if(!app->is_thread_running) { + furi_thread_start(app->bruthread); + app->is_thread_running = true; + } +} + +void subbrute_scene_run_attack_on_enter(SubBruteState* context) { + if(!toSave) { + if(context->attack == SubBruteAttackLoadFile) { + max_value = 0xFF; + } else { + string_t max_value_s; + string_init(max_value_s); + for(uint8_t i = 0; i < context->bit; i++) { + string_cat_printf(max_value_s, "1"); + } + max_value = (uint64_t)strtol(string_get_cstr(max_value_s), NULL, 2); + string_clear(max_value_s); + } + context->str_index = (context->key_index * 3); + string_init_set(context->candidate, context->key); + context->flipper_format = flipper_format_string_alloc(); + context->stream = flipper_format_get_raw_stream(context->flipper_format); + context->environment = subghz_environment_alloc(); + + prepare_emit(context); + context->bruthread = furi_thread_alloc(); + furi_thread_set_name(context->bruthread, "SubBrute Worker"); + furi_thread_set_stack_size(context->bruthread, 2048); + furi_thread_set_context(context->bruthread, context); + furi_thread_set_callback(context->bruthread, subbrute_worker_thread); + } else { + toSave = false; + } +} + +void subbrute_scene_run_attack_on_event(SubBruteEvent event, SubBruteState* context) { + if(event.evt_type == EventTypeKey) { + if(event.input_type == InputTypeShort) { + switch(event.key) { + case InputKeyDown: + break; + case InputKeyUp: + if(!context->is_attacking) { + toSave = true; + context->current_scene = SceneSaveName; + } + break; + case InputKeyLeft: + if(!context->is_attacking && context->payload > 0x00) { + context->payload--; + subbrute_send_packet(context); + notification_message(context->notify, &sequence_blink_blue_10); + } + break; + case InputKeyRight: + if(!context->is_attacking && context->payload < max_value) { + context->payload++; + subbrute_send_packet(context); + notification_message(context->notify, &sequence_blink_blue_10); + } + break; + case InputKeyOk: + if(!context->is_attacking) { + context->is_attacking = true; + start_bruthread(context); + notification_message(context->notify, &sequence_blink_start_blue); + } else { + context->is_attacking = false; + context->close_thread_please = true; + if(context->is_thread_running && context->bruthread) { + furi_thread_join(context->bruthread); // wait until thread is finished + } + context->close_thread_please = false; + notification_message(context->notify, &sequence_blink_stop); + notification_message(context->notify, &sequence_single_vibro); + } + break; + case InputKeyBack: + locked = false; + context->close_thread_please = true; + context->is_attacking = false; + if(context->is_thread_running && context->bruthread) { + furi_thread_join(context->bruthread); // wait until thread is finished + } + context->close_thread_please = false; + string_reset(context->notification_msg); + context->payload = 0x00; + subbrute_counter = 0; + notification_message(context->notify, &sequence_blink_stop); + if(context->attack == SubBruteAttackLoadFile) { + context->current_scene = SceneSelectField; + } else { + context->current_scene = SceneEntryPoint; + } + break; + } + } + } +} + +void subbrute_scene_run_attack_on_draw(Canvas* canvas, SubBruteState* context) { + 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, "Fire in the hole!"); + + char msg_index[26]; + snprintf( + msg_index, sizeof(msg_index), "< %04d / %04d >", (int)context->payload, (int)max_value); + + canvas_draw_str_aligned(canvas, 64, 24, AlignCenter, AlignTop, msg_index); + + canvas_set_font(canvas, FontSecondary); + char start_stop_msg[20]; + snprintf(start_stop_msg, sizeof(start_stop_msg), " Press (^) to save "); + if(context->is_attacking) { + elements_button_center(canvas, "Stop"); + } else { + elements_button_center(canvas, "Start"); + } + canvas_draw_str_aligned(canvas, 64, 39, AlignCenter, AlignTop, start_stop_msg); +} diff --git a/applications/subbrute/scene/subbrute_scene_run_attack.h b/applications/subbrute/scene/subbrute_scene_run_attack.h new file mode 100644 index 000000000..1eb9637d0 --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_run_attack.h @@ -0,0 +1,8 @@ +#include "../subbrute.h" + +void subbrute_scene_run_attack_on_enter(SubBruteState* context); +void subbrute_scene_run_attack_on_exit(SubBruteState* context); +void subbrute_scene_run_attack_on_tick(SubBruteState* context); +void subbrute_scene_run_attack_on_event(SubBruteEvent event, SubBruteState* context); +void subbrute_scene_run_attack_on_draw(Canvas* canvas, SubBruteState* context); +void send_packet(); \ No newline at end of file diff --git a/applications/subbrute/scene/subbrute_scene_save_name.c b/applications/subbrute/scene/subbrute_scene_save_name.c new file mode 100644 index 000000000..e79cf70ed --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_save_name.c @@ -0,0 +1,222 @@ +#include "../subbrute.h" +#include "m-string.h" +#include "subghz/types.h" +#include +#include +#include + +#define MAX_TEXT_INPUT_LEN 22 + +bool backpressed = false; + +bool subbrute_path_is_file(string_t path) { + return string_end_with_str_p(path, ".sub"); +} +// method modified from subghz_i.c +// https://github.com/flipperdevices/flipperzero-firmware/blob/b0daa601ad5b87427a45f9089c8b403a01f72c2a/applications/subghz/subghz_i.c#L417-L456 +bool subbrute_save_protocol_to_file(Stream* flipper_format_stream, const char* dev_file_name) { + furi_assert(dev_file_name); + + Storage* storage = furi_record_open(RECORD_STORAGE); + + bool saved = false; + string_t file_dir; + string_init(file_dir); + + path_extract_dirname(dev_file_name, file_dir); + do { + 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; + } + + stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); + stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); + + saved = true; + FURI_LOG_D(TAG, "(save) OK Save"); + } while(0); + string_clear(file_dir); + furi_record_close(RECORD_STORAGE); + return saved; +} + +void custom_callback(SubBruteState* context) { + if(strcmp(context->file_name_tmp, "")) { + string_cat_printf(context->file_path, "/%s%s", context->file_name_tmp, ".sub"); + if(subbrute_path_is_file(context->file_path_tmp)) { + context->current_scene = SceneAttack; + return; //false; + + } else { + subbrute_save_protocol_to_file(context->stream, string_get_cstr(context->file_path)); + } + + string_set_str(context->file_path, EXT_PATH("subghz")); + string_reset(context->file_path_tmp); + + //scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveSuccess); + context->current_scene = SceneAttack; + return; //true; + } else { + //error no file name + context->current_scene = SceneAttack; + return; //true; + } +} + +void subbrute_scene_save_name_text_input_callback(void* context) { + furi_assert(context); + SubBruteState* statee = context; + custom_callback(statee); +} + +void subbrute_scene_save_name_on_tick(SubBruteState* context) { + if(backpressed) { + void* validator_context = text_input_get_validator_callback_context(context->text_input); + text_input_set_validator(context->text_input, NULL, NULL); + validator_is_file_free(validator_context); + + // Clear view + text_input_reset(context->text_input); + + // TextInput + view_dispatcher_remove_view(context->view_dispatcher, 0); + text_input_free(context->text_input); + + // Popup + view_dispatcher_remove_view(context->view_dispatcher, 1); + popup_free(context->popup); + + context->current_scene = SceneAttack; + } +} + +bool subbrute_back_event_callback(void* context) { + UNUSED(context); + backpressed = true; + return true; +} + +void subbrute_scene_save_name_on_enter(SubBruteState* context) { + // Text Input + context->text_input = text_input_alloc(); + view_dispatcher_add_view( + context->view_dispatcher, 0, text_input_get_view(context->text_input)); + + // Popup + context->popup = popup_alloc(); + view_dispatcher_add_view(context->view_dispatcher, 1, popup_get_view(context->popup)); + + // Setup view + TextInput* text_input = context->text_input; + bool dev_name_empty = false; + + string_t file_name; + string_t dir_name; + string_init(file_name); + string_init(dir_name); + + if(!subbrute_path_is_file(context->file_path)) { + char file_name_buf[64] = {0}; + set_random_name(file_name_buf, 64); + string_set_str(file_name, file_name_buf); + string_set_str(context->file_path, EXT_PATH("subghz")); + //highlighting the entire filename by default + dev_name_empty = true; + } else { + string_set(context->file_path_tmp, context->file_path); + path_extract_dirname(string_get_cstr(context->file_path), dir_name); + path_extract_filename(context->file_path, file_name, true); + string_set(context->file_path, dir_name); + } + + strncpy(context->file_name_tmp, string_get_cstr(file_name), 64); + text_input_set_header_text(text_input, "Name signal"); + text_input_set_result_callback( + text_input, + subbrute_scene_save_name_text_input_callback, + context, + context->file_name_tmp, + MAX_TEXT_INPUT_LEN, // buffer size + dev_name_empty); + + ValidatorIsFile* validator_is_file = + validator_is_file_alloc_init(string_get_cstr(context->file_path), ".sub", ""); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + + string_clear(file_name); + string_clear(dir_name); + + view_dispatcher_set_navigation_event_callback( + context->view_dispatcher, subbrute_back_event_callback); + + view_dispatcher_switch_to_view(context->view_dispatcher, 0); +} + +void subbrute_scene_save_name_on_event(SubBruteEvent event, SubBruteState* context) { + UNUSED(context); + if(event.evt_type == EventTypeKey) { + if(event.input_type == InputTypeShort) { + switch(event.key) { + case InputKeyDown: + case InputKeyUp: + case InputKeyLeft: + case InputKeyRight: + case InputKeyOk: + break; + case InputKeyBack: + //context->current_scene = SceneAttack; + break; + } + } + } +} + +void subbrute_scene_save_name_on_exit(SubBruteState* context) { + if(!backpressed) { + // Clear validator + void* validator_context = text_input_get_validator_callback_context(context->text_input); + text_input_set_validator(context->text_input, NULL, NULL); + validator_is_file_free(validator_context); + + // Clear view + text_input_reset(context->text_input); + + // Setup view + Popup* popup = context->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, context); + popup_set_callback(popup, NULL); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(context->view_dispatcher, 1); + + furi_delay_ms(1050); + // Clear view + //Popup* popup = subghz->popup; + popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 0, NULL); + popup_set_callback(popup, NULL); + popup_set_context(popup, NULL); + popup_set_timeout(popup, 0); + popup_disable_timeout(popup); + + // TextInput + view_dispatcher_remove_view(context->view_dispatcher, 0); + text_input_free(context->text_input); + + // Popup + view_dispatcher_remove_view(context->view_dispatcher, 1); + popup_free(context->popup); + } else { + backpressed = false; + } +} \ No newline at end of file diff --git a/applications/subbrute/scene/subbrute_scene_save_name.h b/applications/subbrute/scene/subbrute_scene_save_name.h new file mode 100644 index 000000000..18a931ad8 --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_save_name.h @@ -0,0 +1,6 @@ +#include "../subbrute.h" + +void subbrute_scene_save_name_on_enter(SubBruteState* context); +void subbrute_scene_save_name_on_exit(SubBruteState* context); +void subbrute_scene_save_name_on_event(SubBruteEvent event, SubBruteState* context); +void subbrute_scene_save_name_on_tick(SubBruteState* context); \ No newline at end of file diff --git a/applications/subbrute/scene/subbrute_scene_select_field.c b/applications/subbrute/scene/subbrute_scene_select_field.c new file mode 100644 index 000000000..c65cd1663 --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_select_field.c @@ -0,0 +1,121 @@ +#include "subbrute_scene_select_field.h" + +void center_displayed_key(SubBruteState* context, uint8_t index) { + const char* key_cstr = string_get_cstr(context->key); + uint8_t str_index = (index * 3); + + char display_menu[17] = { + 'X', 'X', ' ', 'X', 'X', ' ', '<', 'X', 'X', '>', ' ', 'X', 'X', ' ', 'X', 'X', '\0'}; + + if(index > 1) { + display_menu[0] = key_cstr[str_index - 6]; + display_menu[1] = key_cstr[str_index - 5]; + } else { + display_menu[0] = ' '; + display_menu[1] = ' '; + } + + if(index > 0) { + display_menu[3] = key_cstr[str_index - 3]; + display_menu[4] = key_cstr[str_index - 2]; + } else { + display_menu[3] = ' '; + display_menu[4] = ' '; + } + + display_menu[7] = key_cstr[str_index]; + display_menu[8] = key_cstr[str_index + 1]; + + if((str_index + 4) <= (uint8_t)strlen(key_cstr)) { + display_menu[11] = key_cstr[str_index + 3]; + display_menu[12] = key_cstr[str_index + 4]; + } else { + display_menu[11] = ' '; + display_menu[12] = ' '; + } + + if((str_index + 8) <= (uint8_t)strlen(key_cstr)) { + display_menu[14] = key_cstr[str_index + 6]; + display_menu[15] = key_cstr[str_index + 7]; + } else { + display_menu[14] = ' '; + display_menu[15] = ' '; + } + + string_reset(context->notification_msg); + string_set_str(context->notification_msg, display_menu); +} + +void subbrute_scene_select_field_on_enter(SubBruteState* context) { + string_clear(context->notification_msg); +} + +void subbrute_scene_select_field_on_exit(SubBruteState* context) { + UNUSED(context); +} + +void subbrute_scene_select_field_on_tick(SubBruteState* context) { + UNUSED(context); +} + +void subbrute_scene_select_field_on_event(SubBruteEvent event, SubBruteState* context) { + if(event.evt_type == EventTypeKey) { + if(event.input_type == InputTypeShort) { + //const char* key_cstr = string_get_cstr(context->key); + + // don't look, it's ugly but I'm a python dev so... + /*uint8_t nb_bytes = 0; + for(uint8_t i = 0; i < strlen(key_cstr); i++) { + if(' ' == key_cstr[i]) { + nb_bytes++; + } + }*/ + + switch(event.key) { + case InputKeyDown: + case InputKeyUp: + break; + case InputKeyLeft: + if(context->key_index > 0) { + context->key_index--; + } + break; + case InputKeyRight: + if(context->key_index < 7) { + context->key_index++; + } + break; + case InputKeyOk: + string_reset(context->notification_msg); + context->current_scene = SceneAttack; + break; + case InputKeyBack: + string_reset(context->notification_msg); + context->current_scene = SceneSelectFile; + break; + } + //FURI_LOG_D(TAG, "Position: %d/%d", context->key_index, nb_bytes); + } + } +} + +void subbrute_scene_select_field_on_draw(Canvas* canvas, SubBruteState* context) { + 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, 10, AlignCenter, AlignTop, "use < > to select field"); + + char msg_index[18]; + snprintf(msg_index, sizeof(msg_index), "Field index : %d", context->key_index); + canvas_draw_str_aligned(canvas, 64, 26, AlignCenter, AlignTop, msg_index); + + center_displayed_key(context, context->key_index); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, 64, 40, AlignCenter, AlignTop, string_get_cstr(context->notification_msg)); +} diff --git a/applications/subbrute/scene/subbrute_scene_select_field.h b/applications/subbrute/scene/subbrute_scene_select_field.h new file mode 100644 index 000000000..e02a07ee0 --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_select_field.h @@ -0,0 +1,8 @@ +#include "../subbrute.h" + +void subbrute_scene_select_field_on_enter(SubBruteState* context); +void subbrute_scene_select_field_on_exit(SubBruteState* context); +void subbrute_scene_select_field_on_tick(SubBruteState* context); +void subbrute_scene_select_field_on_event(SubBruteEvent event, SubBruteState* context); +void subbrute_scene_select_field_on_draw(Canvas* canvas, SubBruteState* context); +void center_displayed_key(SubBruteState* context, uint8_t index); \ No newline at end of file diff --git a/applications/subbrute/subbrute.c b/applications/subbrute/subbrute.c new file mode 100644 index 000000000..bf5c2295d --- /dev/null +++ b/applications/subbrute/subbrute.c @@ -0,0 +1,269 @@ +#include "subbrute.h" + +#include "scene/subbrute_scene_load_file.h" +#include "scene/subbrute_scene_select_field.h" +#include "scene/subbrute_scene_run_attack.h" +#include "scene/subbrute_scene_entrypoint.h" +#include "scene/subbrute_scene_save_name.h" + +static void draw_callback(Canvas* const canvas, void* ctx) { + SubBruteState* subbrute_state = (SubBruteState*)acquire_mutex((ValueMutex*)ctx, 100); + + if(subbrute_state == NULL) { + return; + } + + // Draw correct Canvas + switch(subbrute_state->current_scene) { + case NoneScene: + case SceneSelectFile: + subbrute_scene_load_file_on_draw(canvas, subbrute_state); + break; + case SceneSelectField: + subbrute_scene_select_field_on_draw(canvas, subbrute_state); + break; + case SceneAttack: + subbrute_scene_run_attack_on_draw(canvas, subbrute_state); + break; + case SceneEntryPoint: + subbrute_scene_entrypoint_on_draw(canvas, subbrute_state); + break; + case SceneSaveName: + break; + } + + release_mutex((ValueMutex*)ctx, subbrute_state); +} + +void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { + furi_assert(event_queue); + + SubBruteEvent event = { + .evt_type = EventTypeKey, .key = input_event->key, .input_type = input_event->type}; + furi_message_queue_put(event_queue, &event, 100); +} + +static void timer_callback(FuriMessageQueue* event_queue) { + furi_assert(event_queue); + SubBruteEvent event = { + .evt_type = EventTypeTick, .key = InputKeyUp, .input_type = InputTypeRelease}; + furi_message_queue_put(event_queue, &event, 100); +} + +SubBruteState* subbrute_alloc() { + SubBruteState* subbrute = malloc(sizeof(SubBruteState)); + + string_init(subbrute->protocol); + string_init(subbrute->preset); + string_init(subbrute->file_path); + string_init(subbrute->file_path_tmp); + string_init_set(subbrute->notification_msg, ""); + string_init(subbrute->candidate); + string_init(subbrute->flipper_format_string); + + subbrute->previous_scene = NoneScene; + subbrute->current_scene = SceneSelectFile; + subbrute->is_running = true; + subbrute->is_attacking = false; + subbrute->key_index = 7; + subbrute->notify = furi_record_open(RECORD_NOTIFICATION); + + subbrute->view_dispatcher = view_dispatcher_alloc(); + + //Dialog + subbrute->dialogs = furi_record_open(RECORD_DIALOGS); + + subbrute->preset_def = malloc(sizeof(SubGhzPresetDefinition)); + + subbrute->flipper_format = flipper_format_string_alloc(); + subbrute->environment = subghz_environment_alloc(); + subbrute->receiver = subghz_receiver_alloc_init(subbrute->environment); + subghz_receiver_set_filter(subbrute->receiver, SubGhzProtocolFlag_Decodable); + + return subbrute; +} + +void subbrute_free(SubBruteState* subbrute) { + //Dialog + furi_record_close(RECORD_DIALOGS); + + notification_message(subbrute->notify, &sequence_blink_stop); + + furi_record_close(RECORD_NOTIFICATION); + + view_dispatcher_free(subbrute->view_dispatcher); + + string_clear(subbrute->preset); + string_clear(subbrute->candidate); + + // Path strings + string_clear(subbrute->file_path); + string_clear(subbrute->file_path_tmp); + string_clear(subbrute->notification_msg); + string_clear(subbrute->candidate); + string_clear(subbrute->flipper_format_string); + + flipper_format_free(subbrute->flipper_format); + subghz_environment_free(subbrute->environment); + subghz_receiver_free(subbrute->receiver); + + free(subbrute->preset_def); + + // The rest + free(subbrute); +} + +// ENTRYPOINT +int32_t subbrute_start(void* p) { + UNUSED(p); + // Input + FURI_LOG_I(TAG, "Initializing input"); + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(SubBruteEvent)); + SubBruteState* subbrute_state = subbrute_alloc(); + ValueMutex subbrute_state_mutex; + + // Mutex + FURI_LOG_I(TAG, "Initializing flipfrid mutex"); + if(!init_mutex(&subbrute_state_mutex, subbrute_state, sizeof(SubBruteState))) { + FURI_LOG_E(TAG, "cannot create mutex\r\n"); + furi_message_queue_free(event_queue); + subbrute_free(subbrute_state); + return 255; + } + + furi_hal_power_suppress_charge_enter(); + + // Configure view port + FURI_LOG_I(TAG, "Initializing viewport"); + ViewPort* view_port = view_port_alloc(); + view_port_draw_callback_set(view_port, draw_callback, &subbrute_state_mutex); + view_port_input_callback_set(view_port, input_callback, event_queue); + + // Configure timer + FURI_LOG_I(TAG, "Initializing timer"); + FuriTimer* timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, event_queue); + furi_timer_start(timer, furi_kernel_get_tick_frequency() / 10); // 10 times per second + + // Register view port in GUI + FURI_LOG_I(TAG, "Initializing gui"); + subbrute_state->gui = furi_record_open(RECORD_GUI); + gui_add_view_port(subbrute_state->gui, view_port, GuiLayerFullscreen); + + view_dispatcher_attach_to_gui( + subbrute_state->view_dispatcher, subbrute_state->gui, ViewDispatcherTypeFullscreen); + + subbrute_state->current_scene = SceneEntryPoint; + + // Init values + SubBruteEvent event; + while(subbrute_state->is_running) { + // Get next event + FuriStatus event_status = furi_message_queue_get(event_queue, &event, 25); + if(event_status == FuriStatusOk) { + if(event.evt_type == EventTypeKey) { + //Handle event key + FURI_LOG_D(TAG, "EVENT ###"); + switch(subbrute_state->current_scene) { + case SceneSelectFile: + subbrute_scene_load_file_on_event(event, subbrute_state); + break; + case SceneSelectField: + subbrute_scene_select_field_on_event(event, subbrute_state); + break; + case SceneSaveName: + subbrute_scene_save_name_on_event(event, subbrute_state); + break; + case SceneAttack: + subbrute_scene_run_attack_on_event(event, subbrute_state); + break; + case NoneScene: + case SceneEntryPoint: + subbrute_scene_entrypoint_on_event(event, subbrute_state); + break; + } + + } else if(event.evt_type == EventTypeTick) { + //Handle event tick + if(subbrute_state->current_scene != subbrute_state->previous_scene) { + // Trigger Exit Scene + switch(subbrute_state->previous_scene) { + case SceneSelectFile: + subbrute_scene_load_file_on_exit(subbrute_state); + break; + case SceneSelectField: + subbrute_scene_select_field_on_exit(subbrute_state); + break; + case SceneAttack: + subbrute_scene_run_attack_on_exit(subbrute_state); + break; + case SceneEntryPoint: + subbrute_scene_entrypoint_on_exit(subbrute_state); + break; + case SceneSaveName: + subbrute_scene_save_name_on_exit(subbrute_state); + break; + case NoneScene: + break; + } + + // Trigger Entry Scene + switch(subbrute_state->current_scene) { + case NoneScene: + case SceneSelectFile: + subbrute_scene_load_file_on_enter(subbrute_state); + break; + case SceneSelectField: + subbrute_scene_select_field_on_enter(subbrute_state); + break; + case SceneAttack: + subbrute_scene_run_attack_on_enter(subbrute_state); + break; + case SceneSaveName: + subbrute_scene_save_name_on_enter(subbrute_state); + break; + case SceneEntryPoint: + subbrute_scene_entrypoint_on_enter(subbrute_state); + break; + } + subbrute_state->previous_scene = subbrute_state->current_scene; + } + + // Trigger Tick Scene + switch(subbrute_state->current_scene) { + case NoneScene: + case SceneSelectFile: + subbrute_scene_load_file_on_tick(subbrute_state); + break; + case SceneSelectField: + subbrute_scene_select_field_on_tick(subbrute_state); + break; + case SceneAttack: + //subbrute_scene_run_attack_on_tick(subbrute_state); + break; + case SceneEntryPoint: + subbrute_scene_entrypoint_on_tick(subbrute_state); + break; + case SceneSaveName: + subbrute_scene_save_name_on_tick(subbrute_state); + break; + } + view_port_update(view_port); + } + } + } + + // Cleanup + furi_timer_stop(timer); + furi_timer_free(timer); + + furi_hal_power_suppress_charge_exit(); + + FURI_LOG_I(TAG, "Cleaning up"); + gui_remove_view_port(subbrute_state->gui, view_port); + view_port_free(view_port); + furi_message_queue_free(event_queue); + furi_record_close(RECORD_GUI); + subbrute_free(subbrute_state); + + return 0; +} \ No newline at end of file diff --git a/applications/subbrute/subbrute.h b/applications/subbrute/subbrute.h new file mode 100644 index 000000000..b6389a910 --- /dev/null +++ b/applications/subbrute/subbrute.h @@ -0,0 +1,109 @@ +#pragma once +#include +#include +#include +#include +#include "m-string.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TAG "SUBBRUTE" + +typedef enum { + NoneScene, + SceneSelectFile, + SceneSelectField, + SceneAttack, + SceneEntryPoint, + SceneSaveName +} SubBruteScene; + +typedef enum { + SubBruteAttackLoadFile, + SubBruteAttackCAME12bit433, + SubBruteAttackCAME12bit868, + SubBruteAttackChamberlain9bit315, + SubBruteAttackChamberlain9bit390, + SubBruteAttackLinear10bit300, + SubBruteAttackLinear10bit310, + SubBruteAttackNICE12bit433, + SubBruteAttackNICE12bit868, +} SubBruteAttacks; + +typedef enum { + EventTypeTick, + EventTypeKey, + EventTypeCustom, +} EventType; + +typedef struct { + EventType evt_type; + InputKey key; + InputType input_type; +} SubBruteEvent; + +// STRUCTS +typedef struct { + // Application stuff + bool is_running; + bool is_attacking; + bool is_thread_running; + bool close_thread_please; + SubBruteScene current_scene; + SubBruteScene previous_scene; + NotificationApp* notify; + Gui* gui; + ViewDispatcher* view_dispatcher; + TextInput* text_input; + Popup* popup; + + // SubGhz Stuff + FuriThread* bruthread; + FlipperFormat* flipper_format; + SubGhzEnvironment* environment; + SubGhzTransmitter* transmitter; + SubGhzReceiver* receiver; + SubGhzProtocolDecoderBase* decoder_result; + SubGhzPresetDefinition* preset_def; + string_t preset; + Stream* stream; + string_t protocol; + uint32_t frequency; + uint32_t frequency_cal; + uint32_t repeat; + uint32_t bit; + string_t key; + uint32_t te; + + // Context Stuff + DialogsApp* dialogs; + char file_name_tmp[64]; + string_t file_path; + string_t file_path_tmp; + string_t notification_msg; + uint8_t key_index; + uint64_t payload; + string_t candidate; + uint8_t str_index; + string_t flipper_format_string; + + SubBruteAttacks attack; + + //Menu stuff + uint8_t menu_index; + + // RAW stuff + string_t subbrute_raw_one; + string_t subbrute_raw_zero; + string_t subbrute_raw_stop; + +} SubBruteState; \ No newline at end of file diff --git a/applications/subbrute/subbrute_utils.c b/applications/subbrute/subbrute_utils.c new file mode 100644 index 000000000..2aafc7175 --- /dev/null +++ b/applications/subbrute/subbrute_utils.c @@ -0,0 +1,13 @@ +#include "subbrute_utils.h" + +bool subbrute_is_frequency_allowed(SubBruteState* context) { + // I know you don't like it but laws are laws + // It's opensource so do whatever you want, but remember the risks :) + // (Yes, this comment is the only purpose of this function) + bool r = furi_hal_subghz_is_tx_allowed(context->frequency); + if(!r) { + FURI_LOG_E(TAG, "Frequency %d is not allowed in your region", context->frequency); + notification_message(context->notify, &sequence_single_vibro); + } + return r; +} \ No newline at end of file diff --git a/applications/subbrute/subbrute_utils.h b/applications/subbrute/subbrute_utils.h new file mode 100644 index 000000000..90f7c60ad --- /dev/null +++ b/applications/subbrute/subbrute_utils.h @@ -0,0 +1,4 @@ +#pragma once +#include "subbrute.h" + +bool subbrute_is_frequency_allowed(SubBruteState* context); \ No newline at end of file diff --git a/applications/subghz/helpers/subghz_types.h b/applications/subghz/helpers/subghz_types.h index 55ed40f84..d6d6d025f 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 47cfe8212..c2731910b 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 000000000..4f532b0fd --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_decode_raw.c @@ -0,0 +1,273 @@ +#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; + subghz->in_decoder_scene = true; + 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 a5bade927..7c1b8f7bf 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 7c1f016d0..9d65072ce 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/scenes/subghz_scene_receiver_info.c b/applications/subghz/scenes/subghz_scene_receiver_info.c index c25d6ef8b..47b4110e2 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->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; } - if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { - subghz->txrx->hopper_state = SubGhzHopperStateRunnig; - } - 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 fab68fb4d..97c8232e6 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_cli.c b/applications/subghz/subghz_cli.c index 1d67f97de..204533134 100644 --- a/applications/subghz/subghz_cli.c +++ b/applications/subghz/subghz_cli.c @@ -109,19 +109,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; } @@ -134,9 +136,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; @@ -144,12 +147,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); @@ -420,7 +424,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"); diff --git a/applications/subghz/subghz_i.h b/applications/subghz/subghz_i.h index 1f6e73572..03e049900 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; }; @@ -137,3 +139,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 c28c33636..747a65d63 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,19 @@ 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_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); + } } switch(model->bar_show) { @@ -334,6 +369,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 +405,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 +424,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 aab7a76c5..829277174 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/applications/subghz/views/subghz_frequency_analyzer.c b/applications/subghz/views/subghz_frequency_analyzer.c index 14942fc75..5be00888f 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; @@ -52,6 +53,7 @@ typedef struct { float rssi; float rssi_last; float trigger; + uint8_t feedback_level; } SubGhzFrequencyAnalyzerModel; void subghz_frequency_analyzer_set_callback( @@ -141,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+"); @@ -174,6 +191,16 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { need_redraw = true; } + if(event->type == InputTypePress && event->key == InputKeyDown) { + 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( @@ -182,6 +209,7 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { 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; }); } @@ -218,7 +246,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 @@ -236,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; }); } @@ -294,6 +334,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( diff --git a/applications/system/system_settings.h b/applications/system/system_settings.h old mode 100755 new mode 100644 diff --git a/applications/unirfremix/unirfremix_app.c b/applications/unirfremix/unirfremix_app.c index b943b44a1..4e0dab2e7 100644 --- a/applications/unirfremix/unirfremix_app.c +++ b/applications/unirfremix/unirfremix_app.c @@ -4,6 +4,8 @@ #include #include #include + +#include #include #include @@ -12,11 +14,30 @@ #include #include +#include +#include +#include +#include +#include + #define UNIRFMAP_FOLDER "/ext/unirf" #define UNIRFMAP_EXTENSION ".txt" #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; @@ -25,6 +46,12 @@ typedef struct { ViewPort* view_port; Gui* gui; + SubGhzSetting* setting; + SubGhzEnvironment* environment; + SubGhzReceiver* subghz_receiver; + NotificationApp* notification; + UniRFPreset* txpreset; + string_t up_file; string_t down_file; string_t left_file; @@ -55,7 +82,10 @@ 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 button; int file_result; @@ -63,9 +93,22 @@ typedef struct { int file_blank; string_t signal; - } UniRFRemix; +UniRFPreset* unirfremix_preset_alloc(void) { + UniRFPreset* preset = malloc(sizeof(UniRFPreset)); + string_init(preset->name); + string_init(preset->protocol); + preset->repeat = 200; + return preset; +} + +void unirfremix_preset_free(UniRFPreset* preset) { + string_clear(preset->name); + string_clear(preset->protocol); + free(preset); +} + static char* char_to_str(char* str, int i) { char* converted = malloc(sizeof(char) * i + 1); memcpy(converted, str, i); @@ -74,7 +117,7 @@ static char* char_to_str(char* str, int i) { return converted; } - +/* static const char* int_to_char(int number) { switch(number) { case 0: @@ -101,38 +144,7 @@ static const char* int_to_char(int number) { return "0"; } } - -/*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; @@ -145,13 +157,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); @@ -170,90 +182,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)); } @@ -264,8 +254,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"; @@ -278,13 +267,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"; } @@ -294,13 +281,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"; } @@ -310,13 +295,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"; } @@ -326,13 +309,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"; } @@ -342,15 +323,14 @@ 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 //Check each file definition if not already set to "N/A" @@ -359,7 +339,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 @@ -372,11 +352,10 @@ 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))) { - 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; @@ -385,78 +364,76 @@ 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))) { - 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); } 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))) { - 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); } 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))) { - 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); } 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))) { - 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); } + furi_record_close(RECORD_STORAGE); + if(app->file_blank == 5) { app->file_result = 1; } else { @@ -469,74 +446,271 @@ static void unirfremix_end_send(UniRFRemix* app) { app->processing = 0; } -static void unirfremix_send_signal( - UniRFRemix* app, - uint32_t frequency, - string_t signal, - string_t protocol) { - 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; +bool unirfremix_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")) { + FURI_LOG_E(TAG, "Custom preset unsupported now"); + return false; + // string_set(p->name, "CUSTOM"); } else { - app->tx_not_allowed = false; + FURI_LOG_E(TAG, "Unsupported preset"); + return 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; + return true; +} - 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); +bool unirfremix_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 false; + } + + string_t temp_str; + string_init(temp_str); + + bool res = false; + + do { + // load frequency from file + if(!flipper_format_read_uint32(fff_file, "Frequency", &preset->frequency, 1)) { + FURI_LOG_W(TAG, "Cannot read frequency. Defaulting to 433.92 MHz"); + preset->frequency = 433920000; } - NotificationApp* notification = furi_record_open("notification"); + // 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(!unirfremix_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 + 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)); + preset->data = subghz_setting_get_preset_data(setting, preset_index); + preset->data_size = subghz_setting_get_preset_data_size(setting, preset_index); - 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)); + // load protocol from file + if(!flipper_format_read_string(fff_file, "Protocol", preset->protocol)) { + FURI_LOG_E(TAG, "Could not read Protocol."); + break; + } + 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)); + } - SubGhzEnvironment* environment = subghz_environment_alloc(); - SubGhzTransmitter* transmitter = - subghz_transmitter_alloc_init(environment, string_get_cstr(protocol)); - subghz_transmitter_deserialize(transmitter, flipper_format); + // 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; + } + } 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 +// 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); + + 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))) { + FURI_LOG_E(TAG, "(save) Cannot mkdir"); + break; + } + + if(!storage_simply_remove(storage, dev_file_name)) { + FURI_LOG_E(TAG, "(save) Cannot remove"); + break; + } + + stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); + stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); + + saved = true; + FURI_LOG_D(TAG, "(save) OK Save"); + } while(0); + string_clear(file_dir); + furi_record_close(RECORD_STORAGE); + return saved; +} + +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(15); + } + } + + //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 { + 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 ", + app->txpreset->frequency); + app->tx_not_allowed = true; + unirfremix_end_send(app); + break; + } else { + app->tx_not_allowed = false; + } + + app->tx_transmitter = subghz_transmitter_alloc_init( + app->environment, string_get_cstr(app->txpreset->protocol)); + if(!app->tx_transmitter) { + break; + } + + subghz_transmitter_deserialize(app->tx_transmitter, fff_data); furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); - furi_hal_subghz_set_frequency_and_path(frequency); + furi_hal_subghz_idle(); + furi_hal_subghz_load_custom_preset(app->txpreset->data); + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); - //printf("Transmitting at %lu, repeat %d.\r\n", frequency, x); + furi_hal_subghz_idle(); + 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); - furi_hal_power_suppress_charge_enter(); - furi_hal_subghz_start_async_tx(subghz_transmitter_yield, transmitter); - - while(!(furi_hal_subghz_is_async_tx_complete())) { - notification_message(notification, &sequence_blink_magenta_10); - //printf("Sending..."); - fflush(stdout); - furi_delay_ms(333); + if(!furi_hal_subghz_tx()) { + FURI_LOG_E(TAG, "Sending not allowed"); + break; } - furi_record_close("notification"); + FURI_LOG_I(TAG, "Sending..."); + notification_message(app->notification, &sequence_blink_start_magenta); - furi_hal_subghz_stop_async_tx(); - furi_hal_subghz_sleep(); + furi_hal_subghz_start_async_tx(subghz_transmitter_yield, app->tx_transmitter); - furi_hal_power_suppress_charge_exit(); + res = true; + } while(0); - flipper_format_free(flipper_format); - subghz_transmitter_free(transmitter); - subghz_environment_free(environment); + return res; +} + +static void unirfremix_send_signal(UniRFRemix* app, Storage* storage, const char* path) { + FURI_LOG_I(TAG, "Sending: %s", path); + + app->tx_file_path = path; + + app->tx_fff_data = flipper_format_string_alloc(); + + app->txpreset = unirfremix_preset_alloc(); + + // 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) { @@ -545,36 +719,9 @@ static void unirfremix_process_signal(UniRFRemix* app, string_t signal) { FURI_LOG_I(TAG, "signal = %s", string_get_cstr(signal)); if(strlen(string_get_cstr(signal)) > 12) { - string_t file_name; - string_init(file_name); - - string_t protocol; - string_init(protocol); - - uint32_t frequency_str; - - string_set(file_name, string_get_cstr(signal)); - Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); - - flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name)); - - flipper_format_read_uint32(fff_data_file, "Frequency", (uint32_t*)&frequency_str, 1); - - 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_file); + unirfremix_send_signal(app, storage, string_get_cstr(signal)); furi_record_close(RECORD_STORAGE); - - FURI_LOG_I(TAG, "%lu", frequency_str); - - string_clear(file_name); - - unirfremix_send_signal(app, frequency_str, signal, protocol); } else if(strlen(string_get_cstr(signal)) < 10) { unirfremix_end_send(app); } @@ -592,7 +739,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); @@ -601,7 +748,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); @@ -632,8 +779,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); @@ -667,8 +813,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); @@ -676,11 +821,28 @@ 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); } -UniRFRemix* unirfremix_alloc() { +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")); + + // 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")); + + 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); @@ -695,6 +857,8 @@ UniRFRemix* unirfremix_alloc() { app->gui = furi_record_open(RECORD_GUI); gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen); + app->notification = furi_record_open(RECORD_NOTIFICATION); + return app; } @@ -713,6 +877,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); @@ -722,6 +887,13 @@ 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); + + furi_record_close(RECORD_NOTIFICATION); + free(app); } @@ -757,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) { @@ -767,10 +939,13 @@ 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) { - FURI_LOG_I( + FURI_LOG_D( TAG, "U: %s - D: %s - L: %s - R: %s - O: %s ", string_get_cstr(app->up_file), @@ -783,19 +958,21 @@ 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 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) { 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), @@ -803,7 +980,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; @@ -813,10 +990,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; @@ -826,10 +1008,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; @@ -839,10 +1026,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; @@ -852,10 +1044,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; @@ -865,30 +1062,26 @@ 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; - } + unirfremix_tx_stop(app); + exit_loop = true; break; } 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"; @@ -931,7 +1124,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), @@ -949,9 +1142,7 @@ int32_t unirfremix_app(void* p) { case InputKeyOk: break; case InputKeyBack: - if(input.type == InputTypeLong) { - exit_loop = true; - } + exit_loop = true; break; } @@ -970,5 +1161,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 diff --git a/applications/unit_tests/subghz/subghz_test.c b/applications/unit_tests/subghz/subghz_test.c index 04f442f6c..df269ed04 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 232 #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,21 @@ 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"); +} + +MU_TEST(subghz_decoder_clemsa_test) { + mu_assert( + subghz_decoder_test( + EXT_PATH("unit_tests/subghz/clemsa_raw.sub"), SUBGHZ_PROTOCOL_CLEMSA_NAME), + "Test decoder " SUBGHZ_PROTOCOL_CLEMSA_NAME " error\r\n"); +} + //test encoders MU_TEST(subghz_encoder_princeton_test) { mu_assert( @@ -528,6 +543,18 @@ 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_encoder_clemsa_test) { + mu_assert( + subghz_encoder_test(EXT_PATH("unit_tests/subghz/clemsa.sub")), + "Test encoder " SUBGHZ_PROTOCOL_CLEMSA_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 +593,8 @@ 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_decoder_clemsa_test); MU_RUN_TEST(subghz_encoder_princeton_test); MU_RUN_TEST(subghz_encoder_came_test); @@ -585,6 +614,8 @@ 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_encoder_clemsa_test); MU_RUN_TEST(subghz_random_test); subghz_test_deinit(); diff --git a/applications/wav_player/application.fam b/applications/wav_player/application.fam index 9a1f48566..609c702f8 100644 --- a/applications/wav_player/application.fam +++ b/applications/wav_player/application.fam @@ -1,9 +1,9 @@ App( appid="wav_player", name="WAV Player", - apptype=FlipperAppType.PLUGIN, + apptype=FlipperAppType.GAME, entry_point="wav_player_app", cdefines=["APP_WAV_PLAYER"], stack_size=4 * 1024, - order=21, + order=46, ) diff --git a/assets/icons/Common/Round_loader_8x8/frame_01.png b/assets/icons/Common/Round_loader_8x8/frame_01.png new file mode 100644 index 000000000..a5dc239d8 Binary files /dev/null and b/assets/icons/Common/Round_loader_8x8/frame_01.png differ diff --git a/assets/icons/Common/Round_loader_8x8/frame_02.png b/assets/icons/Common/Round_loader_8x8/frame_02.png new file mode 100644 index 000000000..162d8a8f4 Binary files /dev/null and b/assets/icons/Common/Round_loader_8x8/frame_02.png differ diff --git a/assets/icons/Common/Round_loader_8x8/frame_03.png b/assets/icons/Common/Round_loader_8x8/frame_03.png new file mode 100644 index 000000000..5483e4734 Binary files /dev/null and b/assets/icons/Common/Round_loader_8x8/frame_03.png differ diff --git a/assets/icons/Common/Round_loader_8x8/frame_04.png b/assets/icons/Common/Round_loader_8x8/frame_04.png new file mode 100644 index 000000000..ce2fbbd47 Binary files /dev/null and b/assets/icons/Common/Round_loader_8x8/frame_04.png differ diff --git a/assets/icons/Common/Round_loader_8x8/frame_05.png b/assets/icons/Common/Round_loader_8x8/frame_05.png new file mode 100644 index 000000000..8b786c029 Binary files /dev/null and b/assets/icons/Common/Round_loader_8x8/frame_05.png differ diff --git a/assets/icons/Common/Round_loader_8x8/frame_rate b/assets/icons/Common/Round_loader_8x8/frame_rate new file mode 100644 index 000000000..d8263ee98 --- /dev/null +++ b/assets/icons/Common/Round_loader_8x8/frame_rate @@ -0,0 +1 @@ +2 \ No newline at end of file diff --git a/assets/icons/Infrared/Rotate_25x27.png b/assets/icons/Infrared/Rotate_25x27.png new file mode 100644 index 000000000..0c62e9dc1 Binary files /dev/null and b/assets/icons/Infrared/Rotate_25x27.png differ diff --git a/assets/icons/Infrared/Rotate_hvr_25x27.png b/assets/icons/Infrared/Rotate_hvr_25x27.png new file mode 100644 index 000000000..d2ab0f3fc Binary files /dev/null and b/assets/icons/Infrared/Rotate_hvr_25x27.png differ diff --git a/assets/icons/Infrared/Swing_25x27.png b/assets/icons/Infrared/Swing_25x27.png new file mode 100644 index 000000000..38a6c9040 Binary files /dev/null and b/assets/icons/Infrared/Swing_25x27.png differ diff --git a/assets/icons/Infrared/Swing_hvr_25x27.png b/assets/icons/Infrared/Swing_hvr_25x27.png new file mode 100644 index 000000000..6e65b4e2e Binary files /dev/null and b/assets/icons/Infrared/Swing_hvr_25x27.png differ diff --git a/assets/icons/Infrared/Timer_25x27.png b/assets/icons/Infrared/Timer_25x27.png new file mode 100644 index 000000000..5ce468198 Binary files /dev/null and b/assets/icons/Infrared/Timer_25x27.png differ diff --git a/assets/icons/Infrared/Timer_hvr_25x27.png b/assets/icons/Infrared/Timer_hvr_25x27.png new file mode 100644 index 000000000..f6959c244 Binary files /dev/null and b/assets/icons/Infrared/Timer_hvr_25x27.png differ diff --git a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_0.png b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_0.png index 4fd68002e..f2fc132ed 100644 Binary files a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_0.png and b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_0.png differ diff --git a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_1.png b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_1.png index f09e6eee5..7bb4f3895 100644 Binary files a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_1.png and b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_1.png differ diff --git a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_2.png b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_2.png index 1192ed0af..3a27b10b2 100644 Binary files a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_2.png and b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_2.png differ diff --git a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_3.png b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_3.png index 8db45a901..72e9b7f83 100644 Binary files a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_3.png and b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_3.png differ diff --git a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_4.png b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_4.png index fbd1b47aa..3a27b10b2 100644 Binary files a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_4.png and b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_4.png differ diff --git a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_5.png b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_5.png index 92d4c523e..7bb4f3895 100644 Binary files a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_5.png and b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_5.png differ diff --git a/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_rate b/assets/icons/MainMenu/SpectrumAnalyzer_14/frame_rate index e440e5c84..bf0d87ab1 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_0.png b/assets/icons/MainMenu/UniRFRemix_14/frame_0.png index 8d135853f..166d2229b 100644 Binary files a/assets/icons/MainMenu/UniRFRemix_14/frame_0.png and b/assets/icons/MainMenu/UniRFRemix_14/frame_0.png differ diff --git a/assets/icons/MainMenu/UniRFRemix_14/frame_1.png b/assets/icons/MainMenu/UniRFRemix_14/frame_1.png index 24c349ead..8bd337c69 100644 Binary files a/assets/icons/MainMenu/UniRFRemix_14/frame_1.png and b/assets/icons/MainMenu/UniRFRemix_14/frame_1.png differ diff --git a/assets/icons/MainMenu/UniRFRemix_14/frame_2.png b/assets/icons/MainMenu/UniRFRemix_14/frame_2.png index c64bad5f2..10727049d 100644 Binary files a/assets/icons/MainMenu/UniRFRemix_14/frame_2.png and b/assets/icons/MainMenu/UniRFRemix_14/frame_2.png differ diff --git a/assets/icons/MainMenu/UniRFRemix_14/frame_3.png b/assets/icons/MainMenu/UniRFRemix_14/frame_3.png index efd7181f0..c6d314d86 100644 Binary files a/assets/icons/MainMenu/UniRFRemix_14/frame_3.png and b/assets/icons/MainMenu/UniRFRemix_14/frame_3.png differ diff --git a/assets/icons/MainMenu/UniRFRemix_14/frame_4.png b/assets/icons/MainMenu/UniRFRemix_14/frame_4.png index 300f00128..13f4bf553 100644 Binary files a/assets/icons/MainMenu/UniRFRemix_14/frame_4.png and b/assets/icons/MainMenu/UniRFRemix_14/frame_4.png differ diff --git a/assets/icons/MainMenu/UniRFRemix_14/frame_5.png b/assets/icons/MainMenu/UniRFRemix_14/frame_5.png index d41a66495..c6d314d86 100644 Binary files a/assets/icons/MainMenu/UniRFRemix_14/frame_5.png and b/assets/icons/MainMenu/UniRFRemix_14/frame_5.png differ 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 000000000..10727049d Binary files /dev/null and b/assets/icons/MainMenu/UniRFRemix_14/frame_6.png differ 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 000000000..8bd337c69 Binary files /dev/null and b/assets/icons/MainMenu/UniRFRemix_14/frame_7.png differ diff --git a/assets/icons/MainMenu/UniRFRemix_14/frame_rate b/assets/icons/MainMenu/UniRFRemix_14/frame_rate index 00750edc0..bf0d87ab1 100644 --- a/assets/icons/MainMenu/UniRFRemix_14/frame_rate +++ b/assets/icons/MainMenu/UniRFRemix_14/frame_rate @@ -1 +1 @@ -3 +4 \ No newline at end of file diff --git a/assets/icons/NFC/Reader_detect.png b/assets/icons/NFC/ArrowC_1_36x36.png similarity index 84% rename from assets/icons/NFC/Reader_detect.png rename to assets/icons/NFC/ArrowC_1_36x36.png index 56d3663ea..3a0c6dd0c 100644 Binary files a/assets/icons/NFC/Reader_detect.png and b/assets/icons/NFC/ArrowC_1_36x36.png differ diff --git a/assets/icons/NFC/Tap_reader_36x38.png b/assets/icons/NFC/Tap_reader_36x38.png new file mode 100644 index 000000000..4e0ba8f05 Binary files /dev/null and b/assets/icons/NFC/Tap_reader_36x38.png differ diff --git a/assets/icons/RFID/RFIDBigChip_37x36.png b/assets/icons/RFID/RFIDBigChip_37x36.png deleted file mode 100644 index a60d51d58..000000000 Binary files a/assets/icons/RFID/RFIDBigChip_37x36.png and /dev/null differ diff --git a/assets/icons/RFID/RFIDSmallChip_14x14.png b/assets/icons/RFID/RFIDSmallChip_14x14.png new file mode 100644 index 000000000..24219a548 Binary files /dev/null and b/assets/icons/RFID/RFIDSmallChip_14x14.png differ diff --git a/assets/resources/Manifest b/assets/resources/Manifest index 35898f60e..01feb4a51 100644 --- a/assets/resources/Manifest +++ b/assets/resources/Manifest @@ -1,10 +1,11 @@ V:0 -T:1661280310 +T:1662725830 D:badusb D:dolphin D:infrared D:music_player D:nfc +D:rfidfuzzer D:subghz D:u2f D:unirf @@ -241,23 +242,25 @@ 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:63ca357ca0b85a6ad900539e7b6a0fed:5086:infrared/assets/projectors.ir -F:0370c1333f1e0d8d690b5afbfc623a60:127656:infrared/assets/tv.ir +F:5e55f221320c8f0bbeafd5df59673e75:139785:infrared/assets/ac.ir +F:1720722745039a27440e62ea08db7f3a:60611:infrared/assets/audio.ir +F:faa49194e6ba4e5bc1ae5b2f90909d29:87512:infrared/assets/fans.ir +F:4193827d68bbdbbda9347d423752b70f:7164:infrared/assets/projectors.ir +F:b2fcc57a3d2f053bca6070c50fda0704:140314:infrared/assets/tv.ir F:a157a80f5a668700403d870c23b9567d:470:music_player/Marble_Machine.fmf D:nfc/assets F:81dc04c7b181f94b644079a71476dff4:4742:nfc/assets/aid.nfc F:86efbebdf41bb6bf15cc51ef88f069d5:2565:nfc/assets/country_code.nfc F:41b4f08774249014cb8d3dffa5f5c07d:1757:nfc/assets/currency_code.nfc F:5f57e2ecfc850efb74c7d2677eb75a2e:51832:nfc/assets/mf_classic_dict.nfc +F:319958d37b2316a2e752ebb856c32524:126:rfidfuzzer/example_uids.txt D:subghz/assets F:dda1ef895b8a25fde57c874feaaef997:650:subghz/assets/came_atomo 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 28c8c03e4..1f7b42d23 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -1,21 +1,68 @@ -Filetype: IR signals file +Filetype: IR library file Version: 1 +# Last Updated 7th Sep, 2022 +# +# TIMER ON +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4421 4371 559 1622 564 530 563 1622 564 1617 559 562 541 553 540 1615 561 561 542 528 565 1646 540 528 565 555 538 1643 543 1622 530 563 1650 536 560 533 562 541 527 566 1641 535 1620 566 1614 562 559 534 1627 559 1627 559 1621 565 1642 534 534 559 562 541 527 566 1619 567 529 564 532 561 1650 536 532 561 1623 563 1618 558 536 567 554 539 531 562 560 533 561 532 1623 563 557 536 1623 563 1617 559 1649 537 1618 558 5224 4420 4368 562 1618 568 552 541 1618 558 1649 537 531 562 532 561 1620 566 530 563 533 560 1625 561 533 560 560 533 1622 564 1617 559 535 558 1629 568 528 565 556 537 557 536 1619 567 1613 563 1618 558 536 567 1619 567 1620 566 1615 561 1620 566 528 565 555 538 530 563 1622 564 558 535 536 567 1617 559 535 568 1643 533 1622 564 531 562 533 560 536 567 555 538 557 536 1619 567 527 566 1645 541 1614 562 1619 567 1617 559 +# TIMER ON +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4407 4355 571 1574 563 509 564 1581 566 506 567 505 568 530 543 528 545 1574 563 1583 564 508 565 506 567 505 568 503 570 502 571 1573 564 509 564 507 566 1579 568 1603 544 1575 572 500 563 536 537 1581 566 506 567 1578 569 1576 571 1574 563 1583 564 1581 566 1580 567 1578 569 1576 571 1575 572 526 537 509 564 507 566 532 541 504 569 503 570 1574 563 510 563 508 565 1580 567 1578 569 503 570 1575 572 1573 564 509 564 5168 4411 4351 565 507 566 1579 568 504 569 1576 571 1574 573 1573 564 1581 566 507 566 505 568 1577 570 1575 572 1574 563 1582 565 1581 566 506 567 1578 569 1576 571 501 572 500 563 509 564 1580 567 1578 569 504 569 1576 571 501 562 510 563 508 565 507 566 531 542 530 543 502 571 527 536 510 563 1581 566 1579 568 1578 569 1576 571 1575 572 1573 564 509 564 1581 566 1579 568 504 569 503 570 1574 563 510 563 508 565 1580 567 +# SWING ON +name: SWING +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9811 9792 9816 9789 4617 2485 383 345 387 925 385 931 379 357 386 926 384 351 381 351 381 363 380 348 384 928 382 353 379 353 379 933 387 348 384 348 384 940 380 351 381 931 379 357 386 346 386 349 383 353 379 353 379 364 378 349 383 352 380 356 387 922 388 924 386 349 383 349 383 361 381 346 386 349 383 352 380 352 380 932 388 347 385 347 385 358 385 344 388 347 385 350 382 350 382 930 380 355 388 345 387 356 386 342 380 355 388 348 384 925 385 926 384 352 380 352 380 363 379 925 385 350 382 933 387 349 383 928 382 354 388 921 379 941 379 20334 4618 +# ON +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4415 4353 570 1577 565 507 569 1577 565 508 568 504 572 501 565 508 568 1578 564 1583 570 503 563 510 566 1580 573 1574 568 504 572 501 565 508 568 505 571 1576 566 506 570 503 563 510 566 506 570 503 573 499 567 1581 572 1575 567 1580 573 1574 568 1579 563 1583 570 1577 565 1581 572 1576 566 1580 573 1575 567 1579 563 1584 569 1578 564 1583 570 1577 565 508 568 1578 564 509 567 506 570 502 564 1583 570 1577 565 508 568 5166 4419 4352 571 501 565 1583 570 502 574 1573 569 1578 564 1582 571 1576 566 506 570 502 574 1573 569 1577 565 507 569 504 572 1574 568 1579 574 1572 570 1576 566 532 544 1576 566 1580 573 1574 568 1577 565 1581 572 1574 568 531 545 527 539 534 542 530 546 526 540 533 543 529 547 525 541 505 571 501 565 508 568 504 572 500 566 506 570 503 573 499 567 1578 564 508 568 1577 565 1580 573 1572 570 502 564 508 568 1577 565 +# ON +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3202 1591 383 411 383 1206 382 413 381 413 381 1207 381 412 382 1207 381 414 380 413 381 1209 379 1209 389 1199 389 406 387 1200 388 406 388 1201 387 1201 387 1202 386 409 385 409 385 411 383 409 385 1204 384 1205 383 411 383 1206 382 413 381 1206 382 1208 380 414 380 414 380 415 389 1198 379 416 388 1201 387 405 389 406 388 1201 387 1202 386 1202 386 408 386 1204 384 1206 382 410 384 1205 383 1207 381 1206 382 1207 381 1207 381 415 389 403 380 1208 380 415 389 405 389 405 389 406 388 1200 388 1201 387 1203 385 407 386 1202 386 1205 383 1203 385 1204 384 412 382 412 382 412 382 1206 382 413 381 413 381 414 380 413 381 1208 380 1208 380 415 389 1199 389 1200 388 1200 388 1201 387 1202 386 410 384 408 386 1202 386 409 385 410 384 411 383 410 384 411 383 1206 382 1206 382 1206 382 1208 380 1210 388 403 380 1210 388 1200 388 405 389 406 388 406 388 406 388 407 387 1203 385 408 386 409 385 1203 385 1203 385 410 384 1205 383 1207 381 411 383 1206 382 1206 382 413 381 414 380 1210 388 404 379 415 379 1209 389 405 389 406 388 1201 387 1201 387 1201 387 1202 386 1204 384 1203 385 1204 384 1205 383 412 382 412 382 413 381 412 382 412 382 414 380 414 380 413 381 414 380 1209 389 1199 389 1199 389 1200 388 1201 387 1201 387 408 386 1201 387 408 385 409 385 410 384 410 384 410 384 411 383 1205 383 +# ON +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4463 4417 539 1598 546 495 546 1591 543 1592 542 501 540 502 539 1597 547 496 545 496 545 1591 543 499 542 500 541 1594 540 1597 547 494 547 1590 544 497 544 499 542 1593 541 1596 538 1597 547 1589 545 1590 544 1593 541 1594 540 1597 547 494 547 496 545 496 545 497 544 497 544 499 542 500 541 500 541 1596 538 503 538 504 547 494 547 495 546 495 546 1590 544 1591 543 499 542 1593 541 1595 539 1596 538 1599 545 1589 545 5190 4441 4412 544 1591 543 500 541 1594 540 1596 538 503 538 505 546 1588 546 497 544 499 542 1592 542 500 541 500 541 1595 539 1595 539 504 547 1586 548 494 547 495 546 1589 545 1590 544 1592 542 1594 540 1597 547 1587 547 1589 545 1589 545 498 543 498 543 499 542 499 542 501 540 502 539 501 540 503 538 1596 538 504 547 493 537 505 546 495 546 494 547 1589 545 1590 544 497 544 1591 543 1593 541 1594 540 1597 547 1589 545 +# +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 +# +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 +# +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 # -# Universal AC IR codes - Brute force updated by jaroslavmraz -# Fixes and tweaks provided by MX (MasterX) -# -# BETA version - Aug 23, 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 # -# Airmet AC by JEREMYNO -# name: POWER type: raw frequency: 38000 @@ -40,8 +87,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 @@ -54,31 +99,36 @@ 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 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 address: 81 00 00 00 command: 6B 00 00 00 -# +# name: TEMP+ type: parsed protocol: NEC @@ -90,30 +140,30 @@ type: parsed 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 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 @@ -121,8 +171,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 @@ -135,8 +183,6 @@ protocol: NECext address: 48 44 00 00 command: 88 08 00 00 # -# Friedrich AC -# name: POWER type: raw frequency: 38000 @@ -155,16 +201,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 @@ -189,8 +231,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 @@ -215,8 +255,6 @@ protocol: NECext address: 98 6F 00 00 command: 08 F7 00 00 # -# Hisense Window AC -# name: POWER type: raw frequency: 38000 @@ -241,8 +279,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 @@ -261,8 +297,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 @@ -275,24 +309,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 @@ -316,8 +344,6 @@ 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 type: parsed @@ -337,8 +363,6 @@ protocol: NECext address: 81 66 00 00 command: 85 7A 00 00 # -# LG Portable AC LP1015WNR -# name: POWER type: parsed protocol: NECext @@ -357,8 +381,6 @@ protocol: NECext address: 10 E7 00 00 command: 0D F2 00 00 # -# Midea_AC_MAW05R1WBL -# name: POWER type: raw frequency: 38000 @@ -383,40 +405,36 @@ 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 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 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 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 @@ -429,36 +447,30 @@ 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 address: 80 00 00 00 command: 9C 00 00 00 -# +# name: MODE type: parsed protocol: NEC address: 80 00 00 00 command: 9D 00 00 00 # -# Toshiba AC -# name: POWER type: parsed protocol: NECext @@ -477,8 +489,6 @@ protocol: NECext address: 01 FF 00 00 command: 13 EC 00 00 # -# Toshiba RAS-13SKV2-E -# name: POWER type: raw frequency: 38000 @@ -496,9 +506,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 @@ -523,16 +530,12 @@ 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 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 @@ -551,365 +554,526 @@ 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 type: parsed protocol: NECext 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 -# 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: TIMER +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 9F 00 00 00 +# 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 +# +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 +# 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 +# +name: TIMER +type: parsed +protocol: NEC +address: 81 00 00 00 +command: 69 00 00 00 +# 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 +# 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: TIMER +type: parsed +protocol: NECext +address: 48 44 00 00 +command: C8 08 00 00 +# 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: TIMER +type: parsed +protocol: NECext +address: 01 FF 00 00 +command: 1B E4 00 00 +# 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: 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 +# +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 +# +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 +# +name: SWING +type: parsed +protocol: NECext +address: 10 E7 00 00 +command: 06 F9 00 00 +# +name: TIMER +type: parsed +protocol: NECext +address: 81 66 00 00 +command: 9F 60 00 00 +# 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 +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 -# +# 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 -# +# POWER OFF 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 +# +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 +# 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: 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 +# 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 +# +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 +# 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 +# +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 +# +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 +# OFF +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4468 4412 543 1593 541 502 539 1596 548 1589 545 496 545 498 543 1593 541 501 540 502 539 1598 546 495 546 497 544 1591 543 1594 540 501 539 1597 547 494 547 1590 544 1591 543 1594 540 1595 539 504 547 1588 546 1590 544 1593 540 501 539 503 538 503 538 505 546 1588 546 497 544 496 545 1592 542 1592 542 1594 540 501 539 503 538 503 538 505 546 494 547 496 545 496 545 497 544 1590 544 1593 541 1594 540 1597 547 1589 545 5188 4430 4421 544 1592 541 499 541 1595 539 1596 538 505 546 494 547 1589 545 497 544 496 545 1592 542 500 540 499 542 1594 540 1596 538 503 538 1599 545 497 544 1591 543 1593 541 1595 539 1596 538 504 547 1588 546 1588 546 1590 544 498 542 498 543 499 541 500 541 1593 541 501 540 502 539 1597 547 1586 548 1587 547 496 545 495 546 497 544 498 543 497 544 498 543 499 542 498 542 1592 542 1594 540 1595 539 1597 547 1589 545 +# AUTO MODE +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4456 4417 538 1597 547 494 547 1589 545 1590 544 498 543 499 541 1593 541 501 539 502 539 1595 539 501 539 502 538 1596 538 1595 538 503 538 1597 547 493 537 504 547 495 546 1587 547 1587 547 1588 545 1588 546 1588 545 1589 545 1590 544 1590 544 497 544 498 543 497 544 498 543 498 543 497 544 1591 543 1592 542 1591 543 1592 542 499 542 498 543 499 542 1592 542 500 541 499 541 499 542 500 541 1591 543 1591 543 1591 543 5185 4434 4411 544 1591 543 498 543 1590 544 1590 544 497 543 497 544 1590 544 497 544 498 543 1589 545 496 545 497 544 1588 545 1588 546 495 545 1587 547 494 547 495 546 494 536 1597 547 1586 547 1585 538 1596 538 1596 537 1596 538 1594 540 1594 539 502 539 501 540 501 540 501 540 500 540 500 540 1593 541 1591 543 1591 543 1591 542 497 544 498 543 498 542 1591 543 496 545 497 544 497 544 496 545 1588 546 1588 546 1586 547 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8968 4464 593 1659 559 593 536 563 566 1660 558 567 562 563 536 590 539 560 559 567 542 584 535 564 565 1660 568 557 562 564 535 1665 594 1658 560 1665 563 588 541 1659 559 1666 593 559 539 586 533 566 563 563 536 1663 585 566 533 593 536 563 566 560 539 587 532 567 562 563 536 590 539 560 559 1667 561 1664 564 1661 587 1664 564 1662 566 1659 589 562 537 589 540 559 560 566 533 593 536 563 566 1658 560 1667 561 1664 584 1667 561 1664 564 1661 587 564 535 591 538 561 568 558 540 585 534 565 564 561 537 588 541 559 560 1665 563 562 567 1659 559 1667 561 590 539 1660 558 593 536 +# OFF +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4412 4354 570 1575 568 504 572 1574 569 503 563 510 567 505 572 527 539 1580 563 509 568 505 572 1574 569 503 563 509 568 505 572 527 539 507 569 503 563 1582 571 500 566 507 569 503 563 535 542 505 561 511 566 1579 564 1582 571 1574 569 1576 567 1578 565 1581 562 1583 570 1575 568 1577 566 1580 563 1582 571 1574 569 1576 567 1579 564 1581 562 1583 570 1575 568 1577 566 1579 564 509 568 1577 566 1580 563 1582 571 501 565 5165 4412 4352 572 500 566 1579 564 509 568 1577 566 1579 564 1581 562 1583 570 502 564 1581 562 1582 571 501 565 1580 563 1582 571 1574 569 1576 567 1578 565 1579 564 509 567 1577 566 1579 564 1581 562 1583 570 1575 568 1577 566 506 571 501 565 534 542 529 537 535 542 531 535 537 539 532 545 527 539 507 569 529 537 509 568 504 562 510 566 532 544 527 539 507 569 528 538 534 542 1576 567 504 562 510 566 506 571 1574 569 +# +name: TEMP+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4411 4378 546 1573 570 502 564 1582 571 500 566 507 570 528 538 508 569 1576 567 1578 565 507 569 1575 568 504 562 510 567 532 544 527 539 507 569 528 538 1580 563 509 568 505 571 501 565 533 543 528 538 1580 563 1582 571 1573 570 1575 568 1577 566 1578 565 1580 563 1582 571 1573 570 1575 568 1577 566 1579 564 1580 563 1582 571 1574 569 1575 568 1577 566 506 570 1574 569 1576 567 505 571 1573 570 1575 568 1577 566 1578 565 5165 4412 4350 563 508 568 1576 567 506 571 1574 569 1575 568 1577 566 1579 564 508 568 504 562 1582 571 501 565 1579 564 1581 562 1583 570 1574 569 1575 568 1577 566 506 570 1574 569 1576 567 1578 565 1580 563 1582 571 500 566 506 570 502 564 534 542 504 562 535 541 531 535 511 565 532 544 528 538 507 569 503 563 509 568 530 536 509 568 531 535 537 540 1578 565 507 569 503 563 1581 562 510 566 506 571 502 564 507 569 +# +name: TEMP- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4465 4299 562 1582 571 501 565 1580 563 509 568 505 561 511 566 506 571 1574 569 1576 567 505 572 1574 569 503 563 509 568 504 562 510 566 505 572 501 565 1579 564 509 567 504 562 510 566 505 572 501 565 507 570 1575 568 1577 566 1579 564 1581 562 1583 571 1574 569 1576 567 1577 566 1579 564 1581 562 1583 570 1574 569 1576 567 1578 565 1580 563 1582 571 501 565 1579 564 1581 562 510 567 1578 565 1580 563 1582 571 501 565 5164 4413 4349 565 508 569 1576 567 505 572 1573 570 1575 568 1577 566 1579 564 508 568 503 563 1582 571 500 566 1579 564 1581 562 1582 571 1574 569 1575 568 1577 566 506 571 1574 569 1576 567 1577 566 1579 564 1581 562 1582 571 501 565 507 569 502 564 508 569 504 562 509 568 505 561 511 566 506 571 501 565 507 570 502 564 508 569 503 563 509 568 505 561 1583 571 502 564 508 568 1576 567 504 562 510 567 506 571 1574 569 +# MODE-AUTO +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4416 4349 564 1581 572 500 566 1580 563 508 568 505 571 449 669 453 571 1575 568 1578 565 507 569 502 564 508 568 504 572 500 566 1579 564 508 568 504 572 1573 570 502 564 508 568 504 572 499 567 505 571 501 565 1580 573 1572 571 1575 568 1577 566 1579 563 1581 572 1573 570 1575 568 1578 565 1580 563 1582 571 1574 569 1576 567 1578 564 1581 572 1573 570 502 564 1581 572 500 566 1579 564 1582 571 1573 570 502 564 508 568 5163 4414 4348 565 507 569 1576 567 505 571 1573 570 1576 567 1578 564 1580 573 499 567 505 571 1574 569 1576 567 1578 565 1580 573 1572 571 502 564 1581 572 1573 570 502 564 1581 572 1573 570 1575 568 1577 566 1580 563 1582 571 501 565 507 569 503 563 509 567 505 571 501 565 507 569 503 563 509 567 504 572 500 566 506 570 502 564 508 568 504 572 499 567 1578 565 508 568 1576 567 505 571 501 565 507 569 1575 568 1577 566 +# SWING OFF +name: SWING +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9830 9789 9825 9795 4618 2487 381 348 384 929 381 936 384 353 379 934 386 350 382 350 382 362 380 349 383 929 381 355 387 346 386 926 384 353 379 354 388 355 387 918 382 354 388 348 384 349 383 353 379 357 385 924 386 358 384 921 389 347 385 351 381 929 381 932 388 348 384 349 383 361 381 347 385 351 381 355 387 345 387 925 385 352 380 353 379 365 388 340 382 354 388 348 384 349 383 929 381 355 387 346 386 358 384 921 379 357 385 351 381 352 380 356 386 930 380 357 385 358 385 344 388 348 384 933 387 349 383 353 379 938 382 354 388 352 380 20353 4625 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 5623 5581 567 552 569 551 570 549 562 557 564 582 539 580 541 1672 571 1671 572 545 566 553 568 1698 545 1668 564 1676 567 1700 543 549 562 589 543 1667 566 552 569 1671 561 1677 566 554 567 552 569 1670 562 561 571 1665 568 1671 572 1667 566 1673 570 550 571 549 562 1676 567 583 538 1671 561 583 538 1674 569 552 569 1670 562 1676 567 579 542 556 565 1669 563 557 564 1700 543 549 562 585 536 1676 567 553 568 1676 567 574 537 1675 568 551 570 551 570 1669 564 1674 569 1669 564 558 563 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3296 1651 412 415 414 414 405 1240 408 420 409 1237 411 416 413 415 414 413 406 1240 408 1238 410 419 410 417 412 415 414 1232 406 1214 434 420 409 418 411 417 412 415 414 413 406 423 406 421 408 419 410 418 411 416 413 414 405 423 406 421 408 1237 411 416 413 415 414 414 405 423 406 421 408 419 410 417 412 1234 414 413 406 422 407 420 409 418 411 1235 413 1233 415 1205 433 1214 434 1212 436 1210 438 1208 440 1207 431 423 406 421 408 1238 410 417 412 415 414 414 405 422 407 420 409 419 410 418 411 416 413 1232 406 1241 407 420 409 418 411 417 412 415 414 413 406 422 407 421 408 1237 411 1235 413 414 415 413 406 422 407 420 409 418 411 416 413 414 405 424 405 422 407 420 409 419 410 417 412 415 414 413 406 422 407 420 409 418 411 416 413 414 405 424 405 422 407 420 409 418 411 416 413 415 404 423 406 421 408 419 410 418 411 416 413 414 405 424 405 422 407 420 409 418 411 416 413 414 405 423 406 421 408 419 410 417 412 415 414 414 405 423 406 421 408 420 409 1236 412 415 414 414 405 422 407 420 409 419 410 417 412 1233 405 424 405 1240 408 420 409 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8518 4245 544 1597 545 1568 543 1597 545 564 517 1570 541 568 513 1601 510 1603 539 4244 514 568 513 1601 541 541 519 1595 537 572 509 547 513 570 511 571 593 19280 8571 4219 539 1600 542 1572 539 1600 542 567 493 1594 538 571 520 1593 518 1595 547 4209 539 570 521 1593 539 544 516 1598 544 565 485 572 519 563 518 565 598 19272 8528 4262 538 1603 518 1595 537 1603 539 544 517 1597 545 537 544 1570 541 1599 543 4213 545 563 518 1596 515 567 514 1600 542 540 521 562 519 564 517 566 597 +# TIMER OFF +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4419 4378 562 1618 568 552 541 1619 567 1640 536 533 560 535 558 1649 537 559 534 537 566 1619 567 554 539 530 563 1618 568 1613 563 532 561 1626 560 537 566 554 539 530 563 557 536 536 1622 564 1616 560 1624 562 1625 561 1620 566 1615 561 1621 565 1616 560 534 559 536 567 529 564 559 534 1625 561 533 560 1625 561 1620 566 528 565 530 563 1620 566 530 563 532 561 1624 562 532 561 1650 536 1645 541 1614 562 1620 566 5226 4418 4372 558 1622 564 557 536 1623 563 1618 568 527 566 529 564 1617 559 564 539 531 562 1623 563 558 535 533 560 1621 565 1616 560 535 568 1619 567 529 564 557 536 532 561 560 533 561 542 1614 562 1619 567 1642 534 1628 569 1613 563 1619 567 1614 562 1619 567 528 565 530 563 533 560 563 540 1619 567 527 566 1619 567 1614 562 533 560 535 558 1625 561 536 567 527 566 1619 567 528 565 1620 566 1615 561 1620 566 1618 558 +# TIMER OFF +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4459 4372 589 1565 597 480 595 1559 592 485 590 487 588 488 598 479 596 1558 593 1562 589 1565 597 1558 593 483 593 485 590 486 589 488 598 479 596 480 595 1559 592 485 590 486 589 1565 597 481 594 1559 592 485 590 1564 598 479 596 481 594 483 592 484 591 1563 588 489 597 1558 593 1561 590 486 589 488 598 479 596 481 594 483 592 484 591 1563 599 478 597 480 595 482 593 483 592 485 590 486 589 488 588 489 597 5158 4462 4367 594 483 592 1563 588 488 598 1557 594 1560 591 1563 599 1556 595 482 593 484 591 485 590 487 588 1566 596 1559 592 1562 589 1565 597 1558 593 1562 589 488 598 1556 595 1559 592 485 590 1564 598 479 596 1558 593 484 591 1563 588 1566 596 1559 592 1562 589 488 598 1557 594 482 593 484 591 1563 588 1566 596 1559 592 1563 588 1565 597 1558 593 484 591 1563 588 1566 596 1559 592 1562 589 1565 597 1558 593 1561 590 1564 598 +# TIMER OFF +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4415 4348 568 1578 569 503 570 1575 572 500 563 510 563 508 565 533 540 1578 569 1576 571 527 546 500 563 509 564 533 540 532 541 1603 544 502 571 500 563 1582 565 1580 567 1578 569 504 569 502 571 1574 563 509 564 1581 566 506 567 504 569 529 544 501 572 500 563 509 564 1580 567 1578 569 529 544 501 572 500 563 509 564 507 566 1578 569 1576 571 501 572 1573 564 508 565 1606 541 504 569 1576 571 501 572 1573 564 5169 4410 4351 565 507 566 1579 568 504 569 1575 572 1573 564 1582 565 1580 567 505 568 503 570 1575 572 1573 564 1581 566 1580 567 1578 569 503 570 1575 572 1573 564 534 539 507 566 505 568 1577 570 1575 572 500 563 1582 565 507 566 1579 568 1577 570 1575 572 1573 564 1582 565 1580 567 505 568 504 569 1576 571 1574 563 1582 565 1580 567 1579 568 504 569 503 570 1574 563 509 564 1581 566 506 567 1578 569 503 570 1574 563 510 563 +# diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index 12088838e..123d63f18 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1,19 +1,12 @@ -Filetype: IR signals file +Filetype: IR library file Version: 1 +# Last Updated 7th Sep, 2022 # -# This file has all the Speakers, SoundBars and Audio Receivers. POWER and MUTE buttons ONLY -# 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 23th August 2022 -# -# | SPEAKERS | -# -# Audioengine +name: POWER +type: parsed +protocol: SIRC +address: 10 00 00 00 +command: 2E 00 00 00 # name: POWER type: parsed @@ -39,8 +32,6 @@ protocol: NECext address: 00 FD 00 00 command: 07 F8 00 00 # -# BOSE -# name: POWER type: raw frequency: 38000 @@ -101,8 +92,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 +176,6 @@ protocol: NEC address: 00 00 00 00 command: 09 00 00 00 # -# EDIFIER -# name: POWER type: parsed protocol: NECext @@ -212,7 +199,7 @@ type: parsed protocol: NECext address: 78 0E 00 00 command: 09 F6 00 00 -# +# name: VOL+ type: parsed protocol: NECext @@ -225,16 +212,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 +242,6 @@ protocol: NEC address: 02 00 00 00 command: 07 00 00 00 # -# JBL -# name: VOL+ type: parsed protocol: NEC @@ -315,8 +296,6 @@ protocol: NECext address: 40 AF 00 00 command: 19 E6 00 00 # -# JVC -# name: VOL+ type: parsed protocol: NECext @@ -341,8 +320,6 @@ protocol: NECext address: 02 BD 00 00 command: AD 52 00 00 # -# SONY -# name: POWER type: parsed protocol: SIRC @@ -361,9 +338,6 @@ protocol: SIRC address: 10 00 00 00 command: 13 00 00 00 # -# -# STEJES -# name: POWER type: parsed protocol: NECext @@ -387,9 +361,6 @@ type: parsed protocol: NECext address: 85 23 00 00 command: 47 B8 00 00 -# -# -# CREATIVE # name: POWER type: parsed @@ -403,10 +374,6 @@ protocol: NEC address: 08 00 00 00 command: 16 00 00 00 # -# | SOUNDBARS | -# -# Audac -# name: VOL+ type: parsed protocol: NECext @@ -419,8 +386,6 @@ protocol: NECext address: 86 FF 00 00 command: 2B D4 00 00 # -# BOSE -# name: VOL+ type: parsed protocol: NECext @@ -493,8 +458,6 @@ protocol: NECext address: BA 4B 00 00 command: 01 FE 00 00 # -# BRAND UNKNOWN -# name: VOL+ type: parsed protocol: NECext @@ -536,8 +499,6 @@ type: parsed protocol: NECext address: 83 22 00 00 command: 08 F7 00 00 -# -# COMHEAR # name: VOL+ type: parsed @@ -550,7 +511,7 @@ type: parsed protocol: NECext address: 0A 1D 00 00 command: 0A F5 00 00 -# +# name: MUTE type: parsed protocol: NECext @@ -562,8 +523,6 @@ type: parsed protocol: NECext address: 0A 1D 00 00 command: 01 FE 00 00 -# -# CREATIVE # name: VOL+ type: parsed @@ -583,8 +542,6 @@ protocol: NEC address: 20 00 00 00 command: 1E 00 00 00 # -# KLIPSCH -# name: MUTE type: parsed protocol: NEC @@ -603,8 +560,6 @@ protocol: NEC address: 80 00 00 00 command: 06 00 00 00 # -# LG -# name: VOL+ type: parsed protocol: Samsung32 @@ -617,8 +572,6 @@ protocol: Samsung32 address: 2C 00 00 00 command: 16 00 00 00 # -# ONN -# name: VOL+ type: parsed protocol: NECext @@ -643,8 +596,6 @@ protocol: NECext address: 83 22 00 00 command: 15 EA 00 00 # -# PANASONIC -# name: VOL+ type: raw frequency: 38000 @@ -669,8 +620,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 +644,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 +685,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 +770,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 +794,6 @@ protocol: RC5 address: 13 00 00 00 command: 0C 00 00 00 # -# SONY -# name: VOL+ type: parsed protocol: SIRC @@ -924,8 +866,6 @@ protocol: SIRC15 address: 30 00 00 00 command: 14 00 00 00 # -# TCL -# name: POWER type: parsed protocol: NECext @@ -938,8 +878,6 @@ protocol: NECext address: 86 FF 00 00 command: 1D E2 00 00 # -# TAOTRONICS -# name: VOL+ type: parsed protocol: NEC @@ -964,7 +902,29 @@ protocol: NEC address: 80 00 00 00 command: 1E 00 00 00 # -# VIZIO +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 # name: POWER type: parsed @@ -990,8 +950,6 @@ protocol: NEC address: 00 00 00 00 command: 48 00 00 00 # -# XIAOMI -# name: VOL+ type: raw frequency: 38000 @@ -1016,8 +974,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 @@ -1042,10 +998,6 @@ protocol: NEC address: 7A 00 00 00 command: 1C 00 00 00 # -# | Audio Receivers | -# -# Denon -# name: POWER type: raw frequency: 38000 @@ -1076,8 +1028,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 @@ -1089,21 +1039,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 @@ -1152,8 +1100,6 @@ protocol: NECext address: D2 03 00 00 command: 05 FA 00 00 # -# PHILLIPS -# name: POWER type: parsed protocol: RC5 @@ -1172,8 +1118,6 @@ protocol: RC5 address: 14 00 00 00 command: 10 00 00 00 # -# REGA -# name: MUTE type: parsed protocol: RC5 @@ -1192,8 +1136,6 @@ protocol: RC5 address: 10 00 00 00 command: 11 00 00 00 # -# SONY -# name: POWER type: parsed protocol: SIRC15 @@ -1224,8 +1166,6 @@ protocol: SIRC15 address: 10 00 00 00 command: 13 00 00 00 # -# YAMAHA -# name: POWER type: parsed protocol: NECext @@ -1285,3 +1225,149 @@ type: parsed 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 +# +name: VOL- +type: parsed +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 +# +# +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: 42 00 00 00 +# +name: VOL- +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 43 00 00 00 +# +name: MUTE +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 1B 00 00 00 +# +name: VOL+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8498 4205 651 1471 576 530 550 1572 547 535 545 536 544 1578 541 540 550 1572 547 535 545 1576 543 539 541 1580 549 1572 547 534 546 1576 543 539 541 540 550 1571 548 533 547 1574 545 537 543 539 541 541 549 532 548 1574 545 536 544 1578 541 540 550 1571 548 1572 547 1574 545 1576 543 26533 8497 4203 653 1468 569 538 542 1579 550 531 549 533 547 1573 546 535 545 1576 543 538 542 1579 550 531 549 1571 548 1573 546 536 544 1576 543 539 541 540 550 1571 548 533 547 1574 545 536 544 538 542 540 550 530 550 1572 547 534 546 1575 544 537 543 1578 541 1579 550 1570 549 1572 547 26524 8496 4207 576 1570 549 533 547 1574 545 537 543 539 541 1580 549 532 548 1573 546 536 544 1577 542 539 551 1570 549 1572 547 534 546 1575 544 538 542 540 550 1571 548 534 546 1575 544 538 542 540 550 531 549 533 547 1575 544 537 543 1579 550 531 549 1571 548 1572 547 1574 545 1576 543 26529 8491 4211 573 1573 546 535 545 1576 543 539 551 530 550 1571 548 533 547 1574 545 536 544 1578 541 540 550 1570 549 1572 547 534 546 1575 544 538 542 539 541 1580 549 532 548 1572 547 535 545 537 543 539 541 540 550 1571 548 533 547 1574 545 537 543 1578 541 1579 550 1571 548 1574 545 26522 8498 4202 571 1574 545 537 543 1578 541 541 549 532 548 1573 546 534 546 1575 544 537 543 1577 542 540 550 1570 549 1571 548 533 547 1574 545 537 543 538 542 1579 550 531 549 1572 547 534 546 536 544 537 543 538 542 1579 550 531 549 1572 547 535 545 1575 544 1577 542 1579 550 1571 548 26522 8498 4203 570 1575 544 537 543 1578 541 541 549 532 548 1573 546 535 545 1575 544 538 542 1579 550 531 549 1571 548 1572 547 535 545 1575 544 538 542 539 541 1580 549 532 548 1572 547 534 546 536 544 537 543 539 541 1579 550 531 549 1571 548 533 547 1573 546 1574 545 1575 544 1577 542 +# +name: VOL- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8490 4211 573 1573 546 535 545 1576 543 539 541 540 550 1571 548 532 548 1573 546 535 545 1576 543 539 541 1579 550 1571 548 533 547 1574 545 536 544 1576 543 1578 541 540 550 1570 549 533 547 534 546 536 544 537 543 539 541 540 550 1570 549 532 548 1572 547 1573 546 1574 545 1576 543 26528 8492 4208 648 1475 572 534 546 1575 544 537 543 539 541 1580 549 532 548 1573 546 535 545 1576 543 538 542 1579 550 1571 548 533 547 1575 544 537 543 1577 542 1579 550 532 548 1573 546 535 545 537 543 539 541 541 549 532 548 533 547 1575 544 537 543 1578 541 1579 550 1571 548 1573 546 26523 8496 4203 622 1499 569 537 543 1578 541 541 549 532 548 1572 547 534 546 1574 545 537 543 1578 541 540 550 1570 549 1571 548 534 546 1575 544 538 542 1578 541 1580 549 532 548 1573 546 536 544 538 542 540 550 532 548 533 547 535 545 1576 543 539 541 1579 550 1571 548 1573 546 1574 545 26521 8498 4201 572 1573 546 536 544 1577 542 540 550 531 549 1571 548 533 547 1573 546 536 544 1576 543 539 541 1579 550 1570 549 532 548 1573 546 535 545 1576 543 1578 541 540 550 1571 548 533 547 535 545 537 543 538 542 540 550 531 549 1572 547 534 546 1575 544 1576 543 1577 542 1579 550 26522 8498 4203 570 1575 544 538 542 1579 550 532 548 533 547 1575 544 537 543 1578 541 540 550 1570 549 533 547 1573 546 1575 544 537 543 1578 541 540 550 1571 548 1573 546 536 544 1578 551 531 549 533 547 535 545 537 543 539 541 540 550 1571 548 533 547 1575 544 1576 543 1578 541 1580 549 26521 8498 4203 570 1576 543 538 542 1580 549 532 548 533 547 1574 545 536 544 1577 542 540 550 1570 549 533 547 1573 546 1575 544 538 542 1579 550 531 549 1571 548 1573 546 536 544 1576 543 539 551 531 549 532 548 534 546 536 544 538 542 1579 550 531 549 1572 547 1573 546 1574 545 1576 543 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8500 4203 653 1468 569 538 542 1579 550 532 548 534 546 1575 544 536 544 1578 541 540 550 1572 547 534 546 1575 544 1577 542 539 541 1580 550 532 548 534 546 535 545 1576 543 1577 542 1579 551 532 548 534 546 536 544 1577 542 1578 552 531 549 533 547 534 546 1574 545 1575 544 1577 542 26533 8492 4211 573 1573 546 535 545 1576 543 539 551 530 550 1571 548 533 547 1574 545 536 544 1577 542 540 550 1570 549 1572 547 534 546 1576 543 539 541 541 549 532 548 1573 546 1574 545 1576 543 539 551 531 549 533 547 1573 546 1576 543 539 541 541 549 532 548 1573 546 1574 545 1576 543 26532 8493 4209 575 1571 548 533 547 1575 544 537 543 539 541 1580 550 531 549 1572 547 534 546 1576 543 538 542 1579 551 1570 549 532 548 1574 545 537 543 538 542 540 550 1570 549 1572 547 1575 544 537 543 539 541 540 550 1571 548 1573 546 536 544 538 542 539 551 1570 549 1572 547 1574 545 26530 8496 4207 567 1579 551 531 549 1572 547 535 545 536 544 1576 543 538 542 1579 551 530 550 1571 548 534 546 1574 545 1576 543 538 542 1579 551 532 548 533 547 534 546 1576 543 1577 542 1579 551 532 548 534 546 535 545 1576 543 1578 541 540 550 532 548 533 547 1574 545 1575 544 1577 542 26531 8495 4210 574 1571 548 534 546 1575 544 538 542 539 551 1569 550 531 549 1572 547 535 545 1576 543 539 541 1579 550 1571 548 534 546 1575 544 538 542 540 550 531 549 1572 547 1549 570 1551 568 539 551 531 549 532 548 1573 546 1550 569 538 542 540 550 531 549 1571 548 1548 571 1550 569 +# +name: POWER +type: parsed +protocol: NECext +address: 00 EF 00 00 +command: 1C E3 00 00 +# +name: VOL+ +type: parsed +protocol: NECext +address: 00 EF 00 00 +command: 00 FF 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: 00 EF 00 00 +command: 04 FB 00 00 +# +name: POWER +type: parsed +protocol: NEC42 +address: 6E 00 00 00 +command: 00 00 00 00 +# +name: VOL+ +type: parsed +protocol: NEC42 +address: 6E 00 00 00 +command: 4D 00 00 00 +# +name: VOL- +type: parsed +protocol: NEC42 +address: 6E 00 00 00 +command: 4E 00 00 00 +# +name: POWER +type: parsed +protocol: NEC42 +address: 6E 00 00 00 +command: 0E 00 00 00 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8441 4184 542 1562 541 1562 542 511 546 506 540 511 546 1557 546 506 540 1563 541 1563 540 1563 541 512 545 507 539 512 545 507 539 512 545 507 539 22605 538 1565 539 1565 538 514 543 509 537 514 543 1560 543 509 548 1555 548 1556 548 1556 547 504 542 510 547 505 541 510 547 505 541 510 547 22597 546 1559 544 1559 545 507 539 513 544 507 539 1564 539 513 544 1559 544 1559 545 545 508 549 513 508 538 513 544 508 538 513 544 22601 542 1562 542 1561 543 510 547 505 541 510 547 1557 547 505 541 1562 542 1562 542 1562 542 510 547 505 541 510 547 505 541 511 546 505 541 22603 540 1564 539 1565 538 513 544 508 538 513 544 1560 544 508 538 1565 538 1565 538 1566 537 514 543 509 548 504 542 509 548 504 542 509 548 22597 546 1558 546 1558 546 506 540 512 545 507 539 1564 540 512 545 1559 545 1559 544 1559 544 507 539 513 544 508 538 513 544 508 538 513 544 22600 543 1561 542 1562 542 510 547 505 541 510 547 1557 547 505 541 1562 541 1563 540 1563 541 511 546 506 540 511 546 506 540 511 546 506 540 22604 539 1565 538 1566 537 514 543 509 548 504 542 1561 543 509 548 1556 548 1556 548 1556 547 504 542 510 547 505 541 510 547 505 541 510 547 22598 545 1559 544 1559 545 507 539 512 545 507 539 1564 540 512 545 1559 544 1559 545 1559 545 508 538 513 544 508 538 513 544 508 538 513 544 22601 542 1562 542 1562 542 511 546 505 541 511 546 1557 546 506 540 1563 541 1563 540 1563 541 511 546 506 540 511 546 506 540 512 545 506 540 22604 539 1565 538 1566 537 514 543 509 548 504 542 1561 543 509 548 1556 547 1556 547 1556 548 504 542 510 547 505 541 510 547 505 541 510 547 +# +name: POWER +type: parsed +protocol: SIRC +address: 10 00 00 00 +command: 60 00 00 00 +# +name: VOL- +type: parsed +protocol: NEC +address: 08 00 00 00 +command: 0E 00 00 00 +# +name: VOL+ +type: parsed +protocol: NEC +address: 08 00 00 00 +command: 1A 00 00 00 +# diff --git a/assets/resources/infrared/assets/fans.ir b/assets/resources/infrared/assets/fans.ir new file mode 100644 index 000000000..0fae27154 --- /dev/null +++ b/assets/resources/infrared/assets/fans.ir @@ -0,0 +1,897 @@ +Filetype: IR library file +Version: 1 +# Last Updated 7th Sep, 2022 +# +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: 50 AF 00 00 +# +name: SPEED- +type: parsed +protocol: NECext +address: BA F0 00 00 +command: 41 BE 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: 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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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: SPEED- +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 9F 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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +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 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1251 410 1245 415 407 1252 1246 415 1250 410 412 1247 408 1252 413 1247 408 1252 413 1247 408 1252 1246 7350 1248 438 1227 433 389 1245 1253 434 1221 439 383 1250 415 1245 410 1250 405 1255 410 1249 406 1255 1253 7340 1247 439 1226 407 415 1245 1253 433 1222 412 410 1250 405 1255 410 1249 406 1254 411 1249 406 1254 1254 7340 1247 412 1253 407 415 1245 1253 407 1248 412 410 1250 405 1255 410 1249 406 1254 411 1248 407 1253 1245 7349 1249 411 1254 406 405 1254 1254 406 1249 411 411 1248 407 1252 413 1246 409 1251 414 1245 410 1250 1248 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1250 409 1246 441 381 1252 1246 414 1252 435 387 1246 409 1250 405 1255 1243 417 405 1281 384 1275 380 8188 1244 416 1249 437 385 1249 1249 437 1218 443 379 1253 412 1248 407 1253 1245 415 407 1252 413 1246 409 8186 1246 414 1251 435 387 1272 1226 408 1247 439 383 1276 379 1281 384 1249 1249 437 385 1248 407 1253 412 8181 1251 409 1246 440 382 1277 1221 439 1226 434 378 1255 410 1249 406 1254 1244 416 406 1253 412 1247 408 8187 1245 441 1225 435 387 1273 1225 435 1220 440 382 1251 414 1245 410 1250 1248 412 410 1249 406 1254 411 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1243 444 1221 438 384 1276 1222 438 1217 443 379 1254 411 1274 381 1252 413 1246 409 1251 1247 413 409 8185 1247 440 1225 435 387 1246 1252 408 1247 440 382 1277 388 1245 410 1276 379 1280 385 1249 1249 411 411 8184 1248 412 1243 444 378 1282 1216 444 1221 439 383 1250 405 1254 411 1248 407 1253 412 1248 1250 410 412 8182 1250 410 1245 442 380 1253 1245 415 1250 437 385 1247 408 1252 413 1272 383 1251 414 1272 1226 408 414 8180 1252 409 1246 440 382 1252 1246 440 1225 435 387 1272 383 1250 405 1254 411 1249 406 1254 1244 416 406 8188 1244 416 1249 437 385 1249 1249 411 1244 443 379 1253 412 1273 382 1278 387 1246 409 1251 1247 413 409 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1305 379 1283 402 434 1251 431 1253 1276 408 1275 411 435 1249 1280 404 432 1253 1276 408 438 1247 1282 7144 1281 404 1279 407 439 1247 435 1250 1310 375 1307 379 467 1218 1311 374 431 1254 1306 379 436 1249 1311 7119 1305 380 1302 382 464 1222 460 1224 1305 380 1302 382 464 1221 1308 377 469 1217 1302 383 463 1222 1307 7121 1303 380 1303 382 464 1221 462 1223 1306 378 1305 381 465 1220 1309 375 430 1254 1306 380 435 1250 1279 7148 1276 408 1274 411 435 1250 432 1252 1277 408 1274 410 436 1249 1280 404 432 1253 1276 408 438 1247 1282 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1282 402 1281 404 432 1252 430 1254 1275 408 1275 410 436 1248 435 1249 434 1251 1278 405 431 1254 439 7984 1277 407 1276 408 438 1246 436 1248 1281 402 1281 403 433 1251 432 1253 430 1254 1275 408 438 1246 437 7985 1276 407 1276 408 438 1246 436 1248 1281 402 1281 403 433 1252 431 1253 440 1245 1274 409 437 1248 435 7990 1333 351 1332 352 433 1252 431 1254 1326 358 1335 349 436 1249 434 1250 433 1252 1328 355 440 1244 438 7984 1328 355 1328 356 439 1245 438 1247 1333 350 1333 351 434 1250 433 1252 431 1253 1327 357 438 1246 437 7988 1273 410 1273 411 435 1249 434 1250 1279 405 1278 406 440 1244 439 1246 436 1247 1282 402 434 1251 432 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1282 403 1279 405 431 1254 439 1246 1273 412 434 1251 432 1254 1275 410 436 1249 433 1251 431 1254 1275 7152 1283 402 1281 405 431 1254 439 1246 1273 412 434 1251 432 1254 1305 379 436 1249 433 1252 430 1254 1306 7122 1302 382 1311 374 462 1223 459 1226 1303 381 465 1221 461 1223 1306 379 467 1218 464 1221 461 1224 1305 7123 1312 373 1310 375 461 1224 469 1216 1303 381 465 1221 461 1223 1306 379 467 1218 464 1221 461 1224 1305 7123 1312 374 1308 376 460 1225 468 1218 1311 374 462 1223 459 1226 1303 382 464 1222 460 1224 469 1217 1302 7128 1306 379 1303 382 464 1221 461 1224 1305 380 466 1219 463 1221 1277 408 469 1217 465 1219 463 1222 1307 7122 1282 403 1279 405 462 1223 459 1226 1283 402 465 1221 461 1224 1274 410 467 1218 464 1221 461 1224 1274 7155 1280 405 1278 408 438 1247 435 1250 1279 406 440 1245 437 1249 1280 405 431 1255 438 1249 433 1252 1277 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1279 406 1307 377 438 1246 436 1249 1311 373 463 1221 462 1224 469 1216 466 1218 465 1220 463 1222 460 7967 1304 380 1303 382 464 1221 462 1223 1276 409 468 1217 466 1220 463 1223 459 1225 468 1217 465 1220 462 7966 1275 410 1303 382 464 1220 463 1222 1276 409 468 1218 465 1220 463 1223 459 1225 468 1217 435 1250 463 7965 1306 378 1304 381 465 1220 463 1222 1307 378 468 1217 465 1219 433 1253 440 1245 437 1248 434 1251 462 7966 1275 411 1282 404 432 1254 439 1248 1281 404 432 1254 439 1247 436 1250 433 1253 440 1246 437 1248 435 7995 1276 409 1284 402 434 1252 431 1255 1274 411 435 1251 431 1254 439 1247 436 1250 433 1253 440 1246 436 7992 1279 407 1276 410 436 1249 433 1252 1277 409 447 1238 434 1252 431 1254 439 1247 435 1250 433 1253 440 7990 1281 404 1278 406 440 1245 438 1249 1280 405 441 1245 437 1248 435 1251 432 1254 439 1247 435 1250 433 +# diff --git a/assets/resources/infrared/assets/projectors.ir b/assets/resources/infrared/assets/projectors.ir index 413fdd5e7..1e4f6f01e 100644 --- a/assets/resources/infrared/assets/projectors.ir +++ b/assets/resources/infrared/assets/projectors.ir @@ -1,318 +1,290 @@ -Filetype: IR signals file +Filetype: IR library file Version: 1 -# -# file: Flipper-IRDB/Projectors/Anker/NebulaMarsLite.ir -# +# Last Updated 8th Sep, 2022 +# +# ON +name: POWER +type: parsed +protocol: NECext +address: 83 F4 00 00 +command: 4F B0 00 00 +# 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 +296,64 @@ type: parsed 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 +# +name: VOL+ +type: parsed +protocol: NEC +address: 32 00 00 00 +command: 11 00 00 00 +# +name: VOL- +type: parsed +protocol: NEC +address: 32 00 00 00 +command: 14 00 00 00 +# OFF +name: POWER +type: parsed +protocol: NECext +address: 83 F4 00 00 +command: 4E B1 00 00 +# +name: POWER +type: parsed +protocol: NEC +address: 03 00 00 00 +command: 1D 00 00 00 +# +name: VOL+ +type: parsed +protocol: NEC +address: 03 00 00 00 +command: 11 00 00 00 +# +name: VOL- +type: parsed +protocol: NEC +address: 03 00 00 00 +command: 15 00 00 00 +# diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir index 8f3d99020..1260c88ff 100755 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -1,18 +1,26 @@ Filetype: IR library file Version: 1 +# Last Updated 9th Sept, 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! -############################################################ +# ON +name: POWER +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 40 00 00 00 +# ON +name: POWER +type: parsed +protocol: NECext +address: A0 B7 00 00 +command: E9 16 00 00 +# ON +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4008 3984 520 1976 517 1980 523 1975 518 1979 514 1016 492 1012 496 1975 518 987 521 1976 517 987 521 1977 516 1014 494 1010 488 990 518 985 523 1008 489 1981 522 1976 517 1013 495 1976 517 987 521 1977 516 987 521 1977 516 8473 4002 3988 516 1979 514 1984 519 1977 516 1982 521 1008 489 988 520 1977 516 988 520 1977 516 988 520 1977 516 987 521 1010 488 989 519 985 523 980 518 2006 487 1984 519 983 514 1983 520 983 515 1983 520 983 515 1982 521 8466 4010 3978 516 1980 523 1974 519 1978 578 1918 522 982 516 1014 494 1977 516 987 521 1976 517 987 521 1976 517 986 522 982 515 1015 493 1011 487 990 518 1979 514 1984 519 984 524 1973 520 984 513 1984 519 983 514 1983 520 # -# Updated on 21th August 2022 -# name: POWER type: parsed protocol: SIRC @@ -109,8 +117,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 +1761,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,9 +2330,6 @@ type: parsed protocol: NEC address: 04 00 00 00 command: 1A 00 00 00 -######################START OF NEW IR's###################### -# -# BAIRD # name: POWER type: parsed @@ -2366,15 +2367,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 @@ -2412,8 +2409,6 @@ protocol: NEC address: 08 00 00 00 command: DF 00 00 00 # -# CONTINENTAL -# name: POWER type: parsed protocol: RC5 @@ -2450,8 +2445,6 @@ protocol: RC5 address: 01 00 00 00 command: 21 00 00 00 # -# DENVER -# name: MUTE type: parsed protocol: NECext @@ -2482,8 +2475,6 @@ protocol: NECext address: 00 7F 00 00 command: 5C A3 00 00 # -# FETCH -# name: POWER type: parsed protocol: NECext @@ -2502,8 +2493,42 @@ protocol: NECext address: 64 46 00 00 command: DB 24 00 00 # -# HISENSE -# +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 +# name: POWER type: parsed protocol: NECext @@ -2540,8 +2565,6 @@ protocol: NECext address: 00 BF 00 00 command: 4B B4 00 00 # -# HITACHI -# name: POWER type: parsed protocol: RC5 @@ -2578,8 +2601,6 @@ protocol: RC5 address: 03 00 00 00 command: 0D 00 00 00 # -# MANTA -# name: POWER type: parsed protocol: NECext @@ -2604,8 +2625,6 @@ protocol: NECext address: 00 BF 00 00 command: 01 FE 00 00 # -# MATSUI -# name: POWER type: parsed protocol: Samsung32 @@ -2642,8 +2661,6 @@ protocol: Samsung32 address: 17 00 00 00 command: 15 00 00 00 # -# PANASONIC -# name: POWER type: raw frequency: 38000 @@ -2680,8 +2697,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 @@ -2730,8 +2745,6 @@ protocol: RC6 address: 00 00 00 00 command: 21 00 00 00 # -# RCA -# name: VOL+ type: raw frequency: 38000 @@ -2755,42 +2768,6 @@ 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 -address: 0F 00 00 00 -command: 3F 00 00 00 # name: POWER type: parsed @@ -2828,8 +2805,6 @@ protocol: NEC address: A0 00 00 00 command: 1F 00 00 00 # -# SAMSUNG -# name: CH+ type: raw frequency: 38000 @@ -2858,7 +2833,7 @@ name: VOL- type: raw frequency: 38000 duty_cycle: 0.330000 -data: 4506 4465 563 1692 546 1658 569 1659 568 559 544 557 536 565 538 563 540 561 542 1687 540 1662 565 1689 538 563 540 561 542 560 543 558 545 556 537 1665 562 1693 545 530 563 1692 546 555 538 564 539 562 541 560 543 558 545 556 537 1665 562 539 564 1690 537 1691 536 1692 535 1693 545 556 537 539 564 563 540 561 542 42974 4505 4464 564 1690 537 1665 562 1667 571 530 563 565 538 563 540 561 542 559 544 1684 543 1659 568 1661 566 561 542 559 544 557 536 565 538 563 540 1663 564 1690 537 563 540 1662 565 -559 558 545 556 537 564 539 562 541 1688 539 561 542 1687 540 1688 539 1688 539 1663 564 563 540 561 542 559 544 557 536 +data: 4506 4465 563 1692 546 1658 569 1659 568 559 544 557 536 565 538 563 540 561 542 1687 540 1662 565 1689 538 563 540 561 542 560 543 558 545 556 537 1665 562 1693 545 530 563 1692 546 555 538 564 539 562 541 560 543 558 545 556 537 1665 562 539 564 1690 537 1691 536 1692 535 1693 545 556 537 539 564 563 540 561 542 42974 4505 4464 564 1690 537 1665 562 1667 571 530 563 565 538 563 540 561 542 559 544 1684 543 1659 568 1661 566 561 542 559 544 557 536 565 538 563 540 1663 564 1690 537 563 540 1662 565 559 558 545 556 537 564 539 562 541 1688 539 561 542 1687 540 1688 539 1688 539 1663 564 563 540 561 542 559 544 557 536 # name: CH+ type: raw @@ -2878,8 +2853,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 @@ -2916,8 +2889,6 @@ protocol: NEC address: 38 00 00 00 command: 0B 00 00 00 # -# SHARP -# name: POWER type: raw frequency: 38000 @@ -2954,8 +2925,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 @@ -2968,16 +2937,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 @@ -3014,8 +2979,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 @@ -3046,8 +3009,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 @@ -3083,3 +3044,178 @@ type: parsed protocol: NECext address: 40 40 00 00 command: 0F F0 00 00 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3476 1735 443 429 446 1300 451 422 453 420 445 428 447 426 449 423 452 448 417 429 446 426 449 424 451 422 443 430 445 1300 451 422 453 420 445 428 447 426 449 423 452 421 444 429 446 427 448 424 451 1295 445 427 448 425 450 423 452 420 445 429 446 426 449 424 451 421 444 1303 448 425 450 1296 444 1301 450 1296 444 1302 448 424 451 422 453 1293 447 426 449 1296 444 1302 448 1297 454 1293 447 425 450 1296 444 74939 3477 1734 444 429 446 1300 451 422 453 419 446 455 420 425 450 423 452 420 445 428 447 426 449 424 451 421 444 429 446 1300 451 422 453 420 445 428 447 425 450 423 452 420 445 429 446 426 449 424 451 1295 445 427 448 425 450 422 453 420 445 428 447 426 449 424 451 421 444 1302 449 424 451 1295 445 1301 450 1296 444 1302 449 424 451 422 453 1292 448 425 450 1296 444 1301 450 1297 443 1302 448 425 450 1295 445 74938 3478 1734 444 428 447 1299 452 421 444 429 446 427 448 425 450 422 453 420 444 428 447 426 449 423 452 421 444 429 446 1300 451 422 453 419 446 428 447 425 450 423 452 421 444 429 446 426 449 424 451 1295 445 427 448 425 450 423 452 420 445 428 447 426 449 424 451 421 444 1302 448 424 451 1295 445 1301 450 1296 444 1302 449 424 451 422 453 1292 448 425 450 1296 444 1301 450 1296 444 1302 449 424 451 1295 445 74938 3479 1733 445 428 447 1299 452 421 444 429 446 426 449 424 451 421 454 419 446 427 448 425 450 422 453 420 445 428 447 1299 452 421 444 429 446 426 449 424 451 422 453 419 446 427 448 425 450 422 453 1293 447 426 449 423 452 421 444 429 446 426 449 424 451 422 453 419 446 1301 450 422 453 1293 447 1299 452 1294 446 1300 451 422 453 419 446 1301 449 423 452 1294 446 1300 451 1295 445 1300 451 422 453 1293 447 +# +name: MUTE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3476 1736 473 399 445 1301 481 392 452 421 444 429 446 427 448 424 451 422 453 419 446 427 448 425 450 423 452 420 445 1301 450 423 452 421 444 429 446 427 448 424 451 422 453 419 446 427 448 425 450 1296 444 428 447 426 449 423 452 421 444 429 446 427 448 424 451 422 453 419 446 1301 450 423 452 420 445 1301 450 1297 443 429 446 427 448 424 451 1295 445 428 478 394 450 1296 444 1302 449 424 451 1294 446 74876 3479 1732 446 427 448 1298 453 420 445 428 447 425 450 423 452 421 444 429 446 426 449 424 451 421 444 429 446 427 448 1298 453 420 445 428 447 426 449 423 452 421 444 429 446 426 449 424 451 421 444 1303 448 425 450 423 452 420 445 428 447 426 449 423 452 421 444 429 446 426 449 1297 454 419 446 428 447 1298 453 1293 447 426 449 423 452 421 444 1302 449 424 451 422 453 1293 447 1298 453 420 445 1302 449 74849 3474 1738 450 422 453 1293 447 425 450 423 452 420 445 428 447 426 449 424 451 421 444 429 446 427 448 425 450 422 453 1293 447 426 449 423 452 421 444 429 446 426 449 424 451 422 453 419 446 427 448 1298 453 420 445 428 447 426 449 423 452 421 444 429 446 426 449 424 451 422 443 1303 448 425 450 423 452 1293 447 1299 452 421 444 429 446 427 448 1298 453 420 445 428 447 1299 452 1294 446 426 449 1297 443 74855 3479 1733 445 427 448 1298 453 420 445 428 447 426 449 423 452 421 444 429 446 427 448 424 451 422 453 419 446 427 448 1298 453 420 445 428 447 426 449 424 451 421 444 429 446 427 448 425 450 422 453 1293 447 426 449 423 452 421 444 429 446 427 448 424 451 422 453 419 446 427 448 1298 453 420 445 428 447 1299 452 1294 446 427 448 424 451 422 453 1293 447 425 450 423 452 1293 447 1299 452 421 444 1302 449 +# +name: VOL+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3482 1730 448 425 450 1296 444 429 446 427 448 424 451 422 453 420 445 428 447 425 450 423 452 421 444 429 446 426 449 1297 454 419 446 427 448 425 450 423 452 420 445 428 447 426 449 424 451 421 444 1303 448 425 450 422 453 420 445 428 447 425 450 423 452 421 444 429 446 427 448 424 451 422 453 419 446 428 447 1298 453 420 445 428 447 426 449 424 451 421 444 429 446 427 448 1298 453 420 445 1301 450 +# +name: VOL- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3512 1700 478 395 480 1266 474 399 476 396 479 394 481 392 473 400 475 397 478 395 480 393 482 390 475 398 477 396 479 1267 473 399 476 397 478 395 480 392 473 400 475 398 477 396 479 394 481 391 474 1272 479 394 481 392 473 400 475 398 477 395 480 393 482 391 474 399 476 1269 482 391 474 399 476 397 478 395 480 1266 474 398 477 396 479 1267 473 399 476 397 478 394 481 392 473 1273 478 395 480 1266 474 +# +name: CH+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3505 1707 481 391 474 1272 479 394 481 392 473 400 475 398 477 395 480 393 482 391 474 399 476 396 479 394 481 392 473 1273 478 395 480 393 482 390 475 398 477 396 479 394 481 391 474 399 476 397 478 1268 472 400 475 398 477 395 480 393 482 391 474 399 476 396 479 394 481 392 473 400 475 1271 480 393 482 1264 476 1269 482 391 474 399 476 397 478 395 480 1266 474 398 477 1269 482 1264 476 397 478 1267 473 106476 3510 1702 476 396 479 1267 473 400 475 398 477 395 480 393 482 391 474 398 477 396 479 394 481 391 474 399 476 397 478 1268 472 401 474 398 477 396 479 394 481 391 474 399 476 397 478 395 480 392 473 1274 477 396 479 393 482 391 474 399 476 397 478 394 481 392 473 400 475 398 477 395 480 1266 474 399 476 1270 481 1265 475 397 478 395 480 393 472 401 474 1271 480 393 482 1264 476 1270 481 392 473 1273 478 +# +name: CH- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3503 1708 480 392 473 1274 477 396 479 393 482 391 474 399 476 397 478 395 480 392 473 400 475 398 446 427 448 424 482 1264 476 397 478 394 481 392 473 400 475 398 477 395 480 393 482 391 474 399 476 1270 480 392 473 400 475 398 477 395 480 393 482 391 474 399 476 397 478 1268 472 400 475 1271 480 393 482 1264 476 1270 481 392 473 400 475 1270 481 393 472 1274 477 396 479 1267 473 1273 478 395 480 1266 474 74632 3510 1702 476 397 478 1268 472 400 475 398 477 395 480 393 482 391 474 399 476 396 479 394 481 392 473 400 475 398 477 1268 483 391 474 399 476 396 479 394 481 391 474 399 476 397 478 395 480 392 473 1273 478 396 479 393 482 391 484 388 477 397 478 395 480 392 473 400 475 1271 479 394 481 1264 476 397 478 1268 472 1273 478 395 480 393 482 1264 476 397 478 1267 473 400 475 1271 480 1266 474 399 476 1270 481 74602 3509 1703 475 397 478 1268 482 390 475 398 477 396 479 394 481 391 474 399 476 397 478 395 480 392 473 400 475 398 477 1269 482 391 474 399 476 397 478 394 481 392 473 400 475 397 478 395 480 393 482 1264 476 396 479 394 481 392 473 400 475 398 477 395 480 393 482 391 474 1272 479 394 481 1265 475 397 478 1268 472 1274 476 396 479 394 481 1264 476 397 478 1268 483 390 475 1272 479 1267 473 400 475 1270 481 +# +name: MUTE +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 41 00 00 00 +# +name: MUTE +type: parsed +protocol: NECext +address: A0 B7 00 00 +command: AF 50 00 00 +# +name: MUTE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3999 3980 517 1984 520 1980 513 1987 517 1983 521 979 513 987 515 1985 519 1983 511 1989 515 1986 518 1982 511 1989 515 984 518 982 520 980 512 989 513 1987 517 1983 521 979 513 988 514 986 516 984 518 982 520 980 512 9042 3991 3987 521 1980 514 1987 517 1983 521 1980 513 986 516 984 518 1982 511 1989 515 1986 518 1982 512 1989 515 1985 519 981 521 979 513 987 515 985 517 1983 521 1979 515 986 516 984 518 982 520 980 512 989 513 987 515 9038 4027 3952 514 1987 517 1983 521 1979 515 1986 518 981 521 979 513 1988 516 1985 519 1981 513 1988 516 1984 520 1980 514 986 516 984 518 982 520 980 522 1978 516 1986 518 982 520 980 512 988 514 986 516 984 518 982 520 9035 4019 3959 517 1983 521 1979 515 1986 518 1982 511 988 514 986 516 1984 520 1981 512 1988 516 1984 520 1980 513 1987 517 983 519 981 521 979 513 987 515 1985 519 1982 511 988 514 986 516 984 518 982 520 980 543 957 545 +# +name: MUTE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4006 3983 521 1975 518 1980 513 1984 519 1977 516 987 521 983 515 1982 521 1977 516 1981 522 1974 519 1979 514 1983 520 983 514 989 519 985 523 981 517 2007 496 1975 518 985 523 981 517 987 521 1009 489 989 519 985 523 8466 4010 3979 515 1981 522 1975 518 1980 513 1984 519 984 513 990 518 2005 488 1983 520 1977 516 1981 522 1974 519 1979 514 1015 493 985 523 980 518 986 522 1975 518 1980 513 990 518 986 522 981 517 988 520 1010 488 989 519 8469 4007 3981 523 1972 521 1976 517 1980 523 1974 519 984 524 980 518 2005 488 1984 519 1978 515 1982 521 1975 518 1980 513 990 518 985 523 1008 489 987 521 1976 517 1981 522 981 517 1013 495 1009 489 988 520 984 513 1016 492 +# +name: VOL+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4008 3980 524 1972 521 1976 517 1980 513 1984 519 983 514 989 519 1979 514 989 519 1978 515 1983 520 1976 517 1980 523 980 518 986 522 1008 490 1014 494 1977 516 1980 523 980 518 1980 513 990 518 1012 496 1007 491 986 522 8465 4011 3978 516 1980 513 1983 520 1977 516 1980 523 980 517 986 522 1975 518 985 523 1974 519 1978 515 1982 521 1975 518 985 523 981 517 986 522 1008 489 1981 522 1974 519 985 523 1974 519 1010 498 979 518 985 523 981 517 8470 4006 3983 521 1974 519 1978 515 1982 521 1976 517 986 522 982 515 1981 522 982 516 1982 521 1975 518 1979 514 1983 520 983 515 989 519 1011 497 981 517 1980 523 1974 519 985 523 1974 519 984 524 1006 491 1012 496 982 516 +# +name: VOL- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4010 3978 515 1980 523 1974 519 1978 515 1982 521 982 515 988 520 1977 516 988 520 1977 516 1981 522 1974 519 1011 497 1006 491 1012 496 1007 490 1013 495 1976 517 1980 523 980 518 1980 523 980 517 985 523 981 516 1981 522 8465 4000 3987 517 1979 513 1984 519 1977 516 1981 522 981 517 987 521 1976 517 987 521 1976 517 1980 523 1974 519 985 523 980 517 986 522 982 516 988 520 1977 516 1981 522 981 517 1981 522 980 517 986 522 982 515 1981 522 8465 3999 3986 518 1977 515 1981 522 1974 519 1978 514 1015 493 984 524 1973 520 1010 487 1983 520 1976 516 1980 523 1006 491 1012 496 1007 490 1013 495 1008 489 1982 521 1975 518 1012 496 1975 518 1011 497 1006 492 1012 496 1975 518 +# +name: CH+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4005 3982 522 1974 519 1978 515 1982 521 1975 518 986 522 982 515 1981 522 981 517 1980 523 1974 519 984 524 1973 520 984 524 979 518 985 523 981 517 1980 523 1973 520 984 524 1973 520 984 513 990 518 1978 515 989 519 8468 4008 3979 514 1981 522 1974 519 1978 515 1982 521 983 515 1014 494 1977 516 1014 494 1977 516 1982 521 982 516 1981 522 982 515 987 521 983 514 989 519 1978 515 1982 521 982 516 1981 522 981 516 988 520 1977 516 988 520 8468 4007 3980 524 1972 521 1976 517 1980 523 1973 520 984 524 979 519 1979 514 989 519 1978 515 1982 521 982 516 1981 522 981 517 986 522 982 516 1014 494 1977 516 1980 523 980 517 1980 523 979 519 985 523 1975 518 985 523 +# +name: CH- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4006 3981 523 1973 520 1977 516 1981 522 1974 519 1011 497 1006 491 1979 524 1005 493 1978 515 1982 521 1009 488 1015 493 1010 498 1006 491 1012 496 1007 490 1980 523 1973 520 1010 498 1973 520 983 515 1016 492 1978 514 1983 520 8468 4007 3982 522 1973 520 1977 516 1981 522 1975 518 986 522 1008 490 1982 521 982 516 1982 521 1976 517 986 522 982 516 988 520 984 524 979 519 985 523 1975 518 1979 514 989 519 1978 515 988 520 984 524 1973 520 1977 516 +# OFF +name: POWER +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 59 00 00 00 +# OFF +name: POWER +type: parsed +protocol: NEC +address: 08 00 00 00 +command: D5 00 00 00 +# OFF +name: POWER +type: parsed +protocol: RC5 +address: 01 00 00 00 +command: 2A 00 00 00 +# OFF +name: POWER +type: parsed +protocol: NECext +address: 00 7F 00 00 +command: 0C F3 00 00 +# OFF +name: POWER +type: parsed +protocol: NECext +address: 86 05 00 00 +command: 13 EC 00 00 +# OFF +name: POWER +type: parsed +protocol: NECext +address: 02 7D 00 00 +command: 11 EE 00 00 +# OFF +name: POWER +type: parsed +protocol: NECext +address: 84 E0 00 00 +command: 22 DD 00 00 +# OFF +name: POWER +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 4E 00 00 00 +# OFF +name: POWER +type: parsed +protocol: NEC +address: 04 00 00 00 +command: 0E 00 00 00 +# OFF +name: POWER +type: parsed +protocol: NEC +address: 04 00 00 00 +command: 1B 00 00 00 +# OFF +name: POWER +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 5E 00 00 00 +# OFF +name: POWER +type: parsed +protocol: NECext +address: EA C7 00 00 +command: 62 9D 00 00 +# OFF +name: POWER +type: parsed +protocol: Samsung32 +address: 07 00 00 00 +command: 03 00 00 00 +# OFF +name: POWER +type: parsed +protocol: SIRC +address: 01 00 00 00 +command: 36 00 00 00 +# OFF +name: POWER +type: parsed +protocol: Samsung32 +address: 07 00 00 00 +command: 24 00 00 00 +# diff --git a/assets/resources/rfidfuzzer/example_uids.txt b/assets/resources/rfidfuzzer/example_uids.txt new file mode 100644 index 000000000..46ce16ba8 --- /dev/null +++ b/assets/resources/rfidfuzzer/example_uids.txt @@ -0,0 +1,8 @@ +# Example file, P.S. keep empty line at the end! +0000000000 +FE00000000 +CAFE000000 +00CAFE0000 +0000CAFE00 +000000CAFE +00000000CA diff --git a/assets/resources/subghz/assets/setting_user b/assets/resources/subghz/assets/setting_user index 32051d45d..de419485c 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 diff --git a/assets/unit_tests/subghz/clemsa.sub b/assets/unit_tests/subghz/clemsa.sub new file mode 100644 index 000000000..b07d031f0 --- /dev/null +++ b/assets/unit_tests/subghz/clemsa.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz Key File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: Clemsa +Bit: 18 +Key: 00 00 00 00 00 02 FC AA diff --git a/assets/unit_tests/subghz/clemsa_raw.sub b/assets/unit_tests/subghz/clemsa_raw.sub new file mode 100644 index 000000000..5f86de98c --- /dev/null +++ b/assets/unit_tests/subghz/clemsa_raw.sub @@ -0,0 +1,14 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: RAW +RAW_Data: -334 10811 -4320 65 -100 65 -698 10157 -7550 65 -200 165 -166 133 -66 531 -66 331 -102 197 -132 133 -298 99 -132 263 -200 261 -988 99 -262 131 -296 97 -132 229 -100 459 -100 131 -132 393 -100 1119 -100 8325 -6376 133 -366 131 -562 65 -1034 131 -198 563 -168 365 -66 229 -332 297 -100 231 -166 429 -132 295 -166 97 -100 195 -724 97 -132 97 -1088 163 -200 1651 -100 2885 -8520 365 -166 97 -1558 163 -198 163 -132 465 -134 131 -66 267 -198 65 -232 299 -66 165 -166 65 -498 165 -100 233 -200 133 -166 131 -68 821 -100 263 -66 7633 -7610 1259 -200 99 -98 165 -1196 99 -132 263 -266 99 -200 463 -66 627 -66 1981 -98 7801 -4004 97 -628 65 -264 133 -1088 163 -134 131 -928 297 -166 133 -134 131 -266 297 -596 229 -164 427 -564 197 -166 265 -198 65 -100 559 -6708 131 -132 131 -430 527 -200 367 -66 263 -198 233 -98 299 -68 365 -296 465 -132 855 -66 857 -98 4741 -8312 99 -364 163 -200 133 -1428 529 -132 65 -166 595 -1392 97 -100 97 -132 99 -264 199 -828 99 -398 297 -66 233 -98 861 -100 663 -100 2357 -100 5075 -4640 131 -3312 231 -100 363 -132 99 -296 99 -132 165 -132 363 -98 165 -130 65 -98 165 -132 163 -130 63 -164 297 -198 9769 -3852 133 -98 67 -1226 329 -526 99 -164 295 -496 1713 -196 1681 -130 131 -132 5497 -7230 65 -1150 133 -330 259 -66 329 -100 97 -988 165 -134 197 -166 67 -100 361 -68 461 -100 231 -132 165 -66 365 -264 231 -100 99 -98 265 -696 99 -166 199 -100 101 -962 7101 -6484 363 -760 363 -132 265 -134 431 -264 329 -66 427 -330 263 -164 593 -130 231 -130 627 -66 399 -432 329 -526 131 -100 591 -166 9305 -4044 65 -3532 361 -98 163 -66 461 -264 197 -98 391 -66 329 -132 165 -136 463 -66 529 -166 131 -100 199 -264 133 -66 361 -98 689 -66 229 -198 627 -66 297 -100 261 -66 1685 -134 7883 -3932 229 -728 133 -98 133 -862 65 -132 99 -498 297 -166 133 -332 197 -132 693 -198 97 -656 1087 -64 6209 -6164 131 -266 99 -496 165 -432 67 -100 97 -330 821 -98 361 -100 493 -164 133 -66 197 -200 431 -66 65 -66 399 -66 331 -200 199 -402 131 -664 10955 -5314 65 -262 97 -198 97 -724 99 -196 65 -592 327 -66 625 -262 131 -66 197 -64 427 -132 65 -628 265 -332 329 -368 789 -66 8809 -6238 129 -328 295 -232 363 -98 431 -100 199 -98 261 -530 561 -592 263 -132 1645 -5358 65 -764 65 -330 165 -1158 197 -432 265 -98 397 -166 463 -498 561 -398 199 -66 199 -66 3479 +RAW_Data: -12124 165 -626 65 -890 229 -362 1329 -66 2187 -98 2081 -66 725 -134 3309 -9856 165 -166 263 -198 65 -960 653 -66 261 -66 821 -66 12463 -4032 97 -166 97 -924 65 -464 97 -68 163 -198 165 -100 263 -232 97 -366 633 -12244 65 -332 231 -200 197 -134 197 -234 2457 -134 399 -132 923 -198 197 -64 331 -132 295 -66 11377 -3896 163 -98 65 -194 131 -132 231 -366 131 -132 65 -1050 197 -200 299 -66 3007 -100 11685 -6172 133 -1154 491 -100 293 -200 65 -98 429 -266 463 -64 797 -98 265 -266 397 -132 1227 -66 8485 -4224 97 -166 65 -100 199 -2706 65 -66 263 -98 299 -298 231 -100 499 -66 97 -134 295 -66 431 -198 565 -66 2093 -100 533 -4056 65 -1482 229 -1160 165 -168 299 -166 459 -66 165 -134 99 -100 497 -166 397 -200 431 -200 65 -66 661 -164 529 -66 4671 -8442 131 -100 65 -66 165 -530 131 -132 597 -66 963 -488 275 -2806 2641 -438 2639 -420 2691 -412 2677 -404 2669 -416 2693 -416 361 -2730 367 -2724 2665 -422 355 -2726 2687 -394 399 -2698 2697 -390 375 -2732 2701 -388 355 -21244 2697 -416 377 -2722 2675 -416 2689 -388 2707 -396 2679 -414 2689 -392 2717 -388 375 -2706 383 -2732 2673 -396 365 -2734 2695 -386 377 -2728 2689 -384 389 -2730 2671 -386 379 -21252 2693 -416 347 -2748 2687 -396 2707 -384 2701 -388 2679 -412 2701 -418 2669 -404 363 -2726 385 -2698 2699 -416 355 -2706 2689 -416 365 -2736 2673 -386 415 -2692 2709 -378 361 -21270 2685 -452 311 -2774 2637 -442 2665 -418 2661 -448 2653 -408 2703 -384 2687 -410 365 -2738 355 -2742 2689 -382 371 -2738 2677 -384 415 -2700 2673 -410 363 -2730 2701 -386 357 -21270 2705 -398 361 -2740 2689 -386 2679 -414 2687 -410 2673 -418 2697 -386 2681 -412 383 -2702 395 -2706 2703 -380 385 -2696 2709 -418 355 -2702 2699 -418 361 -2700 2717 -386 375 -21242 2697 -418 355 -2748 2695 -382 2683 -410 2703 -380 2707 -384 2705 -404 2675 -416 383 -2700 359 -2728 2695 -382 385 -2728 2687 -416 357 -2708 2705 -386 389 -2700 2717 -388 373 -21234 2721 -418 353 -2724 2667 -416 2705 -380 2693 -386 2711 -384 2691 -422 2699 -398 365 -2726 385 -2700 2703 -378 361 -2728 2697 -420 357 -2704 2711 -388 377 -2734 2667 -406 363 -21260 2699 -418 361 -2702 2711 -380 2695 -416 2689 -402 2687 -384 2695 -416 2677 -408 361 -2732 385 -2704 2707 -414 325 -2730 2695 -418 361 -2728 2669 -414 385 -2702 2701 -414 355 -21246 2705 -378 379 -2728 2693 -384 2715 -380 2717 -386 2695 -390 2709 -388 2683 -420 355 -2730 385 -2700 2685 -416 347 -2748 2683 -396 365 -2740 2667 -416 385 -2696 2693 -414 349 -21260 2689 -452 319 -2762 2631 -476 2627 -430 2689 +RAW_Data: -416 2667 -412 2671 -416 2689 -424 347 -2732 353 -2738 2669 -410 363 -2728 2689 -410 349 -2742 2677 -386 415 -2696 2705 -380 361 -21254 2717 -386 413 -2700 2693 -380 2695 -416 2691 -398 2679 -416 2699 -384 2709 -382 367 -2726 361 -2730 2707 -382 377 -2728 2675 -386 411 -2684 2713 -414 357 -2704 2707 -388 357 -21276 2699 -382 385 -2724 2689 -416 2661 -416 2685 -384 2723 -388 2703 -400 2677 -416 385 -2696 357 -2724 2713 -384 375 -2726 2673 -420 355 -2728 2685 -396 397 -2688 2697 -408 363 -21252 2667 -484 311 -2766 2635 -476 2637 -420 2665 -448 2651 -408 2701 -384 2697 -406 355 -2758 327 -2736 2685 -420 361 -2728 2683 -384 385 -2726 2685 -414 357 -2708 2711 -388 375 -21246 2689 -448 323 -2750 2695 -378 2715 -386 2687 -392 2711 -384 2683 -416 2705 -412 327 -2732 387 -2728 2679 -416 357 -2738 2659 -418 363 -2732 2677 -386 413 -2700 2695 -380 391 -21258 2679 -406 383 -2706 2695 -384 2703 -418 2679 -404 2705 -380 2687 -418 2669 -410 359 -2726 387 -2696 2707 -416 357 -2710 2693 -418 361 -2730 2691 -380 385 -2730 2677 -414 357 -21254 2711 -382 385 -2700 2713 -414 2667 -384 2705 -418 2675 -406 2699 -382 2689 -418 365 -2726 377 -2708 2701 -384 389 -2698 2709 -398 361 -2738 2669 -416 385 -2692 2687 -418 357 -77456 131 -398 197 -132 295 -330 97 -132 229 -164 459 -164 295 -264 393 -264 719 -64 427 -98 855 -134 395 -98 297 -164 263 -262 65 -100 63 -132 197 -328 1185 -66 9359 -6420 261 -664 131 -100 299 -134 301 -232 363 -232 299 -200 165 -166 427 -230 299 -164 361 -394 1025 -100 225 -820 165 -1248 491 -100 293 -66 261 -264 131 -98 589 -164 655 -132 427 -132 295 -164 129 -132 163 -328 263 -196 627 -566 129 -100 131 -98 2377 -130 1255 -3878 297 -232 195 -132 65 -98 165 -596 397 -266 99 -198 363 -98 923 -100 431 -66 1383 -3724 297 -166 165 -66 99 -398 265 -266 463 -232 133 -232 65 -230 65 -266 959 -200 99 -298 231 -68 65 -100 97 -398 363 -132 199 -134 133 -134 133 -266 593 -66 363 -66 827 -2374 65 -1724 399 -166 265 -100 331 -198 165 -398 233 -98 233 -66 165 -266 97 -66 231 -132 165 -298 395 -234 99 -132 65 -100 99 -132 131 -66 297 -264 197 -194 229 -530 2189 -166 9577 -3702 199 -98 465 -398 97 -134 395 -132 429 -100 529 -68 263 -132 265 -368 263 -860 97 -100 163 -196 427 -98 163 -166 327 -98 493 -166 327 -98 233 -5094 99 -198 97 -100 65 -1250 131 -560 855 -66 855 -262 859 -164 10219 -7528 761 -66 1121 -100 429 -298 331 -232 263 -166 261 -166 265 -100 1427 -98 9787 -6682 131 -564 429 +RAW_Data: -66 529 -66 2519 -66 265 -68 10101 -1794 65 -1890 393 -562 97 -132 197 -98 493 -330 97 -164 97 -230 327 -326 99 -100 97 -164 65 -132 293 -98 297 -166 161 -130 297 -230 1391 -68 11185 -3800 229 -230 297 -66 65 -198 65 -466 99 -464 99 -430 67 -698 295 -132 165 -164 1095 -66 299 -66 1321 -264 12675 -66 99 -166 229 -134 65 -330 165 -164 65 -890 131 -830 67 -66 1157 -100 167 -168 265 -66 827 -66 2047 -100 261 -594 2279 -134 10701 -3890 163 -1384 67 -98 99 -1322 99 -98 65 -398 823 -66 65 -68 927 -100 495 -132 593 -100 165 -198 1387 -1022 131 -728 99 -662 97 -462 495 -200 829 -330 563 -100 297 -330 65 -598 165 -592 295 -166 131 -764 165 -164 565 -66 131 -166 165 -66 9675 -5052 165 -2878 199 -66 265 -432 265 -66 267 -898 163 -132 231 -198 229 -164 97 -100 4445 -66 7853 -636 199 -662 265 -298 233 -1428 331 -134 1791 -66 1649 -66 297 -100 361 -198 559 -98 363 -200 1315 -66 265 -98 1049 -132 1647 -66 265 -822 295 -526 131 -1712 199 -166 231 -200 165 -66 265 -166 97 -132 163 -164 395 -630 495 -168 297 -298 229 -266 629 -200 133 -132 133 -166 65 -132 99 -100 131 -66 67 -98 133 -496 1391 -98 1751 -164 359 -132 97 -164 263 -64 691 -66 199 -66 293 -98 589 -198 11299 -3968 65 -68 65 -2702 65 -1186 927 -166 65 -66 429 -134 197 -134 529 -200 67 -66 231 -100 2151 -4014 97 -1486 99 -464 65 -330 129 -330 331 -134 599 -66 497 -200 165 -66 661 -166 6881 -8830 295 -100 197 -232 725 -134 299 -166 229 -166 525 -198 295 -66 459 -66 329 -230 595 -98 299 -132 329 -66 99 -98 163 -134 229 -100 8345 -6726 131 -132 295 -66 1579 -66 329 -98 501 -132 231 -66 491 -298 331 -266 363 -132 1193 -168 8847 -4194 199 -828 65 -100 195 -262 197 -298 65 -898 65 -132 629 -66 229 -100 291 -100 623 -66 295 -66 461 -132 529 -632 597 -132 65 -100 97 -134 297 -100 297 -166 397 -168 527 -134 9603 -3850 99 -200 67 -896 959 -198 165 -100 229 -266 531 -64 165 -132 163 -296 3715 -11994 165 -1492 429 -68 263 -100 265 -330 199 -64 495 -132 363 -66 63 -166 297 -398 65 -100 231 -332 199 -100 7683 -4916 65 -1294 297 -1022 1325 -166 393 -132 165 -498 1255 -134 197 -198 427 -164 329 -132 631 -594 199 -196 99 -100 265 -134 1457 -100 3649 -8592 67 -268 131 -332 99 -100 65 -760 101 -198 297 -168 199 -132 369 -100 97 -132 99 -232 397 -198 99 -134 97 -100 231 -332 131 -796 329 -266 263 +RAW_Data: -100 10841 -4030 163 -164 197 -398 195 -592 65 -132 63 -430 295 -298 263 -200 3517 -132 3763 -12296 99 -330 361 -98 99 -200 65 -430 165 -166 2327 -100 4051 -66 9653 -3478 197 -66 163 -198 167 -66 65 -598 165 -298 131 -666 199 -198 299 -298 165 -200 565 -66 797 -98 1125 -98 825 -100 4113 -6956 65 -5536 165 -266 99 -232 461 -198 65 -200 1989 -66 295 -66 723 -66 65 -98 329 -98 955 -66 559 -232 331 -66 10851 -1048 65 -3748 65 -498 99 -1392 99 -794 529 -98 331 -98 397 -164 363 -394 331 -266 299 -230 165 -66 3001 -568 197 -2872 2579 -468 2637 -472 2599 -488 2647 -426 2653 -448 2665 -392 379 -2734 381 -2700 2691 -388 377 -2732 2669 -420 355 -2726 2687 -394 403 -2706 2687 -388 377 -21248 2717 -388 377 -2738 2659 -408 2703 -382 2689 -416 2679 -408 2701 -382 2687 -418 365 -2736 365 -2722 2689 -384 391 -2696 2707 -386 379 -2734 2665 -410 361 -2726 2703 -418 357 -21246 2679 -466 297 -2768 2657 -448 2627 -434 2669 -450 2653 -416 2673 -408 2697 -386 383 -2728 369 -2706 2701 -382 387 -2726 2687 -418 357 -2708 2693 -418 361 -2702 2709 -396 401 -21232 2689 -406 361 -2736 2695 -386 2695 -406 2695 -382 2687 -418 2675 -410 2693 -414 375 -2692 389 -2706 2701 -404 363 -2724 2695 -388 389 -2702 2719 -358 405 -2704 2701 -402 363 -21262 2677 -414 367 -2738 2677 -386 2693 -420 2701 -400 2677 -386 2695 -420 2669 -430 369 -2718 353 -2730 2673 -412 361 -2734 2691 -420 357 -2698 2701 -394 401 -2702 2687 -424 347 -21244 2701 -418 365 -2726 2703 -382 2697 -420 2675 -400 2685 -384 2721 -398 2667 -418 355 -2744 343 -2722 2703 -420 353 -2724 2689 -396 363 -2736 2687 -390 377 -2730 2697 -386 357 -21274 2683 -414 375 -2726 2667 -420 2703 -398 2677 -388 2695 -420 2699 -398 2671 -384 415 -2698 357 -2738 2695 -382 383 -2724 2685 -416 357 -2706 2707 -384 391 -2726 2671 -384 415 -21238 2651 -476 293 -2776 2653 -462 2641 -446 2661 -422 2663 -418 2689 -412 2683 -414 357 -2706 385 -2698 2715 -378 379 -2710 2719 -388 377 -2708 2695 -406 361 -2724 2689 -416 361 -21244 2703 -386 413 -2698 2697 -414 2689 -384 2685 -386 2719 -378 2701 -416 2689 -386 377 -2728 387 -2700 2673 -410 361 -2730 2695 -420 357 -2732 2679 -386 377 -2734 2699 -378 361 -21262 2697 -392 405 -2702 2687 -406 2703 -382 2703 -418 2671 -406 2677 -416 2695 -386 387 -2700 381 -2704 2695 -418 357 -2712 2721 -388 375 -2702 2693 -408 363 -2730 2693 -420 355 -21248 2653 -494 289 -91206 131 -132 97 -232 559 -132 591 -98 691 -66 131 -130 297 -66 231 -66 331 -66 433 -100 499 -132 231 -166 197 -134 593 -100 11707 -4456 133 -200 131 +RAW_Data: -66 133 -66 97 -166 561 -100 895 -132 1323 -66 10873 -3752 99 -722 229 -394 97 -66 99 -98 99 -328 297 -328 265 -298 3089 -132 10573 -1460 133 -432 99 -232 99 -132 333 -232 731 -164 65 -166 165 -132 131 -330 65 -98 131 -596 65 -198 133 -98 397 -568 65 -132 1157 -166 195 -130 131 -64 99 -66 63 -198 265 -98 297 -66 63 -166 295 -100 1747 -232 6099 -11348 199 -528 297 -266 97 -598 99 -198 231 -64 4433 -334 65 -298 65 -3284 67 -530 97 -432 133 -2356 493 -68 231 -168 297 -266 427 -100 559 -98 229 -460 197 -66 261 -132 65 -98 565 -132 231 -66 497 -100 3491 -12356 65 -660 197 -198 165 -132 331 -134 65 -98 2651 -134 4531 -10850 65 -1322 263 -68 431 -232 165 -134 165 -202 231 -300 5625 -66 6951 -8162 65 -398 99 -596 65 -132 461 -598 429 -132 97 -132 463 -232 229 -98 329 -100 397 -100 363 -100 231 -200 163 -200 961 -66 693 -100 397 -134 10601 -3872 263 -100 165 -100 131 -198 99 -696 233 -1524 331 -132 131 -164 229 -132 493 -98 631 -134 231 -100 595 -66 295 -66 5965 -8248 99 -296 99 -98 397 -66 65 -924 229 -398 299 -98 1425 -130 565 -198 827 -262 429 -598 725 -704 729 -12290 131 -98 99 -98 65 -100 163 -164 65 -494 231 -100 97 -100 863 -66 1751 -3948 165 -100 195 -66 165 -296 65 -2042 99 -200 495 -132 557 -100 827 -98 167 -66 433 -100 661 -164 689 -98 10803 -3906 231 -296 295 -232 99 -234 131 -332 395 -266 1283 -164 755 -466 397 -164 335 -66 1355 -14376 557 -66 331 -68 431 -134 599 -364 229 -100 763 -98 265 -132 525 -166 99 -396 495 -98 3867 -134 595 -168 865 -166 503 -200 467 -134 8145 -458 235 -794 599 -458 265 -436 231 -426 333 -368 299 -730 689 -360 327 -370 363 -326 367 -668 733 -328 363 -302 397 -328 371 -296 393 -666 725 -622 795 -634 433 -264 1023 -228 5041 -762 585 -466 233 -826 235 -470 631 -368 299 -402 299 -726 361 -328 331 -370 363 -332 701 -298 401 -692 369 -302 759 -268 461 -236 435 -622 423 -260 465 -266 719 -13608 65 -624 197 -558 921 -164 1315 -134 465 -134 263 -100 295 -132 293 -66 329 -98 197 -132 9977 -5036 197 -798 333 -828 295 -100 197 -100 165 -66 665 -100 763 -300 297 -166 165 -98 823 -8348 229 -100 427 -196 263 -624 197 -134 797 -100 263 -68 529 -132 233 -134 165 -264 131 -132 559 -66 263 -228 927 -132 731 -102 1061 -66 863 -8206 131 -332 299 -166 461 -100 99 -66 429 -66 3271 -98 465 -100 401 -232 331 -66 397 -430 10341 +RAW_Data: -5434 65 -298 133 -132 131 -68 231 -200 661 -132 9517 -424 97 -1456 99 -1694 393 -100 131 -560 131 -196 197 -298 65 -428 229 -196 297 -266 131 -166 2435 -66 10161 -11230 65 -1320 131 -298 265 -532 231 -200 1291 -68 631 -66 12645 -4048 133 -66 67 -132 167 -266 163 -66 397 -132 197 -132 299 -98 197 -198 2903 -66 2361 -66 9627 -3588 197 -332 165 -68 331 -68 197 -132 99 -100 663 -66 363 -230 231 -166 131 -100 201 -298 163 -132 133 -202 363 -300 397 -102 263 -100 165 -66 1221 -66 1479 -132 165 -98 229 -12976 263 -66 363 -134 231 -66 629 -132 327 -100 97 -130 99 -164 227 -64 297 -132 397 -164 425 -198 97 -198 99 -66 365 -164 199 -102 97 -66 1817 -13524 231 -134 16907 -4086 233 -630 65 -396 201 -66 165 -198 67 -198 99 -664 2117 -166 12473 -446 2649 -440 2661 -420 2651 -422 2681 -418 2703 -400 365 -2724 387 -2696 2695 -414 357 -2704 2707 -386 389 -2700 2687 -392 405 -2706 2695 -402 363 -21268 2707 -388 377 -2706 2691 -404 2699 -382 2717 -382 2707 -378 2693 -416 2687 -396 363 -2736 355 -2748 2659 -416 365 -2708 2715 -388 377 -2708 2697 -404 363 -2730 2673 -420 355 -21268 2655 -460 319 -2766 2663 -448 2631 -436 2665 -418 2683 -410 2681 -416 2701 -386 383 -2700 375 -2744 2669 -416 353 -2730 2685 -416 357 -2708 2721 -380 369 -2724 2697 -382 385 -21260 2701 -418 353 -2720 2673 -418 2675 -408 2693 -384 2715 -386 2717 -386 2691 -404 363 -2732 387 -2702 2669 -412 359 -2736 2699 -380 381 -2728 2675 -416 381 -2720 2675 -414 347 -21280 2685 -390 377 -2724 2689 -416 2673 -408 2705 -382 2695 -410 2689 -414 2661 -418 385 -2704 369 -2704 2693 -416 375 -2726 2661 -420 355 -2728 2711 -388 375 -2702 2691 -410 363 -21252 2659 -488 287 -2794 2651 -448 2629 -436 2671 -416 2695 -416 2663 -406 2699 -384 383 -2730 367 -2702 2695 -418 385 -2702 2685 -412 349 -2744 2693 -366 389 -2714 2693 -394 381 -21266 2685 -418 363 -2730 2683 -382 2693 -418 2675 -410 2699 -384 2719 -382 2707 -380 359 -2734 387 -2704 2709 -380 361 -2732 2699 -418 357 -2728 2667 -416 383 -2696 2709 -380 391 -21228 2685 -458 307 -2800 2647 -412 2659 -432 2667 -416 2695 -416 2675 -406 2675 -416 383 -2700 361 -2730 2687 -414 375 -2696 2701 -420 353 -2720 2711 -382 367 -2728 2675 -416 385 -21222 2735 -386 355 -2744 2687 -396 2679 -418 2701 -386 2705 -382 2681 -410 2697 -384 385 -2736 365 -2704 2715 -384 377 -2696 2697 -416 349 -2722 2707 -386 379 -2732 2671 -410 361 -21258 2681 -464 297 -2796 2629 -456 2655 -420 2661 -448 2663 -404 2695 -382 2715 -380 371 -2740 355 -2744 2679 -384 391 -2728 2675 -388 379 +RAW_Data: -2728 2695 -414 357 -2704 2705 -418 357 -21262 2673 -416 383 -2696 2709 -380 2703 -384 2699 -418 2671 -408 2695 -382 2713 -386 379 -2730 357 -2732 2695 -384 383 -2730 2679 -416 357 -2708 2701 -410 349 -2736 2697 -382 385 -21252 2669 -478 289 -2790 2647 -426 2651 -444 2653 -430 2659 -418 2695 -414 2681 -402 349 -2738 383 -2722 2677 -414 347 -2744 2691 -382 369 -2730 2691 -384 383 -2734 2679 -414 347 -21264 2705 -386 379 -2736 2667 -410 2695 -382 2715 -380 2709 -420 2665 -392 2713 -382 383 -2730 365 -2728 2665 -418 383 -2696 2693 -418 357 -2710 2711 -380 375 -2718 2701 -416 357 -21238 2677 -484 311 -2766 2635 -444 2657 -420 2663 -422 2695 -416 2667 -428 2675 -396 363 -73890 133 -98 131 -132 129 -658 99 -66 853 -100 63 -100 361 -98 1589 -66 1231 -132 65 -100 297 -198 65 -132 265 -66 9857 -4672 165 -1030 97 -1394 65 -200 2687 -68 6873 -8336 99 -1156 97 -66 163 -232 163 -262 197 -132 295 -132 263 -166 953 -100 263 -130 393 -164 295 -64 329 -66 393 -164 823 -130 165 -66 6133 -8436 165 -164 265 -266 65 -362 197 -696 3181 -132 363 -98 65 -166 131 -66 399 -132 663 -396 329 -66 7335 -7578 497 -230 627 -264 99 -366 99 -132 131 -134 265 -498 163 -100 1323 -66 265 -66 1129 -100 399 -132 365 -100 795 -68 397 -98 597 -364 297 -132 361 -132 265 -132 8591 -4740 65 -100 131 -166 199 -1088 97 -296 99 -528 131 -98 661 -66 401 -198 1157 -166 361 -164 495 -100 165 -66 297 -100 1423 -66 3067 -5658 67 -6406 197 -1092 65 -530 659 -68 265 -100 991 -68 231 -230 297 -66 327 -66 131 -132 659 -134 131 -100 1183 -132 263 -98 621 -66 2075 -6976 65 -5138 67 -132 129 -664 67 -132 165 -100 331 -466 231 -68 467 -98 563 -66 231 -100 531 -66 465 -66 1023 -166 297 -134 3409 -12290 67 -164 99 -532 133 -166 263 -66 231 -66 721 -64 131 -68 959 -134 495 -100 299 -98 497 -98 365 -100 397 -232 297 -98 531 -66 3029 -12216 265 -132 99 -364 199 -234 131 -66 431 -166 333 -166 397 -132 327 -100 395 -66 197 -132 395 -66 527 -98 295 -100 97 -98 789 -132 363 -132 297 -200 2815 -4914 65 -6620 65 -462 65 -134 297 -66 497 -264 231 -198 2773 -134 365 -100 831 -166 131 -100 297 -132 861 -132 299 -100 561 -66 1381 -6946 65 -5516 231 -266 97 -1362 1093 -68 1621 -134 165 -332 297 -98 361 -228 97 -132 797 -98 3487 -13224 229 -164 65 -132 913 -66 1123 -98 527 -134 929 -98 723 -100 12259 -270 165 -132 67 -132 165 -1326 99 -98 65 -1194 431 -66 695 -66 733 -134 197 +RAW_Data: -134 10801 -166 67 -6130 133 -198 231 -334 365 -98 229 -132 165 -68 231 -166 14501 -524 65 -328 131 -498 129 -1288 65 -494 163 -64 165 -66 527 -132 131 -132 1019 -198 129 -166 393 -198 65 -164 6411 -66 3255 -10642 65 -1320 165 -164 493 -492 559 -264 2555 -66 695 -66 1657 -164 855 -66 4001 -10526 97 -596 133 -298 67 -264 65 -300 65 -100 263 -166 231 -134 99 -100 2703 -68 13643 -4922 297 -100 65 -232 133 -198 331 -300 231 -66 331 -100 12047 -3872 97 -196 65 -494 329 -66 65 -890 97 -98 229 -164 195 -596 797 -66 861 -132 65 -66 231 -100 565 -66 65 -66 1297 -132 265 -66 363 -134 265 -364 297 -164 299 -134 297 -134 495 -98 11309 -3790 131 -1380 65 -758 65 -164 129 -460 65 -360 199 -100 563 -68 497 -198 363 -266 263 -100 165 -66 697 -66 1933 -13594 65 -762 1223 -132 1119 -196 361 -134 131 -100 793 -166 695 -68 231 -68 463 -66 11727 -4204 363 -264 131 -132 133 -1124 97 -100 163 -100 327 -100 331 -198 397 -66 397 -100 395 -100 163 -66 197 -564 1059 -7962 65 -100 65 -198 129 -362 99 -394 197 -296 495 -100 1357 -68 459 -66 593 -66 265 -68 301 -132 465 -66 231 -200 397 -66 397 -232 199 -298 12077 -4350 231 -796 363 -198 133 -264 65 -1132 597 -332 3295 -100 755 -98 231 -164 97 -264 459 -166 759 -164 3265 -12138 99 -232 99 -1228 1025 -100 393 -66 531 -132 693 -132 1063 -66 427 -64 297 -294 229 -98 9723 -5404 67 -466 99 -796 267 -98 201 -100 167 -264 461 -98 1415 -66 861 -66 267 -66 331 -134 1663 -66 2089 -7012 65 -100 101 -4804 431 -728 99 -100 65 -100 995 -134 165 -66 929 -100 65 -66 927 -100 1093 -168 99 -100 497 -66 665 -200 6517 -8312 165 -66 129 -66 559 -166 99 -430 65 -398 67 -66 593 -198 459 -132 261 -132 263 -130 723 -66 459 -100 325 -166 67 -198 559 -66 493 -66 11475 -3896 99 -266 99 -66 197 -1092 129 -198 361 -166 163 -98 263 -196 759 -100 265 -100 365 -630 4635 -12748 65 -1712 461 -100 497 -66 395 -98 265 -98 229 -164 529 -132 297 -66 565 -132 987 -132 8665 -2820 2265 -450 313 -2774 2643 -442 325 -2772 2665 -416 359 -2734 2667 -386 379 -21274 2657 -474 293 -2810 2619 -466 2613 -476 2629 -452 2663 -388 2683 -418 2705 -400 365 -2722 387 -2700 2697 -380 361 -2732 2691 -418 361 -2732 2667 -416 383 -2698 2697 -416 357 -21238 2715 -384 383 -2732 2685 -416 2667 -416 2695 -398 2671 -418 2687 -390 2713 -382 383 -2730 365 -2728 2661 -416 379 -2716 2685 -384 379 -2720 2703 -378 401 -2718 2671 diff --git a/assets/unit_tests/subghz/intertechno_v3.sub b/assets/unit_tests/subghz/intertechno_v3.sub new file mode 100644 index 000000000..af68b7455 --- /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 000000000..2cfc79511 --- /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/assets/unit_tests/subghz/test_random_raw.sub b/assets/unit_tests/subghz/test_random_raw.sub index 06dfb9b4b..928838d3c 100644 --- a/assets/unit_tests/subghz/test_random_raw.sub +++ b/assets/unit_tests/subghz/test_random_raw.sub @@ -139,3 +139,9 @@ RAW_Data: 277 -244 275 -1360 275 -1340 277 -246 277 -236 261 -1380 275 -1346 277 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 +RAW_Data: -66 529 -66 2519 -66 265 -68 10101 -1794 65 -1890 393 -562 97 -132 197 -98 493 -330 97 -164 97 -230 327 -326 99 -100 97 -164 65 -132 293 -98 297 -166 161 -130 297 -230 1391 -68 11185 -3800 229 -230 297 -66 65 -198 65 -466 99 -464 99 -430 67 -698 295 -132 165 -164 1095 -66 299 -66 1321 -264 12675 -66 99 -166 229 -134 65 -330 165 -164 65 -890 131 -830 67 -66 1157 -100 167 -168 265 -66 827 -66 2047 -100 261 -594 2279 -134 10701 -3890 163 -1384 67 -98 99 -1322 99 -98 65 -398 823 -66 65 -68 927 -100 495 -132 593 -100 165 -198 1387 -1022 131 -728 99 -662 97 -462 495 -200 829 -330 563 -100 297 -330 65 -598 165 -592 295 -166 131 -764 165 -164 565 -66 131 -166 165 -66 9675 -5052 165 -2878 199 -66 265 -432 265 -66 267 -898 163 -132 231 -198 229 -164 97 -100 4445 -66 7853 -636 199 -662 265 -298 233 -1428 331 -134 1791 -66 1649 -66 297 -100 361 -198 559 -98 363 -200 1315 -66 265 -98 1049 -132 1647 -66 265 -822 295 -526 131 -1712 199 -166 231 -200 165 -66 265 -166 97 -132 163 -164 395 -630 495 -168 297 -298 229 -266 629 -200 133 -132 133 -166 65 -132 99 -100 131 -66 67 -98 133 -496 1391 -98 1751 -164 359 -132 97 -164 263 -64 691 -66 199 -66 293 -98 589 -198 11299 -3968 65 -68 65 -2702 65 -1186 927 -166 65 -66 429 -134 197 -134 529 -200 67 -66 231 -100 2151 -4014 97 -1486 99 -464 65 -330 129 -330 331 -134 599 -66 497 -200 165 -66 661 -166 6881 -8830 295 -100 197 -232 725 -134 299 -166 229 -166 525 -198 295 -66 459 -66 329 -230 595 -98 299 -132 329 -66 99 -98 163 -134 229 -100 8345 -6726 131 -132 295 -66 1579 -66 329 -98 501 -132 231 -66 491 -298 331 -266 363 -132 1193 -168 8847 -4194 199 -828 65 -100 195 -262 197 -298 65 -898 65 -132 629 -66 229 -100 291 -100 623 -66 295 -66 461 -132 529 -632 597 -132 65 -100 97 -134 297 -100 297 -166 397 -168 527 -134 9603 -3850 99 -200 67 -896 959 -198 165 -100 229 -266 531 -64 165 -132 163 -296 3715 -11994 165 -1492 429 -68 263 -100 265 -330 199 -64 495 -132 363 -66 63 -166 297 -398 65 -100 231 -332 199 -100 7683 -4916 65 -1294 297 -1022 1325 -166 393 -132 165 -498 1255 -134 197 -198 427 -164 329 -132 631 -594 199 -196 99 -100 265 -134 1457 -100 3649 -8592 67 -268 131 -332 99 -100 65 -760 101 -198 297 -168 199 -132 369 -100 97 -132 99 -232 397 -198 99 -134 97 -100 231 -332 131 -796 329 -266 263 +RAW_Data: -100 10841 -4030 163 -164 197 -398 195 -592 65 -132 63 -430 295 -298 263 -200 3517 -132 3763 -12296 99 -330 361 -98 99 -200 65 -430 165 -166 2327 -100 4051 -66 9653 -3478 197 -66 163 -198 167 -66 65 -598 165 -298 131 -666 199 -198 299 -298 165 -200 565 -66 797 -98 1125 -98 825 -100 4113 -6956 65 -5536 165 -266 99 -232 461 -198 65 -200 1989 -66 295 -66 723 -66 65 -98 329 -98 955 -66 559 -232 331 -66 10851 -1048 65 -3748 65 -498 99 -1392 99 -794 529 -98 331 -98 397 -164 363 -394 331 -266 299 -230 165 -66 3001 -568 197 -2872 2579 -468 2637 -472 2599 -488 2647 -426 2653 -448 2665 -392 379 -2734 381 -2700 2691 -388 377 -2732 2669 -420 355 -2726 2687 -394 403 -2706 2687 -388 377 -21248 2717 -388 377 -2738 2659 -408 2703 -382 2689 -416 2679 -408 2701 -382 2687 -418 365 -2736 365 -2722 2689 -384 391 -2696 2707 -386 379 -2734 2665 -410 361 -2726 2703 -418 357 -21246 2679 -466 297 -2768 2657 -448 2627 -434 2669 -450 2653 -416 2673 -408 2697 -386 383 -2728 369 -2706 2701 -382 387 -2726 2687 -418 357 -2708 2693 -418 361 -2702 2709 -396 401 -21232 2689 -406 361 -2736 2695 -386 2695 -406 2695 -382 2687 -418 2675 -410 2693 -414 375 -2692 389 -2706 2701 -404 363 -2724 2695 -388 389 -2702 2719 -358 405 -2704 2701 -402 363 -21262 2677 -414 367 -2738 2677 -386 2693 -420 2701 -400 2677 -386 2695 -420 2669 -430 369 -2718 353 -2730 2673 -412 361 -2734 2691 -420 357 -2698 2701 -394 401 -2702 2687 -424 347 -21244 2701 -418 365 -2726 2703 -382 2697 -420 2675 -400 2685 -384 2721 -398 2667 -418 355 -2744 343 -2722 2703 -420 353 -2724 2689 -396 363 -2736 2687 -390 377 -2730 2697 -386 357 -21274 2683 -414 375 -2726 2667 -420 2703 -398 2677 -388 2695 -420 2699 -398 2671 -384 415 -2698 357 -2738 2695 -382 383 -2724 2685 -416 357 -2706 2707 -384 391 -2726 2671 -384 415 -21238 2651 -476 293 -2776 2653 -462 2641 -446 2661 -422 2663 -418 2689 -412 2683 -414 357 -2706 385 -2698 2715 -378 379 -2710 2719 -388 377 -2708 2695 -406 361 -2724 2689 -416 361 -21244 2703 -386 413 -2698 2697 -414 2689 -384 2685 -386 2719 -378 2701 -416 2689 -386 377 -2728 387 -2700 2673 -410 361 -2730 2695 -420 357 -2732 2679 -386 377 -2734 2699 -378 361 -21262 2697 -392 405 -2702 2687 -406 2703 -382 2703 -418 2671 -406 2677 -416 2695 -386 387 -2700 381 -2704 2695 -418 357 -2712 2721 -388 375 -2702 2693 -408 363 -2730 2693 -420 355 -21248 2653 -494 289 -91206 131 -132 97 -232 559 -132 591 -98 691 -66 131 -130 297 -66 231 -66 331 -66 433 -100 499 -132 231 -166 197 -134 593 -100 11707 -4456 133 -200 131 +RAW_Data: -66 133 -66 97 -166 561 -100 895 -132 1323 -66 10873 -3752 99 -722 229 -394 97 -66 99 -98 99 -328 297 -328 265 -298 3089 -132 10573 -1460 133 -432 99 -232 99 -132 333 -232 731 -164 65 -166 165 -132 131 -330 65 -98 131 -596 65 -198 133 -98 397 -568 65 -132 1157 -166 195 -130 131 -64 99 -66 63 -198 265 -98 297 -66 63 -166 295 -100 1747 -232 6099 -11348 199 -528 297 -266 97 -598 99 -198 231 -64 4433 -334 65 -298 65 -3284 67 -530 97 -432 133 -2356 493 -68 231 -168 297 -266 427 -100 559 -98 229 -460 197 -66 261 -132 65 -98 565 -132 231 -66 497 -100 3491 -12356 65 -660 197 -198 165 -132 331 -134 65 -98 2651 -134 4531 -10850 65 -1322 263 -68 431 -232 165 -134 165 -202 231 -300 5625 -66 6951 -8162 65 -398 99 -596 65 -132 461 -598 429 -132 97 -132 463 -232 229 -98 329 -100 397 -100 363 -100 231 -200 163 -200 961 -66 693 -100 397 -134 10601 -3872 263 -100 165 -100 131 -198 99 -696 233 -1524 331 -132 131 -164 229 -132 493 -98 631 -134 231 -100 595 -66 295 -66 5965 -8248 99 -296 99 -98 397 -66 65 -924 229 -398 299 -98 1425 -130 565 -198 827 -262 429 -598 725 -704 729 -12290 131 -98 99 -98 65 -100 163 -164 65 -494 231 -100 97 -100 863 -66 1751 -3948 165 -100 195 -66 165 -296 65 -2042 99 -200 495 -132 557 -100 827 -98 167 -66 433 -100 661 -164 689 -98 10803 -3906 231 -296 295 -232 99 -234 131 -332 395 -266 1283 -164 755 -466 397 -164 335 -66 1355 -14376 557 -66 331 -68 431 -134 599 -364 229 -100 763 -98 265 -132 525 -166 99 -396 495 -98 3867 -134 595 -168 865 -166 503 -200 467 -134 8145 -458 235 -794 599 -458 265 -436 231 -426 333 -368 299 -730 689 -360 327 -370 363 -326 367 -668 733 -328 363 -302 397 -328 371 -296 393 -666 725 -622 795 -634 433 -264 1023 -228 5041 -762 585 -466 233 -826 235 -470 631 -368 299 -402 299 -726 361 -328 331 -370 363 -332 701 -298 401 -692 369 -302 759 -268 461 -236 435 -622 423 -260 465 -266 719 -13608 65 -624 197 -558 921 -164 1315 -134 465 -134 263 -100 295 -132 293 -66 329 -98 197 -132 9977 -5036 197 -798 333 -828 295 -100 197 -100 165 -66 665 -100 763 -300 297 -166 165 -98 823 -8348 229 -100 427 -196 263 -624 197 -134 797 -100 263 -68 529 -132 233 -134 165 -264 131 -132 559 -66 263 -228 927 -132 731 -102 1061 -66 863 -8206 131 -332 299 -166 461 -100 99 -66 429 -66 3271 -98 465 -100 401 -232 331 -66 397 -430 10341 +RAW_Data: -5434 65 -298 133 -132 131 -68 231 -200 661 -132 9517 -424 97 -1456 99 -1694 393 -100 131 -560 131 -196 197 -298 65 -428 229 -196 297 -266 131 -166 2435 -66 10161 -11230 65 -1320 131 -298 265 -532 231 -200 1291 -68 631 -66 12645 -4048 133 -66 67 -132 167 -266 163 -66 397 -132 197 -132 299 -98 197 -198 2903 -66 2361 -66 9627 -3588 197 -332 165 -68 331 -68 197 -132 99 -100 663 -66 363 -230 231 -166 131 -100 201 -298 163 -132 133 -202 363 -300 397 -102 263 -100 165 -66 1221 -66 1479 -132 165 -98 229 -12976 263 -66 363 -134 231 -66 629 -132 327 -100 97 -130 99 -164 227 -64 297 -132 397 -164 425 -198 97 -198 99 -66 365 -164 199 -102 97 -66 1817 -13524 231 -134 16907 -4086 233 -630 65 -396 201 -66 165 -198 67 -198 99 -664 2117 -166 12473 -446 2649 -440 2661 -420 2651 -422 2681 -418 2703 -400 365 -2724 387 -2696 2695 -414 357 -2704 2707 -386 389 -2700 2687 -392 405 -2706 2695 -402 363 -21268 2707 -388 377 -2706 2691 -404 2699 -382 2717 -382 2707 -378 2693 -416 2687 -396 363 -2736 355 -2748 2659 -416 365 -2708 2715 -388 377 -2708 2697 -404 363 -2730 2673 -420 355 -21268 2655 -460 319 -2766 2663 -448 2631 -436 2665 -418 2683 -410 2681 -416 2701 -386 383 -2700 375 -2744 2669 -416 353 -2730 2685 -416 357 -2708 2721 -380 369 -2724 2697 -382 385 -21260 2701 -418 353 -2720 2673 -418 2675 -408 2693 -384 2715 -386 2717 -386 2691 -404 363 -2732 387 -2702 2669 -412 359 -2736 2699 -380 381 -2728 2675 -416 381 -2720 2675 -414 347 -21280 2685 -390 377 -2724 2689 -416 2673 -408 2705 -382 2695 -410 2689 -414 2661 -418 385 -2704 369 -2704 2693 -416 375 -2726 2661 -420 355 -2728 2711 -388 375 -2702 2691 -410 363 -21252 2659 -488 287 -2794 2651 -448 2629 -436 2671 -416 2695 -416 2663 -406 2699 -384 383 -2730 367 -2702 2695 -418 385 -2702 2685 -412 349 -2744 2693 -366 389 -2714 2693 -394 381 -21266 2685 -418 363 -2730 2683 -382 2693 -418 2675 -410 2699 -384 2719 -382 2707 -380 359 -2734 387 -2704 2709 -380 361 -2732 2699 -418 357 -2728 2667 -416 383 -2696 2709 -380 391 -21228 2685 -458 307 -2800 2647 -412 2659 -432 2667 -416 2695 -416 2675 -406 2675 -416 383 -2700 361 -2730 2687 -414 375 -2696 2701 -420 353 -2720 2711 -382 367 -2728 2675 -416 385 -21222 2735 -386 355 -2744 2687 -396 2679 -418 2701 -386 2705 -382 2681 -410 2697 -384 385 -2736 365 -2704 2715 -384 377 -2696 2697 -416 349 -2722 2707 -386 379 -2732 2671 -410 361 -21258 2681 -464 297 -2796 2629 -456 2655 -420 2661 -448 2663 -404 2695 -382 2715 -380 371 -2740 355 -2744 2679 -384 391 -2728 2675 -388 379 +RAW_Data: -2728 2695 -414 357 -2704 2705 -418 357 -21262 2673 -416 383 -2696 2709 -380 2703 -384 2699 -418 2671 -408 2695 -382 2713 -386 379 -2730 357 -2732 2695 -384 383 -2730 2679 -416 357 -2708 2701 -410 349 -2736 2697 -382 385 -21252 2669 -478 289 -2790 2647 -426 2651 -444 2653 -430 2659 -418 2695 -414 2681 -402 349 -2738 383 -2722 2677 -414 347 -2744 2691 -382 369 -2730 2691 -384 383 -2734 2679 -414 347 -21264 2705 -386 379 -2736 2667 -410 2695 -382 2715 -380 2709 -420 2665 -392 2713 -382 383 -2730 365 -2728 2665 -418 383 -2696 2693 -418 357 -2710 2711 -380 375 -2718 2701 -416 357 -21238 2677 -484 311 -2766 2635 -444 2657 -420 2663 -422 2695 -416 2667 -428 2675 -396 363 -73890 133 -98 131 -132 129 -658 99 -66 853 -100 63 -100 361 -98 1589 -66 1231 -132 65 -100 297 -198 65 -132 265 -66 9857 -4672 165 -1030 97 -1394 65 -200 2687 -68 6873 -8336 99 -1156 97 -66 163 -232 163 -262 197 -132 295 -132 263 -166 953 -100 263 -130 393 -164 295 -64 329 -66 393 -164 823 -130 165 -66 6133 -8436 165 -164 265 -266 65 -362 197 -696 3181 -132 363 -98 65 -166 131 -66 399 -132 663 -396 329 -66 7335 -7578 497 -230 627 -264 99 -366 99 -132 131 -134 265 -498 163 -100 1323 -66 265 -66 1129 -100 399 -132 365 -100 795 -68 397 -98 597 -364 297 -132 361 -132 265 -132 8591 -4740 65 -100 131 -166 199 -1088 97 -296 99 -528 131 -98 661 -66 401 -198 1157 -166 361 -164 495 -100 165 -66 297 -100 1423 -66 3067 -5658 67 -6406 197 -1092 65 -530 659 -68 265 -100 991 -68 231 -230 297 -66 327 -66 131 -132 659 -134 131 -100 1183 -132 263 -98 621 -66 2075 -6976 65 -5138 67 -132 129 -664 67 -132 165 -100 331 -466 231 -68 467 -98 563 -66 231 -100 531 -66 465 -66 1023 -166 297 -134 3409 -12290 67 -164 99 -532 133 -166 263 -66 231 -66 721 -64 131 -68 959 -134 495 -100 299 -98 497 -98 365 -100 397 -232 297 -98 531 -66 3029 -12216 265 -132 99 -364 199 -234 131 -66 431 -166 333 -166 397 -132 327 -100 395 -66 197 -132 395 -66 527 -98 295 -100 97 -98 789 -132 363 -132 297 -200 2815 -4914 65 -6620 65 -462 65 -134 297 -66 497 -264 231 -198 2773 -134 365 -100 831 -166 131 -100 297 -132 861 -132 299 -100 561 -66 1381 -6946 65 -5516 231 -266 97 -1362 1093 -68 1621 -134 165 -332 297 -98 361 -228 97 -132 797 -98 3487 -13224 229 -164 65 -132 913 -66 1123 -98 527 -134 929 -98 723 -100 12259 -270 165 -132 67 -132 165 -1326 99 -98 65 -1194 431 -66 695 -66 733 -134 197 +RAW_Data: -134 10801 -166 67 -6130 133 -198 231 -334 365 -98 229 -132 165 -68 231 -166 14501 -524 65 -328 131 -498 129 -1288 65 -494 163 -64 165 -66 527 -132 131 -132 1019 -198 129 -166 393 -198 65 -164 6411 -66 3255 -10642 65 -1320 165 -164 493 -492 559 -264 2555 -66 695 -66 1657 -164 855 -66 4001 -10526 97 -596 133 -298 67 -264 65 -300 65 -100 263 -166 231 -134 99 -100 2703 -68 13643 -4922 297 -100 65 -232 133 -198 331 -300 231 -66 331 -100 12047 -3872 97 -196 65 -494 329 -66 65 -890 97 -98 229 -164 195 -596 797 -66 861 -132 65 -66 231 -100 565 -66 65 -66 1297 -132 265 -66 363 -134 265 -364 297 -164 299 -134 297 -134 495 -98 11309 -3790 131 -1380 65 -758 65 -164 129 -460 65 -360 199 -100 563 -68 497 -198 363 -266 263 -100 165 -66 697 -66 1933 -13594 65 -762 1223 -132 1119 -196 361 -134 131 -100 793 -166 695 -68 231 -68 463 -66 11727 -4204 363 -264 131 -132 133 -1124 97 -100 163 -100 327 -100 331 -198 397 -66 397 -100 395 -100 163 -66 197 -564 1059 -7962 65 -100 65 -198 129 -362 99 -394 197 -296 495 -100 1357 -68 459 -66 593 -66 265 -68 301 -132 465 -66 231 -200 397 -66 397 -232 199 -298 12077 -4350 231 -796 363 -198 133 -264 65 -1132 597 -332 3295 -100 755 -98 231 -164 97 -264 459 -166 759 -164 3265 -12138 99 -232 99 -1228 1025 -100 393 -66 531 -132 693 -132 1063 -66 427 -64 297 -294 229 -98 9723 -5404 67 -466 99 -796 267 -98 201 -100 167 -264 461 -98 1415 -66 861 -66 267 -66 331 -134 1663 -66 2089 -7012 65 -100 101 -4804 431 -728 99 -100 65 -100 995 -134 165 -66 929 -100 65 -66 927 -100 1093 -168 99 -100 497 -66 665 -200 6517 -8312 165 -66 129 -66 559 -166 99 -430 65 -398 67 -66 593 -198 459 -132 261 -132 263 -130 723 -66 459 -100 325 -166 67 -198 559 -66 493 -66 11475 -3896 99 -266 99 -66 197 -1092 129 -198 361 -166 163 -98 263 -196 759 -100 265 -100 365 -630 4635 -12748 65 -1712 461 -100 497 -66 395 -98 265 -98 229 -164 529 -132 297 -66 565 -132 987 -132 8665 -2820 2265 -450 313 -2774 2643 -442 325 -2772 2665 -416 359 -2734 2667 -386 379 -21274 2657 -474 293 -2810 2619 -466 2613 -476 2629 -452 2663 -388 2683 -418 2705 -400 365 -2722 387 -2700 2697 -380 361 -2732 2691 -418 361 -2732 2667 -416 383 -2698 2697 -416 357 -21238 2715 -384 383 -2732 2685 -416 2667 -416 2695 -398 2671 -418 2687 -390 2713 -382 383 -2730 365 -2728 2661 -416 379 -2716 2685 -384 379 -2720 2703 -378 401 -2718 2671 diff --git a/documentation/AppManifests.md b/documentation/AppManifests.md index 7b1177890..d17c11c0e 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/BarcodeGenerator.md b/documentation/BarcodeGenerator.md index b9ea7a86f..f2b5b2213 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. diff --git a/documentation/HowToInstall.md b/documentation/HowToInstall.md index 956b8ef65..18021418b 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) diff --git a/documentation/SubGHzRemotePlugin.md b/documentation/SubGHzRemotePlugin.md index 82885be56..615c8ba09 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). diff --git a/documentation/fbt.md b/documentation/fbt.md index 53fc4b5e3..48726273e 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/fbt_options.py b/fbt_options.py index 73f5d191b..ab70ae8ae 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -86,19 +86,19 @@ FIRMWARE_APPS = { # Custom Games "custom_games", # Debug - "debug_apps", + "debug_apps_lite", ], "unit_tests": [ "basic_services", "updater_app", "unit_tests", ], - "no_custom_apps": [ + "debug_pack": [ "crypto_start", # Svc "basic_services", # Apps - "basic_apps", + #"basic_apps", "updater_app", "storage_move_to_sd", "archive", @@ -107,7 +107,7 @@ FIRMWARE_APPS = { "system_settings", "about", # Plugins - "basic_plugins", + #"basic_plugins", # Debug "debug_apps", ], diff --git a/firmware/targets/f7/Inc/FreeRTOSConfig.h b/firmware/targets/f7/Inc/FreeRTOSConfig.h index 4f9d1fcf9..1df5fce78 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 000000000..5a4f1b978 --- /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 000000000..5fe4a2ed8 --- /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 6db430a53..07cae31fe 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 0cef33ddf..dc3b1637e 100644 --- a/firmware/targets/f7/furi_hal/furi_hal.c +++ b/firmware/targets/f7/furi_hal/furi_hal.c @@ -1,4 +1,5 @@ #include +#include #include @@ -75,6 +76,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 000000000..43dc56f11 --- /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_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index 2d6db8fbf..946774819 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; @@ -215,7 +217,6 @@ bool furi_hal_nfc_listen( } rfalLowPowerModeStop(); rfalNfcDiscoverParam params = { - .compMode = RFAL_COMPLIANCE_MODE_NFC, .techs2Find = RFAL_NFC_LISTEN_TECH_A, .totalDuration = 1000, .devLimit = 1, @@ -228,6 +229,11 @@ bool furi_hal_nfc_listen( .notifyCb = NULL, .activate_after_sak = activate_after_sak, }; + if(FURI_BIT(sak, 5)) { + params.compMode = RFAL_COMPLIANCE_MODE_EMV; + } else { + params.compMode = RFAL_COMPLIANCE_MODE_NFC; + } params.lmConfigPA.nfcidLen = uid_len; memcpy(params.lmConfigPA.nfcid, uid, uid_len); params.lmConfigPA.SENS_RES[0] = atqa[0]; @@ -269,6 +275,10 @@ void furi_hal_nfc_listen_sleep() { st25r3916ExecuteCommand(ST25R3916_CMD_GOTO_SLEEP); } +void furi_hal_nfc_stop_cmd() { + st25r3916ExecuteCommand(ST25R3916_CMD_STOP); +} + bool furi_hal_nfc_listen_rx(FuriHalNfcTxRxContext* tx_rx, uint32_t timeout_ms) { furi_assert(tx_rx); @@ -281,6 +291,9 @@ bool furi_hal_nfc_listen_rx(FuriHalNfcTxRxContext* tx_rx, uint32_t timeout_ms) { if(st25r3916GetInterrupt(ST25R3916_IRQ_MASK_RXE)) { furi_hal_nfc_read_fifo(tx_rx->rx_data, &tx_rx->rx_bits); data_received = true; + if(tx_rx->sniff_rx) { + tx_rx->sniff_rx(tx_rx->rx_data, tx_rx->rx_bits, false, tx_rx->sniff_context); + } break; } continue; @@ -495,14 +508,14 @@ static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_ furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc); st25r3916ExecuteCommand(ST25R3916_CMD_UNMASK_RECEIVE_DATA); - if(tx_rx->sniff_tx) { - tx_rx->sniff_tx(tx_rx->tx_data, tx_rx->tx_bits, false, tx_rx->sniff_context); - } - // Manually wait for interrupt furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeInput, GpioPullDown, GpioSpeedVeryHigh); st25r3916ClearAndEnableInterrupts(ST25R3916_IRQ_MASK_RXE); + if(tx_rx->sniff_tx) { + tx_rx->sniff_tx(tx_rx->tx_data, tx_rx->tx_bits, false, tx_rx->sniff_context); + } + uint32_t irq = 0; uint8_t rxe = 0; uint32_t start = DWT->CYCCNT; diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi.c b/firmware/targets/f7/furi_hal/furi_hal_spi.c index f8c5a2c78..2d54278d6 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/furi_hal/furi_hal_subghz.c b/firmware/targets/f7/furi_hal/furi_hal_subghz.c index 9db44933d..221f7da33 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.c +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.c @@ -18,6 +18,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; @@ -395,6 +417,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, @@ -405,6 +430,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, @@ -466,6 +494,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(); } @@ -479,6 +512,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); @@ -664,6 +702,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; } @@ -695,6 +759,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); diff --git a/firmware/targets/f7/stm32wb55xx_flash.ld b/firmware/targets/f7/stm32wb55xx_flash.ld index 20314ba3c..4124c096d 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 8c4d41c5b..1b7fe3600 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 000000000..e9efa08c1 --- /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/firmware/targets/furi_hal_include/furi_hal_nfc.h b/firmware/targets/furi_hal_include/furi_hal_nfc.h index 71186076f..0bcb45068 100644 --- a/firmware/targets/furi_hal_include/furi_hal_nfc.h +++ b/firmware/targets/furi_hal_include/furi_hal_nfc.h @@ -120,6 +120,8 @@ void furi_hal_nfc_field_off(); */ void furi_hal_nfc_start_sleep(); +void furi_hal_nfc_stop_cmd(); + /** NFC stop sleep */ void furi_hal_nfc_exit_sleep(); diff --git a/furi/core/core_defines.h b/furi/core/core_defines.h index 801810f6a..487fe2ca3 100644 --- a/furi/core/core_defines.h +++ b/furi/core/core_defines.h @@ -85,7 +85,11 @@ extern "C" { #endif #ifndef FURI_BIT_SET -#define FURI_BIT_SET(x, n) ((x) |= (1 << (n))) +#define FURI_BIT_SET(x, n) \ + ({ \ + __typeof__(x) _x = (1); \ + (x) |= (_x << (n)); \ + }) #endif #ifndef FURI_BIT_CLEAR diff --git a/furi/core/memmgr.c b/furi/core/memmgr.c index 01cf573eb..6bad14027 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); @@ -79,3 +80,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 d7285fb23..fdecfd72d 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 044f83711..a68472b56 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 7f746f03f..f15b9ff66 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/core/timer.c b/furi/core/timer.c index 807f477e4..462a2e89e 100644 --- a/furi/core/timer.c +++ b/furi/core/timer.c @@ -1,5 +1,7 @@ #include "timer.h" #include "check.h" +#include "memmgr.h" +#include "kernel.h" #include "core/common_defines.h" #include @@ -39,7 +41,7 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co /* Dynamic memory allocation is available: if memory for callback and */ /* its context is not provided, allocate it from dynamic memory pool */ if(callb == NULL) { - callb = (TimerCallback_t*)pvPortMalloc(sizeof(TimerCallback_t)); + callb = (TimerCallback_t*)malloc(sizeof(TimerCallback_t)); if(callb != NULL) { /* Callback memory was allocated from dynamic pool, set flag */ @@ -65,7 +67,7 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co if((hTimer == NULL) && (callb != NULL) && (callb_dyn == 1U)) { /* Failed to create a timer, release allocated resources */ callb = (TimerCallback_t*)((uint32_t)callb & ~1U); - vPortFree(callb); + free(callb); } } @@ -82,14 +84,16 @@ void furi_timer_free(FuriTimer* instance) { callb = (TimerCallback_t*)pvTimerGetTimerID(hTimer); - if(xTimerDelete(hTimer, portMAX_DELAY) == pdPASS) { - if((uint32_t)callb & 1U) { - /* Callback memory was allocated from dynamic pool, clear flag */ - callb = (TimerCallback_t*)((uint32_t)callb & ~1U); + furi_check(xTimerDelete(hTimer, portMAX_DELAY) == pdPASS); - /* Return allocated memory to dynamic pool */ - vPortFree(callb); - } + while (furi_timer_is_running(instance)) furi_delay_tick(2); + + if((uint32_t)callb & 1U) { + /* Callback memory was allocated from dynamic pool, clear flag */ + callb = (TimerCallback_t*)((uint32_t)callb & ~1U); + + /* Return allocated memory to dynamic pool */ + free(callb); } } @@ -120,11 +124,8 @@ FuriStatus furi_timer_stop(FuriTimer* instance) { if(xTimerIsTimerActive(hTimer) == pdFALSE) { stat = FuriStatusErrorResource; } else { - if(xTimerStop(hTimer, portMAX_DELAY) == pdPASS) { - stat = FuriStatusOk; - } else { - stat = FuriStatusError; - } + furi_check(xTimerStop(hTimer, portMAX_DELAY) == pdPASS); + stat = FuriStatusOk; } /* Return execution status */ diff --git a/furi/flipper.c b/furi/flipper.c index c7d7c5a6c..2acfea015 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 diff --git a/lib/ST25RFAL002/include/rfal_picopass.h b/lib/ST25RFAL002/include/rfal_picopass.h index 2baf96f37..e7fb272ce 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_nfc.c b/lib/ST25RFAL002/source/rfal_nfc.c old mode 100755 new mode 100644 diff --git a/lib/ST25RFAL002/source/rfal_picopass.c b/lib/ST25RFAL002/source/rfal_picopass.c index d4422e412..f33fcdf8c 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; } diff --git a/lib/drivers/nrf24.c b/lib/drivers/nrf24.c index f2e315d9f..e70acad65 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) { diff --git a/lib/flipper_format/flipper_format_stream.c b/lib/flipper_format/flipper_format_stream.c index 81189b69b..e4b7b3003 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/lfrfid_worker_modes.c b/lib/lfrfid/lfrfid_worker_modes.c index f41a7194a..16936cca1 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 @@ -522,9 +534,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); } diff --git a/lib/lfrfid/protocols/lfrfid_protocols.c b/lib/lfrfid/protocols/lfrfid_protocols.c index 5df01b19e..bd29bd8e0 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.c +++ b/lib/lfrfid/protocols/lfrfid_protocols.c @@ -8,6 +8,13 @@ #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" +#include "protocol_pac_stanley.h" +#include "protocol_keri.h" +#include "protocol_gallagher.h" const ProtocolBase* lfrfid_protocols[] = { [LFRFIDProtocolEM4100] = &protocol_em4100, @@ -19,4 +26,11 @@ 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, + [LFRFIDProtocolPACStanley] = &protocol_pac_stanley, + [LFRFIDProtocolKeri] = &protocol_keri, + [LFRFIDProtocolGallagher] = &protocol_gallagher, }; \ No newline at end of file diff --git a/lib/lfrfid/protocols/lfrfid_protocols.h b/lib/lfrfid/protocols/lfrfid_protocols.h index 4b8f6573d..26065c9aa 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.h +++ b/lib/lfrfid/protocols/lfrfid_protocols.h @@ -17,7 +17,13 @@ typedef enum { LFRFIDProtocolFDXB, LFRFIDProtocolHidGeneric, LFRFIDProtocolHidExGeneric, - + LFRFIDProtocolPyramid, + LFRFIDProtocolViking, + LFRFIDProtocolJablotron, + LFRFIDProtocolParadox, + LFRFIDProtocolPACStanley, + LFRFIDProtocolKeri, + LFRFIDProtocolGallagher, LFRFIDProtocolMax, } LFRFIDProtocol; diff --git a/lib/lfrfid/protocols/protocol_awid.c b/lib/lfrfid/protocols/protocol_awid.c index 243b5edeb..97c07d7b2 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 92721fcdc..17f57421a 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_gallagher.c b/lib/lfrfid/protocols/protocol_gallagher.c new file mode 100644 index 000000000..c205ab8a5 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_gallagher.c @@ -0,0 +1,300 @@ +#include +#include +#include +#include +#include "lfrfid_protocols.h" + +#define GALLAGHER_CLOCK_PER_BIT (32) + +#define GALLAGHER_ENCODED_BIT_SIZE (96) +#define GALLAGHER_ENCODED_BYTE_SIZE ((GALLAGHER_ENCODED_BIT_SIZE) / 8) +#define GALLAGHER_PREAMBLE_BIT_SIZE (16) +#define GALLAGHER_PREAMBLE_BYTE_SIZE ((GALLAGHER_PREAMBLE_BIT_SIZE) / 8) +#define GALLAGHER_ENCODED_BYTE_FULL_SIZE \ + (GALLAGHER_ENCODED_BYTE_SIZE + GALLAGHER_PREAMBLE_BYTE_SIZE) +#define GALLAGHER_DECODED_DATA_SIZE 8 + +#define GALLAGHER_READ_SHORT_TIME (128) +#define GALLAGHER_READ_LONG_TIME (256) +#define GALLAGHER_READ_JITTER_TIME (60) + +#define GALLAGHER_READ_SHORT_TIME_LOW (GALLAGHER_READ_SHORT_TIME - GALLAGHER_READ_JITTER_TIME) +#define GALLAGHER_READ_SHORT_TIME_HIGH (GALLAGHER_READ_SHORT_TIME + GALLAGHER_READ_JITTER_TIME) +#define GALLAGHER_READ_LONG_TIME_LOW (GALLAGHER_READ_LONG_TIME - GALLAGHER_READ_JITTER_TIME) +#define GALLAGHER_READ_LONG_TIME_HIGH (GALLAGHER_READ_LONG_TIME + GALLAGHER_READ_JITTER_TIME) + +typedef struct { + uint8_t data[GALLAGHER_DECODED_DATA_SIZE]; + uint8_t encoded_data[GALLAGHER_ENCODED_BYTE_FULL_SIZE]; + + uint8_t encoded_data_index; + bool encoded_polarity; + + ManchesterState decoder_manchester_state; +} ProtocolGallagher; + +ProtocolGallagher* protocol_gallagher_alloc(void) { + ProtocolGallagher* proto = malloc(sizeof(ProtocolGallagher)); + return (void*)proto; +}; + +void protocol_gallagher_free(ProtocolGallagher* protocol) { + free(protocol); +}; + +uint8_t* protocol_gallagher_get_data(ProtocolGallagher* protocol) { + return protocol->data; +}; + +static void protocol_gallagher_scramble(uint8_t* data, size_t length) { + const uint8_t lut[] = { + 0xa3, 0xb0, 0x80, 0xc6, 0xb2, 0xf4, 0x5c, 0x6c, 0x81, 0xf1, 0xbb, 0xeb, 0x55, 0x67, 0x3c, + 0x05, 0x1a, 0x0e, 0x61, 0xf6, 0x22, 0xce, 0xaa, 0x8f, 0xbd, 0x3b, 0x1f, 0x5e, 0x44, 0x04, + 0x51, 0x2e, 0x4d, 0x9a, 0x84, 0xea, 0xf8, 0x66, 0x74, 0x29, 0x7f, 0x70, 0xd8, 0x31, 0x7a, + 0x6d, 0xa4, 0x00, 0x82, 0xb9, 0x5f, 0xb4, 0x16, 0xab, 0xff, 0xc2, 0x39, 0xdc, 0x19, 0x65, + 0x57, 0x7c, 0x20, 0xfa, 0x5a, 0x49, 0x13, 0xd0, 0xfb, 0xa8, 0x91, 0x73, 0xb1, 0x33, 0x18, + 0xbe, 0x21, 0x72, 0x48, 0xb6, 0xdb, 0xa0, 0x5d, 0xcc, 0xe6, 0x17, 0x27, 0xe5, 0xd4, 0x53, + 0x42, 0xf3, 0xdd, 0x7b, 0x24, 0xac, 0x2b, 0x58, 0x1e, 0xa7, 0xe7, 0x86, 0x40, 0xd3, 0x98, + 0x97, 0x71, 0xcb, 0x3a, 0x0f, 0x01, 0x9b, 0x6e, 0x1b, 0xfc, 0x34, 0xa6, 0xda, 0x07, 0x0c, + 0xae, 0x37, 0xca, 0x54, 0xfd, 0x26, 0xfe, 0x0a, 0x45, 0xa2, 0x2a, 0xc4, 0x12, 0x0d, 0xf5, + 0x4f, 0x69, 0xe0, 0x8a, 0x77, 0x60, 0x3f, 0x99, 0x95, 0xd2, 0x38, 0x36, 0x62, 0xb7, 0x32, + 0x7e, 0x79, 0xc0, 0x46, 0x93, 0x2f, 0xa5, 0xba, 0x5b, 0xaf, 0x52, 0x1d, 0xc3, 0x75, 0xcf, + 0xd6, 0x4c, 0x83, 0xe8, 0x3d, 0x30, 0x4e, 0xbc, 0x08, 0x2d, 0x09, 0x06, 0xd9, 0x25, 0x9e, + 0x89, 0xf2, 0x96, 0x88, 0xc1, 0x8c, 0x94, 0x0b, 0x28, 0xf0, 0x47, 0x63, 0xd5, 0xb3, 0x68, + 0x56, 0x9c, 0xf9, 0x6f, 0x41, 0x50, 0x85, 0x8b, 0x9d, 0x59, 0xbf, 0x9f, 0xe2, 0x8e, 0x6a, + 0x11, 0x23, 0xa1, 0xcd, 0xb5, 0x7d, 0xc7, 0xa9, 0xc8, 0xef, 0xdf, 0x02, 0xb8, 0x03, 0x6b, + 0x35, 0x3e, 0x2c, 0x76, 0xc9, 0xde, 0x1c, 0x4b, 0xd1, 0xed, 0x14, 0xc5, 0xad, 0xe9, 0x64, + 0x4a, 0xec, 0x8d, 0xf7, 0x10, 0x43, 0x78, 0x15, 0x87, 0xe4, 0xd7, 0x92, 0xe1, 0xee, 0xe3, + 0x90}; + for(size_t i = 0; i < length; i++) { + data[i] = lut[data[i]]; + } +} + +static void protocol_gallagher_descramble(uint8_t* data, size_t length) { + const uint8_t lut[] = { + 0x2f, 0x6e, 0xdd, 0xdf, 0x1d, 0x0f, 0xb0, 0x76, 0xad, 0xaf, 0x7f, 0xbb, 0x77, 0x85, 0x11, + 0x6d, 0xf4, 0xd2, 0x84, 0x42, 0xeb, 0xf7, 0x34, 0x55, 0x4a, 0x3a, 0x10, 0x71, 0xe7, 0xa1, + 0x62, 0x1a, 0x3e, 0x4c, 0x14, 0xd3, 0x5e, 0xb2, 0x7d, 0x56, 0xbc, 0x27, 0x82, 0x60, 0xe3, + 0xae, 0x1f, 0x9b, 0xaa, 0x2b, 0x95, 0x49, 0x73, 0xe1, 0x92, 0x79, 0x91, 0x38, 0x6c, 0x19, + 0x0e, 0xa9, 0xe2, 0x8d, 0x66, 0xc7, 0x5a, 0xf5, 0x1c, 0x80, 0x99, 0xbe, 0x4e, 0x41, 0xf0, + 0xe8, 0xa6, 0x20, 0xab, 0x87, 0xc8, 0x1e, 0xa0, 0x59, 0x7b, 0x0c, 0xc3, 0x3c, 0x61, 0xcc, + 0x40, 0x9e, 0x06, 0x52, 0x1b, 0x32, 0x8c, 0x12, 0x93, 0xbf, 0xef, 0x3b, 0x25, 0x0d, 0xc2, + 0x88, 0xd1, 0xe0, 0x07, 0x2d, 0x70, 0xc6, 0x29, 0x6a, 0x4d, 0x47, 0x26, 0xa3, 0xe4, 0x8b, + 0xf6, 0x97, 0x2c, 0x5d, 0x3d, 0xd7, 0x96, 0x28, 0x02, 0x08, 0x30, 0xa7, 0x22, 0xc9, 0x65, + 0xf8, 0xb7, 0xb4, 0x8a, 0xca, 0xb9, 0xf2, 0xd0, 0x17, 0xff, 0x46, 0xfb, 0x9a, 0xba, 0x8f, + 0xb6, 0x69, 0x68, 0x8e, 0x21, 0x6f, 0xc4, 0xcb, 0xb3, 0xce, 0x51, 0xd4, 0x81, 0x00, 0x2e, + 0x9c, 0x74, 0x63, 0x45, 0xd9, 0x16, 0x35, 0x5f, 0xed, 0x78, 0x9f, 0x01, 0x48, 0x04, 0xc1, + 0x33, 0xd6, 0x4f, 0x94, 0xde, 0x31, 0x9d, 0x0a, 0xac, 0x18, 0x4b, 0xcd, 0x98, 0xb8, 0x37, + 0xa2, 0x83, 0xec, 0x03, 0xd8, 0xda, 0xe5, 0x7a, 0x6b, 0x53, 0xd5, 0x15, 0xa4, 0x43, 0xe9, + 0x90, 0x67, 0x58, 0xc0, 0xa5, 0xfa, 0x2a, 0xb1, 0x75, 0x50, 0x39, 0x5c, 0xe6, 0xdc, 0x89, + 0xfc, 0xcf, 0xfe, 0xf9, 0x57, 0x54, 0x64, 0xa8, 0xee, 0x23, 0x0b, 0xf1, 0xea, 0xfd, 0xdb, + 0xbd, 0x09, 0xb5, 0x5b, 0x05, 0x86, 0x13, 0xf3, 0x24, 0xc5, 0x3f, 0x44, 0x72, 0x7c, 0x7e, + 0x36}; + + for(size_t i = 0; i < length; i++) { + data[i] = lut[data[i]]; + } +} + +static void protocol_gallagher_decode(ProtocolGallagher* protocol) { + bit_lib_remove_bit_every_nth(protocol->encoded_data, 16, 9 * 8, 9); + protocol_gallagher_descramble(protocol->encoded_data + 2, 8); + + // Region code + bit_lib_set_bits(protocol->data, 0, (protocol->encoded_data[5] & 0x1E) >> 1, 4); + + // Issue Level + bit_lib_set_bits(protocol->data, 4, (protocol->encoded_data[9] & 0x0F), 4); + + // Facility Code + uint32_t fc = (protocol->encoded_data[7] & 0x0F) << 12 | protocol->encoded_data[3] << 4 | + ((protocol->encoded_data[9] >> 4) & 0x0F); + protocol->data[3] = (uint8_t)fc; + protocol->data[2] = (uint8_t)(fc >>= 8); + protocol->data[1] = (uint8_t)(fc >>= 8); + + // Card Number + uint32_t card = protocol->encoded_data[2] << 16 | (protocol->encoded_data[6] & 0x1F) << 11 | + protocol->encoded_data[4] << 3 | (protocol->encoded_data[5] & 0xE0) >> 5; + protocol->data[7] = (uint8_t)card; + protocol->data[6] = (uint8_t)(card >>= 8); + protocol->data[5] = (uint8_t)(card >>= 8); + protocol->data[4] = (uint8_t)(card >>= 8); +} + +static bool protocol_gallagher_can_be_decoded(ProtocolGallagher* protocol) { + // check 16 bits preamble + if(bit_lib_get_bits_16(protocol->encoded_data, 0, 16) != 0b0111111111101010) return false; + + // check next 16 bits preamble + if(bit_lib_get_bits_16(protocol->encoded_data, 96, 16) != 0b0111111111101010) return false; + + uint8_t checksum_arr[8] = {0}; + for(int i = 0, pos = 0; i < 8; i++) { + // Following the preamble, every 9th bit is a checksum-bit for the preceding byte + pos = 16 + (9 * i); + checksum_arr[i] = bit_lib_get_bits(protocol->encoded_data, pos, 8); + } + uint8_t crc = bit_lib_get_bits(protocol->encoded_data, 16 + (9 * 8), 8); + uint8_t calc_crc = bit_lib_crc8(checksum_arr, 8, 0x7, 0x2c, false, false, 0x00); + + // crc + if(crc != calc_crc) return false; + + return true; +} + +void protocol_gallagher_decoder_start(ProtocolGallagher* protocol) { + memset(protocol->encoded_data, 0, GALLAGHER_ENCODED_BYTE_FULL_SIZE); + manchester_advance( + protocol->decoder_manchester_state, + ManchesterEventReset, + &protocol->decoder_manchester_state, + NULL); +}; + +bool protocol_gallagher_decoder_feed(ProtocolGallagher* protocol, bool level, uint32_t duration) { + bool result = false; + + ManchesterEvent event = ManchesterEventReset; + + if(duration > GALLAGHER_READ_SHORT_TIME_LOW && duration < GALLAGHER_READ_SHORT_TIME_HIGH) { + if(!level) { + event = ManchesterEventShortHigh; + } else { + event = ManchesterEventShortLow; + } + } else if(duration > GALLAGHER_READ_LONG_TIME_LOW && duration < GALLAGHER_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, GALLAGHER_ENCODED_BYTE_FULL_SIZE, data); + + if(protocol_gallagher_can_be_decoded(protocol)) { + protocol_gallagher_decode(protocol); + result = true; + } + } + } + + return result; +}; + +bool protocol_gallagher_encoder_start(ProtocolGallagher* protocol) { + // Preamble + bit_lib_set_bits(protocol->encoded_data, 0, 0b01111111, 8); + bit_lib_set_bits(protocol->encoded_data, 8, 0b11101010, 8); + + uint8_t rc = bit_lib_get_bits(protocol->data, 0, 4); + uint8_t il = bit_lib_get_bits(protocol->data, 4, 4); + uint32_t fc = bit_lib_get_bits_32(protocol->data, 8, 24); + uint32_t cn = bit_lib_get_bits_32(protocol->data, 32, 32); + + uint8_t payload[8] = {0}; + payload[0] = (cn & 0xffffff) >> 16; + payload[1] = (fc & 0xfff) >> 4; + payload[2] = (cn & 0x7ff) >> 3; + payload[3] = (cn & 0x7) << 5 | (rc & 0xf) << 1; + payload[4] = (cn & 0xffff) >> 11; + payload[5] = (fc & 0xffff) >> 12; + payload[6] = 0; + payload[7] = (fc & 0xf) << 4 | (il & 0xf); + + // Gallagher scramble + protocol_gallagher_scramble(payload, 8); + + for(int i = 0; i < 8; i++) { + // data byte + bit_lib_set_bits(protocol->encoded_data, 16 + (i * 9), payload[i], 8); + + // every byte is followed by a bit which is the inverse of the last bit + bit_lib_set_bit(protocol->encoded_data, 16 + (i * 9) + 8, !(payload[i] & 0x1)); + } + + // checksum + uint8_t crc = bit_lib_crc8(payload, 8, 0x7, 0x2c, false, false, 0x00); + bit_lib_set_bits(protocol->encoded_data, 16 + (9 * 8), crc, 8); + + return true; +}; + +LevelDuration protocol_gallagher_encoder_yield(ProtocolGallagher* protocol) { + bool level = bit_lib_get_bit(protocol->encoded_data, protocol->encoded_data_index); + uint32_t duration = GALLAGHER_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, GALLAGHER_ENCODED_BIT_SIZE); + } + + return level_duration_make(level, duration); +}; + +bool protocol_gallagher_write_data(ProtocolGallagher* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_gallagher_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = + (LFRFID_T5577_MODULATION_MANCHESTER | LFRFID_T5577_BITRATE_RF_32 | + (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_gallagher_render_data(ProtocolGallagher* protocol, string_t result) { + UNUSED(protocol); + uint8_t rc = bit_lib_get_bits(protocol->data, 0, 4); + uint8_t il = bit_lib_get_bits(protocol->data, 4, 4); + uint32_t fc = bit_lib_get_bits_32(protocol->data, 8, 24); + uint32_t card_id = bit_lib_get_bits_32(protocol->data, 32, 32); + + string_cat_printf(result, "Region: %u, Issue Level: %u\r\n", rc, il); + string_cat_printf(result, "FC: %u, C: %lu\r\n", fc, card_id); +}; + +const ProtocolBase protocol_gallagher = { + .name = "Gallagher", + .manufacturer = "Gallagher", + .data_size = GALLAGHER_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_gallagher_alloc, + .free = (ProtocolFree)protocol_gallagher_free, + .get_data = (ProtocolGetData)protocol_gallagher_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_gallagher_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_gallagher_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_gallagher_encoder_start, + .yield = (ProtocolEncoderYield)protocol_gallagher_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_gallagher_render_data, + .render_brief_data = (ProtocolRenderData)protocol_gallagher_render_data, + .write_data = (ProtocolWriteData)protocol_gallagher_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_gallagher.h b/lib/lfrfid/protocols/protocol_gallagher.h new file mode 100644 index 000000000..2d922f605 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_gallagher.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_gallagher; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_jablotron.c b/lib/lfrfid/protocols/protocol_jablotron.c new file mode 100644 index 000000000..e00b1e59c --- /dev/null +++ b/lib/lfrfid/protocols/protocol_jablotron.c @@ -0,0 +1,207 @@ +#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); +}; + +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_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 000000000..4de57de42 --- /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 diff --git a/lib/lfrfid/protocols/protocol_keri.c b/lib/lfrfid/protocols/protocol_keri.c new file mode 100644 index 000000000..7e6625546 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_keri.c @@ -0,0 +1,264 @@ +#include +#include +#include +#include "lfrfid_protocols.h" + +#define KERI_PREAMBLE_BIT_SIZE (33) +#define KERI_PREAMBLE_DATA_SIZE (5) + +#define KERI_ENCODED_BIT_SIZE (64) +#define KERI_ENCODED_DATA_SIZE (((KERI_ENCODED_BIT_SIZE) / 8) + KERI_PREAMBLE_DATA_SIZE) +#define KERI_ENCODED_DATA_LAST ((KERI_ENCODED_BIT_SIZE) / 8) + +#define KERI_DECODED_BIT_SIZE (28) +#define KERI_DECODED_DATA_SIZE (4) + +#define KERI_US_PER_BIT (255) +#define KERI_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; +} ProtocolKeriEncoder; + +typedef struct { + uint8_t encoded_data[KERI_ENCODED_DATA_SIZE]; + uint8_t negative_encoded_data[KERI_ENCODED_DATA_SIZE]; + uint8_t corrupted_encoded_data[KERI_ENCODED_DATA_SIZE]; + uint8_t corrupted_negative_encoded_data[KERI_ENCODED_DATA_SIZE]; + + uint8_t data[KERI_DECODED_DATA_SIZE]; + ProtocolKeriEncoder encoder; +} ProtocolKeri; + +ProtocolKeri* protocol_keri_alloc(void) { + ProtocolKeri* protocol = malloc(sizeof(ProtocolKeri)); + return protocol; +}; + +void protocol_keri_free(ProtocolKeri* protocol) { + free(protocol); +}; + +uint8_t* protocol_keri_get_data(ProtocolKeri* protocol) { + return protocol->data; +}; + +void protocol_keri_decoder_start(ProtocolKeri* protocol) { + memset(protocol->encoded_data, 0, KERI_ENCODED_DATA_SIZE); + memset(protocol->negative_encoded_data, 0, KERI_ENCODED_DATA_SIZE); + memset(protocol->corrupted_encoded_data, 0, KERI_ENCODED_DATA_SIZE); + memset(protocol->corrupted_negative_encoded_data, 0, KERI_ENCODED_DATA_SIZE); +}; + +static bool protocol_keri_check_preamble(uint8_t* data, size_t bit_index) { + // Preamble 11100000 00000000 00000000 00000000 1 + if(*(uint32_t*)&data[bit_index / 8] != 0b00000000000000000000000011100000) return false; + if(bit_lib_get_bit(data, bit_index + 32) != 1) return false; + return true; +} + +static bool protocol_keri_can_be_decoded(uint8_t* data) { + if(!protocol_keri_check_preamble(data, 0)) return false; + if(!protocol_keri_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_keri_decoder_feed_internal(bool polarity, uint32_t time, uint8_t* data) { + time += (KERI_US_PER_BIT / 2); + + size_t bit_count = (time / KERI_US_PER_BIT); + bool result = false; + + if(bit_count < KERI_ENCODED_BIT_SIZE) { + for(size_t i = 0; i < bit_count; i++) { + bit_lib_push_bit(data, KERI_ENCODED_DATA_SIZE, polarity); + if(protocol_keri_can_be_decoded(data)) { + result = true; + break; + } + } + } + + return result; +} + +static void protocol_keri_descramble(uint32_t* fc, uint32_t* cn, uint32_t* internal_id) { + const uint8_t card_to_id[] = {255, 255, 255, 255, 13, 12, 20, 5, 16, 6, 21, + 17, 8, 255, 0, 7, 10, 15, 255, 11, 4, 1, + 255, 18, 255, 19, 2, 14, 3, 9, 255, 255}; + + const uint8_t card_to_fc[] = {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 0, 255, 255, 255, 255, 2, 255, 255, 255, + 3, 255, 4, 255, 255, 255, 255, 255, 1, 255}; + + *fc = 0; + *cn = 0; + for(uint8_t card_idx = 0; card_idx < 32; card_idx++) { + bool bit = (*internal_id >> card_idx) & 1; + // Card ID + if(card_to_id[card_idx] < 32) { + *cn = *cn | (bit << card_to_id[card_idx]); + } + // Card FC + if(card_to_fc[card_idx] < 32) { + *fc = *fc | (bit << card_to_fc[card_idx]); + } + } +} + +static void protocol_keri_decoder_save(uint8_t* data_to, const uint8_t* data_from) { + uint32_t id = bit_lib_get_bits_32(data_from, 32, 32); + data_to[3] = (uint8_t)id; + data_to[2] = (uint8_t)(id >>= 8); + data_to[1] = (uint8_t)(id >>= 8); + data_to[0] = (uint8_t)(id >>= 8); +} + +bool protocol_keri_decoder_feed(ProtocolKeri* protocol, bool level, uint32_t duration) { + bool result = false; + + if(duration > (KERI_US_PER_BIT / 2)) { + if(protocol_keri_decoder_feed_internal(level, duration, protocol->encoded_data)) { + protocol_keri_decoder_save(protocol->data, protocol->encoded_data); + result = true; + return result; + } + + if(protocol_keri_decoder_feed_internal(!level, duration, protocol->negative_encoded_data)) { + protocol_keri_decoder_save(protocol->data, protocol->negative_encoded_data); + result = true; + return result; + } + } + + if(duration > (KERI_US_PER_BIT / 4)) { + // Try to decode wrong phase synced data + if(level) { + duration += 120; + } else { + if(duration > 120) { + duration -= 120; + } + } + + if(protocol_keri_decoder_feed_internal(level, duration, protocol->corrupted_encoded_data)) { + protocol_keri_decoder_save(protocol->data, protocol->corrupted_encoded_data); + + result = true; + return result; + } + + if(protocol_keri_decoder_feed_internal( + !level, duration, protocol->corrupted_negative_encoded_data)) { + protocol_keri_decoder_save(protocol->data, protocol->corrupted_negative_encoded_data); + + result = true; + return result; + } + } + + return result; +}; + +bool protocol_keri_encoder_start(ProtocolKeri* protocol) { + memset(protocol->encoded_data, 0, KERI_ENCODED_DATA_SIZE); + *(uint32_t*)&protocol->encoded_data[0] = 0b00000000000000000000000011100000; + bit_lib_copy_bits(protocol->encoded_data, 32, 32, protocol->data, 0); + + protocol->encoder.last_bit = + bit_lib_get_bit(protocol->encoded_data, KERI_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_keri_encoder_yield(ProtocolKeri* protocol) { + LevelDuration level_duration; + ProtocolKeriEncoder* 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 >= KERI_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, KERI_ENCODED_BIT_SIZE); + } + } + + return level_duration; +}; + +void protocol_keri_render_data(ProtocolKeri* protocol, string_t result) { + uint32_t data = bit_lib_get_bits_32(protocol->data, 0, 32); + uint32_t internal_id = data & 0x7FFFFFFF; + uint32_t fc = 0; + uint32_t cn = 0; + protocol_keri_descramble(&fc, &cn, &data); + string_printf(result, "Internal ID: %u\r\nFC: %u, Card: %u\r\n", internal_id, fc, cn); +} + +bool protocol_keri_write_data(ProtocolKeri* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_keri_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_TESTMODE_DISABLED | LFRFID_T5577_X_MODE | + LFRFID_T5577_MODULATION_PSK1 | LFRFID_T5577_PSKCF_RF_2 | + (2 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[0] |= 0xF << 18; + 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_keri = { + .name = "Keri", + .manufacturer = "Keri", + .data_size = KERI_DECODED_DATA_SIZE, + .features = LFRFIDFeaturePSK, + .validate_count = 6, + .alloc = (ProtocolAlloc)protocol_keri_alloc, + .free = (ProtocolFree)protocol_keri_free, + .get_data = (ProtocolGetData)protocol_keri_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_keri_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_keri_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_keri_encoder_start, + .yield = (ProtocolEncoderYield)protocol_keri_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_keri_render_data, + .render_brief_data = (ProtocolRenderData)protocol_keri_render_data, + .write_data = (ProtocolWriteData)protocol_keri_write_data, +}; \ No newline at end of file diff --git a/lib/lfrfid/protocols/protocol_keri.h b/lib/lfrfid/protocols/protocol_keri.h new file mode 100644 index 000000000..4cf5f370c --- /dev/null +++ b/lib/lfrfid/protocols/protocol_keri.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_keri; diff --git a/lib/lfrfid/protocols/protocol_pac_stanley.c b/lib/lfrfid/protocols/protocol_pac_stanley.c new file mode 100644 index 000000000..7ab16a103 --- /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 000000000..3ca329cf7 --- /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/protocols/protocol_paradox.c b/lib/lfrfid/protocols/protocol_paradox.c new file mode 100644 index 000000000..be627600b --- /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, "FC: %03u, Card: %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 000000000..a80696c35 --- /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 diff --git a/lib/lfrfid/protocols/protocol_pyramid.c b/lib/lfrfid/protocols/protocol_pyramid.c new file mode 100644 index 000000000..a0404b485 --- /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 000000000..940ecaec2 --- /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 new file mode 100644 index 000000000..6119b7348 --- /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 000000000..3286e03a7 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_viking.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_viking; diff --git a/lib/lfrfid/tools/bit_lib.c b/lib/lfrfid/tools/bit_lib.c index b57bda8a8..c84f4b7ed 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; @@ -262,6 +301,43 @@ 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_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 24aae0e9c..1b048db35 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. * @@ -194,6 +217,35 @@ 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 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 * diff --git a/lib/lfs_config.h b/lib/lfs_config.h index 59b3c486e..ff8bc4b23 100644 --- a/lib/lfs_config.h +++ b/lib/lfs_config.h @@ -5,21 +5,26 @@ #ifdef FURI_NDEBUG #define LFS_NO_ASSERT #define LFS_ASSERT(x) -#else +#else #define LFS_ASSERT furi_assert #endif #define LFS_TAG "Lfs" +#ifdef FURI_LFS_DEBUG #define LFS_TRACE(...) FURI_LOG_T(LFS_TAG, __VA_ARGS__); #define LFS_DEBUG(...) FURI_LOG_D(LFS_TAG, __VA_ARGS__); +#else +#define LFS_TRACE(...) + +#define LFS_DEBUG(...) +#endif // FURI_LFS_DEBUG #define LFS_WARN(...) FURI_LOG_W(LFS_TAG, __VA_ARGS__); #define LFS_ERROR(...) FURI_LOG_E(LFS_TAG, __VA_ARGS__); - // Because crc #undef LFS_CONFIG @@ -35,16 +40,13 @@ #ifndef LFS_NO_ASSERT #include #endif -#if !defined(LFS_NO_DEBUG) || \ - !defined(LFS_NO_WARN) || \ - !defined(LFS_NO_ERROR) || \ - defined(LFS_YES_TRACE) +#if !defined(LFS_NO_DEBUG) || !defined(LFS_NO_WARN) || !defined(LFS_NO_ERROR) || \ + defined(LFS_YES_TRACE) #include #endif #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif // Builtin functions, these may be replaced by more efficient @@ -66,21 +68,29 @@ static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { } static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { - return lfs_aligndown(a + alignment-1, alignment); + return lfs_aligndown(a + alignment - 1, alignment); } // Find the smallest power of 2 greater than or equal to a static inline uint32_t lfs_npw2(uint32_t a) { #if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) - return 32 - __builtin_clz(a-1); + return 32 - __builtin_clz(a - 1); #else uint32_t r = 0; uint32_t s; a -= 1; - s = (a > 0xffff) << 4; a >>= s; r |= s; - s = (a > 0xff ) << 3; a >>= s; r |= s; - s = (a > 0xf ) << 2; a >>= s; r |= s; - s = (a > 0x3 ) << 1; a >>= s; r |= s; + s = (a > 0xffff) << 4; + a >>= s; + r |= s; + s = (a > 0xff) << 3; + a >>= s; + r |= s; + s = (a > 0xf) << 2; + a >>= s; + r |= s; + s = (a > 0x3) << 1; + a >>= s; + r |= s; return (r | (a >> 1)) + 1; #endif } @@ -114,20 +124,23 @@ static inline int lfs_scmp(uint32_t a, uint32_t b) { // Convert between 32-bit little-endian and native order static inline uint32_t lfs_fromle32(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && ( \ - (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ - (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) +#if !defined(LFS_NO_INTRINSICS) && \ + ((defined(BYTE_ORDER) && defined(ORDER_LITTLE_ENDIAN) && \ + BYTE_ORDER == ORDER_LITTLE_ENDIAN) || \ + (defined(__BYTE_ORDER) && defined(__ORDER_LITTLE_ENDIAN) && \ + __BYTE_ORDER == __ORDER_LITTLE_ENDIAN) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ + __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) return a; -#elif !defined(LFS_NO_INTRINSICS) && ( \ - (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ - (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) +#elif !defined(LFS_NO_INTRINSICS) && \ + ((defined(BYTE_ORDER) && defined(ORDER_BIG_ENDIAN) && BYTE_ORDER == ORDER_BIG_ENDIAN) || \ + (defined(__BYTE_ORDER) && defined(__ORDER_BIG_ENDIAN) && \ + __BYTE_ORDER == __ORDER_BIG_ENDIAN) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ + __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) return __builtin_bswap32(a); #else - return (((uint8_t*)&a)[0] << 0) | - (((uint8_t*)&a)[1] << 8) | - (((uint8_t*)&a)[2] << 16) | + return (((uint8_t*)&a)[0] << 0) | (((uint8_t*)&a)[1] << 8) | (((uint8_t*)&a)[2] << 16) | (((uint8_t*)&a)[3] << 24); #endif } @@ -138,21 +151,24 @@ static inline uint32_t lfs_tole32(uint32_t a) { // Convert between 32-bit big-endian and native order static inline uint32_t lfs_frombe32(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && ( \ - (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ - (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) +#if !defined(LFS_NO_INTRINSICS) && \ + ((defined(BYTE_ORDER) && defined(ORDER_LITTLE_ENDIAN) && \ + BYTE_ORDER == ORDER_LITTLE_ENDIAN) || \ + (defined(__BYTE_ORDER) && defined(__ORDER_LITTLE_ENDIAN) && \ + __BYTE_ORDER == __ORDER_LITTLE_ENDIAN) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ + __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) return __builtin_bswap32(a); -#elif !defined(LFS_NO_INTRINSICS) && ( \ - (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ - (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) +#elif !defined(LFS_NO_INTRINSICS) && \ + ((defined(BYTE_ORDER) && defined(ORDER_BIG_ENDIAN) && BYTE_ORDER == ORDER_BIG_ENDIAN) || \ + (defined(__BYTE_ORDER) && defined(__ORDER_BIG_ENDIAN) && \ + __BYTE_ORDER == __ORDER_BIG_ENDIAN) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ + __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) return a; #else - return (((uint8_t*)&a)[0] << 24) | - (((uint8_t*)&a)[1] << 16) | - (((uint8_t*)&a)[2] << 8) | - (((uint8_t*)&a)[3] << 0); + return (((uint8_t*)&a)[0] << 24) | (((uint8_t*)&a)[1] << 16) | (((uint8_t*)&a)[2] << 8) | + (((uint8_t*)&a)[3] << 0); #endif } @@ -161,11 +177,11 @@ static inline uint32_t lfs_tobe32(uint32_t a) { } // Calculate CRC-32 with polynomial = 0x04c11db7 -uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); +uint32_t lfs_crc(uint32_t crc, const void* buffer, size_t size); // Allocate memory, only used if buffers are not provided to littlefs // Note, memory must be 64-bit aligned -static inline void *lfs_malloc(size_t size) { +static inline void* lfs_malloc(size_t size) { #ifndef LFS_NO_MALLOC return malloc(size); #else @@ -175,7 +191,7 @@ static inline void *lfs_malloc(size_t size) { } // Deallocate memory, only used if buffers are not provided to littlefs -static inline void lfs_free(void *p) { +static inline void lfs_free(void* p) { #ifndef LFS_NO_MALLOC free(p); #else @@ -183,7 +199,6 @@ static inline void lfs_free(void *p) { #endif } - #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/lib/littlefs b/lib/littlefs index 1863dc788..40dba4a55 160000 --- a/lib/littlefs +++ b/lib/littlefs @@ -1 +1 @@ -Subproject commit 1863dc7883d82bd6ca79faa164b65341064d1c16 +Subproject commit 40dba4a556e0d81dfbe64301a6aa4e18ceca896c diff --git a/lib/nfc/helpers/mfkey32.c b/lib/nfc/helpers/mfkey32.c new file mode 100644 index 000000000..64b06e259 --- /dev/null +++ b/lib/nfc/helpers/mfkey32.c @@ -0,0 +1,230 @@ +#include "mfkey32.h" + +#include +#include +#include +#include +#include + +#include +#include + +#define TAG "Mfkey32" + +#define MFKEY32_LOGS_PATH EXT_PATH("nfc/.mfkey32.log") + +typedef enum { + Mfkey32StateIdle, + Mfkey32StateAuthReceived, + Mfkey32StateAuthNtSent, + Mfkey32StateAuthArNrReceived, +} Mfkey32State; + +typedef struct { + uint32_t cuid; + uint8_t sector; + MfClassicKey key; + uint32_t nt0; + uint32_t nr0; + uint32_t ar0; + uint32_t nt1; + uint32_t nr1; + uint32_t ar1; +} Mfkey32Params; + +ARRAY_DEF(Mfkey32Params, Mfkey32Params, M_POD_OPLIST); + +typedef struct { + uint8_t sector; + MfClassicKey key; + uint32_t nt; + uint32_t nr; + uint32_t ar; +} Mfkey32Nonce; + +struct Mfkey32 { + Mfkey32State state; + Stream* file_stream; + Mfkey32Params_t params_arr; + Mfkey32Nonce nonce; + uint32_t cuid; + Mfkey32ParseDataCallback callback; + void* context; +}; + +Mfkey32* mfkey32_alloc(uint32_t cuid) { + Mfkey32* instance = malloc(sizeof(Mfkey32)); + instance->cuid = cuid; + instance->state = Mfkey32StateIdle; + Storage* storage = furi_record_open(RECORD_STORAGE); + instance->file_stream = buffered_file_stream_alloc(storage); + if(!buffered_file_stream_open( + instance->file_stream, MFKEY32_LOGS_PATH, FSAM_WRITE, FSOM_OPEN_APPEND)) { + buffered_file_stream_close(instance->file_stream); + stream_free(instance->file_stream); + free(instance); + instance = NULL; + } else { + Mfkey32Params_init(instance->params_arr); + } + + furi_record_close(RECORD_STORAGE); + + return instance; +} + +void mfkey32_free(Mfkey32* instance) { + furi_assert(instance != NULL); + + Mfkey32Params_clear(instance->params_arr); + buffered_file_stream_close(instance->file_stream); + stream_free(instance->file_stream); + free(instance); +} + +void mfkey32_set_callback(Mfkey32* instance, Mfkey32ParseDataCallback callback, void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; +} + +static bool mfkey32_write_params(Mfkey32* instance, Mfkey32Params* params) { + string_t str; + string_init_printf( + str, + "Sector %d key %c cuid %08x nt0 %08x nr0 %08x ar0 %08x nt1 %08x nr1 %08x ar1 %08x\n", + params->sector, + params->key == MfClassicKeyA ? 'A' : 'B', + params->cuid, + params->nt0, + params->nr0, + params->ar0, + params->nt1, + params->nr1, + params->ar1); + bool write_success = stream_write_string(instance->file_stream, str); + string_clear(str); + return write_success; +} + +static void mfkey32_add_params(Mfkey32* instance) { + Mfkey32Nonce* nonce = &instance->nonce; + bool nonce_added = false; + // Search if we partially collected params + if(Mfkey32Params_size(instance->params_arr)) { + Mfkey32Params_it_t it; + for(Mfkey32Params_it(it, instance->params_arr); !Mfkey32Params_end_p(it); + Mfkey32Params_next(it)) { + Mfkey32Params* params = Mfkey32Params_ref(it); + if((params->sector == nonce->sector) && (params->key == nonce->key)) { + params->nt1 = nonce->nt; + params->nr1 = nonce->nr; + params->ar1 = nonce->ar; + nonce_added = true; + FURI_LOG_I( + TAG, + "Params for sector %d key %c collected", + params->sector, + params->key == MfClassicKeyA ? 'A' : 'B'); + // Write on sd card + if(mfkey32_write_params(instance, params)) { + Mfkey32Params_remove(instance->params_arr, it); + if(instance->callback) { + instance->callback(Mfkey32EventParamCollected, instance->context); + } + } + } + } + } + if(!nonce_added) { + Mfkey32Params params = { + .sector = nonce->sector, + .key = nonce->key, + .cuid = instance->cuid, + .nt0 = nonce->nt, + .nr0 = nonce->nr, + .ar0 = nonce->ar, + }; + Mfkey32Params_push_back(instance->params_arr, params); + } +} + +void mfkey32_process_data( + Mfkey32* instance, + uint8_t* data, + uint16_t len, + bool reader_to_tag, + bool crc_dropped) { + furi_assert(instance); + furi_assert(data); + + Mfkey32Nonce* nonce = &instance->nonce; + uint16_t data_len = len; + if((data_len > 3) && !crc_dropped) { + data_len -= 2; + } + + bool data_processed = false; + if(instance->state == Mfkey32StateIdle) { + if(reader_to_tag) { + if((data[0] == 0x60) || (data[0] == 0x61)) { + nonce->key = data[0] == 0x60 ? MfClassicKeyA : MfClassicKeyB; + nonce->sector = mf_classic_get_sector_by_block(data[1]); + instance->state = Mfkey32StateAuthReceived; + data_processed = true; + } + } + } else if(instance->state == Mfkey32StateAuthReceived) { + if(!reader_to_tag) { + if(len == 4) { + nonce->nt = nfc_util_bytes2num(data, 4); + instance->state = Mfkey32StateAuthNtSent; + data_processed = true; + } + } + } else if(instance->state == Mfkey32StateAuthNtSent) { + if(reader_to_tag) { + if(len == 8) { + nonce->nr = nfc_util_bytes2num(data, 4); + nonce->ar = nfc_util_bytes2num(&data[4], 4); + mfkey32_add_params(instance); + instance->state = Mfkey32StateIdle; + } + } + } + if(!data_processed) { + instance->state = Mfkey32StateIdle; + } +} + +uint16_t mfkey32_get_auth_sectors(string_t data_str) { + furi_assert(data_str); + + uint16_t nonces_num = 0; + Storage* storage = furi_record_open(RECORD_STORAGE); + Stream* file_stream = buffered_file_stream_alloc(storage); + string_t temp_str; + string_init(temp_str); + + do { + if(!buffered_file_stream_open( + file_stream, MFKEY32_LOGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) + break; + while(true) { + if(!stream_read_line(file_stream, temp_str)) break; + size_t uid_pos = string_search_str(temp_str, "cuid"); + string_left(temp_str, uid_pos); + string_push_back(temp_str, '\n'); + string_cat(data_str, temp_str); + nonces_num++; + } + } while(false); + + buffered_file_stream_close(file_stream); + stream_free(file_stream); + string_clear(temp_str); + + return nonces_num; +} diff --git a/lib/nfc/helpers/mfkey32.h b/lib/nfc/helpers/mfkey32.h new file mode 100644 index 000000000..c4f13cc2c --- /dev/null +++ b/lib/nfc/helpers/mfkey32.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +typedef struct Mfkey32 Mfkey32; + +typedef enum { + Mfkey32EventParamCollected, +} Mfkey32Event; + +typedef void (*Mfkey32ParseDataCallback)(Mfkey32Event event, void* context); + +Mfkey32* mfkey32_alloc(uint32_t cuid); + +void mfkey32_free(Mfkey32* instance); + +void mfkey32_process_data( + Mfkey32* instance, + uint8_t* data, + uint16_t len, + bool reader_to_tag, + bool crc_dropped); + +void mfkey32_set_callback(Mfkey32* instance, Mfkey32ParseDataCallback callback, void* context); + +uint16_t mfkey32_get_auth_sectors(string_t string); diff --git a/lib/nfc/helpers/nfc_debug_log.c b/lib/nfc/helpers/nfc_debug_log.c new file mode 100644 index 000000000..1cbc5224f --- /dev/null +++ b/lib/nfc/helpers/nfc_debug_log.c @@ -0,0 +1,72 @@ +#include "nfc_debug_log.h" + +#include +#include +#include + +#define TAG "NfcDebugLog" + +#define NFC_DEBUG_PCAP_FILENAME EXT_PATH("nfc/debug.txt") + +struct NfcDebugLog { + Stream* file_stream; + string_t data_str; +}; + +NfcDebugLog* nfc_debug_log_alloc() { + NfcDebugLog* instance = malloc(sizeof(NfcDebugLog)); + + Storage* storage = furi_record_open(RECORD_STORAGE); + instance->file_stream = buffered_file_stream_alloc(storage); + + if(!buffered_file_stream_open( + instance->file_stream, NFC_DEBUG_PCAP_FILENAME, FSAM_WRITE, FSOM_OPEN_APPEND)) { + buffered_file_stream_close(instance->file_stream); + stream_free(instance->file_stream); + instance->file_stream = NULL; + } + + if(!instance->file_stream) { + free(instance); + instance = NULL; + } else { + string_init(instance->data_str); + } + furi_record_close(RECORD_STORAGE); + + return instance; +} + +void nfc_debug_log_free(NfcDebugLog* instance) { + furi_assert(instance); + furi_assert(instance->file_stream); + furi_assert(instance->data_str); + + buffered_file_stream_close(instance->file_stream); + stream_free(instance->file_stream); + string_clear(instance->data_str); + + free(instance); +} + +void nfc_debug_log_process_data( + NfcDebugLog* instance, + uint8_t* data, + uint16_t len, + bool reader_to_tag, + bool crc_dropped) { + furi_assert(instance); + furi_assert(instance->file_stream); + furi_assert(instance->data_str); + furi_assert(data); + UNUSED(crc_dropped); + + string_printf(instance->data_str, "%lu %c:", furi_get_tick(), reader_to_tag ? 'R' : 'T'); + uint16_t data_len = len; + for(size_t i = 0; i < data_len; i++) { + string_cat_printf(instance->data_str, " %02x", data[i]); + } + string_push_back(instance->data_str, '\n'); + + stream_write_string(instance->file_stream, instance->data_str); +} diff --git a/lib/nfc/helpers/nfc_debug_log.h b/lib/nfc/helpers/nfc_debug_log.h new file mode 100644 index 000000000..261b8008b --- /dev/null +++ b/lib/nfc/helpers/nfc_debug_log.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +typedef struct NfcDebugLog NfcDebugLog; + +NfcDebugLog* nfc_debug_log_alloc(); + +void nfc_debug_log_free(NfcDebugLog* instance); + +void nfc_debug_log_process_data( + NfcDebugLog* instance, + uint8_t* data, + uint16_t len, + bool reader_to_tag, + bool crc_dropped); diff --git a/lib/nfc/helpers/nfc_debug_pcap.c b/lib/nfc/helpers/nfc_debug_pcap.c index 48d72bfbf..6c7654ad5 100644 --- a/lib/nfc/helpers/nfc_debug_pcap.c +++ b/lib/nfc/helpers/nfc_debug_pcap.c @@ -1,7 +1,9 @@ #include "nfc_debug_pcap.h" +#include +#include +#include #include -#include #define TAG "NfcDebugPcap" @@ -16,48 +18,94 @@ #define DATA_PCD_TO_PICC_CRC_DROPPED 0xFA #define NFC_DEBUG_PCAP_FILENAME EXT_PATH("nfc/debug.pcap") -#define NFC_DEBUG_PCAP_BUFFER_SIZE 64 -struct NfcDebugPcapWorker { - bool alive; - Storage* storage; - File* file; - StreamBufferHandle_t stream; - FuriThread* thread; +struct NfcDebugPcap { + Stream* file_stream; }; -static File* nfc_debug_pcap_open(Storage* storage) { - File* file = storage_file_alloc(storage); - if(!storage_file_open(file, NFC_DEBUG_PCAP_FILENAME, FSAM_WRITE, FSOM_OPEN_APPEND)) { - storage_file_free(file); - return NULL; - } - if(!storage_file_tell(file)) { - struct { - uint32_t magic; - uint16_t major, minor; - uint32_t reserved[2]; - uint32_t snaplen; - uint32_t link_type; - } __attribute__((__packed__)) pcap_hdr = { - .magic = PCAP_MAGIC, - .major = PCAP_MAJOR, - .minor = PCAP_MINOR, - .snaplen = FURI_HAL_NFC_DATA_BUFF_SIZE, - .link_type = DLT_ISO_14443, - }; - if(storage_file_write(file, &pcap_hdr, sizeof(pcap_hdr)) != sizeof(pcap_hdr)) { - FURI_LOG_E(TAG, "Failed to write pcap header"); +static Stream* nfc_debug_pcap_open(Storage* storage) { + Stream* stream = NULL; + stream = buffered_file_stream_alloc(storage); + if(!buffered_file_stream_open(stream, NFC_DEBUG_PCAP_FILENAME, FSAM_WRITE, FSOM_OPEN_APPEND)) { + buffered_file_stream_close(stream); + stream_free(stream); + stream = NULL; + } else { + if(!stream_tell(stream)) { + struct { + uint32_t magic; + uint16_t major, minor; + uint32_t reserved[2]; + uint32_t snaplen; + uint32_t link_type; + } __attribute__((__packed__)) pcap_hdr = { + .magic = PCAP_MAGIC, + .major = PCAP_MAJOR, + .minor = PCAP_MINOR, + .snaplen = FURI_HAL_NFC_DATA_BUFF_SIZE, + .link_type = DLT_ISO_14443, + }; + if(stream_write(stream, (uint8_t*)&pcap_hdr, sizeof(pcap_hdr)) != sizeof(pcap_hdr)) { + FURI_LOG_E(TAG, "Failed to write pcap header"); + buffered_file_stream_close(stream); + stream_free(stream); + stream = NULL; + } } } - return file; + return stream; } -static void - nfc_debug_pcap_write(NfcDebugPcapWorker* instance, uint8_t event, uint8_t* data, uint16_t len) { +NfcDebugPcap* nfc_debug_pcap_alloc() { + NfcDebugPcap* instance = malloc(sizeof(NfcDebugPcap)); + + Storage* storage = furi_record_open(RECORD_STORAGE); + instance->file_stream = nfc_debug_pcap_open(storage); + if(!instance->file_stream) { + free(instance); + instance = NULL; + } + furi_record_close(RECORD_STORAGE); + + return instance; +} + +void nfc_debug_pcap_free(NfcDebugPcap* instance) { + furi_assert(instance); + furi_assert(instance->file_stream); + + buffered_file_stream_close(instance->file_stream); + stream_free(instance->file_stream); + + free(instance); +} + +void nfc_debug_pcap_process_data( + NfcDebugPcap* instance, + uint8_t* data, + uint16_t len, + bool reader_to_tag, + bool crc_dropped) { + furi_assert(instance); + furi_assert(data); FuriHalRtcDateTime datetime; furi_hal_rtc_get_datetime(&datetime); + uint8_t event = 0; + if(reader_to_tag) { + if(crc_dropped) { + event = DATA_PCD_TO_PICC_CRC_DROPPED; + } else { + event = DATA_PCD_TO_PICC; + } + } else { + if(crc_dropped) { + event = DATA_PICC_TO_PCD_CRC_DROPPED; + } else { + event = DATA_PICC_TO_PCD; + } + } + struct { // https://wiki.wireshark.org/Development/LibpcapFileFormat#record-packet-header uint32_t ts_sec; @@ -77,90 +125,6 @@ static void .event = event, .len = len << 8 | len >> 8, }; - xStreamBufferSend(instance->stream, &pkt_hdr, sizeof(pkt_hdr), FuriWaitForever); - xStreamBufferSend(instance->stream, data, len, FuriWaitForever); -} - -static void - nfc_debug_pcap_write_tx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) { - NfcDebugPcapWorker* instance = context; - uint8_t event = crc_dropped ? DATA_PCD_TO_PICC_CRC_DROPPED : DATA_PCD_TO_PICC; - nfc_debug_pcap_write(instance, event, data, bits / 8); -} - -static void - nfc_debug_pcap_write_rx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) { - NfcDebugPcapWorker* instance = context; - uint8_t event = crc_dropped ? DATA_PICC_TO_PCD_CRC_DROPPED : DATA_PICC_TO_PCD; - nfc_debug_pcap_write(instance, event, data, bits / 8); -} - -int32_t nfc_debug_pcap_thread(void* context) { - NfcDebugPcapWorker* instance = context; - uint8_t buffer[NFC_DEBUG_PCAP_BUFFER_SIZE]; - - while(instance->alive) { - size_t ret = - xStreamBufferReceive(instance->stream, buffer, NFC_DEBUG_PCAP_BUFFER_SIZE, 50); - if(storage_file_write(instance->file, buffer, ret) != ret) { - FURI_LOG_E(TAG, "Failed to write pcap data"); - } - } - - return 0; -} - -NfcDebugPcapWorker* nfc_debug_pcap_alloc(Storage* storage) { - NfcDebugPcapWorker* instance = malloc(sizeof(NfcDebugPcapWorker)); - - instance->alive = true; - - instance->storage = storage; - - instance->file = nfc_debug_pcap_open(storage); - - instance->stream = xStreamBufferCreate(4096, 1); - - instance->thread = furi_thread_alloc(); - furi_thread_set_name(instance->thread, "PcapWorker"); - furi_thread_set_stack_size(instance->thread, 1024); - furi_thread_set_callback(instance->thread, nfc_debug_pcap_thread); - furi_thread_set_context(instance->thread, instance); - furi_thread_start(instance->thread); - - return instance; -} - -void nfc_debug_pcap_free(NfcDebugPcapWorker* instance) { - furi_assert(instance); - - instance->alive = false; - - furi_thread_join(instance->thread); - furi_thread_free(instance->thread); - - vStreamBufferDelete(instance->stream); - - if(instance->file) storage_file_free(instance->file); - - instance->storage = NULL; - - free(instance); -} - -void nfc_debug_pcap_prepare_tx_rx( - NfcDebugPcapWorker* instance, - FuriHalNfcTxRxContext* tx_rx, - bool is_picc) { - if(!instance || !instance->file) return; - - if(is_picc) { - tx_rx->sniff_tx = nfc_debug_pcap_write_rx; - tx_rx->sniff_rx = nfc_debug_pcap_write_tx; - } else { - tx_rx->sniff_tx = nfc_debug_pcap_write_tx; - tx_rx->sniff_rx = nfc_debug_pcap_write_rx; - } - - tx_rx->sniff_context = instance; + stream_write(instance->file_stream, (uint8_t*)&pkt_hdr, sizeof(pkt_hdr)); + stream_write(instance->file_stream, data, len); } diff --git a/lib/nfc/helpers/nfc_debug_pcap.h b/lib/nfc/helpers/nfc_debug_pcap.h index 6d2a449ae..eeddc5611 100644 --- a/lib/nfc/helpers/nfc_debug_pcap.h +++ b/lib/nfc/helpers/nfc_debug_pcap.h @@ -1,21 +1,17 @@ #pragma once -#include -#include +#include +#include -typedef struct NfcDebugPcapWorker NfcDebugPcapWorker; +typedef struct NfcDebugPcap NfcDebugPcap; -NfcDebugPcapWorker* nfc_debug_pcap_alloc(Storage* storage); +NfcDebugPcap* nfc_debug_pcap_alloc(); -void nfc_debug_pcap_free(NfcDebugPcapWorker* instance); +void nfc_debug_pcap_free(NfcDebugPcap* instance); -/** Prepare tx/rx context for debug pcap logging, if enabled. - * - * @param instance NfcDebugPcapWorker* instance, can be NULL - * @param tx_rx TX/RX context to log - * @param is_picc if true, record Flipper as PICC, else PCD. - */ -void nfc_debug_pcap_prepare_tx_rx( - NfcDebugPcapWorker* instance, - FuriHalNfcTxRxContext* tx_rx, - bool is_picc); +void nfc_debug_pcap_process_data( + NfcDebugPcap* instance, + uint8_t* data, + uint16_t len, + bool reader_to_tag, + bool crc_dropped); diff --git a/lib/nfc/helpers/reader_analyzer.c b/lib/nfc/helpers/reader_analyzer.c new file mode 100644 index 000000000..680b8cef9 --- /dev/null +++ b/lib/nfc/helpers/reader_analyzer.c @@ -0,0 +1,261 @@ +#include "reader_analyzer.h" +#include +#include +#include +#include + +#include "mfkey32.h" +#include "nfc_debug_pcap.h" +#include "nfc_debug_log.h" + +#define TAG "ReaderAnalyzer" + +#define READER_ANALYZER_MAX_BUFF_SIZE (1024) + +typedef struct { + bool reader_to_tag; + bool crc_dropped; + uint16_t len; +} ReaderAnalyzerHeader; + +typedef enum { + ReaderAnalyzerNfcDataMfClassic, +} ReaderAnalyzerNfcData; + +struct ReaderAnalyzer { + FuriHalNfcDevData nfc_data; + + bool alive; + StreamBufferHandle_t stream; + FuriThread* thread; + + ReaderAnalyzerParseDataCallback callback; + void* context; + + ReaderAnalyzerMode mode; + Mfkey32* mfkey32; + NfcDebugLog* debug_log; + NfcDebugPcap* pcap; +}; + +const FuriHalNfcDevData reader_analyzer_nfc_data[] = { + [ReaderAnalyzerNfcDataMfClassic] = + {.sak = 0x08, + .atqa = {0x44, 0x00}, + .interface = FuriHalNfcInterfaceRf, + .type = FuriHalNfcTypeA, + .uid_len = 7, + .uid = {0x04, 0x77, 0x70, 0x2A, 0x23, 0x4F, 0x80}, + .cuid = 0x2A234F80}, +}; + +void reader_analyzer_parse(ReaderAnalyzer* instance, uint8_t* buffer, size_t size) { + if(size < sizeof(ReaderAnalyzerHeader)) return; + + size_t bytes_i = 0; + while(bytes_i < size) { + ReaderAnalyzerHeader* header = (ReaderAnalyzerHeader*)&buffer[bytes_i]; + uint16_t len = header->len; + if(bytes_i + len > size) break; + bytes_i += sizeof(ReaderAnalyzerHeader); + if(instance->mfkey32) { + mfkey32_process_data( + instance->mfkey32, + &buffer[bytes_i], + len, + header->reader_to_tag, + header->crc_dropped); + } + if(instance->pcap) { + nfc_debug_pcap_process_data( + instance->pcap, &buffer[bytes_i], len, header->reader_to_tag, header->crc_dropped); + } + if(instance->debug_log) { + nfc_debug_log_process_data( + instance->debug_log, + &buffer[bytes_i], + len, + header->reader_to_tag, + header->crc_dropped); + } + bytes_i += len; + } +} + +int32_t reader_analyzer_thread(void* context) { + ReaderAnalyzer* reader_analyzer = context; + uint8_t buffer[READER_ANALYZER_MAX_BUFF_SIZE] = {}; + + while(reader_analyzer->alive || !xStreamBufferIsEmpty(reader_analyzer->stream)) { + size_t ret = xStreamBufferReceive( + reader_analyzer->stream, buffer, READER_ANALYZER_MAX_BUFF_SIZE, 50); + if(ret) { + reader_analyzer_parse(reader_analyzer, buffer, ret); + } + } + + return 0; +} + +ReaderAnalyzer* reader_analyzer_alloc() { + ReaderAnalyzer* instance = malloc(sizeof(ReaderAnalyzer)); + + instance->nfc_data = reader_analyzer_nfc_data[ReaderAnalyzerNfcDataMfClassic]; + instance->alive = false; + instance->stream = + xStreamBufferCreate(READER_ANALYZER_MAX_BUFF_SIZE, sizeof(ReaderAnalyzerHeader)); + + instance->thread = furi_thread_alloc(); + furi_thread_set_name(instance->thread, "ReaderAnalyzerWorker"); + furi_thread_set_stack_size(instance->thread, 2048); + furi_thread_set_callback(instance->thread, reader_analyzer_thread); + furi_thread_set_context(instance->thread, instance); + furi_thread_set_priority(instance->thread, FuriThreadPriorityLow); + + return instance; +} + +static void reader_analyzer_mfkey_callback(Mfkey32Event event, void* context) { + furi_assert(context); + ReaderAnalyzer* instance = context; + + if(event == Mfkey32EventParamCollected) { + if(instance->callback) { + instance->callback(ReaderAnalyzerEventMfkeyCollected, instance->context); + } + } +} + +void reader_analyzer_start(ReaderAnalyzer* instance, ReaderAnalyzerMode mode) { + furi_assert(instance); + + xStreamBufferReset(instance->stream); + if(mode & ReaderAnalyzerModeDebugLog) { + instance->debug_log = nfc_debug_log_alloc(); + } + if(mode & ReaderAnalyzerModeMfkey) { + instance->mfkey32 = mfkey32_alloc(instance->nfc_data.cuid); + if(instance->mfkey32) { + mfkey32_set_callback(instance->mfkey32, reader_analyzer_mfkey_callback, instance); + } + } + if(mode & ReaderAnalyzerModeDebugPcap) { + instance->pcap = nfc_debug_pcap_alloc(); + } + + instance->alive = true; + furi_thread_start(instance->thread); +} + +void reader_analyzer_stop(ReaderAnalyzer* instance) { + furi_assert(instance); + + instance->alive = false; + furi_thread_join(instance->thread); + + if(instance->debug_log) { + nfc_debug_log_free(instance->debug_log); + instance->debug_log = NULL; + } + if(instance->mfkey32) { + mfkey32_free(instance->mfkey32); + instance->mfkey32 = NULL; + } + if(instance->pcap) { + nfc_debug_pcap_free(instance->pcap); + } +} + +void reader_analyzer_free(ReaderAnalyzer* instance) { + furi_assert(instance); + + reader_analyzer_stop(instance); + furi_thread_free(instance->thread); + vStreamBufferDelete(instance->stream); + free(instance); +} + +void reader_analyzer_set_callback( + ReaderAnalyzer* instance, + ReaderAnalyzerParseDataCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; +} + +NfcProtocol + reader_analyzer_guess_protocol(ReaderAnalyzer* instance, uint8_t* buff_rx, uint16_t len) { + furi_assert(instance); + furi_assert(buff_rx); + UNUSED(len); + NfcProtocol protocol = NfcDeviceProtocolUnknown; + + if((buff_rx[0] == 0x60) || (buff_rx[0] == 0x61)) { + protocol = NfcDeviceProtocolMifareClassic; + } + + return protocol; +} + +FuriHalNfcDevData* reader_analyzer_get_nfc_data(ReaderAnalyzer* instance) { + furi_assert(instance); + + return &instance->nfc_data; +} + +static void reader_analyzer_write( + ReaderAnalyzer* instance, + uint8_t* data, + uint16_t len, + bool reader_to_tag, + bool crc_dropped) { + ReaderAnalyzerHeader header = { + .reader_to_tag = reader_to_tag, .crc_dropped = crc_dropped, .len = len}; + size_t data_sent = 0; + data_sent = xStreamBufferSend( + instance->stream, &header, sizeof(ReaderAnalyzerHeader), FuriWaitForever); + if(data_sent != sizeof(ReaderAnalyzerHeader)) { + FURI_LOG_W(TAG, "Sent %d out of %d bytes", data_sent, sizeof(ReaderAnalyzerHeader)); + } + data_sent = xStreamBufferSend(instance->stream, data, len, FuriWaitForever); + if(data_sent != len) { + FURI_LOG_W(TAG, "Sent %d out of %d bytes", data_sent, len); + } +} + +static void + reader_analyzer_write_rx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) { + UNUSED(crc_dropped); + ReaderAnalyzer* reader_analyzer = context; + uint16_t bytes = bits < 8 ? 1 : bits / 8; + reader_analyzer_write(reader_analyzer, data, bytes, false, crc_dropped); +} + +static void + reader_analyzer_write_tx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) { + UNUSED(crc_dropped); + ReaderAnalyzer* reader_analyzer = context; + uint16_t bytes = bits < 8 ? 1 : bits / 8; + reader_analyzer_write(reader_analyzer, data, bytes, true, crc_dropped); +} + +void reader_analyzer_prepare_tx_rx( + ReaderAnalyzer* instance, + FuriHalNfcTxRxContext* tx_rx, + bool is_picc) { + furi_assert(instance); + furi_assert(tx_rx); + + if(is_picc) { + tx_rx->sniff_tx = reader_analyzer_write_rx; + tx_rx->sniff_rx = reader_analyzer_write_tx; + } else { + tx_rx->sniff_rx = reader_analyzer_write_rx; + tx_rx->sniff_tx = reader_analyzer_write_tx; + } + + tx_rx->sniff_context = instance; +} diff --git a/lib/nfc/helpers/reader_analyzer.h b/lib/nfc/helpers/reader_analyzer.h new file mode 100644 index 000000000..cc501f5a6 --- /dev/null +++ b/lib/nfc/helpers/reader_analyzer.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include + +typedef enum { + ReaderAnalyzerModeDebugLog = 0x01, + ReaderAnalyzerModeMfkey = 0x02, + ReaderAnalyzerModeDebugPcap = 0x04, +} ReaderAnalyzerMode; + +typedef enum { + ReaderAnalyzerEventMfkeyCollected, +} ReaderAnalyzerEvent; + +typedef struct ReaderAnalyzer ReaderAnalyzer; + +typedef void (*ReaderAnalyzerParseDataCallback)(ReaderAnalyzerEvent event, void* context); + +ReaderAnalyzer* reader_analyzer_alloc(); + +void reader_analyzer_free(ReaderAnalyzer* instance); + +void reader_analyzer_set_callback( + ReaderAnalyzer* instance, + ReaderAnalyzerParseDataCallback callback, + void* context); + +void reader_analyzer_start(ReaderAnalyzer* instance, ReaderAnalyzerMode mode); + +void reader_analyzer_stop(ReaderAnalyzer* instance); + +NfcProtocol + reader_analyzer_guess_protocol(ReaderAnalyzer* instance, uint8_t* buff_rx, uint16_t len); + +FuriHalNfcDevData* reader_analyzer_get_nfc_data(ReaderAnalyzer* instance); + +void reader_analyzer_prepare_tx_rx( + ReaderAnalyzer* instance, + FuriHalNfcTxRxContext* tx_rx, + bool is_picc); diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 0bfdb3dac..ea06ae70f 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -195,6 +195,7 @@ bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) { } data->data_size = pages_total * 4; data->data_read = pages_read * 4; + if(data->data_size > MF_UL_MAX_DUMP_SIZE || data->data_read > MF_UL_MAX_DUMP_SIZE) break; bool pages_parsed = true; for(uint16_t i = 0; i < pages_total; i++) { string_printf(temp_str, "Page %d", i); @@ -782,7 +783,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/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index f07ea616c..6355f8d1e 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -28,9 +28,7 @@ NfcWorker* nfc_worker_alloc() { } nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { - nfc_worker->debug_pcap_worker = nfc_debug_pcap_alloc(nfc_worker->storage); - } + nfc_worker->reader_analyzer = reader_analyzer_alloc(nfc_worker->storage); return nfc_worker; } @@ -42,7 +40,7 @@ void nfc_worker_free(NfcWorker* nfc_worker) { furi_record_close(RECORD_STORAGE); - if(nfc_worker->debug_pcap_worker) nfc_debug_pcap_free(nfc_worker->debug_pcap_worker); + reader_analyzer_free(nfc_worker->reader_analyzer); free(nfc_worker); } @@ -105,6 +103,8 @@ int32_t nfc_worker_task(void* context) { nfc_worker_mf_ultralight_read_auth(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) { nfc_worker_mf_classic_dict_attack(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateAnalyzeReader) { + nfc_worker_analyze_reader(nfc_worker); } furi_hal_nfc_sleep(); nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); @@ -117,7 +117,11 @@ static bool nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker, FuriHalNfcTxRxC MfUltralightReader reader = {}; MfUltralightData data = {}; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, tx_rx, false); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, tx_rx, false); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + do { // Read card if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 200)) break; @@ -127,6 +131,10 @@ static bool nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker, FuriHalNfcTxRxC read_success = true; } while(false); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } + return read_success; } @@ -134,7 +142,11 @@ static bool nfc_worker_read_mf_classic(NfcWorker* nfc_worker, FuriHalNfcTxRxCont furi_assert(nfc_worker->callback); bool read_success = false; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, tx_rx, false); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, tx_rx, false); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + do { // Try to read supported card FURI_LOG_I(TAG, "Try read supported card ..."); @@ -162,6 +174,9 @@ static bool nfc_worker_read_mf_classic(NfcWorker* nfc_worker, FuriHalNfcTxRxCont } } while(false); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } return read_success; } @@ -169,13 +184,21 @@ static bool nfc_worker_read_mf_desfire(NfcWorker* nfc_worker, FuriHalNfcTxRxCont bool read_success = false; MifareDesfireData* data = &nfc_worker->dev_data->mf_df_data; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, tx_rx, false); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, tx_rx, false); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + do { if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 300)) break; if(!mf_df_read_card(tx_rx, data)) break; read_success = true; } while(false); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } + return read_success; } @@ -184,7 +207,11 @@ static bool nfc_worker_read_bank_card(NfcWorker* nfc_worker, FuriHalNfcTxRxConte EmvApplication emv_app = {}; EmvData* result = &nfc_worker->dev_data->emv_data; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, tx_rx, false); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, tx_rx, false); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + do { // Read card if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 300)) break; @@ -211,6 +238,10 @@ static bool nfc_worker_read_bank_card(NfcWorker* nfc_worker, FuriHalNfcTxRxConte read_success = true; } while(false); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } + return read_success; } @@ -320,18 +351,14 @@ void nfc_worker_read(NfcWorker* nfc_worker) { void nfc_worker_emulate_uid(NfcWorker* nfc_worker) { FuriHalNfcTxRxContext tx_rx = {}; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true); FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data; NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data; // TODO add support for RATS - // Now remove bit 6 in SAK to support ISO-14443A-3 emulation // Need to save ATS to support ISO-14443A-4 emulation - uint8_t sak = data->sak; - FURI_BIT_CLEAR(sak, 5); while(nfc_worker->state == NfcWorkerStateUidEmulate) { - if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, sak, true, 100)) { + if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, false, 100)) { if(furi_hal_nfc_tx_rx(&tx_rx, 100)) { reader_data->size = tx_rx.rx_bits / 8; if(reader_data->size > 0) { @@ -349,7 +376,6 @@ void nfc_worker_emulate_uid(NfcWorker* nfc_worker) { void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { FuriHalNfcTxRxContext tx_rx = {}; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true); FuriHalNfcDevData params = { .uid = {0xCF, 0x72, 0xd4, 0x40}, .uid_len = 4, @@ -358,6 +384,11 @@ void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { .type = FuriHalNfcTypeA, }; + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, &tx_rx, true); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + while(nfc_worker->state == NfcWorkerStateEmulateApdu) { if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) { FURI_LOG_D(TAG, "POS terminal detected"); @@ -370,6 +401,10 @@ void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { furi_hal_nfc_sleep(); furi_delay_ms(20); } + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } } void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker) { @@ -484,7 +519,6 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) { FuriHalNfcTxRxContext tx_rx = {}; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true); FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; MfClassicEmulator emulator = { .cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4), @@ -525,6 +559,11 @@ void nfc_worker_mf_ultralight_read_auth(NfcWorker* nfc_worker) { MfUltralightReader reader = {}; mf_ul_reset(data); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, &tx_rx, true); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + uint32_t key = 0; uint16_t pack = 0; while(nfc_worker->state == NfcWorkerStateReadMfUltralightReadAuth) { @@ -577,4 +616,61 @@ void nfc_worker_mf_ultralight_read_auth(NfcWorker* nfc_worker) { furi_delay_ms(10); } } + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } +} + +static void nfc_worker_reader_analyzer_callback(ReaderAnalyzerEvent event, void* context) { + furi_assert(context); + NfcWorker* nfc_worker = context; + + if(event == ReaderAnalyzerEventMfkeyCollected) { + if(nfc_worker->callback) { + nfc_worker->callback(NfcWorkerEventDetectReaderMfkeyCollected, nfc_worker->context); + } + } +} + +void nfc_worker_analyze_reader(NfcWorker* nfc_worker) { + FuriHalNfcTxRxContext tx_rx = {}; + + ReaderAnalyzer* reader_analyzer = nfc_worker->reader_analyzer; + FuriHalNfcDevData* nfc_data = reader_analyzer_get_nfc_data(reader_analyzer); + MfClassicEmulator emulator = { + .cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4), + .data = nfc_worker->dev_data->mf_classic_data, + .data_changed = false, + }; + NfcaSignal* nfca_signal = nfca_signal_alloc(); + tx_rx.nfca_signal = nfca_signal; + reader_analyzer_prepare_tx_rx(reader_analyzer, &tx_rx, true); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeMfkey); + reader_analyzer_set_callback(reader_analyzer, nfc_worker_reader_analyzer_callback, nfc_worker); + + rfal_platform_spi_acquire(); + + FURI_LOG_D(TAG, "Start reader analyzer"); + while(nfc_worker->state == NfcWorkerStateAnalyzeReader) { + furi_hal_nfc_stop_cmd(); + furi_delay_ms(5); + furi_hal_nfc_listen_start(nfc_data); + if(furi_hal_nfc_listen_rx(&tx_rx, 300)) { + NfcProtocol protocol = + reader_analyzer_guess_protocol(reader_analyzer, tx_rx.rx_data, tx_rx.rx_bits / 8); + if(protocol == NfcDeviceProtocolMifareClassic) { + mf_classic_emulator(&emulator, &tx_rx); + } + } else { + FURI_LOG_D(TAG, "No data from reader"); + continue; + } + } + + rfal_platform_spi_release(); + + reader_analyzer_stop(nfc_worker->reader_analyzer); + + nfca_signal_free(nfca_signal); } diff --git a/lib/nfc/nfc_worker.h b/lib/nfc/nfc_worker.h old mode 100755 new mode 100644 index 22cbc3dcc..b7bf4da9a --- a/lib/nfc/nfc_worker.h +++ b/lib/nfc/nfc_worker.h @@ -16,6 +16,7 @@ typedef enum { NfcWorkerStateMfClassicEmulate, NfcWorkerStateReadMfUltralightReadAuth, NfcWorkerStateMfClassicDictAttack, + NfcWorkerStateAnalyzeReader, // Debug NfcWorkerStateEmulateApdu, NfcWorkerStateField, @@ -54,8 +55,12 @@ typedef enum { NfcWorkerEventFoundKeyA, NfcWorkerEventFoundKeyB, + // Detect Reader events + NfcWorkerEventDetectReaderMfkeyCollected, + // Mifare Ultralight events NfcWorkerEventMfUltralightPassKey, + } NfcWorkerEvent; typedef bool (*NfcWorkerCallback)(NfcWorkerEvent event, void* context); diff --git a/lib/nfc/nfc_worker_i.h b/lib/nfc/nfc_worker_i.h old mode 100755 new mode 100644 index 1e98879a7..526182f9a --- a/lib/nfc/nfc_worker_i.h +++ b/lib/nfc/nfc_worker_i.h @@ -12,8 +12,7 @@ #include #include #include - -#include "helpers/nfc_debug_pcap.h" +#include struct NfcWorker { FuriThread* thread; @@ -27,7 +26,7 @@ struct NfcWorker { NfcWorkerState state; - NfcDebugPcapWorker* debug_pcap_worker; + ReaderAnalyzer* reader_analyzer; }; void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state); @@ -49,3 +48,5 @@ void nfc_worker_mf_ultralight_read_auth(NfcWorker* nfc_worker); void nfc_worker_mf_ul_auth_attack(NfcWorker* nfc_worker); void nfc_worker_emulate_apdu(NfcWorker* nfc_worker); + +void nfc_worker_analyze_reader(NfcWorker* nfc_worker); 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/mifare_ultralight.c b/lib/nfc/protocols/mifare_ultralight.c index f637d378a..b3d80deb3 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; } diff --git a/lib/nfc/protocols/nfca.c b/lib/nfc/protocols/nfca.c old mode 100755 new mode 100644 diff --git a/lib/subghz/protocols/bett.c b/lib/subghz/protocols/bett.c index aca8b8c4f..08080dc6c 100644 --- a/lib/subghz/protocols/bett.c +++ b/lib/subghz/protocols/bett.c @@ -92,7 +92,7 @@ void* subghz_protocol_encoder_bett_alloc(SubGhzEnvironment* environment) { instance->generic.protocol_name = instance->base.protocol->name; instance->encoder.repeat = 10; - instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop) + instance->encoder.size_upload = 52; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; return instance; @@ -233,7 +233,8 @@ void subghz_protocol_decoder_bett_feed(void* context, bool level, uint32_t durat case BETTDecoderStepReset: if((!level) && (DURATION_DIFF(duration, subghz_protocol_bett_const.te_short * 44) < (subghz_protocol_bett_const.te_delta * 15))) { - //Found Preambula + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; instance->decoder.parser_step = BETTDecoderStepCheckDuration; } break; @@ -288,20 +289,6 @@ void subghz_protocol_decoder_bett_feed(void* context, bool level, uint32_t durat } } -/** - * Analysis of received data - * @param instance Pointer to a SubGhzBlockGeneric* instance - */ -static void subghz_protocol_bett_check_remote_controller(SubGhzBlockGeneric* instance) { - uint32_t code_found_reverse = - subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit); - - instance->serial = (code_found_reverse & 0xFF) << 12 | - ((code_found_reverse >> 8) & 0xFF) << 4 | - ((code_found_reverse >> 20) & 0x0F); - instance->btn = ((code_found_reverse >> 16) & 0x0F); -} - uint8_t subghz_protocol_decoder_bett_get_hash_data(void* context) { furi_assert(context); SubGhzProtocolDecoderBETT* instance = context; @@ -339,8 +326,7 @@ bool subghz_protocol_decoder_bett_deserialize(void* context, FlipperFormat* flip void subghz_protocol_decoder_bett_get_string(void* context, string_t output) { furi_assert(context); SubGhzProtocolDecoderBETT* instance = context; - subghz_protocol_bett_check_remote_controller(&instance->generic); - uint32_t data = (uint32_t)(instance->generic.data & 0xFFFFFF); + uint32_t data = (uint32_t)(instance->generic.data & 0x3FFFF); string_cat_printf( output, "%s %dbit\r\n" @@ -350,7 +336,7 @@ void subghz_protocol_decoder_bett_get_string(void* context, string_t output) { " -: " DIP_PATTERN "\r\n", instance->generic.protocol_name, instance->generic.data_count_bit, - (uint32_t)(instance->generic.data & 0xFFFFFF), + data, SHOW_DIP_P(data, DIP_P), SHOW_DIP_P(data, DIP_O), SHOW_DIP_P(data, DIP_N)); diff --git a/lib/subghz/protocols/came.c b/lib/subghz/protocols/came.c index 37048017e..14c66b7fa 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, @@ -112,8 +115,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 == 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); @@ -147,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; } @@ -213,8 +219,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; } @@ -306,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; } @@ -332,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); diff --git a/lib/subghz/protocols/chamberlain_code.c b/lib/subghz/protocols/chamberlain_code.c index 6c99d8451..51f2bcd32 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; diff --git a/lib/subghz/protocols/clemsa.c b/lib/subghz/protocols/clemsa.c new file mode 100644 index 000000000..357a0b06d --- /dev/null +++ b/lib/subghz/protocols/clemsa.c @@ -0,0 +1,365 @@ +#include "clemsa.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +// protocol BERNER / ELKA / TEDSEN / TELETASTER +#define TAG "SubGhzProtocolClemsa" + +#define DIP_P 0b11 //(+) +#define DIP_O 0b10 //(0) +#define DIP_N 0b00 //(-) + +#define DIP_PATTERN "%c%c%c%c%c%c%c%c" +#define SHOW_DIP_P(dip, check_dip) \ + ((((dip >> 0xE) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0xC) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0xA) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x8) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x6) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x4) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x2) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x0) & 0x3) == check_dip) ? '*' : '_') + +static const SubGhzBlockConst subghz_protocol_clemsa_const = { + .te_short = 385, + .te_long = 2695, + .te_delta = 150, + .min_count_bit_for_found = 18, +}; + +struct SubGhzProtocolDecoderClemsa { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; +}; + +struct SubGhzProtocolEncoderClemsa { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + ClemsaDecoderStepReset = 0, + ClemsaDecoderStepSaveDuration, + ClemsaDecoderStepCheckDuration, +} ClemsaDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_clemsa_decoder = { + .alloc = subghz_protocol_decoder_clemsa_alloc, + .free = subghz_protocol_decoder_clemsa_free, + + .feed = subghz_protocol_decoder_clemsa_feed, + .reset = subghz_protocol_decoder_clemsa_reset, + + .get_hash_data = subghz_protocol_decoder_clemsa_get_hash_data, + .serialize = subghz_protocol_decoder_clemsa_serialize, + .deserialize = subghz_protocol_decoder_clemsa_deserialize, + .get_string = subghz_protocol_decoder_clemsa_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_clemsa_encoder = { + .alloc = subghz_protocol_encoder_clemsa_alloc, + .free = subghz_protocol_encoder_clemsa_free, + + .deserialize = subghz_protocol_encoder_clemsa_deserialize, + .stop = subghz_protocol_encoder_clemsa_stop, + .yield = subghz_protocol_encoder_clemsa_yield, +}; + +const SubGhzProtocol subghz_protocol_clemsa = { + .name = SUBGHZ_PROTOCOL_CLEMSA_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_clemsa_decoder, + .encoder = &subghz_protocol_clemsa_encoder, +}; + +void* subghz_protocol_encoder_clemsa_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderClemsa* instance = malloc(sizeof(SubGhzProtocolEncoderClemsa)); + + instance->base.protocol = &subghz_protocol_clemsa; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 52; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + return instance; +} + +void subghz_protocol_encoder_clemsa_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderClemsa* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderClemsa instance + * @return true On success + */ +static bool subghz_protocol_encoder_clemsa_get_upload(SubGhzProtocolEncoderClemsa* instance) { + furi_assert(instance); + size_t index = 0; + size_t size_upload = (instance->generic.data_count_bit * 2); + if(size_upload > instance->encoder.size_upload) { + FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); + return false; + } else { + instance->encoder.size_upload = size_upload; + } + + for(uint8_t i = instance->generic.data_count_bit; i > 1; i--) { + if(bit_read(instance->generic.data, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_clemsa_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_clemsa_const.te_short); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_clemsa_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_clemsa_const.te_long); + } + } + if(bit_read(instance->generic.data, 0)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_clemsa_const.te_long); + instance->encoder.upload[index++] = level_duration_make( + false, + (uint32_t)subghz_protocol_clemsa_const.te_short + + subghz_protocol_clemsa_const.te_long * 7); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_clemsa_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + false, + (uint32_t)subghz_protocol_clemsa_const.te_long + + subghz_protocol_clemsa_const.te_long * 7); + } + return true; +} + +bool subghz_protocol_encoder_clemsa_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderClemsa* 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_clemsa_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_clemsa_get_upload(instance); + instance->encoder.is_running = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_clemsa_stop(void* context) { + SubGhzProtocolEncoderClemsa* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_clemsa_yield(void* context) { + SubGhzProtocolEncoderClemsa* 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_clemsa_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderClemsa* instance = malloc(sizeof(SubGhzProtocolDecoderClemsa)); + instance->base.protocol = &subghz_protocol_clemsa; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_clemsa_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderClemsa* instance = context; + free(instance); +} + +void subghz_protocol_decoder_clemsa_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderClemsa* instance = context; + instance->decoder.parser_step = ClemsaDecoderStepReset; +} + +void subghz_protocol_decoder_clemsa_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderClemsa* instance = context; + + switch(instance->decoder.parser_step) { + case ClemsaDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_clemsa_const.te_short * 51) < + subghz_protocol_clemsa_const.te_delta * 25)) { + instance->decoder.parser_step = ClemsaDecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } + break; + + case ClemsaDecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = ClemsaDecoderStepCheckDuration; + } else { + instance->decoder.parser_step = ClemsaDecoderStepReset; + } + break; + + case ClemsaDecoderStepCheckDuration: + if(!level) { + if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_clemsa_const.te_short) < + subghz_protocol_clemsa_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_clemsa_const.te_long) < + subghz_protocol_clemsa_const.te_delta * 3)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = ClemsaDecoderStepSaveDuration; + } else if( + (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_clemsa_const.te_long) < + subghz_protocol_clemsa_const.te_delta * 3) && + (DURATION_DIFF(duration, subghz_protocol_clemsa_const.te_short) < + subghz_protocol_clemsa_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = ClemsaDecoderStepSaveDuration; + } else if( + DURATION_DIFF(duration, subghz_protocol_clemsa_const.te_short * 51) < + subghz_protocol_clemsa_const.te_delta * 25) { + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_clemsa_const.te_short) < + subghz_protocol_clemsa_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + } else if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_clemsa_const.te_long) < + subghz_protocol_clemsa_const.te_delta * 3)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + } else { + instance->decoder.parser_step = ClemsaDecoderStepReset; + } + + if(instance->decoder.decode_count_bit == + subghz_protocol_clemsa_const.min_count_bit_for_found) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + instance->decoder.parser_step = ClemsaDecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + + } else { + instance->decoder.parser_step = ClemsaDecoderStepReset; + } + } else { + instance->decoder.parser_step = ClemsaDecoderStepReset; + } + break; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_clemsa_check_remote_controller(SubGhzBlockGeneric* instance) { + instance->serial = (instance->data >> 2) & 0xFFFF; + instance->btn = (instance->data & 0x03); +} + +uint8_t subghz_protocol_decoder_clemsa_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderClemsa* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_clemsa_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset) { + furi_assert(context); + SubGhzProtocolDecoderClemsa* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_clemsa_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderClemsa* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_clemsa_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_clemsa_get_string(void* context, string_t output) { + furi_assert(context); + SubGhzProtocolDecoderClemsa* instance = context; + subghz_protocol_clemsa_check_remote_controller(&instance->generic); + //uint32_t data = (uint32_t)(instance->generic.data & 0xFFFFFF); + string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%05lX Btn %X\r\n" + " +: " DIP_PATTERN "\r\n" + " o: " DIP_PATTERN "\r\n" + " -: " DIP_PATTERN "\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data & 0x3FFFF), + instance->generic.btn, + SHOW_DIP_P(instance->generic.serial, DIP_P), + SHOW_DIP_P(instance->generic.serial, DIP_O), + SHOW_DIP_P(instance->generic.serial, DIP_N)); +} diff --git a/lib/subghz/protocols/clemsa.h b/lib/subghz/protocols/clemsa.h new file mode 100644 index 000000000..a83983122 --- /dev/null +++ b/lib/subghz/protocols/clemsa.h @@ -0,0 +1,107 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_CLEMSA_NAME "Clemsa" + +typedef struct SubGhzProtocolDecoderClemsa SubGhzProtocolDecoderClemsa; +typedef struct SubGhzProtocolEncoderClemsa SubGhzProtocolEncoderClemsa; + +extern const SubGhzProtocolDecoder subghz_protocol_clemsa_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_clemsa_encoder; +extern const SubGhzProtocol subghz_protocol_clemsa; + +/** + * Allocate SubGhzProtocolEncoderClemsa. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderClemsa* pointer to a SubGhzProtocolEncoderClemsa instance + */ +void* subghz_protocol_encoder_clemsa_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderClemsa. + * @param context Pointer to a SubGhzProtocolEncoderClemsa instance + */ +void subghz_protocol_encoder_clemsa_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderClemsa instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_clemsa_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderClemsa instance + */ +void subghz_protocol_encoder_clemsa_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderClemsa instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_clemsa_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderClemsa. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderClemsa* pointer to a SubGhzProtocolDecoderClemsa instance + */ +void* subghz_protocol_decoder_clemsa_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderClemsa. + * @param context Pointer to a SubGhzProtocolDecoderClemsa instance + */ +void subghz_protocol_decoder_clemsa_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderClemsa. + * @param context Pointer to a SubGhzProtocolDecoderClemsa instance + */ +void subghz_protocol_decoder_clemsa_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderClemsa instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_clemsa_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderClemsa instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_clemsa_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderClemsa. + * @param context Pointer to a SubGhzProtocolDecoderClemsa 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_clemsa_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset); + +/** + * Deserialize data SubGhzProtocolDecoderClemsa. + * @param context Pointer to a SubGhzProtocolDecoderClemsa instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_clemsa_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderClemsa instance + * @param output Resulting text + */ +void subghz_protocol_decoder_clemsa_get_string(void* context, string_t output); diff --git a/lib/subghz/protocols/intertechno_v3.c b/lib/subghz/protocols/intertechno_v3.c new file mode 100644 index 000000000..e70bb8c8b --- /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 000000000..65d6f61d1 --- /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/keeloq.c b/lib/subghz/protocols/keeloq.c index 32582faf9..a0953b1df 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -485,7 +485,7 @@ void subghz_protocol_decoder_keeloq_feed(void* context, bool level, uint32_t dur (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_keeloq_const.te_short) < subghz_protocol_keeloq_const.te_delta) && (DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_long) < - subghz_protocol_keeloq_const.te_delta)) { + subghz_protocol_keeloq_const.te_delta * 2)) { if(instance->decoder.decode_count_bit < subghz_protocol_keeloq_const.min_count_bit_for_found) { subghz_protocol_blocks_add_bit(&instance->decoder, 1); @@ -493,7 +493,7 @@ void subghz_protocol_decoder_keeloq_feed(void* context, bool level, uint32_t dur instance->decoder.parser_step = KeeloqDecoderStepSaveDuration; } else if( (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_keeloq_const.te_long) < - subghz_protocol_keeloq_const.te_delta) && + subghz_protocol_keeloq_const.te_delta * 2) && (DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_short) < subghz_protocol_keeloq_const.te_delta)) { if(instance->decoder.decode_count_bit < @@ -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); + } } diff --git a/lib/subghz/protocols/magellen.c b/lib/subghz/protocols/magellen.c index 859f80351..bb0600a74 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 b72278788..8bb45e9ad 100644 --- a/lib/subghz/protocols/registry.c +++ b/lib/subghz/protocols/registry.c @@ -11,7 +11,8 @@ 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, + &subghz_protocol_clemsa }; diff --git a/lib/subghz/protocols/registry.h b/lib/subghz/protocols/registry.h index 36a560765..ad1151024 100644 --- a/lib/subghz/protocols/registry.h +++ b/lib/subghz/protocols/registry.h @@ -34,6 +34,8 @@ #include "phoenix_v2.h" #include "honeywell_wdb.h" #include "magellen.h" +#include "intertechno_v3.h" +#include "clemsa.h" /** * Registration by name SubGhzProtocol. diff --git a/lib/subghz/subghz_file_encoder_worker.c b/lib/subghz/subghz_file_encoder_worker.c index 8f65ea004..81bd94f09 100644 --- a/lib/subghz/subghz_file_encoder_worker.c +++ b/lib/subghz/subghz_file_encoder_worker.c @@ -79,6 +79,18 @@ bool subghz_file_encoder_worker_data_parse(SubGhzFileEncoderWorker* instance, co return res; } +void subghz_file_encoder_worker_get_text_progress( + SubGhzFileEncoderWorker* instance, + string_t output) { + UNUSED(output); + Stream* stream = flipper_format_get_raw_stream(instance->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 a87be5cd6..e7280a636 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 diff --git a/lib/subghz/subghz_keystore.c b/lib/subghz/subghz_keystore.c index 0abd2d5e6..4d2eb0e50 100644 --- a/lib/subghz/subghz_keystore.c +++ b/lib/subghz/subghz_keystore.c @@ -114,62 +114,69 @@ static bool subghz_keystore_read_file(SubGhzKeystore* instance, Stream* stream, char* encrypted_line = malloc(SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE); size_t encrypted_line_cursor = 0; - if(iv) furi_hal_crypto_store_load_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT, iv); - - size_t ret = 0; do { - ret = stream_read(stream, buffer, FILE_BUFFER_SIZE); - for(uint16_t i = 0; i < ret; i++) { - if(buffer[i] == '\n' && encrypted_line_cursor > 0) { - // Process line - if(iv) { - // Data alignment check, 32 instead of 16 because of hex encoding - size_t len = strlen(encrypted_line); - if(len % 32 == 0) { - // Inplace hex to bin conversion - for(size_t i = 0; i < len; i += 2) { - uint8_t hi_nibble = 0; - uint8_t lo_nibble = 0; - hex_char_to_hex_nibble(encrypted_line[i], &hi_nibble); - hex_char_to_hex_nibble(encrypted_line[i + 1], &lo_nibble); - encrypted_line[i / 2] = (hi_nibble << 4) | lo_nibble; - } - len /= 2; - - if(furi_hal_crypto_decrypt( - (uint8_t*)encrypted_line, (uint8_t*)decrypted_line, len)) { - subghz_keystore_process_line(instance, decrypted_line); - } else { - FURI_LOG_E(TAG, "Decryption failed"); - result = false; - break; - } - } else { - FURI_LOG_E(TAG, "Invalid encrypted data: %s", encrypted_line); - } - } else { - subghz_keystore_process_line(instance, encrypted_line); - } - // reset line buffer - memset(decrypted_line, 0, SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE); - memset(encrypted_line, 0, SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE); - encrypted_line_cursor = 0; - } else if(buffer[i] == '\r' || buffer[i] == '\n') { - // do not add line endings to the buffer - } else { - if(encrypted_line_cursor < SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE) { - encrypted_line[encrypted_line_cursor] = buffer[i]; - encrypted_line_cursor++; - } else { - FURI_LOG_E(TAG, "Malformed file"); - result = false; - break; - } + if(iv) { + if(!furi_hal_crypto_store_load_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT, iv)) { + FURI_LOG_E(TAG, "Unable to load decryption key"); + break; } } - } while(ret > 0 && result); - if(iv) furi_hal_crypto_store_unload_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT); + size_t ret = 0; + do { + ret = stream_read(stream, buffer, FILE_BUFFER_SIZE); + for(uint16_t i = 0; i < ret; i++) { + if(buffer[i] == '\n' && encrypted_line_cursor > 0) { + // Process line + if(iv) { + // Data alignment check, 32 instead of 16 because of hex encoding + size_t len = strlen(encrypted_line); + if(len % 32 == 0) { + // Inplace hex to bin conversion + for(size_t i = 0; i < len; i += 2) { + uint8_t hi_nibble = 0; + uint8_t lo_nibble = 0; + hex_char_to_hex_nibble(encrypted_line[i], &hi_nibble); + hex_char_to_hex_nibble(encrypted_line[i + 1], &lo_nibble); + encrypted_line[i / 2] = (hi_nibble << 4) | lo_nibble; + } + len /= 2; + + if(furi_hal_crypto_decrypt( + (uint8_t*)encrypted_line, (uint8_t*)decrypted_line, len)) { + subghz_keystore_process_line(instance, decrypted_line); + } else { + FURI_LOG_E(TAG, "Decryption failed"); + result = false; + break; + } + } else { + FURI_LOG_E(TAG, "Invalid encrypted data: %s", encrypted_line); + } + } else { + subghz_keystore_process_line(instance, encrypted_line); + } + // reset line buffer + memset(decrypted_line, 0, SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE); + memset(encrypted_line, 0, SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE); + encrypted_line_cursor = 0; + } else if(buffer[i] == '\r' || buffer[i] == '\n') { + // do not add line endings to the buffer + } else { + if(encrypted_line_cursor < SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE) { + encrypted_line[encrypted_line_cursor] = buffer[i]; + encrypted_line_cursor++; + } else { + FURI_LOG_E(TAG, "Malformed file"); + result = false; + break; + } + } + } + } while(ret > 0 && result); + + if(iv) furi_hal_crypto_store_unload_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT); + } while(false); free(encrypted_line); free(decrypted_line); diff --git a/lib/toolbox/hex.c b/lib/toolbox/hex.c index 41bb24bba..7b2719b79 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 c6683a52c..740f23b77 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 diff --git a/lib/u8g2/u8g2_glue.c b/lib/u8g2/u8g2_glue.c index 77f37f14c..17a702b50 100644 --- a/lib/u8g2/u8g2_glue.c +++ b/lib/u8g2/u8g2_glue.c @@ -225,7 +225,7 @@ uint8_t u8x8_d_st756x_flipper(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* * RR = 10 / ((1 - (63 - 32) / 162) * 2.1) ~= 5.88 is 6 (0b110) * Bias = 1/9 (false) */ - u8x8_d_st756x_init(u8x8, 32, 0b110, false); + u8x8_d_st756x_init(u8x8, 31, 0b110, false); } else { /* ERC v1(ST7565) and v2(ST7567) * EV = 33 @@ -233,7 +233,7 @@ uint8_t u8x8_d_st756x_flipper(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* * RR = 9.3 / ((1 - (63 - 32) / 162) * 2.1) ~= 5.47 is 5.5 (0b101) * Bias = 1/9 (false) */ - u8x8_d_st756x_init(u8x8, 33, 0b101, false); + u8x8_d_st756x_init(u8x8, 32, 0b101, false); } break; case U8X8_MSG_DISPLAY_SET_FLIP_MODE: diff --git a/lib/update_util/update_operation.c b/lib/update_util/update_operation.c index 138828ff0..56f412a95 100644 --- a/lib/update_util/update_operation.c +++ b/lib/update_util/update_operation.c @@ -12,7 +12,7 @@ #define UPDATE_ROOT_DIR EXT_PATH("update") /* Need at least 4 free LFS pages before update */ -#define UPDATE_MIN_INT_FREE_SPACE 4 * 4 * 1024 +#define UPDATE_MIN_INT_FREE_SPACE 2 * 4 * 1024 static const char* update_prepare_result_descr[] = { [UpdatePrepareResultOK] = "OK", diff --git a/scripts/ReadMe.md b/scripts/ReadMe.md index d06303957..d37e67c90 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. diff --git a/scripts/get_env.py b/scripts/get_env.py new file mode 100644 index 000000000..d05273094 --- /dev/null +++ b/scripts/get_env.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 + +import ssl +import json +import os +import shlex +import re +import string +import random +import argparse +import datetime +import urllib.request + + +def id_gen(size=5, chars=string.ascii_uppercase + string.digits): + return "".join(random.choice(chars) for _ in range(size)) + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument("--event_file", help="Current GitHub event file", required=True) + parser.add_argument( + "--type", + help="Event file type", + required=True, + choices=["pull", "tag", "other"], + ) + args = parser.parse_args() + return args + + +def get_commit_json(event): + context = ssl._create_unverified_context() + with urllib.request.urlopen( + event["pull_request"]["_links"]["commits"]["href"], context=context + ) as commit_file: + commit_json = json.loads(commit_file.read().decode("utf-8")) + return commit_json + + +def get_details(event, args): + data = {} + current_time = datetime.datetime.utcnow().date() + if args.type == "pull": + commit_json = get_commit_json(event) + data["commit_comment"] = shlex.quote(commit_json[-1]["commit"]["message"]) + data["commit_hash"] = commit_json[-1]["sha"] + ref = event["pull_request"]["head"]["ref"] + data["pull_id"] = event["pull_request"]["number"] + data["pull_name"] = shlex.quote(event["pull_request"]["title"]) + elif args.type == "tag": + data["commit_comment"] = shlex.quote(event["head_commit"]["message"]) + data["commit_hash"] = event["head_commit"]["id"] + ref = event["ref"] + else: + data["commit_comment"] = shlex.quote(event["commits"][-1]["message"]) + data["commit_hash"] = event["commits"][-1]["id"] + ref = event["ref"] + data["commit_sha"] = data["commit_hash"][:8] + data["branch_name"] = re.sub("refs/\w+/", "", ref) + data["suffix"] = ( + data["branch_name"].replace("/", "_") + + "-" + + current_time.strftime("%d%m%Y") + + "-" + + data["commit_sha"] + ) + if ref.startswith("refs/tags/"): + data["suffix"] = data["branch_name"].replace("/", "_") + return data + + +def add_env(name, value, file): + delimeter = id_gen() + print(f"{name}<<{delimeter}", file=file) + print(f"{value}", file=file) + print(f"{delimeter}", file=file) + + +def add_envs(data, env_file, args): + add_env("COMMIT_MSG", data["commit_comment"], env_file) + add_env("COMMIT_HASH", data["commit_hash"], env_file) + add_env("COMMIT_SHA", data["commit_sha"], env_file) + add_env("SUFFIX", data["suffix"], env_file) + add_env("BRANCH_NAME", data["branch_name"], env_file) + add_env("DIST_SUFFIX", data["suffix"], env_file) + add_env("WORKFLOW_BRANCH_OR_TAG", data["branch_name"], env_file) + if args.type == "pull": + add_env("PULL_ID", data["pull_id"], env_file) + add_env("PULL_NAME", data["pull_name"], env_file) + + +def main(): + args = parse_args() + event_file = open(args.event_file) + event = json.load(event_file) + env_file = open(os.environ["GITHUB_ENV"], "a") + data = get_details(event, args) + add_envs(data, env_file, args) + event_file.close() + env_file.close() + + +if __name__ == "__main__": + main() diff --git a/scripts/lint.py b/scripts/lint.py index b3c3e7da4..30a5699a7 100755 --- a/scripts/lint.py +++ b/scripts/lint.py @@ -88,7 +88,7 @@ class Main(App): 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 @@ class Main(App): 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 @@ class Main(App): 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__": diff --git a/scripts/toolchain/fbtenv.cmd b/scripts/toolchain/fbtenv.cmd index f955a4db3..1403837d9 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=9" +set "FLIPPER_TOOLCHAIN_VERSION=15" set "FBT_TOOLCHAIN_ROOT=%FBT_ROOT%\toolchain\i686-windows" diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index 0ef81114a..cfbf25a4d 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:-"15"}"; FBT_TOOLCHAIN_PATH="${FBT_TOOLCHAIN_PATH:-$SCRIPT_PATH}"; fbtenv_show_usage() @@ -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 @@ -43,13 +64,13 @@ fbtenv_check_sourced() fbtenv_chck_many_source() { - if ! echo "${PS1:-""}" | grep -q "[fbt]"; then - if ! echo "${PROMPT:-""}" | grep -q "[fbt]"; then + if ! echo "${PS1:-""}" | grep -qF "[fbt]"; then + if ! echo "${PROMPT:-""}" | grep -qF "[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!"; + echo "Warning! FBT environment script sourced more than once!"; + echo "This may signal that you are making mistakes, please open a new shell!"; return 1; } @@ -148,15 +169,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"; } @@ -185,8 +208,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; } @@ -232,12 +259,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; } @@ -245,15 +273,19 @@ 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; + if [ "$1" = "--restore" ]; then + fbtenv_restore_env; + return 0; + fi + fbtenv_chck_many_source; # many source it's just a warning + fbtenv_check_script_path || 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:-""}";