diff --git a/applications/external/airmouse/air_mouse.c b/applications/external/airmouse/air_mouse.c index 0c127cab..38739a52 100644 --- a/applications/external/airmouse/air_mouse.c +++ b/applications/external/airmouse/air_mouse.c @@ -10,6 +10,7 @@ enum AirMouseSubmenuIndex { AirMouseSubmenuIndexBtMouse, AirMouseSubmenuIndexUsbMouse, AirMouseSubmenuIndexCalibration, + AirMouseSubmenuIndexRemovePairing, }; void air_mouse_submenu_callback(void* context, uint32_t index) { @@ -24,6 +25,8 @@ void air_mouse_submenu_callback(void* context, uint32_t index) { } else if(index == AirMouseSubmenuIndexCalibration) { app->view_id = AirMouseViewCalibration; view_dispatcher_switch_to_view(app->view_dispatcher, AirMouseViewCalibration); + } else if(index == AirMouseSubmenuIndexRemovePairing) { + bt_mouse_remove_pairing(); } } @@ -78,6 +81,12 @@ AirMouse* air_mouse_app_alloc() { AirMouseSubmenuIndexCalibration, air_mouse_submenu_callback, app); + submenu_add_item( + app->submenu, + "Effacer paires bluetooth", + AirMouseSubmenuIndexRemovePairing, + air_mouse_submenu_callback, + app); view_set_previous_callback(submenu_get_view(app->submenu), air_mouse_exit); view_dispatcher_add_view( app->view_dispatcher, AirMouseViewSubmenu, submenu_get_view(app->submenu)); diff --git a/applications/external/airmouse/application.fam b/applications/external/airmouse/application.fam index 566fa35d..145d9724 100644 --- a/applications/external/airmouse/application.fam +++ b/applications/external/airmouse/application.fam @@ -6,7 +6,7 @@ App( stack_size=10 * 1024, fap_category="GPIO", fap_icon="mouse_10px.png", - fap_version="0.9", - sources=["*.c", "*.cc"], + fap_version="1.1", fap_libs=["ble_profile"], + sources=["*.c", "*.cc"], ) diff --git a/applications/external/airmouse/tracking/sensors/mean_filter.h b/applications/external/airmouse/tracking/sensors/mean_filter.h index 6b4956fe..35b8a27d 100644 --- a/applications/external/airmouse/tracking/sensors/mean_filter.h +++ b/applications/external/airmouse/tracking/sensors/mean_filter.h @@ -17,6 +17,7 @@ #define CARDBOARD_SDK_SENSORS_MEAN_FILTER_H_ #include +#include #include "../util/vector.h" diff --git a/applications/external/airmouse/tracking/sensors/median_filter.h b/applications/external/airmouse/tracking/sensors/median_filter.h index 9a8e7cfc..103c2bc2 100644 --- a/applications/external/airmouse/tracking/sensors/median_filter.h +++ b/applications/external/airmouse/tracking/sensors/median_filter.h @@ -17,6 +17,7 @@ #define CARDBOARD_SDK_SENSORS_MEDIAN_FILTER_H_ #include +#include #include "../util/vector.h" diff --git a/applications/external/airmouse/views/bt_mouse.c b/applications/external/airmouse/views/bt_mouse.c index c2ee8da7..ff2c4cd0 100644 --- a/applications/external/airmouse/views/bt_mouse.c +++ b/applications/external/airmouse/views/bt_mouse.c @@ -3,12 +3,14 @@ #include #include -#include #include +#include +#include #include #include #include #include +#include typedef struct ButtonEvent { int8_t button; @@ -18,10 +20,10 @@ typedef struct ButtonEvent { #define BTN_EVT_QUEUE_SIZE 32 struct BtMouse { + FuriHalBleProfileBase* hid; View* view; ViewDispatcher* view_dispatcher; Bt* bt; - FuriHalBleProfileBase* ble_hid_profile; NotificationApp* notifications; FuriMutex* mutex; FuriThread* thread; @@ -41,12 +43,19 @@ struct BtMouse { ButtonEvent queue[BTN_EVT_QUEUE_SIZE]; }; +static const BleProfileHidParams ble_hid_params = { + .device_name_prefix = "AirMouse", + .mac_xor = 0x0001, +}; + #define BT_MOUSE_FLAG_INPUT_EVENT (1UL << 0) #define BT_MOUSE_FLAG_KILL_THREAD (1UL << 1) #define BT_MOUSE_FLAG_ALL (BT_MOUSE_FLAG_INPUT_EVENT | BT_MOUSE_FLAG_KILL_THREAD) #define MOUSE_SCROLL 2 +#define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys" + static void bt_mouse_notify_event(BtMouse* bt_mouse) { FuriThreadId thread_id = furi_thread_get_id(bt_mouse->thread); furi_assert(thread_id); @@ -119,7 +128,7 @@ static bool bt_mouse_input_callback(InputEvent* event, void* context) { bool consumed = false; if(event->type == InputTypeLong && event->key == InputKeyBack) { - ble_profile_hid_mouse_release_all(bt_mouse->ble_hid_profile); + ble_profile_hid_mouse_release_all(bt_mouse->hid); } else { bt_mouse_process(bt_mouse, event); consumed = true; @@ -204,18 +213,18 @@ static int32_t bt_mouse_thread_callback(void* context) { if(bt_mouse->connected && send_buttons) { if(event.state) { - ble_profile_hid_mouse_press(bt_mouse->ble_hid_profile, event.button); + ble_profile_hid_mouse_press(bt_mouse->hid, event.button); } else { - ble_profile_hid_mouse_release(bt_mouse->ble_hid_profile, event.button); + ble_profile_hid_mouse_release(bt_mouse->hid, event.button); } } if(bt_mouse->connected && (dx != 0 || dy != 0)) { - ble_profile_hid_mouse_move(bt_mouse->ble_hid_profile, dx, dy); + ble_profile_hid_mouse_move(bt_mouse->hid, dx, dy); } if(bt_mouse->connected && wheel != 0) { - ble_profile_hid_mouse_scroll(bt_mouse->ble_hid_profile, wheel); + ble_profile_hid_mouse_scroll(bt_mouse->hid, wheel); } } } @@ -251,15 +260,37 @@ void bt_mouse_enter_callback(void* context) { BtMouse* bt_mouse = context; bt_mouse->bt = furi_record_open(RECORD_BT); + bt_disconnect(bt_mouse->bt); + + furi_delay_ms(200); + bt_keys_storage_set_storage_path(bt_mouse->bt, APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME)); + bt_mouse->notifications = furi_record_open(RECORD_NOTIFICATION); bt_set_status_changed_callback( bt_mouse->bt, bt_mouse_connection_status_changed_callback, bt_mouse); - bt_mouse->ble_hid_profile = bt_profile_start(bt_mouse->bt, ble_profile_hid, NULL); - furi_check(bt_mouse->ble_hid_profile); + bt_mouse->hid = bt_profile_start(bt_mouse->bt, ble_profile_hid, (void*)&ble_hid_params); + furi_assert(bt_mouse->hid); furi_hal_bt_start_advertising(); bt_mouse_thread_start(bt_mouse); } +void bt_mouse_remove_pairing(void) { + Bt* bt = furi_record_open(RECORD_BT); + bt_disconnect(bt); + + furi_delay_ms(200); + furi_hal_bt_stop_advertising(); + + bt_keys_storage_set_storage_path(bt, APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME)); + bt_forget_bonded_devices(bt); + + furi_delay_ms(200); + bt_keys_storage_set_default_path(bt); + + furi_check(bt_profile_restore_default(bt)); + furi_record_close(RECORD_BT); +} + bool bt_mouse_custom_callback(uint32_t event, void* context) { UNUSED(event); furi_assert(context); @@ -281,7 +312,13 @@ void bt_mouse_exit_callback(void* context) { notification_internal_message(bt_mouse->notifications, &sequence_reset_blue); bt_set_status_changed_callback(bt_mouse->bt, NULL, NULL); - furi_check(bt_profile_restore_default(bt_mouse->bt)); + bt_disconnect(bt_mouse->bt); + + furi_delay_ms(200); + bt_keys_storage_set_default_path(bt_mouse->bt); + + furi_hal_bt_stop_advertising(); + bt_profile_restore_default(bt_mouse->bt); furi_record_close(RECORD_NOTIFICATION); bt_mouse->notifications = NULL; diff --git a/applications/external/airmouse/views/bt_mouse.h b/applications/external/airmouse/views/bt_mouse.h index 09153d8f..e880a94c 100644 --- a/applications/external/airmouse/views/bt_mouse.h +++ b/applications/external/airmouse/views/bt_mouse.h @@ -12,3 +12,5 @@ void bt_mouse_free(BtMouse* bt_mouse); View* bt_mouse_get_view(BtMouse* bt_mouse); void bt_mouse_set_connected_status(BtMouse* bt_mouse, bool connected); + +void bt_mouse_remove_pairing(void); diff --git a/applications/external/atomicdiceroller/flipper_atomicdiceroller.c b/applications/external/atomicdiceroller/flipper_atomicdiceroller.c index a399b9c8..4e5b1447 100644 --- a/applications/external/atomicdiceroller/flipper_atomicdiceroller.c +++ b/applications/external/atomicdiceroller/flipper_atomicdiceroller.c @@ -165,8 +165,6 @@ int32_t flipper_atomicdiceroller_app() { EventApp event; FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(EventApp)); - furi_hal_gpio_init(&gpio_ext_pa7, GpioModeInterruptFall, GpioPullUp, GpioSpeedVeryHigh); - mutexStruct mutexVal; mutexVal.cps = 0; mutexVal.dice = 0; @@ -190,6 +188,7 @@ int32_t flipper_atomicdiceroller_app() { furi_hal_gpio_add_int_callback(&gpio_ext_pa7, gpiocallback, event_queue); furi_hal_gpio_enable_int_callback(&gpio_ext_pa7); + furi_hal_gpio_init(&gpio_ext_pa7, GpioModeInterruptFall, GpioPullUp, GpioSpeedVeryHigh); Gui* gui = furi_record_open(RECORD_GUI); gui_add_view_port(gui, view_port, GuiLayerFullscreen); diff --git a/applications/external/barcode_gen/README.md b/applications/external/barcode_gen/README.md index ec944cb2..431f7bf7 100644 --- a/applications/external/barcode_gen/README.md +++ b/applications/external/barcode_gen/README.md @@ -34,12 +34,8 @@ Note: Barcode save locations have been moved from `/barcodes` to `/apps_data/bar ## Building 1) Clone the [flipperzero-firmware](https://github.com/flipperdevices/flipperzero-firmware) repository or a firmware of your choice 2) Clone this repository and put it in the `applications_user` folder -3) Build this app by using the command `./fbt fap_Barcode_App` -4) Copy the `.fap` from `build\f7-firmware-D\.extapps\Barcode_App.fap` to `apps\Misc` using the qFlipper app -5) While still in the qFlipper app, navigate to the root folder of the SD card and create the folder `apps_data`, if not already there -6) Navigate into `apps_data` and create another folder called `barcode_data` -7) Navigate into `barcode_data` -8) Drag & drop the encoding txts (`code39_encodings.txt`, `code128_encodings.txt` & `codabar_encodings.txt`) from the `encoding_tables` folder in this repository into the `barcode_data` folder +3) Build this app by using the command `./fbt fap_barcode_App` +4) Copy the `.fap` from `build\f7-firmware-D\.extapps\Barcode_App.fap` to `apps\Tools` using the qFlipper app ## Usage diff --git a/applications/external/barcode_gen/application.fam b/applications/external/barcode_gen/application.fam index 0b5069b2..21164745 100644 --- a/applications/external/barcode_gen/application.fam +++ b/applications/external/barcode_gen/application.fam @@ -8,9 +8,9 @@ App( fap_category="Outils", fap_icon="images/barcode_10.png", fap_icon_assets="images", - fap_file_assets="encoding_tables", + fap_file_assets="barcode_encoding_files", fap_author="@Kingal1337", fap_weburl="https://github.com/Kingal1337/flipper-barcode-generator", - fap_version="1.1", + fap_version="1.2", fap_description="L'application vous permet d'afficher divers codes-barres sur l'écran du flipper", ) diff --git a/applications/external/barcode_gen/barcode_app.c b/applications/external/barcode_gen/barcode_app.c index 905c9861..2cb5b384 100644 --- a/applications/external/barcode_gen/barcode_app.c +++ b/applications/external/barcode_gen/barcode_app.c @@ -243,6 +243,10 @@ void submenu_callback(void* context, uint32_t index) { edit_barcode_item(app); } else if(index == CreateBarcodeItem) { create_barcode_item(app); + } else if(index == AboutWidgetItem) { + view_dispatcher_switch_to_view(app->view_dispatcher, AboutWidgetView); + } else if(index == ErrorCodesWidgetItem) { + view_dispatcher_switch_to_view(app->view_dispatcher, ErrorCodesWidgetView); } } @@ -270,6 +274,12 @@ void free_app(BarcodeApp* app) { view_dispatcher_remove_view(app->view_dispatcher, TextInputView); text_input_free(app->text_input); + view_dispatcher_remove_view(app->view_dispatcher, AboutWidgetView); + widget_free(app->about_widget); + + view_dispatcher_remove_view(app->view_dispatcher, ErrorCodesWidgetView); + widget_free(app->error_codes_widget); + view_dispatcher_remove_view(app->view_dispatcher, MessageErrorView); message_view_free(app->message_view); @@ -350,6 +360,71 @@ int32_t barcode_main(void* p) { view_dispatcher_add_view( app->view_dispatcher, CreateBarcodeView, create_get_view(app->create_view)); + /***************************** + * Creating Error Codes View + ******************************/ + app->error_codes_widget = widget_alloc(); + widget_add_text_scroll_element( + app->error_codes_widget, + 0, + 0, + 128, + 64, + "\e#Error Codes\n" + "\e#Wrong # Of Characters\n" + "The barcode data has too \nmany or too few characters\n" + "UPC-A: 11-12 characters\n" + "EAN-8: 7-8 characters\n" + "EAN-13: 12-13 characters\n" + "Code128C - even # of \ncharacters\n" + "\n" + "\e#Invalid Characters\n" + "The barcode data has invalid \ncharacters.\n" + "Ex: UPC-A, EAN-8, EAN-13 barcodes can only have \nnumbers while Code128 can \nhave almost any character\n" + "\n" + "\e#Unsupported Type\n" + "The barcode type is not \nsupported by this application\n" + "\n" + "\e#File Opening Error\n" + "The barcode file could not be opened. One reason could be \nthat the file no longer exists\n" + "\n" + "\e#Invalid File Data\n" + "The barcode file could not find the keys \"Type\" or \"Data\". \nThis usually occurs when you edit the file manually and \naccidently change the keys\n" + "\n" + "\e#Missing Encoding Table\n" + "The encoding table files are \nmissing. This only occurs \nwhen you need to handle the \nencoding files manually. If you \ndownload the files from the \napp store this should not \noccur\n" + "\n" + "\e#Encoding Table Error\n" + "This occurs when the \nprogram cannot find a \ncharacter in the encoding \ntable, meaning that either the\ncharacter isn't supported \nor the character is missing \nfrom the encoding table\n" + ""); + view_set_previous_callback(widget_get_view(app->error_codes_widget), main_menu_callback); + view_dispatcher_add_view( + app->view_dispatcher, ErrorCodesWidgetView, widget_get_view(app->error_codes_widget)); + submenu_add_item( + app->main_menu, "Error Codes Info", ErrorCodesWidgetItem, submenu_callback, app); + + /***************************** + * Creating About View + ******************************/ + app->about_widget = widget_alloc(); + widget_add_text_scroll_element( + app->about_widget, + 0, + 0, + 128, + 64, + "Un générateur de codes-barres\n" + "capable de générer UPC-A,\n" + "EAN-8, EAN-13, Code-39,\n" + "Codabar, et Code-128\n" + "Pour plus d'informations ou\n" + "problèmes, allez à\n" + "https://github.com/Kingal1337/flipper-barcode-generator"); + view_set_previous_callback(widget_get_view(app->about_widget), main_menu_callback); + view_dispatcher_add_view( + app->view_dispatcher, AboutWidgetView, widget_get_view(app->about_widget)); + submenu_add_item(app->main_menu, "About", AboutWidgetItem, submenu_callback, app); + /***************************** * Creating Barcode View ******************************/ diff --git a/applications/external/barcode_gen/barcode_app.h b/applications/external/barcode_gen/barcode_app.h index bddc8223..c47fc11c 100644 --- a/applications/external/barcode_gen/barcode_app.h +++ b/applications/external/barcode_gen/barcode_app.h @@ -3,10 +3,12 @@ #include #include +#include #include #include #include #include +#include #include #include @@ -59,6 +61,8 @@ struct BarcodeApp { CreateView* create_view; Barcode* barcode_view; + Widget* about_widget; + Widget* error_codes_widget; MessageView* message_view; TextInput* text_input; }; @@ -66,16 +70,18 @@ struct BarcodeApp { enum SubmenuItems { SelectBarcodeItem, EditBarcodeItem, - - CreateBarcodeItem + CreateBarcodeItem, + ErrorCodesWidgetItem, + AboutWidgetItem }; enum Views { TextInputView, + AboutWidgetView, + ErrorCodesWidgetView, MessageErrorView, MainMenuView, CreateBarcodeView, - BarcodeView }; diff --git a/applications/external/barcode_gen/barcode_encoding_files/codabar_encodings.txt b/applications/external/barcode_gen/barcode_encoding_files/codabar_encodings.txt new file mode 100644 index 00000000..5f0684cb --- /dev/null +++ b/applications/external/barcode_gen/barcode_encoding_files/codabar_encodings.txt @@ -0,0 +1,22 @@ +# alternates between bars and spaces, always begins with bar +# 0 for narrow, 1 for wide +0: 0000011 +1: 0000110 +2: 0001001 +3: 1100000 +4: 0010010 +5: 1000010 +6: 0100001 +7: 0100100 +8: 0110000 +9: 1001000 +-: 0001100 +$: 0011000 +:: 1000101 +/: 1010001 +.: 1010100 ++: 0010101 +A: 0011010 +B: 0101001 +C: 0001011 +D: 0001110 \ No newline at end of file diff --git a/applications/external/barcode_gen/barcode_encoding_files/code128_encodings.txt b/applications/external/barcode_gen/barcode_encoding_files/code128_encodings.txt new file mode 100644 index 00000000..3837e98c --- /dev/null +++ b/applications/external/barcode_gen/barcode_encoding_files/code128_encodings.txt @@ -0,0 +1,203 @@ + : 000 +!: 001 +": 002 +H#: 003 +$: 004 +%: 005 +&: 006 +': 007 +(: 008 +): 009 +*: 010 ++: 011 +,: 012 +-: 013 +.: 014 +/: 015 +0: 016 +1: 017 +2: 018 +3: 019 +4: 020 +5: 021 +6: 022 +7: 023 +8: 024 +9: 025 +:: 026 +;: 027 +<: 028 +=: 029 +>: 030 +?: 031 +@: 032 +A: 033 +B: 034 +C: 035 +D: 036 +E: 037 +F: 038 +G: 039 +H: 040 +I: 041 +J: 042 +K: 043 +L: 044 +M: 045 +N: 046 +O: 047 +P: 048 +Q: 049 +R: 050 +S: 051 +T: 052 +U: 053 +V: 054 +W: 055 +X: 056 +Y: 057 +Z: 058 +[: 059 +\: 060 +]: 061 +^: 062 +_: 063 +`: 064 +a: 065 +b: 066 +c: 067 +d: 068 +e: 069 +f: 070 +g: 071 +h: 072 +i: 073 +j: 074 +k: 075 +l: 076 +m: 077 +n: 078 +o: 079 +p: 080 +q: 081 +r: 082 +s: 083 +t: 084 +u: 085 +v: 086 +w: 087 +x: 088 +y: 089 +z: 090 +{: 091 +|: 092 +}: 093 +~: 094 + +ENCODINGS: 000 +000: 11011001100 +001: 11001101100 +002: 11001100110 +003: 10010011000 +004: 10010001100 +005: 10001001100 +006: 10011001000 +007: 10011000100 +008: 10001100100 +009: 11001001000 +010: 11001000100 +011: 11000100100 +012: 10110011100 +013: 10011011100 +014: 10011001110 +015: 10111001100 +016: 10011101100 +017: 10011100110 +018: 11001110010 +019: 11001011100 +020: 11001001110 +021: 11011100100 +022: 11001110100 +023: 11101101110 +024: 11101001100 +025: 11100101100 +026: 11100100110 +027: 11101100100 +028: 11100110100 +029: 11100110010 +030: 11011011000 +031: 11011000110 +032: 11000110110 +033: 10100011000 +034: 10001011000 +035: 10001000110 +036: 10110001000 +037: 10001101000 +038: 10001100010 +039: 11010001000 +040: 11000101000 +041: 11000100010 +042: 10110111000 +043: 10110001110 +044: 10001101110 +045: 10111011000 +046: 10111000110 +047: 10001110110 +048: 11101110110 +049: 11010001110 +050: 11000101110 +051: 11011101000 +052: 11011100010 +053: 11011101110 +054: 11101011000 +055: 11101000110 +056: 11100010110 +057: 11101101000 +058: 11101100010 +059: 11100011010 +060: 11101111010 +061: 11001000010 +062: 11110001010 +063: 10100110000 +064: 10100001100 +065: 10010110000 +066: 10010000110 +067: 10000101100 +068: 10000100110 +069: 10110010000 +070: 10110000100 +071: 10011010000 +072: 10011000010 +073: 10000110100 +074: 10000110010 +075: 11000010010 +076: 11001010000 +077: 11110111010 +078: 11000010100 +079: 10001111010 +080: 10100111100 +081: 10010111100 +082: 10010011110 +083: 10111100100 +084: 10011110100 +085: 10011110010 +086: 11110100100 +087: 11110010100 +088: 11110010010 +089: 11011011110 +090: 11011110110 +091: 11110110110 +092: 10101111000 +093: 10100011110 +094: 10001011110 +095: 10111101000 +096: 10111100010 +097: 11110101000 +098: 11110100010 +099: 10111011110 +100: 10111101110 +101: 11101011110 +102: 11110101110 +103: 11010000100 +104: 11010010000 +105: 11010011100 \ No newline at end of file diff --git a/applications/external/barcode_gen/barcode_encoding_files/code128c_encodings.txt b/applications/external/barcode_gen/barcode_encoding_files/code128c_encodings.txt new file mode 100644 index 00000000..75cc7113 --- /dev/null +++ b/applications/external/barcode_gen/barcode_encoding_files/code128c_encodings.txt @@ -0,0 +1,106 @@ +00: 11011001100 +01: 11001101100 +02: 11001100110 +03: 10010011000 +04: 10010001100 +05: 10001001100 +06: 10011001000 +07: 10011000100 +08: 10001100100 +09: 11001001000 +10: 11001000100 +11: 11000100100 +12: 10110011100 +13: 10011011100 +14: 10011001110 +15: 10111001100 +16: 10011101100 +17: 10011100110 +18: 11001110010 +19: 11001011100 +20: 11001001110 +21: 11011100100 +22: 11001110100 +23: 11101101110 +24: 11101001100 +25: 11100101100 +26: 11100100110 +27: 11101100100 +28: 11100110100 +29: 11100110010 +30: 11011011000 +31: 11011000110 +32: 11000110110 +33: 10100011000 +34: 10001011000 +35: 10001000110 +36: 10110001000 +37: 10001101000 +38: 10001100010 +39: 11010001000 +40: 11000101000 +41: 11000100010 +42: 10110111000 +43: 10110001110 +44: 10001101110 +45: 10111011000 +46: 10111000110 +47: 10001110110 +48: 11101110110 +49: 11010001110 +50: 11000101110 +51: 11011101000 +52: 11011100010 +53: 11011101110 +54: 11101011000 +55: 11101000110 +56: 11100010110 +57: 11101101000 +58: 11101100010 +59: 11100011010 +60: 11101111010 +61: 11001000010 +62: 11110001010 +63: 10100110000 +64: 10100001100 +65: 10010110000 +66: 10010000110 +67: 10000101100 +68: 10000100110 +69: 10110010000 +70: 10110000100 +71: 10011010000 +72: 10011000010 +73: 10000110100 +74: 10000110010 +75: 11000010010 +76: 11001010000 +77: 11110111010 +78: 11000010100 +79: 10001111010 +80: 10100111100 +81: 10010111100 +82: 10010011110 +83: 10111100100 +84: 10011110100 +85: 10011110010 +86: 11110100100 +87: 11110010100 +88: 11110010010 +89: 11011011110 +90: 11011110110 +91: 11110110110 +92: 10101111000 +93: 10100011110 +94: 10001011110 +95: 10111101000 +96: 10111100010 +97: 11110101000 +98: 11110100010 +99: 10111011110 +100: 10111101110 +101: 11101011110 +102: 11110101110 +103: 11010000100 +104: 11010010000 +105: 11010011100 diff --git a/applications/external/barcode_gen/barcode_encoding_files/code39_encodings.txt b/applications/external/barcode_gen/barcode_encoding_files/code39_encodings.txt new file mode 100644 index 00000000..a41ad16e --- /dev/null +++ b/applications/external/barcode_gen/barcode_encoding_files/code39_encodings.txt @@ -0,0 +1,44 @@ +0: 000110100 +1: 100100001 +2: 001100001 +3: 101100000 +4: 000110001 +5: 100110000 +6: 001110000 +7: 000100101 +8: 100100100 +9: 001100100 +A: 100001001 +B: 001001001 +C: 101001000 +D: 000011001 +E: 100011000 +F: 001011000 +G: 000001101 +H: 100001100 +I: 001001100 +J: 000011100 +K: 100000011 +L: 001000011 +M: 101000010 +N: 000010011 +O: 100010010 +P: 001010010 +Q: 000000111 +R: 100000110 +S: 001000110 +T: 000010110 +U: 110000001 +V: 011000001 +W: 111000000 +X: 010010001 +Y: 110010000 +Z: 011010000 +-: 010000101 +.: 110000100 + : 011000100 +*: 010010100 +$: 010101000 +/: 010100010 ++: 010001010 +%: 000101010 \ No newline at end of file diff --git a/applications/external/barcode_gen/views/barcode_view.c b/applications/external/barcode_gen/views/barcode_view.c index d7cb93f2..affde5a6 100644 --- a/applications/external/barcode_gen/views/barcode_view.c +++ b/applications/external/barcode_gen/views/barcode_view.c @@ -21,11 +21,12 @@ static void draw_bit(Canvas* canvas, int bit, int x, int y, int width, int heigh } /** - * + * Draws the error name and message on the screen */ -static void draw_error_str(Canvas* canvas, const char* error) { +static void draw_error_str(Canvas* canvas, const char* title, const char* error) { canvas_clear(canvas); - canvas_draw_str_aligned(canvas, 62, 30, AlignCenter, AlignCenter, error); + elements_multiline_text_aligned(canvas, 0, 0, AlignLeft, AlignTop, title); + elements_multiline_text_aligned(canvas, 0, 12, AlignLeft, AlignTop, error); } /** @@ -417,32 +418,8 @@ static void barcode_draw_callback(Canvas* canvas, void* ctx) { break; } } else { - switch(data->reason) { - case WrongNumberOfDigits: - draw_error_str(canvas, "Nbr caractères incorrect"); - break; - case InvalidCharacters: - draw_error_str(canvas, "Caractères invalides"); - break; - case UnsupportedType: - draw_error_str(canvas, "Type non pris en charge"); - break; - case FileOpening: - draw_error_str(canvas, "Impossible ouvrir fichier"); - break; - case InvalidFileData: - draw_error_str(canvas, "Données fichier invalides"); - break; - case MissingEncodingTable: - draw_error_str(canvas, "Table encodage manquante"); - break; - case EncodingTableError: - draw_error_str(canvas, "Erreur table d'encodage"); - break; - default: - draw_error_str(canvas, "Lecture données impossible"); - break; - } + draw_error_str( + canvas, get_error_code_name(data->reason), get_error_code_message(data->reason)); } } diff --git a/applications/external/ble_spam/assets/nameflood.txt b/applications/external/ble_spam/assets/nameflood.txt new file mode 100644 index 00000000..f78c2412 --- /dev/null +++ b/applications/external/ble_spam/assets/nameflood.txt @@ -0,0 +1,4 @@ +Salut :) +Flopper :C +Flipper 🐬 +👋 \ No newline at end of file diff --git a/applications/external/ble_spam/assets/swiftpair.txt b/applications/external/ble_spam/assets/swiftpair.txt new file mode 100644 index 00000000..f78c2412 --- /dev/null +++ b/applications/external/ble_spam/assets/swiftpair.txt @@ -0,0 +1,4 @@ +Salut :) +Flopper :C +Flipper 🐬 +👋 \ No newline at end of file diff --git a/applications/external/ble_spam/ble_spam.c b/applications/external/ble_spam/ble_spam.c index a4cf10de..3821c3cd 100644 --- a/applications/external/ble_spam/ble_spam.c +++ b/applications/external/ble_spam/ble_spam.c @@ -697,6 +697,9 @@ int32_t ble_spam(void* p) { furi_thread_free(state->thread); free(state); + if(furi_hal_bt_extra_beacon_is_active()) { + furi_check(furi_hal_bt_extra_beacon_stop()); + } if(prev_cfg_ptr) { furi_check(furi_hal_bt_extra_beacon_set_config(&prev_cfg)); } diff --git a/applications/external/ble_spam/protocols/nameflood.c b/applications/external/ble_spam/protocols/nameflood.c index 429024ae..6302046b 100644 --- a/applications/external/ble_spam/protocols/nameflood.c +++ b/applications/external/ble_spam/protocols/nameflood.c @@ -1,25 +1,54 @@ #include "nameflood.h" #include "_protocols.h" +#include +#include + // Hacked together by @Willy-JL -static const char* names[] = { - "Assquach💦", - "Flipper 🐬", - "iOS 17 🍎", - "Yo bro", - "Comment vas-tu?", - "Kink💦", - "👉👌", - "🔵🦷", -}; -static const uint8_t names_count = COUNT_OF(names); +static char names[256][sizeof(((NamefloodCfg*)0)->name)]; +static uint8_t names_count = 0; static const char* get_name(const Payload* payload) { UNUSED(payload); return "NameFlood"; } +static const char* random_name() { + if(names_count == 0) { + // Fill random names + Storage* storage = furi_record_open(RECORD_STORAGE); + Stream* stream = file_stream_alloc(storage); + FuriString* line = furi_string_alloc(); + if(!storage_file_exists(storage, APP_DATA_PATH("nameflood.txt"))) { + // Copy default names + storage_common_copy( + storage, APP_ASSETS_PATH("nameflood.txt"), APP_DATA_PATH("nameflood.txt")); + } + if(file_stream_open( + stream, APP_DATA_PATH("nameflood.txt"), FSAM_READ, FSOM_OPEN_EXISTING)) { + while(stream_read_line(stream, line)) { + furi_string_replace_all(line, "\r", ""); + furi_string_replace_all(line, "\n", ""); + if(furi_string_size(line)) { + strlcpy(names[names_count++], furi_string_get_cstr(line), sizeof(names[0])); + } + } + } + furi_string_free(line); + file_stream_close(stream); + stream_free(stream); + furi_record_close(RECORD_STORAGE); + + if(names_count == 0) { + // Add fallback if list is empty + strlcpy(names[names_count++], "NameFlood", sizeof(names[0])); + } + } + + return names[rand() % names_count]; +} + static void make_packet(uint8_t* _size, uint8_t** _packet, Payload* payload) { NamefloodCfg* cfg = payload ? &payload->cfg.nameflood : NULL; @@ -27,7 +56,7 @@ static void make_packet(uint8_t* _size, uint8_t** _packet, Payload* payload) { switch(cfg ? payload->mode : PayloadModeRandom) { case PayloadModeRandom: default: - name = names[rand() % names_count]; + name = random_name(); break; case PayloadModeValue: name = cfg->name; diff --git a/applications/external/ble_spam/protocols/swiftpair.c b/applications/external/ble_spam/protocols/swiftpair.c index 796dba3d..a6b459ef 100644 --- a/applications/external/ble_spam/protocols/swiftpair.c +++ b/applications/external/ble_spam/protocols/swiftpair.c @@ -1,24 +1,55 @@ #include "swiftpair.h" #include "_protocols.h" +#include +#include + // Hacked together by @Willy-JL and @Spooks4576 // Documentation at https://learn.microsoft.com/en-us/windows-hardware/design/component-guidelines/bluetooth-swift-pair -static const char* names[] = { - "Assquach💦", - "Flipper 🐬", - "iOS 17 🍎", - "Kink💦", - "👉👌", - "🔵🦷", -}; -static const uint8_t names_count = COUNT_OF(names); +static char names[256][sizeof(((SwiftpairCfg*)0)->name)]; +static uint8_t names_count = 0; static const char* get_name(const Payload* payload) { UNUSED(payload); return "SwiftPair"; } +static const char* random_name() { + if(names_count == 0) { + // Fill random names + Storage* storage = furi_record_open(RECORD_STORAGE); + Stream* stream = file_stream_alloc(storage); + FuriString* line = furi_string_alloc(); + if(!storage_file_exists(storage, APP_DATA_PATH("swiftpair.txt"))) { + // Copy default names + storage_common_copy( + storage, APP_ASSETS_PATH("swiftpair.txt"), APP_DATA_PATH("swiftpair.txt")); + } + if(file_stream_open( + stream, APP_DATA_PATH("swiftpair.txt"), FSAM_READ, FSOM_OPEN_EXISTING)) { + while(stream_read_line(stream, line)) { + furi_string_replace_all(line, "\r", ""); + furi_string_replace_all(line, "\n", ""); + if(furi_string_size(line)) { + strlcpy(names[names_count++], furi_string_get_cstr(line), sizeof(names[0])); + } + } + } + furi_string_free(line); + file_stream_close(stream); + stream_free(stream); + furi_record_close(RECORD_STORAGE); + + if(names_count == 0) { + // Add fallback if list is empty + strlcpy(names[names_count++], "SwiftPair", sizeof(names[0])); + } + } + + return names[rand() % names_count]; +} + static void make_packet(uint8_t* _size, uint8_t** _packet, Payload* payload) { SwiftpairCfg* cfg = payload ? &payload->cfg.swiftpair : NULL; @@ -26,7 +57,7 @@ static void make_packet(uint8_t* _size, uint8_t** _packet, Payload* payload) { switch(cfg ? payload->mode : PayloadModeRandom) { case PayloadModeRandom: default: - name = names[rand() % names_count]; + name = random_name(); break; case PayloadModeValue: name = cfg->name; diff --git a/applications/external/camera_suite/application.fam b/applications/external/camera_suite/application.fam index 527148ae..ab0d87b1 100644 --- a/applications/external/camera_suite/application.fam +++ b/applications/external/camera_suite/application.fam @@ -7,7 +7,7 @@ App( fap_category="GPIO", fap_description="A camera suite application for the Flipper Zero ESP32-CAM module.", fap_icon="icons/camera_suite.png", - fap_version="1.6", + fap_version="1.7", fap_weburl="https://github.com/CodyTolene/Flipper-Zero-Cam", name="[ESP32] Camera Suite", order=1, diff --git a/applications/external/camera_suite/assets/.gitkeep b/applications/external/camera_suite/assets/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/applications/external/camera_suite/camera_suite.c b/applications/external/camera_suite/camera_suite.c index c21992f8..c8289d72 100644 --- a/applications/external/camera_suite/camera_suite.c +++ b/applications/external/camera_suite/camera_suite.c @@ -72,12 +72,6 @@ CameraSuite* camera_suite_app_alloc() { CameraSuiteViewIdCamera, camera_suite_view_camera_get_view(app->camera_suite_view_camera)); - app->camera_suite_view_wifi_camera = camera_suite_view_wifi_camera_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, - CameraSuiteViewIdWiFiCamera, - camera_suite_view_wifi_camera_get_view(app->camera_suite_view_wifi_camera)); - app->camera_suite_view_guide = camera_suite_view_guide_alloc(); view_dispatcher_add_view( app->view_dispatcher, @@ -111,7 +105,6 @@ void camera_suite_app_free(CameraSuite* app) { view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdStartscreen); view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdMenu); view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdCamera); - view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdWiFiCamera); view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdGuide); view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdAppSettings); view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdCamSettings); @@ -123,7 +116,6 @@ void camera_suite_app_free(CameraSuite* app) { // Free remaining resources camera_suite_view_start_free(app->camera_suite_view_start); camera_suite_view_camera_free(app->camera_suite_view_camera); - camera_suite_view_wifi_camera_free(app->camera_suite_view_wifi_camera); camera_suite_view_guide_free(app->camera_suite_view_guide); button_menu_free(app->button_menu); diff --git a/applications/external/camera_suite/camera_suite.h b/applications/external/camera_suite/camera_suite.h index fa71f4e6..71995496 100644 --- a/applications/external/camera_suite/camera_suite.h +++ b/applications/external/camera_suite/camera_suite.h @@ -16,7 +16,6 @@ #include "views/camera_suite_view_guide.h" #include "views/camera_suite_view_start.h" #include "views/camera_suite_view_camera.h" -#include "views/camera_suite_view_wifi_camera.h" #include "helpers/camera_suite_storage.h" #include @@ -32,7 +31,6 @@ typedef struct { VariableItemList* variable_item_list; CameraSuiteViewStart* camera_suite_view_start; CameraSuiteViewCamera* camera_suite_view_camera; - CameraSuiteViewWiFiCamera* camera_suite_view_wifi_camera; CameraSuiteViewGuide* camera_suite_view_guide; uint32_t orientation; uint32_t dither; @@ -48,7 +46,6 @@ typedef enum { CameraSuiteViewIdStartscreen, CameraSuiteViewIdMenu, CameraSuiteViewIdCamera, - CameraSuiteViewIdWiFiCamera, CameraSuiteViewIdGuide, CameraSuiteViewIdAppSettings, CameraSuiteViewIdCamSettings, diff --git a/applications/external/camera_suite/docs/CHANGELOG.md b/applications/external/camera_suite/docs/CHANGELOG.md index 4a772567..2638599e 100644 --- a/applications/external/camera_suite/docs/CHANGELOG.md +++ b/applications/external/camera_suite/docs/CHANGELOG.md @@ -5,6 +5,11 @@ - Full screen 90 degree and 270 degree fill (#6). - WiFi streaming/connection support (#35). +## v1.7 + +- Add support for new Flipper Zero Firmware UART updates. +- Remove staged WiFi streaming/connection support for now. Until I can fully test. + ## v1.6 - Add new splash/start screen. diff --git a/applications/external/camera_suite/helpers/camera_suite_custom_event.h b/applications/external/camera_suite/helpers/camera_suite_custom_event.h index eb545b7d..4d472d57 100644 --- a/applications/external/camera_suite/helpers/camera_suite_custom_event.h +++ b/applications/external/camera_suite/helpers/camera_suite_custom_event.h @@ -15,13 +15,6 @@ typedef enum { CameraSuiteCustomEventSceneCameraRight, CameraSuiteCustomEventSceneCameraOk, CameraSuiteCustomEventSceneCameraBack, - // Scene events: WiFi Camera - CameraSuiteCustomEventSceneWiFiCameraUp, - CameraSuiteCustomEventSceneWiFiCameraDown, - CameraSuiteCustomEventSceneWiFiCameraLeft, - CameraSuiteCustomEventSceneWiFiCameraRight, - CameraSuiteCustomEventSceneWiFiCameraOk, - CameraSuiteCustomEventSceneWiFiCameraBack, // Scene events: Guide CameraSuiteCustomEventSceneGuideUp, CameraSuiteCustomEventSceneGuideDown, diff --git a/applications/external/camera_suite/helpers/camera_suite_storage.c b/applications/external/camera_suite/helpers/camera_suite_storage.c index f735707e..712346d4 100644 --- a/applications/external/camera_suite/helpers/camera_suite_storage.c +++ b/applications/external/camera_suite/helpers/camera_suite_storage.c @@ -98,8 +98,6 @@ void camera_suite_read_settings(void* context) { } furi_string_free(temp_str); - furi_string_free(temp_str); - if(file_version < BOILERPLATE_SETTINGS_FILE_VERSION) { FURI_LOG_I(TAG, "old config version, will be removed."); camera_suite_close_config_file(fff_file); diff --git a/applications/external/camera_suite/scenes/camera_suite_scene_config.h b/applications/external/camera_suite/scenes/camera_suite_scene_config.h index fce4c9e8..a9f0e057 100644 --- a/applications/external/camera_suite/scenes/camera_suite_scene_config.h +++ b/applications/external/camera_suite/scenes/camera_suite_scene_config.h @@ -1,7 +1,6 @@ ADD_SCENE(camera_suite, start, Start) ADD_SCENE(camera_suite, menu, Menu) ADD_SCENE(camera_suite, camera, Camera) -ADD_SCENE(camera_suite, wifi_camera, WiFiCamera) ADD_SCENE(camera_suite, guide, Guide) ADD_SCENE(camera_suite, app_settings, AppSettings) ADD_SCENE(camera_suite, cam_settings, CamSettings) diff --git a/applications/external/camera_suite/scenes/camera_suite_scene_menu.c b/applications/external/camera_suite/scenes/camera_suite_scene_menu.c index a1ca0229..c6c88038 100644 --- a/applications/external/camera_suite/scenes/camera_suite_scene_menu.c +++ b/applications/external/camera_suite/scenes/camera_suite_scene_menu.c @@ -3,8 +3,6 @@ enum SubmenuIndex { /** Camera. */ SubmenuIndexSceneCamera = 10, - /** WiFi Camera */ - SubmenuIndexSceneWiFiCamera, /** Cam settings menu. */ SubmenuIndexCamSettings, /** App settings menu. */ @@ -28,13 +26,6 @@ void camera_suite_scene_menu_on_enter(void* context) { camera_suite_scene_menu_submenu_callback, app); - submenu_add_item( - app->submenu, - "Stream Camera to WiFi", - SubmenuIndexSceneWiFiCamera, - camera_suite_scene_menu_submenu_callback, - app); - submenu_add_item( app->submenu, "Camera Settings", @@ -76,11 +67,6 @@ bool camera_suite_scene_menu_on_event(void* context, SceneManagerEvent event) { app->scene_manager, CameraSuiteSceneMenu, SubmenuIndexSceneCamera); scene_manager_next_scene(app->scene_manager, CameraSuiteSceneCamera); return true; - } else if(event.event == SubmenuIndexSceneWiFiCamera) { - scene_manager_set_scene_state( - app->scene_manager, CameraSuiteSceneMenu, SubmenuIndexSceneWiFiCamera); - scene_manager_next_scene(app->scene_manager, CameraSuiteSceneWiFiCamera); - return true; } else if(event.event == SubmenuIndexAppSettings) { scene_manager_set_scene_state( app->scene_manager, CameraSuiteSceneMenu, SubmenuIndexAppSettings); diff --git a/applications/external/camera_suite/scenes/camera_suite_scene_wifi_camera.c b/applications/external/camera_suite/scenes/camera_suite_scene_wifi_camera.c deleted file mode 100644 index 2df3db81..00000000 --- a/applications/external/camera_suite/scenes/camera_suite_scene_wifi_camera.c +++ /dev/null @@ -1,51 +0,0 @@ -#include "../camera_suite.h" -#include "../helpers/camera_suite_custom_event.h" -#include "../views/camera_suite_view_wifi_camera.h" - -void camera_suite_view_wifi_camera_callback(CameraSuiteCustomEvent event, void* context) { - furi_assert(context); - CameraSuite* app = context; - view_dispatcher_send_custom_event(app->view_dispatcher, event); -} - -void camera_suite_scene_wifi_camera_on_enter(void* context) { - furi_assert(context); - CameraSuite* app = context; - camera_suite_view_wifi_camera_set_callback( - app->camera_suite_view_wifi_camera, camera_suite_view_wifi_camera_callback, app); - view_dispatcher_switch_to_view(app->view_dispatcher, CameraSuiteViewIdWiFiCamera); -} - -bool camera_suite_scene_wifi_camera_on_event(void* context, SceneManagerEvent event) { - CameraSuite* app = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - switch(event.event) { - case CameraSuiteCustomEventSceneWiFiCameraLeft: - case CameraSuiteCustomEventSceneWiFiCameraRight: - case CameraSuiteCustomEventSceneWiFiCameraUp: - case CameraSuiteCustomEventSceneWiFiCameraDown: - // Do nothing. - break; - case CameraSuiteCustomEventSceneWiFiCameraBack: - notification_message(app->notification, &sequence_reset_red); - notification_message(app->notification, &sequence_reset_green); - notification_message(app->notification, &sequence_reset_blue); - if(!scene_manager_search_and_switch_to_previous_scene( - app->scene_manager, CameraSuiteSceneMenu)) { - scene_manager_stop(app->scene_manager); - view_dispatcher_stop(app->view_dispatcher); - } - consumed = true; - break; - } - } - - return consumed; -} - -void camera_suite_scene_wifi_camera_on_exit(void* context) { - CameraSuite* app = context; - UNUSED(app); -} \ No newline at end of file diff --git a/applications/external/camera_suite/views/camera_suite_view_camera.c b/applications/external/camera_suite/views/camera_suite_view_camera.c index 115fba65..3f936aee 100644 --- a/applications/external/camera_suite/views/camera_suite_view_camera.c +++ b/applications/external/camera_suite/views/camera_suite_view_camera.c @@ -179,10 +179,20 @@ static void save_image_to_flipper_sd_card(void* model) { FuriString* file_name = furi_string_alloc(); // Get the current date and time. + + // Not supported in "Release" F0 build. + // TODO: Remove when DateTime is supported in "Release" F0 build. + // FuriHalRtcDateTime datetime = {0}; + + // Only supported in "RC" & "Dev" builds. + // TODO: Uncomment when DateTime is supported in "Release" F0 build. DateTime datetime = {0}; + + // TODO: Uncomment when DateTime is supported in "Release" F0 build. furi_hal_rtc_get_datetime(&datetime); - // Create the file name. + // Create the file name using DateTime. + // TODO: Uncomment when DateTime is supported in "Release" F0 build. furi_string_printf( file_name, EXT_PATH("DCIM/%.4d%.2d%.2d-%.2d%.2d%.2d.bmp"), @@ -193,6 +203,10 @@ static void save_image_to_flipper_sd_card(void* model) { datetime.minute, datetime.second); + // Just use a random number for now instead of DateTime. + // int random_number = rand(); + // furi_string_printf(file_name, EXT_PATH("DCIM/%d.bmp"), random_number); + // Open the file for writing. If the file does not exist (it shouldn't), // create it. bool result = @@ -468,8 +482,6 @@ static void // Cast `context` to `CameraSuiteViewCamera*` and store it in `instance`. CameraSuiteViewCamera* instance = context; - // If `uartIrqEvent` is `UartIrqEventRXNE`, send the data to the - // `camera_rx_stream` and set the `WorkerEventRx` flag. if(event == FuriHalSerialRxEventData) { uint8_t data = furi_hal_serial_async_rx(handle); furi_stream_buffer_send(instance->camera_rx_stream, &data, 1, 0); @@ -608,12 +620,12 @@ CameraSuiteViewCamera* camera_suite_view_camera_alloc() { instance->camera_worker_thread = thread; furi_thread_start(instance->camera_worker_thread); - // 115200 is the default baud rate for the ESP32-CAM. + // Allocate the serial handle for the camera. instance->serial_handle = furi_hal_serial_control_acquire(UART_CH); furi_check(instance->serial_handle); furi_hal_serial_init(instance->serial_handle, 230400); - // Enable UART1 and set the IRQ callback. + // Start the asynchronous receive. furi_hal_serial_async_rx_start(instance->serial_handle, camera_on_irq_cb, instance, false); return instance; @@ -630,7 +642,7 @@ void camera_suite_view_camera_free(CameraSuiteViewCamera* instance) { // Free the allocated stream buffer. furi_stream_buffer_free(instance->camera_rx_stream); - // Re-enable the console. + // Deinitialize the serial handle and release the control. furi_hal_serial_deinit(instance->serial_handle); furi_hal_serial_control_release(instance->serial_handle); diff --git a/applications/external/camera_suite/views/camera_suite_view_wifi_camera.c b/applications/external/camera_suite/views/camera_suite_view_wifi_camera.c deleted file mode 100644 index ce0da794..00000000 --- a/applications/external/camera_suite/views/camera_suite_view_wifi_camera.c +++ /dev/null @@ -1,170 +0,0 @@ -#include "../camera_suite.h" -#include -#include -#include -#include -#include -#include "../helpers/camera_suite_haptic.h" -#include "../helpers/camera_suite_speaker.h" -#include "../helpers/camera_suite_led.h" - -void camera_suite_view_wifi_camera_set_callback( - CameraSuiteViewWiFiCamera* instance, - CameraSuiteViewWiFiCameraCallback callback, - void* context) { - furi_assert(instance); - furi_assert(callback); - instance->callback = callback; - instance->context = context; -} - -static void camera_suite_view_wifi_camera_draw(Canvas* canvas, void* model) { - furi_assert(canvas); - furi_assert(model); - - CameraSuiteViewWiFiCameraModel* instance = model; - - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - canvas_draw_frame(canvas, 0, 0, FRAME_WIDTH, FRAME_HEIGHT); - - canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, "Feature coming soon!"); - - // Draw log from camera. - canvas_draw_str_aligned( - canvas, 3, 13, AlignLeft, AlignTop, furi_string_get_cstr(instance->log)); -} - -static bool camera_suite_view_wifi_camera_input(InputEvent* event, void* context) { - furi_assert(context); - furi_assert(event); - - CameraSuiteViewWiFiCamera* instance = context; - - if(event->type == InputTypeRelease) { - switch(event->key) { - default: - with_view_model( - instance->view, - CameraSuiteViewWiFiCameraModel * model, - { - UNUSED(model); - // Stop all sounds, reset the LED. - camera_suite_play_bad_bump(instance->context); - camera_suite_stop_all_sound(instance->context); - camera_suite_led_set_rgb(instance->context, 0, 0, 0); - }, - true); - break; - } - } else if(event->type == InputTypePress) { - switch(event->key) { - case InputKeyBack: { - with_view_model( - instance->view, - CameraSuiteViewWiFiCameraModel * model, - { - UNUSED(model); - - // Stop camera WiFi stream. - // furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t[]){'w'}, 1); - // furi_delay_ms(50); - - // Go back to the main menu. - instance->callback(CameraSuiteCustomEventSceneCameraBack, instance->context); - }, - true); - break; - } - case InputKeyLeft: - case InputKeyRight: - case InputKeyUp: - case InputKeyDown: - case InputKeyOk: - case InputKeyMAX: - default: { - break; - } - } - } - - return false; -} - -static void camera_suite_view_wifi_camera_exit(void* context) { - furi_assert(context); -} - -static void camera_suite_view_wifi_camera_model_init(CameraSuiteViewWiFiCameraModel* const model) { - model->log = furi_string_alloc(); - furi_string_reserve(model->log, 4096); -} - -static void camera_suite_view_wifi_camera_enter(void* context) { - furi_assert(context); - - // Get the camera suite instance context. - CameraSuiteViewWiFiCamera* instance = (CameraSuiteViewWiFiCamera*)context; - - // Start wifi camera stream. - // furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t[]){'W'}, 1); - - with_view_model( - instance->view, - CameraSuiteViewWiFiCameraModel * model, - { camera_suite_view_wifi_camera_model_init(model); }, - true); -} - -CameraSuiteViewWiFiCamera* camera_suite_view_wifi_camera_alloc() { - // Allocate memory for the instance - CameraSuiteViewWiFiCamera* instance = malloc(sizeof(CameraSuiteViewWiFiCamera)); - - // Allocate the view object - instance->view = view_alloc(); - - // Allocate model - view_allocate_model( - instance->view, ViewModelTypeLocking, sizeof(CameraSuiteViewWiFiCameraModel)); - - // Set context for the view (furi_assert crashes in events without this) - view_set_context(instance->view, instance); - - // Set draw callback - view_set_draw_callback(instance->view, (ViewDrawCallback)camera_suite_view_wifi_camera_draw); - - // Set input callback - view_set_input_callback(instance->view, camera_suite_view_wifi_camera_input); - - // Set enter callback - view_set_enter_callback(instance->view, camera_suite_view_wifi_camera_enter); - - // Set exit callback - view_set_exit_callback(instance->view, camera_suite_view_wifi_camera_exit); - - with_view_model( - instance->view, - CameraSuiteViewWiFiCameraModel * model, - { camera_suite_view_wifi_camera_model_init(model); }, - true); - - return instance; -} - -void camera_suite_view_wifi_camera_free(CameraSuiteViewWiFiCamera* instance) { - furi_assert(instance); - - with_view_model( - instance->view, - CameraSuiteViewWiFiCameraModel * model, - { furi_string_free(model->log); }, - true); - view_free(instance->view); - free(instance); -} - -View* camera_suite_view_wifi_camera_get_view(CameraSuiteViewWiFiCamera* instance) { - furi_assert(instance); - return instance->view; -} diff --git a/applications/external/camera_suite/views/camera_suite_view_wifi_camera.h b/applications/external/camera_suite/views/camera_suite_view_wifi_camera.h deleted file mode 100644 index ec9dbb69..00000000 --- a/applications/external/camera_suite/views/camera_suite_view_wifi_camera.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../helpers/camera_suite_custom_event.h" - -typedef void (*CameraSuiteViewWiFiCameraCallback)(CameraSuiteCustomEvent event, void* context); - -typedef struct CameraSuiteViewWiFiCamera { - View* view; - CameraSuiteViewCameraCallback callback; - void* context; -} CameraSuiteViewWiFiCamera; - -typedef struct { - FuriString* log; -} CameraSuiteViewWiFiCameraModel; - -CameraSuiteViewWiFiCamera* camera_suite_view_wifi_camera_alloc(); - -View* camera_suite_view_wifi_camera_get_view(CameraSuiteViewWiFiCamera* camera_suite_static); - -void camera_suite_view_wifi_camera_free(CameraSuiteViewWiFiCamera* camera_suite_static); - -void camera_suite_view_wifi_camera_set_callback( - CameraSuiteViewWiFiCamera* camera_suite_view_wifi_camera, - CameraSuiteViewWiFiCameraCallback callback, - void* context); diff --git a/applications/external/esp_flasher/esp_flasher_worker.c b/applications/external/esp_flasher/esp_flasher_worker.c index ccefb2a8..38120a32 100644 --- a/applications/external/esp_flasher/esp_flasher_worker.c +++ b/applications/external/esp_flasher/esp_flasher_worker.c @@ -378,9 +378,13 @@ void loader_port_reset_target(void) { void loader_port_enter_bootloader(void) { // Also support for the Multi-fucc and Xeon boards furi_hal_gpio_write(&gpio_swclk, false); - furi_hal_power_disable_otg(); + if(furi_hal_power_is_otg_enabled()) { + furi_hal_power_disable_otg(); + } loader_port_delay_ms(100); - furi_hal_power_enable_otg(); + if(!furi_hal_power_is_otg_enabled()) { + furi_hal_power_enable_otg(); + } furi_hal_gpio_init_simple(&gpio_swclk, GpioModeAnalog); loader_port_delay_ms(100); @@ -429,4 +433,4 @@ void esp_flasher_worker_handle_rx_data_cb(uint8_t* buf, size_t len, void* contex // done flashing if(global_app) esp_flasher_console_output_handle_rx_data_cb(buf, len, global_app); } -} \ No newline at end of file +} diff --git a/applications/external/esp_flasher/resources/apps_data/esp_flasher/assets/marauder/S2/esp32_marauder.flipper.bin b/applications/external/esp_flasher/resources/apps_data/esp_flasher/assets/marauder/S2/esp32_marauder.flipper.bin index ce672f20..50b8a706 100644 Binary files a/applications/external/esp_flasher/resources/apps_data/esp_flasher/assets/marauder/S2/esp32_marauder.flipper.bin and b/applications/external/esp_flasher/resources/apps_data/esp_flasher/assets/marauder/S2/esp32_marauder.flipper.bin differ diff --git a/applications/external/esp_flasher/resources/apps_data/esp_flasher/assets/marauder/WROOM/esp32_marauder.dev_board_pro.bin b/applications/external/esp_flasher/resources/apps_data/esp_flasher/assets/marauder/WROOM/esp32_marauder.dev_board_pro.bin index a8d3ca98..d25db4c0 100644 Binary files a/applications/external/esp_flasher/resources/apps_data/esp_flasher/assets/marauder/WROOM/esp32_marauder.dev_board_pro.bin and b/applications/external/esp_flasher/resources/apps_data/esp_flasher/assets/marauder/WROOM/esp32_marauder.dev_board_pro.bin differ diff --git a/applications/external/geiger/flipper_geiger.c b/applications/external/geiger/flipper_geiger.c index 5f38d174..72023a80 100644 --- a/applications/external/geiger/flipper_geiger.c +++ b/applications/external/geiger/flipper_geiger.c @@ -147,7 +147,7 @@ static void draw_callback(Canvas* canvas, void* ctx) { } else { canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 64, 10, AlignCenter, AlignBottom, "Geiger Counter"); - canvas_draw_str_aligned(canvas, 64, 20, AlignCenter, AlignBottom, "Version 20240222"); + canvas_draw_str_aligned(canvas, 64, 20, AlignCenter, AlignBottom, "Version 20240311"); canvas_draw_str_aligned(canvas, 64, 40, AlignCenter, AlignBottom, "github.com/nmrr"); } } @@ -187,7 +187,6 @@ int32_t flipper_geiger_app() { EventApp event; FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(EventApp)); - furi_hal_gpio_init(&gpio_ext_pa7, GpioModeInterruptFall, GpioPullUp, GpioSpeedVeryHigh); furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 5, 50); mutexStruct mutexVal; @@ -216,6 +215,7 @@ int32_t flipper_geiger_app() { furi_hal_gpio_add_int_callback(&gpio_ext_pa7, gpiocallback, event_queue); furi_hal_gpio_enable_int_callback(&gpio_ext_pa7); + furi_hal_gpio_init(&gpio_ext_pa7, GpioModeInterruptFall, GpioPullUp, GpioSpeedVeryHigh); Gui* gui = furi_record_open(RECORD_GUI); gui_add_view_port(gui, view_port, GuiLayerFullscreen); diff --git a/applications/external/seader/application.fam b/applications/external/seader/application.fam index 92bb7c39..3b5c6bce 100644 --- a/applications/external/seader/application.fam +++ b/applications/external/seader/application.fam @@ -19,7 +19,7 @@ App( ], fap_icon="icons/logo.png", fap_category="NFC", - fap_version="2.5", + fap_version="2.6", fap_author="bettse", # fap_extbuild=( # ExtFile( diff --git a/applications/external/seader/ccid.c b/applications/external/seader/ccid.c index 4633efcb..5d12895d 100644 --- a/applications/external/seader/ccid.c +++ b/applications/external/seader/ccid.c @@ -309,7 +309,7 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) { FURI_LOG_I(TAG, "SAM ATR!"); hasSAM = true; sam_slot = message.bSlot; - seader_worker_send_version(seader_worker); + seader_worker_send_version(seader); if(seader_worker->callback) { seader_worker->callback( SeaderWorkerEventSamPresent, seader_worker->context); @@ -318,7 +318,7 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) { FURI_LOG_I(TAG, "SAM ATR2!"); hasSAM = true; sam_slot = message.bSlot; - seader_worker_send_version(seader_worker); + seader_worker_send_version(seader); if(seader_worker->callback) { seader_worker->callback( SeaderWorkerEventSamPresent, seader_worker->context); diff --git a/applications/external/seader/sam_api.c b/applications/external/seader/sam_api.c index 46adb4df..67cd5bfe 100644 --- a/applications/external/seader/sam_api.c +++ b/applications/external/seader/sam_api.c @@ -14,7 +14,6 @@ const uint8_t picopass_iclass_key[] = {0xaf, 0xa7, 0x85, 0xa7, 0xda, 0xb3, 0x33, static char display[SEADER_UART_RX_BUF_SIZE * 2 + 1] = {0}; char asn1_log[SEADER_UART_RX_BUF_SIZE] = {0}; -bool requestPacs = true; uint8_t read4Block6[] = {RFAL_PICOPASS_CMD_READ4, 0x06, 0x45, 0x56}; uint8_t read4Block9[] = {RFAL_PICOPASS_CMD_READ4, 0x09, 0xB2, 0xAE}; @@ -195,7 +194,7 @@ void seader_send_payload( #ifdef ASN1_DEBUG if(er.encoded > -1) { - char payloadDebug[384] = {0}; + char payloadDebug[1024] = {0}; memset(payloadDebug, 0, sizeof(payloadDebug)); (&asn_DEF_Payload) ->op->print_struct( @@ -203,6 +202,8 @@ void seader_send_payload( if(strlen(payloadDebug) > 0) { FURI_LOG_D(TAG, "Sending payload[%d %d %d]: %s", to, from, replyTo, payloadDebug); } + } else { + FURI_LOG_W(TAG, "Failed to print_struct payload"); } #endif //0xa0, 0xda, 0x02, 0x63, 0x00, 0x00, 0x0a, @@ -232,7 +233,10 @@ void seader_send_response( ASN_STRUCT_FREE(asn_DEF_Payload, payload); } -void sendRequestPacs(SeaderUartBridge* seader_uart) { +void seader_send_request_pacs(Seader* seader) { + SeaderWorker* seader_worker = seader->worker; + SeaderUartBridge* seader_uart = seader_worker->uart; + RequestPacs_t* requestPacs = 0; requestPacs = calloc(1, sizeof *requestPacs); assert(requestPacs); @@ -244,6 +248,8 @@ void sendRequestPacs(SeaderUartBridge* seader_uart) { assert(samCommand); samCommand->present = SamCommand_PR_requestPacs; + seader->samCommand = samCommand->present; + samCommand->choice.requestPacs = *requestPacs; Payload_t* payload = 0; @@ -260,13 +266,16 @@ void sendRequestPacs(SeaderUartBridge* seader_uart) { ASN_STRUCT_FREE(asn_DEF_Payload, payload); } -void seader_worker_send_serial_number(SeaderWorker* seader_worker) { +void seader_worker_send_serial_number(Seader* seader) { + SeaderWorker* seader_worker = seader->worker; SeaderUartBridge* seader_uart = seader_worker->uart; + SamCommand_t* samCommand = 0; samCommand = calloc(1, sizeof *samCommand); assert(samCommand); samCommand->present = SamCommand_PR_serialNumber; + seader->samCommand = samCommand->present; Payload_t* payload = 0; payload = calloc(1, sizeof *payload); @@ -281,13 +290,16 @@ void seader_worker_send_serial_number(SeaderWorker* seader_worker) { ASN_STRUCT_FREE(asn_DEF_Payload, payload); } -void seader_worker_send_version(SeaderWorker* seader_worker) { +void seader_worker_send_version(Seader* seader) { + SeaderWorker* seader_worker = seader->worker; + SeaderUartBridge* seader_uart = seader_worker->uart; SamCommand_t* samCommand = 0; samCommand = calloc(1, sizeof *samCommand); assert(samCommand); samCommand->present = SamCommand_PR_version; + seader->samCommand = samCommand->present; Payload_t* payload = 0; payload = calloc(1, sizeof *payload); @@ -302,7 +314,9 @@ void seader_worker_send_version(SeaderWorker* seader_worker) { ASN_STRUCT_FREE(asn_DEF_Payload, payload); } -void seader_send_card_detected(SeaderUartBridge* seader_uart, CardDetails_t* cardDetails) { +void seader_send_card_detected(Seader* seader, CardDetails_t* cardDetails) { + SeaderWorker* seader_worker = seader->worker; + SeaderUartBridge* seader_uart = seader_worker->uart; CardDetected_t* cardDetected = 0; cardDetected = calloc(1, sizeof *cardDetected); assert(cardDetected); @@ -314,6 +328,7 @@ void seader_send_card_detected(SeaderUartBridge* seader_uart, CardDetails_t* car assert(samCommand); samCommand->present = SamCommand_PR_cardDetected; + seader->samCommand = samCommand->present; samCommand->choice.cardDetected = *cardDetected; Payload_t* payload = 0; @@ -505,31 +520,37 @@ bool seader_parse_serial_number(Seader* seader, uint8_t* buf, size_t size) { bool seader_parse_sam_response(Seader* seader, SamResponse_t* samResponse) { SeaderWorker* seader_worker = seader->worker; - SeaderUartBridge* seader_uart = seader_worker->uart; - if(samResponse->size == 0) { - if(requestPacs) { - FURI_LOG_D(TAG, "samResponse %d => requesting PACS", samResponse->size); - sendRequestPacs(seader_uart); - requestPacs = false; - } else { - FURI_LOG_D( - TAG, "samResponse %d, PACS already requested, pushing view", samResponse->size); - view_dispatcher_send_custom_event( - seader->view_dispatcher, SeaderCustomEventWorkerExit); - } - } else if(seader_parse_version(seader_worker, samResponse->buf, samResponse->size)) { - seader_worker_send_serial_number(seader_worker); - } else if(seader_parse_serial_number(seader, samResponse->buf, samResponse->size)) { - // no-op - } else if(seader_unpack_pacs(seader, samResponse->buf, samResponse->size)) { + switch(seader->samCommand) { + case SamCommand_PR_requestPacs: + FURI_LOG_I(TAG, "samResponse SamCommand_PR_requestPacs"); + seader_unpack_pacs(seader, samResponse->buf, samResponse->size); view_dispatcher_send_custom_event(seader->view_dispatcher, SeaderCustomEventPollerSuccess); - } else { + seader->samCommand = SamCommand_PR_NOTHING; + break; + case SamCommand_PR_version: + FURI_LOG_I(TAG, "samResponse SamCommand_PR_version"); + seader_parse_version(seader_worker, samResponse->buf, samResponse->size); + seader_worker_send_serial_number(seader); + break; + case SamCommand_PR_serialNumber: + FURI_LOG_I(TAG, "samResponse SamCommand_PR_serialNumber"); + seader_parse_serial_number(seader, samResponse->buf, samResponse->size); + seader->samCommand = SamCommand_PR_NOTHING; + break; + case SamCommand_PR_cardDetected: + FURI_LOG_I(TAG, "samResponse SamCommand_PR_cardDetected"); + seader_send_request_pacs(seader); + break; + case SamCommand_PR_NOTHING: + FURI_LOG_I(TAG, "samResponse SamCommand_PR_NOTHING"); memset(display, 0, sizeof(display)); for(uint8_t i = 0; i < samResponse->size; i++) { snprintf(display + (i * 2), sizeof(display), "%02x", samResponse->buf[i]); } - FURI_LOG_D(TAG, "Unknown samResponse %d: %s", samResponse->size, display); + FURI_LOG_I(TAG, "Unknown samResponse %d: %s", samResponse->size, display); + view_dispatcher_send_custom_event(seader->view_dispatcher, SeaderCustomEventWorkerExit); + break; } return false; @@ -873,11 +894,6 @@ NfcCommand seader_worker_card_detect( UNUSED(ats); UNUSED(ats_len); - // We're telling the SAM we've seen a new card, so reset out requestPacs check - requestPacs = true; - - SeaderWorker* seader_worker = seader->worker; - SeaderUartBridge* seader_uart = seader_worker->uart; SeaderCredential* credential = seader->credential; CardDetails_t* cardDetails = 0; @@ -910,7 +926,7 @@ NfcCommand seader_worker_card_detect( } } - seader_send_card_detected(seader_uart, cardDetails); + seader_send_card_detected(seader, cardDetails); ASN_STRUCT_FREE(asn_DEF_CardDetails, cardDetails); return NfcCommandContinue; diff --git a/applications/external/seader/seader.c b/applications/external/seader/seader.c index d9d880a9..3d757bd7 100644 --- a/applications/external/seader/seader.c +++ b/applications/external/seader/seader.c @@ -29,6 +29,7 @@ Seader* seader_alloc() { furi_hal_power_enable_otg(); } seader->is_debug_enabled = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug); + seader->samCommand = SamCommand_PR_NOTHING; seader->worker = seader_worker_alloc(); seader->view_dispatcher = view_dispatcher_alloc(); diff --git a/applications/external/seader/seader_bridge.h b/applications/external/seader/seader_bridge.h index c621deb2..06005766 100644 --- a/applications/external/seader/seader_bridge.h +++ b/applications/external/seader/seader_bridge.h @@ -9,7 +9,7 @@ #include #include -#define SEADER_UART_RX_BUF_SIZE (128) +#define SEADER_UART_RX_BUF_SIZE (256) typedef struct { uint8_t uart_ch; diff --git a/applications/external/seader/seader_i.h b/applications/external/seader/seader_i.h index 03907671..09fe3fc0 100644 --- a/applications/external/seader/seader_i.h +++ b/applications/external/seader/seader_i.h @@ -95,6 +95,7 @@ struct Seader { SceneManager* scene_manager; SeaderUartBridge* uart; SeaderCredential* credential; + SamCommand_PR samCommand; char text_store[SEADER_TEXT_STORE_SIZE + 1]; FuriString* text_box_store; diff --git a/applications/external/seader/seader_worker.c b/applications/external/seader/seader_worker.c index 12ede3d5..7630742c 100644 --- a/applications/external/seader/seader_worker.c +++ b/applications/external/seader/seader_worker.c @@ -98,7 +98,7 @@ bool seader_process_success_response(Seader* seader, uint8_t* apdu, size_t len) if(seader_process_success_response_i(seader, apdu, len, false, NULL)) { // no-op, message was processed } else { - FURI_LOG_I(TAG, "Queue New SAM Message, %d bytes", len); + FURI_LOG_I(TAG, "Enqueue SAM message, %d bytes", len); uint32_t space = furi_message_queue_get_space(seader_worker->messages); if(space > 0) { SeaderAPDU seaderApdu = {}; @@ -166,7 +166,7 @@ void seader_worker_virtual_credential(Seader* seader) { if(furi_mutex_acquire(seader_worker->mq_mutex, 0) == FuriStatusOk) { uint32_t count = furi_message_queue_get_count(seader_worker->messages); if(count > 0) { - FURI_LOG_D(TAG, "MessageQueue: %ld messages", count); + FURI_LOG_I(TAG, "Dequeue SAM message [%ld messages]", count); SeaderAPDU seaderApdu = {}; FuriStatus status = @@ -225,7 +225,7 @@ void seader_worker_poller_conversation(Seader* seader, SeaderPollerContainer* sp furi_thread_set_current_priority(FuriThreadPriorityHighest); uint32_t count = furi_message_queue_get_count(seader_worker->messages); if(count > 0) { - FURI_LOG_D(TAG, "MessageQueue: %ld messages", count); + FURI_LOG_I(TAG, "Dequeue SAM message [%ld messages]", count); SeaderAPDU seaderApdu = {}; FuriStatus status = diff --git a/applications/external/seader/seader_worker.h b/applications/external/seader/seader_worker.h index 9868b209..0194a762 100644 --- a/applications/external/seader/seader_worker.h +++ b/applications/external/seader/seader_worker.h @@ -62,7 +62,7 @@ void seader_worker_start( void seader_worker_stop(SeaderWorker* seader_worker); bool seader_worker_process_sam_message(Seader* seader, CCID_Message* message); -void seader_worker_send_version(SeaderWorker* seader_worker); +void seader_worker_send_version(Seader* seader); NfcCommand seader_worker_poller_callback_iso14443_4a(NfcGenericEvent event, void* context); diff --git a/applications/external/totp/application.fam b/applications/external/totp/application.fam index e5d47647..61b386a6 100644 --- a/applications/external/totp/application.fam +++ b/applications/external/totp/application.fam @@ -7,7 +7,7 @@ App( requires=["gui", "cli", "dialogs", "storage", "input", "notification", "bt"], stack_size=2 * 1024, order=20, - fap_version="5.120", + fap_version="5.130", fap_author="Alexander Kopachov (@akopachov)", fap_description="Software-based TOTP/HOTP authenticator for Flipper Zero device", fap_weburl="https://github.com/akopachov/flipper-zero_authenticator", diff --git a/applications/external/totp/ui/scenes/authenticate/totp_scene_authenticate.c b/applications/external/totp/ui/scenes/authenticate/totp_scene_authenticate.c index 5acc5715..4cf9ede7 100644 --- a/applications/external/totp/ui/scenes/authenticate/totp_scene_authenticate.c +++ b/applications/external/totp/ui/scenes/authenticate/totp_scene_authenticate.c @@ -122,42 +122,6 @@ bool totp_scene_authenticate_handle_event( } break; case InputKeyOk: { - CryptoSeedIVResult seed_result = totp_crypto_seed_iv( - &plugin_state->crypto_settings, - &scene_state->code_input[0], - scene_state->code_length); - - if(seed_result & CryptoSeedIVResultFlagSuccess && - seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) { - totp_config_file_update_crypto_signatures(plugin_state); - } - - if(totp_crypto_verify_key(&plugin_state->crypto_settings)) { - totp_config_file_ensure_latest_encryption( - plugin_state, &scene_state->code_input[0], scene_state->code_length); - totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken); - } else { - memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH); - memset(&plugin_state->crypto_settings.iv[0], 0, CRYPTO_IV_LENGTH); - scene_state->code_length = 0; - - DialogMessage* message = dialog_message_alloc(); - dialog_message_set_buttons(message, "Try again", NULL, NULL); - dialog_message_set_header( - message, - "You entered\ninvalid PIN", - SCREEN_WIDTH_CENTER - 25, - SCREEN_HEIGHT_CENTER - 5, - AlignCenter, - AlignCenter); -#if __has_include() - dialog_message_set_icon(message, &I_WarningDolphinFlip_45x42, 83, 22); -#else - dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17); -#endif - dialog_message_show(plugin_state->dialogs_app, message); - dialog_message_free(message); - } break; } case InputKeyBack: @@ -165,6 +129,41 @@ bool totp_scene_authenticate_handle_event( default: break; } + } else if(event->input.type == InputTypeRelease && event->input.key == InputKeyOk) { + CryptoSeedIVResult seed_result = totp_crypto_seed_iv( + &plugin_state->crypto_settings, &scene_state->code_input[0], scene_state->code_length); + + if(seed_result & CryptoSeedIVResultFlagSuccess && + seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) { + totp_config_file_update_crypto_signatures(plugin_state); + } + + if(totp_crypto_verify_key(&plugin_state->crypto_settings)) { + totp_config_file_ensure_latest_encryption( + plugin_state, &scene_state->code_input[0], scene_state->code_length); + totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken); + } else { + memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH); + memset(&plugin_state->crypto_settings.iv[0], 0, CRYPTO_IV_LENGTH); + scene_state->code_length = 0; + + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_buttons(message, "Try again", NULL, NULL); + dialog_message_set_header( + message, + "You entered\ninvalid PIN", + SCREEN_WIDTH_CENTER - 25, + SCREEN_HEIGHT_CENTER - 5, + AlignCenter, + AlignCenter); +#if __has_include() + dialog_message_set_icon(message, &I_WarningDolphinFlip_45x42, 83, 22); +#else + dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17); +#endif + dialog_message_show(plugin_state->dialogs_app, message); + dialog_message_free(message); + } } return true; diff --git a/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c b/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c index 3a1f7133..30b67023 100644 --- a/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c +++ b/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c @@ -373,7 +373,9 @@ bool totp_scene_generate_token_handle_event( scene_state->notification_app, get_notification_sequence_automation(plugin_state, scene_state)); return true; - } else if(event->input.key == InputKeyOk) { + } +#endif + else if(event->input.key == InputKeyOk) { TokenInfoIteratorContext* iterator_context = totp_config_get_token_iterator_context(plugin_state); const TokenInfo* token_info = @@ -389,7 +391,6 @@ bool totp_scene_generate_token_handle_event( get_notification_sequence_new_token(plugin_state, scene_state)); } } -#endif } else if(event->input.type == InputTypePress || event->input.type == InputTypeRepeat) { switch(event->input.key) { case InputKeyUp: @@ -427,13 +428,14 @@ bool totp_scene_generate_token_handle_event( break; } case InputKeyOk: - totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu); break; case InputKeyBack: break; default: break; } + } else if(event->input.type == InputTypeShort && event->input.key == InputKeyOk) { + totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu); } return true; diff --git a/applications/external/totp/version.h b/applications/external/totp/version.h index 1340fd92..3c74e12c 100644 --- a/applications/external/totp/version.h +++ b/applications/external/totp/version.h @@ -1,5 +1,5 @@ #pragma once #define TOTP_APP_VERSION_MAJOR (5) -#define TOTP_APP_VERSION_MINOR (12) +#define TOTP_APP_VERSION_MINOR (13) #define TOTP_APP_VERSION_PATCH (0) \ No newline at end of file diff --git a/applications/external/uhf_rfid/application.fam b/applications/external/uhf_rfid/application.fam index eafbc83e..33d90bee 100644 --- a/applications/external/uhf_rfid/application.fam +++ b/applications/external/uhf_rfid/application.fam @@ -8,9 +8,9 @@ App( "storage", "gui", ], - stack_size=8 * 1024, + stack_size=10 * 1024, order=30, - fap_icon="uhf_10px.png", + fap_icon="icons/uhf_10px.png", fap_category="GPIO", fap_icon_assets="icons", fap_icon_assets_symbol="uhf_rfid", diff --git a/applications/external/uhf_rfid/icons/DolphinMafia_115x62.png b/applications/external/uhf_rfid/icons/DolphinMafia_115x62.png new file mode 100644 index 00000000..66fdb40f Binary files /dev/null and b/applications/external/uhf_rfid/icons/DolphinMafia_115x62.png differ diff --git a/applications/external/uhf_rfid/icons/DolphinNice_96x59.png b/applications/external/uhf_rfid/icons/DolphinNice_96x59.png new file mode 100644 index 00000000..a299d363 Binary files /dev/null and b/applications/external/uhf_rfid/icons/DolphinNice_96x59.png differ diff --git a/applications/external/uhf_rfid/icons/Nfc_10px.png b/applications/external/uhf_rfid/icons/Nfc_10px.png new file mode 100644 index 00000000..6bc02711 Binary files /dev/null and b/applications/external/uhf_rfid/icons/Nfc_10px.png differ diff --git a/applications/external/uhf_rfid/icons/RFIDDolphinReceive_97x61.png b/applications/external/uhf_rfid/icons/RFIDDolphinReceive_97x61.png new file mode 100644 index 00000000..e1f5f9f8 Binary files /dev/null and b/applications/external/uhf_rfid/icons/RFIDDolphinReceive_97x61.png differ diff --git a/applications/external/uhf_rfid/icons/RFIDDolphinSend_97x61.png b/applications/external/uhf_rfid/icons/RFIDDolphinSend_97x61.png new file mode 100644 index 00000000..380a970d Binary files /dev/null and b/applications/external/uhf_rfid/icons/RFIDDolphinSend_97x61.png differ diff --git a/applications/external/uhf_rfid/icons/uhf_10px.png b/applications/external/uhf_rfid/icons/uhf_10px.png new file mode 100644 index 00000000..aa9a29f8 Binary files /dev/null and b/applications/external/uhf_rfid/icons/uhf_10px.png differ diff --git a/applications/external/uhf_rfid/scenes/uhf_scene_save_name.c b/applications/external/uhf_rfid/scenes/uhf_scene_save_name.c index 2c0e152e..3dcea3d4 100644 --- a/applications/external/uhf_rfid/scenes/uhf_scene_save_name.c +++ b/applications/external/uhf_rfid/scenes/uhf_scene_save_name.c @@ -1,5 +1,5 @@ #include "../uhf_app_i.h" -#include +#include #include #include @@ -14,9 +14,7 @@ void uhf_scene_save_name_on_enter(void* context) { // Setup view TextInput* text_input = uhf_app->text_input; - name_generator_make_auto(uhf_app->text_store, sizeof(uhf_app->text_store), "UHF"); - text_input_set_header_text(text_input, "Name the tag"); text_input_set_result_callback( text_input, diff --git a/applications/external/uhf_rfid/scenes/uhf_scene_settings.c b/applications/external/uhf_rfid/scenes/uhf_scene_settings.c index f1cb30bc..49210260 100644 --- a/applications/external/uhf_rfid/scenes/uhf_scene_settings.c +++ b/applications/external/uhf_rfid/scenes/uhf_scene_settings.c @@ -2,15 +2,15 @@ #include "../uhf_module.h" void uhf_settings_set_module_baudrate(VariableItem* item) { - M100Module* uhf_module = variable_item_get_context(item); + M100Module* module = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); if(index >= BAUD_RATES_COUNT) { return; } uint32_t baudrate = BAUD_RATES[index]; - m100_set_baudrate(uhf_module, baudrate); + m100_set_baudrate(module, baudrate); char text_buf[10]; - snprintf(text_buf, sizeof(text_buf), "%lu", uhf_module->baudrate); + snprintf(text_buf, sizeof(text_buf), "%lu", module->uart->baudrate); variable_item_set_current_value_text(item, text_buf); } @@ -40,7 +40,7 @@ void uhf_settings_set_module_working_region(VariableItem* item) { uint8_t uhf_settings_get_module_baudrate_index(M100Module* module) { for(uint8_t i = 0; i < BAUD_RATES_COUNT; i++) { - if(BAUD_RATES[i] == module->baudrate) { + if(BAUD_RATES[i] == module->uart->baudrate) { return i; } } @@ -73,7 +73,7 @@ void uhf_scene_settings_on_enter(void* ctx) { uint8_t value_index = uhf_settings_get_module_baudrate_index(uhf_module); char text_buf[10]; - snprintf(text_buf, sizeof(text_buf), "%lu", uhf_module->baudrate); + snprintf(text_buf, sizeof(text_buf), "%lu", uhf_module->uart->baudrate); item = variable_item_list_add( variable_item_list, "Baudrate:", diff --git a/applications/external/uhf_rfid/uhf_app.c b/applications/external/uhf_rfid/uhf_app.c index df23dd11..8e6fe5e9 100644 --- a/applications/external/uhf_rfid/uhf_app.c +++ b/applications/external/uhf_rfid/uhf_app.c @@ -201,7 +201,6 @@ int32_t uhf_app_main(void* ctx) { expansion_disable(expansion); UHFApp* uhf_app = uhf_alloc(); - // enable 5v pin uint8_t attempts = 0; bool otg_was_enabled = furi_hal_power_is_otg_enabled(); @@ -209,17 +208,13 @@ int32_t uhf_app_main(void* ctx) { furi_hal_power_enable_otg(); furi_delay_ms(10); } - furi_delay_ms(200); - // init pin a2 - // furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeOutputPushPull); + // enter app scene_manager_next_scene(uhf_app->scene_manager, UHFSceneModuleInfo); view_dispatcher_run(uhf_app->view_dispatcher); - // disable 5v pin if(furi_hal_power_is_otg_enabled() && !otg_was_enabled) { furi_hal_power_disable_otg(); } - // furi_hal_gpio_disable_int_callback() // exit app uhf_free(uhf_app); diff --git a/applications/external/uhf_rfid/uhf_app_i.h b/applications/external/uhf_rfid/uhf_app_i.h index 85c0df9d..78b2948a 100644 --- a/applications/external/uhf_rfid/uhf_app_i.h +++ b/applications/external/uhf_rfid/uhf_app_i.h @@ -27,8 +27,6 @@ #include -#include - #define UHF_TEXT_STORE_SIZE 128 // #define UHF_APPS_DATA_FOLDER EXT_PATH("apps_data") // #define UHF_APPS_STORAGE_FOLDER diff --git a/applications/external/uhf_rfid/uhf_buffer.c b/applications/external/uhf_rfid/uhf_buffer.c index 8e56f88d..5ee32c40 100644 --- a/applications/external/uhf_rfid/uhf_buffer.c +++ b/applications/external/uhf_rfid/uhf_buffer.c @@ -2,7 +2,7 @@ #include #include -Buffer* buffer_alloc(size_t initial_capacity) { +Buffer* uhf_buffer_alloc(size_t initial_capacity) { Buffer* buf = (Buffer*)malloc(sizeof(Buffer)); buf->data = (uint8_t*)malloc(sizeof(uint8_t) * initial_capacity); if(!buf->data) { @@ -14,7 +14,7 @@ Buffer* buffer_alloc(size_t initial_capacity) { return buf; } -bool buffer_append_single(Buffer* buf, uint8_t data) { +bool uhf_buffer_append_single(Buffer* buf, uint8_t data) { if(buf->closed) return false; if(buf->size + 1 > buf->capacity) { size_t new_capacity = buf->capacity * 2; @@ -27,7 +27,7 @@ bool buffer_append_single(Buffer* buf, uint8_t data) { return true; } -bool buffer_append(Buffer* buf, uint8_t* data, size_t data_size) { +bool uhf_buffer_append(Buffer* buf, uint8_t* data, size_t data_size) { if(buf->closed) return false; if(buf->size + data_size > buf->capacity) { size_t new_capacity = buf->capacity * 2; @@ -43,19 +43,23 @@ bool buffer_append(Buffer* buf, uint8_t* data, size_t data_size) { return true; } -uint8_t* buffer_get_data(Buffer* buf) { +uint8_t* uhf_buffer_get_data(Buffer* buf) { return buf->data; } -size_t buffer_get_size(Buffer* buf) { +size_t uhf_buffer_get_size(Buffer* buf) { return buf->size; } -void buffer_close(Buffer* buf) { +bool uhf_is_buffer_closed(Buffer* buf) { + return buf->closed; +} + +void uhf_buffer_close(Buffer* buf) { buf->closed = true; } -void buffer_reset(Buffer* buf) { +void uhf_buffer_reset(Buffer* buf) { for(size_t i = 0; i < MAX_BUFFER_SIZE; i++) { buf->data[i] = 0; } @@ -63,7 +67,7 @@ void buffer_reset(Buffer* buf) { buf->closed = false; } -void buffer_free(Buffer* buf) { +void uhf_buffer_free(Buffer* buf) { free(buf->data); free(buf); } \ No newline at end of file diff --git a/applications/external/uhf_rfid/uhf_buffer.h b/applications/external/uhf_rfid/uhf_buffer.h index 045b0e3e..d1420094 100644 --- a/applications/external/uhf_rfid/uhf_buffer.h +++ b/applications/external/uhf_rfid/uhf_buffer.h @@ -12,11 +12,13 @@ typedef struct Buffer { bool closed; } Buffer; -Buffer* buffer_alloc(size_t inital_capacity); -bool buffer_append_single(Buffer* buf, uint8_t value); -bool buffer_append(Buffer* buf, uint8_t* data, size_t size); -uint8_t* buffer_get_data(Buffer* buf); -size_t buffer_get_size(Buffer* buf); -void buffer_close(Buffer* buf); -void buffer_reset(Buffer* buf); -void buffer_free(Buffer* buf); \ No newline at end of file +Buffer* uhf_buffer_alloc(size_t inital_capacity); +bool uhf_buffer_append_single(Buffer* buf, uint8_t value); +bool uhf_buffer_append(Buffer* buf, uint8_t* data, size_t size); + +uint8_t* uhf_buffer_get_data(Buffer* buf); +size_t uhf_buffer_get_size(Buffer* buf); +bool uhf_is_buffer_closed(Buffer* buf); +void uhf_buffer_close(Buffer* buf); +void uhf_buffer_reset(Buffer* buf); +void uhf_buffer_free(Buffer* buf); \ No newline at end of file diff --git a/applications/external/uhf_rfid/uhf_device.c b/applications/external/uhf_rfid/uhf_device.c index 79ab5016..812aa565 100644 --- a/applications/external/uhf_rfid/uhf_device.c +++ b/applications/external/uhf_rfid/uhf_device.c @@ -3,14 +3,10 @@ #include #include -#include - #define TAG "UHFDevice" static const char* uhf_file_header = "Flipper UHF RFID device"; static const uint32_t uhf_file_version = 1; -// static const uint8_t bank_data_start = 20; -// static const uint8_t bank_data_length = 16; UHFDevice* uhf_device_alloc() { UHFDevice* uhf_device = malloc(sizeof(UHFDevice)); @@ -180,15 +176,6 @@ static bool uhf_device_load_data(UHFDevice* dev, FuriString* path, bool show_dia return parsed; } -// void picopass_device_clear(UHFDevice* dev) { -// furi_assert(dev); - -// picopass_device_data_clear(&dev->dev_data); -// memset(&dev->dev_data, 0, sizeof(dev->dev_data)); -// dev->format = PicopassDeviceSaveFormatHF; -// furi_string_reset(dev->load_path); -// } - void uhf_device_free(UHFDevice* uhf_dev) { furi_assert(uhf_dev); furi_record_close(RECORD_STORAGE); @@ -226,16 +213,6 @@ bool uhf_file_select(UHFDevice* dev) { return res; } -// void uhf_device_data_clear(UHFDevice* dev_data) { -// for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) { -// memset(dev_data->AA1[i].data, 0, sizeof(dev_data->AA1[i].data)); -// } -// dev_data->pacs.legacy = false; -// dev_data->pacs.se_enabled = false; -// dev_data->pacs.elite_kdf = false; -// dev_data->pacs.pin_length = 0; -// } - bool uhf_device_delete(UHFDevice* dev, bool use_load_path) { furi_assert(dev); @@ -267,84 +244,4 @@ void uhf_device_set_loading_callback(UHFDevice* dev, UHFLoadingCallback callback dev->loading_cb = callback; dev->loading_cb_ctx = context; -} - -// ReturnCode picopass_device_decrypt(uint8_t* enc_data, uint8_t* dec_data) { -// uint8_t key[32] = {0}; -// memcpy(key, picopass_iclass_decryptionkey, sizeof(picopass_iclass_decryptionkey)); -// mbedtls_des3_context ctx; -// mbedtls_des3_init(&ctx); -// mbedtls_des3_set2key_dec(&ctx, key); -// mbedtls_des3_crypt_ecb(&ctx, enc_data, dec_data); -// mbedtls_des3_free(&ctx); -// return ERR_NONE; -// } - -// ReturnCode picopass_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pacs) { -// ReturnCode err; - -// pacs->biometrics = AA1[6].data[4]; -// pacs->pin_length = AA1[6].data[6] & 0x0F; -// pacs->encryption = AA1[6].data[7]; - -// if(pacs->encryption == PicopassDeviceEncryption3DES) { -// FURI_LOG_D(TAG, "3DES Encrypted"); -// err = picopass_device_decrypt(AA1[7].data, pacs->credential); -// if(err != ERR_NONE) { -// FURI_LOG_E(TAG, "decrypt error %d", err); -// return err; -// } - -// err = picopass_device_decrypt(AA1[8].data, pacs->pin0); -// if(err != ERR_NONE) { -// FURI_LOG_E(TAG, "decrypt error %d", err); -// return err; -// } - -// err = picopass_device_decrypt(AA1[9].data, pacs->pin1); -// if(err != ERR_NONE) { -// FURI_LOG_E(TAG, "decrypt error %d", err); -// return err; -// } -// } else if(pacs->encryption == PicopassDeviceEncryptionNone) { -// FURI_LOG_D(TAG, "No Encryption"); -// memcpy(pacs->credential, AA1[7].data, PICOPASS_BLOCK_LEN); -// memcpy(pacs->pin0, AA1[8].data, PICOPASS_BLOCK_LEN); -// memcpy(pacs->pin1, AA1[9].data, PICOPASS_BLOCK_LEN); -// } else if(pacs->encryption == PicopassDeviceEncryptionDES) { -// FURI_LOG_D(TAG, "DES Encrypted"); -// } else { -// FURI_LOG_D(TAG, "Unknown encryption"); -// } - -// pacs->sio = (AA1[10].data[0] == 0x30); // rough check - -// return ERR_NONE; -// } - -// ReturnCode picopass_device_parse_wiegand(uint8_t* data, PicopassWiegandRecord* record) { -// uint32_t* halves = (uint32_t*)data; -// if(halves[0] == 0) { -// uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[1])); -// record->bitLength = 31 - leading0s; -// } else { -// uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[0])); -// record->bitLength = 63 - leading0s; -// } -// FURI_LOG_D(TAG, "bitLength: %d", record->bitLength); - -// if(record->bitLength == 26) { -// uint8_t* v4 = data + 4; -// uint32_t bot = v4[3] | (v4[2] << 8) | (v4[1] << 16) | (v4[0] << 24); - -// record->CardNumber = (bot >> 1) & 0xFFFF; -// record->FacilityCode = (bot >> 17) & 0xFF; -// FURI_LOG_D(TAG, "FC: %u CN: %u", record->FacilityCode, record->CardNumber); -// record->valid = true; -// } else { -// record->CardNumber = 0; -// record->FacilityCode = 0; -// record->valid = false; -// } -// return ERR_NONE; -// } +} \ No newline at end of file diff --git a/applications/external/uhf_rfid/uhf_module.c b/applications/external/uhf_rfid/uhf_module.c index b07639dc..2e002aac 100644 --- a/applications/external/uhf_rfid/uhf_module.c +++ b/applications/external/uhf_rfid/uhf_module.c @@ -2,33 +2,23 @@ #include "uhf_module_cmd.h" #define DELAY_MS 100 -#define WAIT_TICK 8000 // max wait time in between each byte - -volatile uint16_t tick = 0; - -void rx_callback(FuriHalSerialHandle* handle, FuriHalSerialRxEvent event, void* ctx) { - UNUSED(event); - Buffer* buffer = ctx; - if(buffer->closed) return; // buffer closed - if(event == FuriHalSerialRxEventData) { - uint8_t data = furi_hal_serial_async_rx(handle); - buffer_append_single(buffer, data); // append data - if(data == FRAME_END) buffer_close(buffer); // end of frame - tick = WAIT_TICK; // reset tick - } -} +#define WAIT_TICK 4000 // max wait time in between each byte static M100ResponseType setup_and_send_rx(M100Module* module, uint8_t* cmd, size_t cmd_length) { - buffer_reset(module->buf); - tick = WAIT_TICK; - furi_hal_serial_tx(module->serial_handle, cmd, cmd_length); - while(--tick) { - furi_delay_us(5); + UHFUart* uart = module->uart; + Buffer* buffer = uart->buffer; + // clear buffer + uhf_buffer_reset(buffer); + // send cmd + uhf_uart_send_wait(uart, cmd, cmd_length); + // wait for response by polling + while(!uhf_is_buffer_closed(buffer) && !uhf_uart_tick(uart)) { } - buffer_close(module->buf); + // reset tick + uhf_uart_tick_reset(uart); // Validation Checks - uint8_t* data = buffer_get_data(module->buf); - size_t length = buffer_get_size(module->buf); + uint8_t* data = uhf_buffer_get_data(buffer); + size_t length = uhf_buffer_get_size(buffer); // check if size > 0 if(!length) return M100EmptyResponse; // check if data is valid @@ -44,30 +34,24 @@ M100ModuleInfo* m100_module_info_alloc() { } void m100_module_info_free(M100ModuleInfo* module_info) { - free(module_info->hw_version); - free(module_info->sw_version); - free(module_info->manufacturer); + if(module_info->hw_version != NULL) free(module_info->hw_version); + if(module_info->sw_version != NULL) free(module_info->sw_version); + if(module_info->manufacturer != NULL) free(module_info->manufacturer); free(module_info); } + M100Module* m100_module_alloc() { M100Module* module = (M100Module*)malloc(sizeof(M100Module)); - module->info = m100_module_info_alloc(); - module->buf = buffer_alloc(MAX_BUFFER_SIZE); - module->baudrate = DEFAULT_BAUDRATE; module->transmitting_power = DEFAULT_TRANSMITTING_POWER; module->region = DEFAULT_WORKING_REGION; - module->serial_handle = furi_hal_serial_control_acquire(FuriHalSerialIdUsart); - furi_check(module->serial_handle); - furi_hal_serial_init(module->serial_handle, module->baudrate); - furi_hal_serial_async_rx_start(module->serial_handle, rx_callback, module->buf, false); + module->info = m100_module_info_alloc(); + module->uart = uhf_uart_alloc(); return module; } void m100_module_free(M100Module* module) { - furi_hal_serial_deinit(module->serial_handle); - furi_hal_serial_control_release(module->serial_handle); m100_module_info_free(module->info); - buffer_free(module->buf); + uhf_uart_free(module->uart); free(module); } @@ -100,8 +84,8 @@ uint16_t crc16_genibus(const uint8_t* data, size_t length) { } char* _m100_info_helper(M100Module* module, char** info) { - if(!buffer_get_size(module->buf)) return NULL; - uint8_t* data = buffer_get_data(module->buf); + if(!uhf_buffer_get_size(module->uart->buffer)) return NULL; + uint8_t* data = uhf_buffer_get_data(module->uart->buffer); uint16_t payload_len = data[3]; payload_len = (payload_len << 8) + data[4]; FuriString* temp_str = furi_string_alloc(); @@ -137,8 +121,7 @@ M100ResponseType m100_single_poll(M100Module* module, UHFTag* uhf_tag) { M100ResponseType rp_type = setup_and_send_rx(module, (uint8_t*)&CMD_SINGLE_POLLING.cmd[0], CMD_SINGLE_POLLING.length); if(rp_type != M100SuccessResponse) return rp_type; - uint8_t* data = buffer_get_data(module->buf); - size_t length = buffer_get_size(module->buf); + uint8_t* data = uhf_buffer_get_data(module->uart->buffer); uint16_t pc = data[6]; uint16_t crc = 0; // mask out epc length from protocol control @@ -152,8 +135,6 @@ M100ResponseType m100_single_poll(M100Module* module, UHFTag* uhf_tag) { crc = data[8 + epc_len]; crc <<= 8; crc += data[8 + epc_len + 1]; - // validate checksum - if(checksum(data + 1, length - 3) != data[length - 2]) return M100ValidationFail; // validate crc if(crc16_genibus(data + 6, epc_len + 2) != crc) return M100ValidationFail; uhf_tag_set_epc_pc(uhf_tag, pc); @@ -192,25 +173,26 @@ M100ResponseType m100_set_select(M100Module* module, UHFTag* uhf_tag) { // end frame cmd[cmd_length - 1] = FRAME_END; - setup_and_send_rx(module, cmd, 12 + mask_length_bytes + 3); + M100ResponseType rp_type = setup_and_send_rx(module, cmd, 12 + mask_length_bytes + 3); + + if(rp_type != M100SuccessResponse) return rp_type; - uint8_t* data = buffer_get_data(module->buf); - if(checksum(data + 1, 5) != data[6]) return M100ValidationFail; // error in rx + uint8_t* data = uhf_buffer_get_data(module->uart->buffer); if(data[5] != 0x00) return M100ValidationFail; // error if not 0 return M100SuccessResponse; } UHFTag* m100_get_select_param(M100Module* module) { - buffer_reset(module->buf); - // furi_hal_uart_set_irq_cb(FuriHalUartIdLPUART1, rx_callback, module->buf); - furi_hal_serial_tx( - module->serial_handle, - (uint8_t*)&CMD_GET_SELECT_PARAMETER.cmd, - CMD_GET_SELECT_PARAMETER.length); - furi_delay_ms(DELAY_MS); + uhf_buffer_reset(module->uart->buffer); + // furi_hal_uart_set_irq_cb(FuriHalUartIdLPUART1, rx_callback, module->uart->buffer); + // furi_hal_uart_tx( + // FuriHalUartIdUSART1, + // (uint8_t*)&CMD_GET_SELECT_PARAMETER.cmd, + // CMD_GET_SELECT_PARAMETER.length); + // furi_delay_ms(DELAY_MS); // UHFTag* uhf_tag = uhf_tag_alloc(); - // uint8_t* data = buffer_get_data(module->buf); + // uint8_t* data = buffer_get_data(module->uart->buffer); // size_t mask_length = // uhf_tag_set_epc(uhf_tag, data + 12, ) // TODO : implement @@ -246,7 +228,7 @@ M100ResponseType m100_read_label_data_storage( M100ResponseType rp_type = setup_and_send_rx(module, cmd, cmd_length); if(rp_type != M100SuccessResponse) return rp_type; - uint8_t* data = buffer_get_data(module->buf); + uint8_t* data = uhf_buffer_get_data(module->uart->buffer); uint8_t rtn_command = data[2]; uint16_t payload_len = data[3]; @@ -326,17 +308,10 @@ M100ResponseType m100_write_label_data_storage( cmd[cmd_length - 2] = checksum(cmd + 1, cmd_length - 3); cmd[cmd_length - 1] = FRAME_END; // send cmd - // furi_hal_serial_async_rx_start(module->serial_handle, rx_callback, module->buf, false); - // furi_hal_serial_tx(module->serial_handle, cmd, cmd_length); - // unsigned int delay = DELAY_MS / 2; - // unsigned int timeout = 15; - // while(!buffer_get_size(module->buf)) { - // furi_delay_ms(delay); - // if(!timeout--) break; - // } - setup_and_send_rx(module, cmd, cmd_length); - uint8_t* buff_data = buffer_get_data(module->buf); - size_t buff_length = buffer_get_size(module->buf); + M100ResponseType rp_type = setup_and_send_rx(module, cmd, cmd_length); + if(rp_type != M100SuccessResponse) return rp_type; + uint8_t* buff_data = uhf_buffer_get_data(module->uart->buffer); + size_t buff_length = uhf_buffer_get_size(module->uart->buffer); if(buff_data[2] == 0xFF && buff_length == 8) return M100NoTagResponse; else if(buff_data[2] == 0xFF) @@ -351,9 +326,10 @@ void m100_set_baudrate(M100Module* module, uint32_t baudrate) { cmd[6] = 0xFF & br_mod; // pow LSB cmd[5] = 0xFF & (br_mod >> 8); // pow MSB cmd[length - 2] = checksum(cmd + 1, length - 3); - furi_hal_serial_tx(module->serial_handle, cmd, length); - furi_hal_serial_set_br(module->serial_handle, baudrate); - module->baudrate = baudrate; + // setup_and_send_rx(module, cmd, length); + uhf_uart_send_wait(module->uart, cmd, length); + uhf_uart_set_baudrate(module->uart, baudrate); + module->uart->baudrate = baudrate; } bool m100_set_working_region(M100Module* module, WorkingRegion region) { @@ -392,5 +368,5 @@ bool m100_set_power(M100Module* module, uint8_t* power) { } uint32_t m100_get_baudrate(M100Module* module) { - return module->baudrate; + return module->uart->baudrate; } \ No newline at end of file diff --git a/applications/external/uhf_rfid/uhf_module.h b/applications/external/uhf_rfid/uhf_module.h index 7303f737..320f7514 100644 --- a/applications/external/uhf_rfid/uhf_module.h +++ b/applications/external/uhf_rfid/uhf_module.h @@ -1,13 +1,11 @@ #pragma once - +#include #include #include #include -#include +#include "uhf_uart.h" #include "uhf_tag.h" #include "uhf_buffer.h" -#include "uhf_tag.h" -#include #include "uhf_module_settings.h" #define FRAME_START 0xBB @@ -33,13 +31,12 @@ typedef enum { typedef struct { M100ModuleInfo* info; - uint32_t baudrate; WorkingRegion region; uint16_t region_frequency; uint16_t transmitting_power; + uint16_t max_transmitting_power; bool freq_hopping; - Buffer* buf; - FuriHalSerialHandle* serial_handle; + UHFUart* uart; } M100Module; M100ModuleInfo* m100_module_info_alloc(); diff --git a/applications/external/uhf_rfid/uhf_uart.c b/applications/external/uhf_rfid/uhf_uart.c new file mode 100644 index 00000000..f052a83f --- /dev/null +++ b/applications/external/uhf_rfid/uhf_uart.c @@ -0,0 +1,129 @@ +#include "uhf_uart.h" + +// int32_t uhf_uart_worker_callback(void *ctx){ +// UHFUart* uart = (UHFUart*)ctx; +// Buffer* buffer = (Buffer*)uart->buffer; +// uint32_t events; +// size_t length_read = 0; +// uint8_t read_buffer[1]; +// FURI_LOG_E("UHF_UART_WORKER", "UHF UART WORKER STARTED"); +// do{ +// events = furi_thread_flags_wait( +// UHFUartWorkerWaitingDataFlag | UHFUartWorkerExitingFlag, FuriFlagWaitAny, FuriWaitForever +// ); +// FURI_LOG_E("UHF_UART_WORKER", "events = %lu", events); +// if(events & UHFUartWorkerWaitingDataFlag){ +// FURI_LOG_E("UHF_UART_WORKER", "Waiting data..."); +// length_read = furi_stream_buffer_receive(uart->rx_buff_stream, read_buffer, 1, 0); +// if(length_read){ +// do{ +// length_read = furi_stream_buffer_receive(uart->rx_buff_stream, read_buffer, 1, 0); +// uhf_buffer_append_single(buffer, read_buffer[0]); +// uhf_uart_tick_reset(uart); +// }while(read_buffer[0] != UHF_UART_FRAME_END && length_read > 0); +// FURI_LOG_E("UHF_UART_WORKER", "UHF Total length read = %u", uhf_buffer_get_size(buffer)); +// uhf_buffer_close(buffer); +// furi_stream_buffer_reset(uart->rx_buff_stream); +// } +// } +// }while((events & UHFUartWorkerExitingFlag) != UHFUartWorkerExitingFlag); +// return 0; +// } + +void uhf_uart_default_rx_callback( + FuriHalSerialHandle* handle, + FuriHalSerialRxEvent event, + void* ctx) { + UHFUart* uart = (UHFUart*)ctx; + // FURI_LOG_E("UHF_UART", "UHF UART RX CALLBACK"); + if((event & FuriHalSerialRxEventData) == FuriHalSerialRxEventData) { + uint8_t data = furi_hal_serial_async_rx(handle); + // if(data == UHF_UART_FRAME_START){ + // uhf_buffer_reset(uart->buffer); + // } + if(uhf_is_buffer_closed(uart->buffer)) { + return; + } + if(data == UHF_UART_FRAME_END) { + uhf_buffer_append_single(uart->buffer, data); + uhf_buffer_close(uart->buffer); + FURI_LOG_E( + "UHF_UART", "UHF Total length read = %u", uhf_buffer_get_size(uart->buffer)); + } + uhf_buffer_append_single(uart->buffer, data); + uhf_uart_tick_reset(uart); + // furi_stream_buffer_send(uart->rx_buff_stream, (void*)&data, 1, 0); + // furi_thread_flags_set(furi_thread_get_id(uart->thread), UHFUartWorkerWaitingDataFlag); + } +} + +UHFUart* uhf_uart_alloc() { + UHFUart* uart = (UHFUart*)malloc(sizeof(UHFUart)); + uart->bus = FuriHalBusUSART1; + uart->handle = furi_hal_serial_control_acquire(FuriHalSerialIdUsart); + // uart->rx_buff_stream = furi_stream_buffer_alloc(UHF_UART_RX_BUFFER_SIZE, 1); + uart->init_by_app = !furi_hal_bus_is_enabled(uart->bus); + uart->tick = UHF_UART_WAIT_TICK; + uart->baudrate = UHF_UART_DEFAULT_BAUDRATE; + // expansion_disable(); + if(uart->init_by_app) { + FURI_LOG_E("UHF_UART", "UHF UART INIT BY APP"); + furi_hal_serial_init(uart->handle, uart->baudrate); + } else { + FURI_LOG_E("UHF_UART", "UHF UART INIT BY HAL"); + } + uart->buffer = uhf_buffer_alloc(UHF_UART_RX_BUFFER_SIZE); + // uart->thread = furi_thread_alloc_ex("UHFUartWorker", UHF_UART_WORKER_STACK_SIZE, uhf_uart_worker_callback, uart); + // furi_thread_start(uart->thread); + furi_hal_serial_async_rx_start(uart->handle, uhf_uart_default_rx_callback, uart, false); + return uart; +} + +void uhf_uart_free(UHFUart* uart) { + furi_assert(uart); + // furi_assert(uart->thread); + // furi_thread_flags_set(furi_thread_get_id(uart->thread), UHFUartWorkerExitingFlag); + // furi_thread_join(uart->thread); + // furi_thread_free(uart->thread); + // furi_stream_buffer_free(uart->rx_buff_stream); + uhf_buffer_free(uart->buffer); + if(uart->init_by_app) { + furi_hal_serial_deinit(uart->handle); + } + furi_hal_serial_control_release(uart->handle); + free(uart); +} + +void uhf_uart_set_receive_byte_callback( + UHFUart* uart, + FuriHalSerialAsyncRxCallback callback, + void* ctx, + bool report_errors) { + furi_hal_serial_async_rx_start(uart->handle, callback, ctx, report_errors); +} + +void uhf_uart_send(UHFUart* uart, uint8_t* data, size_t size) { + furi_hal_serial_tx(uart->handle, data, size); +} + +void uhf_uart_send_wait(UHFUart* uart, uint8_t* data, size_t size) { + uhf_uart_send(uart, data, size); + furi_hal_serial_tx_wait_complete(uart->handle); + // furi_thread_flags_set(furi_thread_get_id(uart->thread), UHFUartWorkerWaitingDataFlag); +} + +void uhf_uart_set_baudrate(UHFUart* uart, uint32_t baudrate) { + furi_hal_serial_set_br(uart->handle, baudrate); + uart->baudrate = baudrate; +} + +bool uhf_uart_tick(UHFUart* uart) { + if(uart->tick > 0) { + uart->tick--; + } + return uart->tick == 0; +} + +void uhf_uart_tick_reset(UHFUart* uart) { + uart->tick = UHF_UART_WAIT_TICK; +} \ No newline at end of file diff --git a/applications/external/uhf_rfid/uhf_uart.h b/applications/external/uhf_rfid/uhf_uart.h new file mode 100644 index 00000000..47298cfd --- /dev/null +++ b/applications/external/uhf_rfid/uhf_uart.h @@ -0,0 +1,48 @@ +#pragma once +#include +// #include +#include +#include +#include "uhf_buffer.h" + +#define UHF_UART_RX_BUFFER_SIZE 250 +// #define UHF_UART_WORKER_STACK_SIZE 1 * 1024 +#define UHF_UART_DEFAULT_BAUDRATE 115200 +#define UHF_UART_FRAME_START 0xBB +#define UHF_UART_FRAME_END 0x7E +#define UHF_UART_WAIT_TICK 1000 + +typedef void (*CallbackFunction)(uint8_t* data, void* ctx); + +typedef enum { + UHFUartWorkerWaitingDataFlag = 1 << 0, + UHFUartWorkerExitingFlag = 1 << 2, +} UHFUartWorkerEventFlag; + +typedef struct { + FuriHalBus bus; + FuriHalSerialHandle* handle; + // FuriStreamBuffer *rx_buff_stream; + // FuriThread *thread; + CallbackFunction callback; + Buffer* buffer; + uint32_t baudrate; + bool init_by_app; + void* ctx; + volatile int tick; +} UHFUart; + +int32_t uhf_uart_worker_callback(void* ctx); + +UHFUart* uhf_uart_alloc(); +void uhf_uart_free(UHFUart* uart); +void uhf_uart_send(UHFUart* uart, uint8_t* data, size_t size); +void uhf_uart_send_wait(UHFUart* uart, uint8_t* data, size_t size); +void uhf_uart_set_receive_byte_callback( + UHFUart* uart, + FuriHalSerialAsyncRxCallback callback, + void* ctx, + bool report_errors); +void uhf_uart_set_baudrate(UHFUart* uart, uint32_t baudrate); +bool uhf_uart_tick(UHFUart* uart); +void uhf_uart_tick_reset(UHFUart* uart); diff --git a/applications/external/uhf_rfid/uhf_worker.c b/applications/external/uhf_rfid/uhf_worker.c index 75911463..1b695537 100644 --- a/applications/external/uhf_rfid/uhf_worker.c +++ b/applications/external/uhf_rfid/uhf_worker.c @@ -14,14 +14,14 @@ UHFWorkerEvent verify_module_connected(UHFWorker* uhf_worker) { UHFTag* send_polling_command(UHFWorker* uhf_worker) { // read epc bank UHFTag* uhf_tag = uhf_tag_alloc(); - while(true) { - M100ResponseType status = m100_single_poll(uhf_worker->module, uhf_tag); + M100ResponseType status; + do { if(uhf_worker->state == UHFWorkerStateStop) { uhf_tag_free(uhf_tag); return NULL; } - if(status == M100SuccessResponse) break; - } + status = m100_single_poll(uhf_worker->module, uhf_tag); + } while(status != M100SuccessResponse); return uhf_tag; } @@ -48,8 +48,8 @@ UHFWorkerEvent read_single_card(UHFWorker* uhf_worker) { if(uhf_tag == NULL) return UHFWorkerEventAborted; uhf_tag_wrapper_set_tag(uhf_worker->uhf_tag_wrapper, uhf_tag); // set select - if(m100_set_select(uhf_worker->module, uhf_tag) != M100SuccessResponse) - return UHFWorkerEventFail; + while(m100_set_select(uhf_worker->module, uhf_tag) != M100SuccessResponse) { + } // read tid UHFWorkerEvent event; event = read_bank_till_max_length(uhf_worker, uhf_tag, TIDBank); @@ -64,16 +64,20 @@ UHFWorkerEvent write_single_card(UHFWorker* uhf_worker) { UHFTag* uhf_tag_des = send_polling_command(uhf_worker); if(uhf_tag_des == NULL) return UHFWorkerEventAborted; UHFTag* uhf_tag_from = uhf_worker->uhf_tag_wrapper->uhf_tag; - if(m100_set_select(uhf_worker->module, uhf_tag_des) != M100SuccessResponse) - return UHFWorkerEventFail; + M100ResponseType rp_type; + do { + rp_type = m100_set_select(uhf_worker->module, uhf_tag_des); + if(uhf_worker->state == UHFWorkerStateStop) return UHFWorkerEventAborted; + if(rp_type == M100SuccessResponse) break; + } while(true); do { - M100ResponseType rp_type = m100_write_label_data_storage( + rp_type = m100_write_label_data_storage( uhf_worker->module, uhf_tag_from, uhf_tag_des, UserBank, 0, 0); if(uhf_worker->state == UHFWorkerStateStop) return UHFWorkerEventAborted; if(rp_type == M100SuccessResponse) break; } while(true); do { - M100ResponseType rp_type = m100_write_label_data_storage( + rp_type = m100_write_label_data_storage( uhf_worker->module, uhf_tag_from, uhf_tag_des, EPCBank, 0, 0); if(uhf_worker->state == UHFWorkerStateStop) return UHFWorkerEventAborted; if(rp_type == M100SuccessResponse) break; @@ -98,7 +102,8 @@ int32_t uhf_worker_task(void* ctx) { UHFWorker* uhf_worker_alloc() { UHFWorker* uhf_worker = (UHFWorker*)malloc(sizeof(UHFWorker)); - uhf_worker->thread = furi_thread_alloc_ex("UHFWorker", 8 * 1024, uhf_worker_task, uhf_worker); + uhf_worker->thread = + furi_thread_alloc_ex("UHFWorker", UHF_WORKER_STACK_SIZE, uhf_worker_task, uhf_worker); uhf_worker->module = m100_module_alloc(); uhf_worker->callback = NULL; uhf_worker->ctx = NULL; diff --git a/applications/external/uhf_rfid/uhf_worker.h b/applications/external/uhf_rfid/uhf_worker.h index b4f5aef1..09d1c14e 100644 --- a/applications/external/uhf_rfid/uhf_worker.h +++ b/applications/external/uhf_rfid/uhf_worker.h @@ -4,6 +4,8 @@ #include #include "uhf_module.h" +#define UHF_WORKER_STACK_SIZE 1 * 1024 + typedef enum { // Init states UHFWorkerStateNone, diff --git a/applications/external/wifi_marauder_companion/application.fam b/applications/external/wifi_marauder_companion/application.fam index 2973513e..7561fef2 100644 --- a/applications/external/wifi_marauder_companion/application.fam +++ b/applications/external/wifi_marauder_companion/application.fam @@ -1,7 +1,7 @@ App( appid="esp32_wifi_marauder", name="[ESP32] WiFi Marauder", - fap_version=(7, 0), + fap_version=(7, 1), apptype=FlipperAppType.EXTERNAL, entry_point="wifi_marauder_app", requires=["gui"], diff --git a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_console_output.c b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_console_output.c index 1f3c61b5..61d26035 100644 --- a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_console_output.c +++ b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_console_output.c @@ -8,7 +8,7 @@ char* _wifi_marauder_get_prefix_from_cmd(const char* command) { return prefix; } -bool _wifi_marauder_is_save_pcaps_enabled(WifiMarauderApp* app) { +bool _wifi_marauder_is_saving_enabled(WifiMarauderApp* app) { // If it is a script that contains a sniff function if(app->script != NULL) { if(app->script->save_pcap == WifiMarauderScriptBooleanFalse) { @@ -32,9 +32,12 @@ bool _wifi_marauder_is_save_pcaps_enabled(WifiMarauderApp* app) { if(!app->ok_to_save_pcaps) { return false; } - // If it is a sniff function + // If it is a sniff/wardrive/btwardrive/evilportal function return app->is_command && app->selected_tx_string && - strncmp("sniff", app->selected_tx_string, strlen("sniff")) == 0; + (strncmp("sniff", app->selected_tx_string, strlen("sniff")) == 0 || + strncmp("wardrive", app->selected_tx_string, strlen("wardrive")) == 0 || + strncmp("btwardrive", app->selected_tx_string, strlen("btwardrive")) == 0 || + strncmp("evilportal", app->selected_tx_string, strlen("evilportal")) == 0); } void wifi_marauder_console_output_handle_rx_data_cb(uint8_t* buf, size_t len, void* context) { @@ -118,33 +121,48 @@ void wifi_marauder_scene_console_output_on_enter(void* context) { // Get ready to send command if((app->is_command && app->selected_tx_string) || app->script) { - const char* prefix = - strlen(app->selected_tx_string) > 0 ? - _wifi_marauder_get_prefix_from_cmd(app->selected_tx_string) : // Function name - app->script->name; // Script name + char* prefix_buf = NULL; + if(strlen(app->selected_tx_string) > 0) { + prefix_buf = _wifi_marauder_get_prefix_from_cmd(app->selected_tx_string); + } + const char* prefix = prefix_buf ? prefix_buf : // Function name + app->script->name; // Script name // Create files *before* sending command // (it takes time to iterate through the directory) if(app->ok_to_save_logs) { - strcpy( - app->log_file_path, - sequential_file_resolve_path( - app->storage, MARAUDER_APP_FOLDER_LOGS, prefix, "log")); - if(storage_file_open( - app->log_file, app->log_file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) { - app->is_writing_log = true; + char* resolved_path = sequential_file_resolve_path( + app->storage, MARAUDER_APP_FOLDER_LOGS, prefix, "log"); + if(resolved_path != NULL) { + strcpy(app->log_file_path, resolved_path); + free(resolved_path); + if(storage_file_open( + app->log_file, app->log_file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) { + app->is_writing_log = true; + } else { + dialog_message_show_storage_error(app->dialogs, "Cannot open log file"); + } } else { dialog_message_show_storage_error(app->dialogs, "Cannot open log file"); } } - // If it is a sniff function or script, open the pcap file for recording - if(_wifi_marauder_is_save_pcaps_enabled(app)) { - if(sequential_file_open( - app->storage, app->capture_file, MARAUDER_APP_FOLDER_PCAPS, prefix, "pcap")) { + // If it is a sniff/wardrive/btwardrive/evilportal function or script, open the capture file for recording + if(_wifi_marauder_is_saving_enabled(app)) { + const char* folder = NULL; + const char* extension = NULL; + if(app->script || // Scripts only support sniff functions, but selected_tx_string is empty + strncmp("sniff", app->selected_tx_string, strlen("sniff")) == 0) { + folder = MARAUDER_APP_FOLDER_PCAPS; + extension = "pcap"; + } else { + folder = MARAUDER_APP_FOLDER_DUMPS; + extension = "txt"; + } + if(sequential_file_open(app->storage, app->capture_file, folder, prefix, extension)) { app->is_writing_pcap = true; } else { - dialog_message_show_storage_error(app->dialogs, "Cannot open pcap file"); + dialog_message_show_storage_error(app->dialogs, "Cannot open capture file"); } } @@ -185,6 +203,10 @@ void wifi_marauder_scene_console_output_on_enter(void* context) { app->script_worker = wifi_marauder_script_worker_alloc(app->uart); wifi_marauder_script_worker_start(app->script_worker, app->script); } + + if(prefix_buf) { + free(prefix_buf); + } } } diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app.c b/applications/external/wifi_marauder_companion/wifi_marauder_app.c index ae19865a..e60806cf 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app.c +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app.c @@ -101,13 +101,21 @@ void wifi_marauder_make_app_folder(WifiMarauderApp* app) { dialog_message_show_storage_error(app->dialogs, "Cannot create\npcaps folder"); } + if(!storage_simply_mkdir(app->storage, MARAUDER_APP_FOLDER_DUMPS)) { + dialog_message_show_storage_error(app->dialogs, "Cannot create\ndumps folder"); + } + if(!storage_simply_mkdir(app->storage, MARAUDER_APP_FOLDER_LOGS)) { - dialog_message_show_storage_error(app->dialogs, "Cannot create\npcaps folder"); + dialog_message_show_storage_error(app->dialogs, "Cannot create\nlogs folder"); } if(!storage_simply_mkdir(app->storage, MARAUDER_APP_FOLDER_SCRIPTS)) { dialog_message_show_storage_error(app->dialogs, "Cannot create\nscripts folder"); } + + if(!storage_simply_mkdir(app->storage, MARAUDER_APP_FOLDER_HTML)) { + dialog_message_show_storage_error(app->dialogs, "Cannot create\nhtml folder"); + } } void wifi_marauder_load_settings(WifiMarauderApp* app) { diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app.h b/applications/external/wifi_marauder_companion/wifi_marauder_app.h index 86f2c13f..d37b619e 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app.h @@ -4,7 +4,7 @@ extern "C" { #endif -#define WIFI_MARAUDER_APP_VERSION "v0.7.0" +#define WIFI_MARAUDER_APP_VERSION "v0.7.1" typedef struct WifiMarauderApp WifiMarauderApp; diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h b/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h index 9658dee4..a7d8d098 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h @@ -38,6 +38,7 @@ #define MARAUDER_APP_FOLDER EXT_PATH(MARAUDER_APP_FOLDER_USER) #define MARAUDER_APP_FOLDER_HTML MARAUDER_APP_FOLDER "/html" #define MARAUDER_APP_FOLDER_PCAPS MARAUDER_APP_FOLDER "/pcaps" +#define MARAUDER_APP_FOLDER_DUMPS MARAUDER_APP_FOLDER "/dumps" #define MARAUDER_APP_FOLDER_LOGS MARAUDER_APP_FOLDER "/logs" #define MARAUDER_APP_FOLDER_USER_PCAPS MARAUDER_APP_FOLDER_USER "/pcaps" #define MARAUDER_APP_FOLDER_USER_LOGS MARAUDER_APP_FOLDER_USER "/logs" diff --git a/applications/external/xremote/README.md b/applications/external/xremote/README.md index 7e9d29f6..ad5a2f21 100644 --- a/applications/external/xremote/README.md +++ b/applications/external/xremote/README.md @@ -1,4 +1,9 @@

Advanced IR Remote App for Flipper Device

+ +

+ Version 1.3 - Changelog +

+

XRemote

@@ -31,6 +36,7 @@ The application is compatible with standard `.ir` files. However, to ensure func Button name | Description ------------|------------------- `Power` | Power +`Eject` | Eject `Setup` | Setup/Settings `Input` | Input/Source `Menu` | Menu @@ -57,6 +63,46 @@ Button name | Description `Play` | Play `Stop` | Stop +## Alternative button names +In addition to the predefined names, `XRemote` uses alternative button names to make it as easy as possible to interact with different types of IR dumps. That means if a button with the appropriate name is not found in the file, the application will try to find the same button with alternative names. Ensure this feature is enabled in the application settings before you use it. + +The application stores and reads alternate names from the following file: +``` +SD Card/apps_data/flipper_xremote/alt_names.txt +``` + +If the `Alt-Names` option is enabled in the config and the file does not exist, it will be created automatically with default values during the application's startup. You can edit, add, or remove any button or alternate name values from this file. Button names must either have only the first uppercase or be entirely lowercase. As for alternate names, they are case-insensitive. The button can have one or several comma-separated alternate names. + +This is the default `alt_names.txt` file: + +``` +Filetype: XRemote Alt-Names +Version: 1 +# +Power: shutdown,off,on,standby +Setup: settings,config,cfg +Input: source,select +Menu: osd,gui +List: guide +Info: display +Mode: aspect,format +Back: return,exit +Ok: enter,select +Up: uparrow +Down: downarrow +Left: leftarrow +Right: rightarrow +Mute: silence,silent,unmute +Vol_up: vol+,volume+,volup,+ +Vol_dn: vol-,volume-,voldown,- +Ch_next: ch+,channel+,chup +Ch_prev: ch-,channel-,chdown +Next: next,skip,ffwd +Prev: prev,back,rewind,rew +Fast_fo: fastfwd,fastforward,ff +Fast_ba: fastback,fastrewind,fb +Play_pa: playpause,play,pause +``` ## Installation options @@ -73,8 +119,10 @@ Button name | Description - Use deploy script from this repository to build and run the application on the device: ```bash - ./deploy.sh --fw=/path/to/the/firmware + ./deploy.sh --fw=/path/to/the/firmware -b -l ``` + + Do not use `-l` (link) option of you are building the project directly from the `applications_user` directory of the firmware. 2. If you don't have the firmware or the Linux please refer to the [official documentation](https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/AppsOnSDCard.md) for build instructions. ## Progress @@ -89,6 +137,7 @@ Button name | Description - [x] Player buttons page - [x] Custom buttons page - [x] Edit custom layout + - [x] Alternative button names - [ ] Add or remove button - [ ] All buttons page - [x] Application settings @@ -98,6 +147,7 @@ Button name | Description - [x] Vertical/horizontal views - [x] IR command repeat count - [x] Exit button behavior + - [x] Enable/disable alt names ## Screens diff --git a/applications/external/xremote/application.fam b/applications/external/xremote/application.fam index 468375ab..2c199b7b 100644 --- a/applications/external/xremote/application.fam +++ b/applications/external/xremote/application.fam @@ -6,7 +6,7 @@ App( requires=["gui", "dialogs", "infrared"], stack_size=3 * 1024, order=1, - fap_version="1.2", + fap_version="1.3", fap_category="Infrarouge", fap_icon_assets="assets", fap_icon_assets_symbol="xc", diff --git a/applications/external/xremote/deploy.sh b/applications/external/xremote/deploy.sh index 0f1c47f8..79815a71 100644 --- a/applications/external/xremote/deploy.sh +++ b/applications/external/xremote/deploy.sh @@ -9,11 +9,39 @@ XCLR_DIM="\x1B[2m" XCLR_RED="\x1B[31m" XCLR_RESET="\x1B[0m\n" -# Parse firmware path from arguments if present +FBT_CMD="./fbt" +FBT_DBG="DEBUG=0" +FBT_ARGS="COMPACT=1 launch" + +BUILD_PROJECT=0 +LINK_PROJECT=0 +RUN_QFLIPPER=0 +BUILD_DONE=0 + for arg in "$@"; do if [[ $arg == --firmware=* || $arg == --fw=* ]]; then FLIPPER_FIRMWARE="${arg#*=}" fi + + if [[ $arg == "--build" || $arg == "-b" ]]; then + BUILD_PROJECT=1 + fi + + if [[ $arg == "--run" || $arg == "-r" ]]; then + RUN_PROJECT=1 + fi + + if [[ $arg == "--link" || $arg == "-l" ]]; then + LINK_PROJECT=1 + fi + + if [[ $arg == "--debug" || $arg == "-d" ]]; then + FBT_DBG="DEBUG=1" + fi + + if [[ $arg == "--sudo" || $arg == "-s" ]]; then + FBT_CMD="sudo ./fbt" + fi done # Check if FLIPPER_FIRMWARE variable is set @@ -41,21 +69,25 @@ XREMOTE_PROJ_NAME=$(basename "$XREMOTE_PROJ_PATH") FLIPPER_APPSRC="applications_user/$XREMOTE_PROJ_NAME" FLIPPER_USER_APP="$FLIPPER_FIRMWARE/$FLIPPER_APPSRC" -# Unlink existing user application first -[ -s $FLIPPER_USER_APP ] && rm -f $FLIPPER_USER_APP -ln -s $XREMOTE_PROJ_PATH $FLIPPER_FIRMWARE/applications_user +link_project() { + [ -s $FLIPPER_USER_APP ] && rm -f $FLIPPER_USER_APP + ln -s $XREMOTE_PROJ_PATH $FLIPPER_FIRMWARE/applications_user +} -# Build and deploy the project -cd $FLIPPER_FIRMWARE -DEPLOY_DONE=0 -sudo ./fbt COMPACT=1 DEBUG=0 launch APPSRC=$FLIPPER_APPSRC && DEPLOY_DONE=1 +build_project() { + cd $FLIPPER_FIRMWARE + $FBT_CMD $FBT_ARGS $FBT_DBG APPSRC=$FLIPPER_APPSRC && BUILD_DONE=1 +} -# Run qflipper command if asked -for arg in "$@"; do - if [[ $arg == "--run" || $arg == "-r" ]]; then - [ $DEPLOY_DONE -eq 1 ] && sudo qflipper +run_project() { + if [[ $BUILD_PROJECT -eq 0 || $BUILD_DONE -eq 1 ]]; then + qFlipper fi -done +} + +[ $LINK_PROJECT -eq 1 ] && link_project +[ $BUILD_PROJECT -eq 1 ] && build_project +[ $RUN_PROJECT -eq 1 ] && run_project # Return with success -exit 0 \ No newline at end of file +exit 0 diff --git a/applications/external/xremote/docs/README.md b/applications/external/xremote/docs/README.md index adeb034a..c4dc5466 100644 --- a/applications/external/xremote/docs/README.md +++ b/applications/external/xremote/docs/README.md @@ -48,3 +48,40 @@ Play_pa | Play/Pause Pause | Pause Play | Play Stop | Stop + +## Alternative button names + +In addition to the predefined names, XRemote uses alternative button names to make it as easy as possible to interact with different types of IR dumps. That means if a button with the appropriate name is not found in the file, the application will try to find the same button with alternative names. Ensure this feature is enabled in the application settings before you use it. + +The application stores and reads alternate names from the following file: +SD_Card/apps_data/flipper_xremote/alt_names.txt + +If the Alt-Names option is enabled in the config and the file does not exist, it will be created automatically with default values during the application's startup. You can edit, add, or remove any button or alternate name values from this file. Button names must either have only the first uppercase or be entirely lowercase. As for alternate names, they are case-insensitive. The button can have one or several comma-separated alternate names. + +## Default alternative names + +Button name | Alternative names +------------|------------------- +Power | shutdown,off,on,standby +Setup | settings,config,cfg +Input | source,select +Menu | osd,gui +List | guide +Info | display +Mode | aspect,format +Back | return,exit +Ok | enter,select +Up | uparrow +Down | downarrow +Left | leftarrow +Right | rightarrow +Mute | silence,silent,unmute +Vol_up | vol+,volume+,volup,+ +Vol_dn | vol-,volume-,voldown,- +Ch_next | ch+,channel+,chup +Ch_prev | ch-,channel-,chdown +Next | next,skip,ffwd +Prev | prev,back,rewind,rew +Fast_fo | fastfwd,fastforward,ff +Fast_ba | fastback,fastrewind,fb +Play_pa | playpause,play,pause \ No newline at end of file diff --git a/applications/external/xremote/docs/changelog.md b/applications/external/xremote/docs/changelog.md index 79bf05d5..5ba6d60c 100644 --- a/applications/external/xremote/docs/changelog.md +++ b/applications/external/xremote/docs/changelog.md @@ -1,3 +1,20 @@ +## v1.3 + +Alternative names + +- Implemented alternative names functionality +- Implemented case-insensitive button search +- Added Eject button support +- Fixed bugs and refactored code + +## v1.2 + +Bug fixing and performance improvements + +- Fixed build issues with new Flipper Zero SDK +- Fixed several crashes and refactored code +- Improved button search performance + ## v1.1 Custom layout and bug fixing diff --git a/applications/external/xremote/infrared/infrared_remote.c b/applications/external/xremote/infrared/infrared_remote.c index d9075cca..1563ef0c 100644 --- a/applications/external/xremote/infrared/infrared_remote.c +++ b/applications/external/xremote/infrared/infrared_remote.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -89,7 +91,9 @@ InfraredRemoteButton* infrared_remote_get_button(InfraredRemote* remote, size_t bool infrared_remote_find_button_by_name(InfraredRemote* remote, const char* name, size_t* index) { for(size_t i = 0; i < InfraredButtonArray_size(remote->buttons); i++) { InfraredRemoteButton* button = *InfraredButtonArray_get(remote->buttons, i); - if(!strcmp(infrared_remote_button_get_name(button), name)) { + FuriString* furi_name = infrared_remote_button_get_furi_name(button); + + if(button && !furi_string_cmpi_str(furi_name, name)) { *index = i; return true; } @@ -101,9 +105,8 @@ InfraredRemoteButton* infrared_remote_get_button_by_name(InfraredRemote* remote, const char* name) { for(size_t i = 0; i < InfraredButtonArray_size(remote->buttons); i++) { InfraredRemoteButton* button = *InfraredButtonArray_get(remote->buttons, i); - if(!strcmp(infrared_remote_button_get_name(button), name)) { - return button; - } + FuriString* furi_name = infrared_remote_button_get_furi_name(button); + if(button && !furi_string_cmpi_str(furi_name, name)) return button; } return NULL; } diff --git a/applications/external/xremote/infrared/infrared_remote_button.c b/applications/external/xremote/infrared/infrared_remote_button.c index 613761a2..80747c41 100644 --- a/applications/external/xremote/infrared/infrared_remote_button.c +++ b/applications/external/xremote/infrared/infrared_remote_button.c @@ -3,7 +3,9 @@ https://github.com/DarkFlippers/unleashed-firmware The original project is licensed under the GNU GPLv3 - No modifications were made to this file. + + Modifications made: + - Added function infrared_remote_button_get_furi_name() */ #include "infrared_remote_button.h" @@ -36,6 +38,10 @@ const char* infrared_remote_button_get_name(InfraredRemoteButton* button) { return furi_string_get_cstr(button->name); } +FuriString* infrared_remote_button_get_furi_name(InfraredRemoteButton* button) { + return button->name; +} + void infrared_remote_button_set_signal(InfraredRemoteButton* button, InfraredSignal* signal) { infrared_signal_set_signal(button->signal, signal); } diff --git a/applications/external/xremote/infrared/infrared_remote_button.h b/applications/external/xremote/infrared/infrared_remote_button.h index e55d28fd..158b623c 100644 --- a/applications/external/xremote/infrared/infrared_remote_button.h +++ b/applications/external/xremote/infrared/infrared_remote_button.h @@ -3,7 +3,9 @@ https://github.com/DarkFlippers/unleashed-firmware The original project is licensed under the GNU GPLv3 - No modifications were made to this file. + + Modifications made: + - Added function infrared_remote_button_get_furi_name() */ #pragma once @@ -17,6 +19,7 @@ void infrared_remote_button_free(InfraredRemoteButton* button); void infrared_remote_button_set_name(InfraredRemoteButton* button, const char* name); const char* infrared_remote_button_get_name(InfraredRemoteButton* button); +FuriString* infrared_remote_button_get_furi_name(InfraredRemoteButton* button); void infrared_remote_button_set_signal(InfraredRemoteButton* button, InfraredSignal* signal); InfraredSignal* infrared_remote_button_get_signal(InfraredRemoteButton* button); diff --git a/applications/external/xremote/screens/settings_menu.png b/applications/external/xremote/screens/settings_menu.png index c2f7a753..a038a56d 100644 Binary files a/applications/external/xremote/screens/settings_menu.png and b/applications/external/xremote/screens/settings_menu.png differ diff --git a/applications/external/xremote/views/xremote_common_view.c b/applications/external/xremote/views/xremote_common_view.c index 670bb1d8..1cc3d750 100644 --- a/applications/external/xremote/views/xremote_common_view.c +++ b/applications/external/xremote/views/xremote_common_view.c @@ -18,29 +18,30 @@ static const XRemoteButton g_buttons[XREMOTE_BUTTON_COUNT + 1] = { {0, XREMOTE_COMMAND_POWER}, {1, XREMOTE_COMMAND_SETUP}, {2, XREMOTE_COMMAND_INPUT}, - {3, XREMOTE_COMMAND_MENU}, - {4, XREMOTE_COMMAND_LIST}, - {5, XREMOTE_COMMAND_INFO}, - {6, XREMOTE_COMMAND_BACK}, - {7, XREMOTE_COMMAND_OK}, - {8, XREMOTE_COMMAND_UP}, - {9, XREMOTE_COMMAND_DOWN}, - {10, XREMOTE_COMMAND_LEFT}, - {11, XREMOTE_COMMAND_RIGHT}, - {12, XREMOTE_COMMAND_JUMP_FORWARD}, - {13, XREMOTE_COMMAND_JUMP_BACKWARD}, - {14, XREMOTE_COMMAND_FAST_FORWARD}, - {15, XREMOTE_COMMAND_FAST_BACKWARD}, - {16, XREMOTE_COMMAND_PLAY_PAUSE}, - {17, XREMOTE_COMMAND_PAUSE}, - {18, XREMOTE_COMMAND_PLAY}, - {19, XREMOTE_COMMAND_STOP}, - {20, XREMOTE_COMMAND_MUTE}, - {21, XREMOTE_COMMAND_MODE}, - {22, XREMOTE_COMMAND_VOL_UP}, - {23, XREMOTE_COMMAND_VOL_DOWN}, - {24, XREMOTE_COMMAND_NEXT_CHAN}, - {25, XREMOTE_COMMAND_PREV_CHAN}, + {3, XREMOTE_COMMAND_EJECT}, + {4, XREMOTE_COMMAND_MENU}, + {5, XREMOTE_COMMAND_LIST}, + {6, XREMOTE_COMMAND_INFO}, + {7, XREMOTE_COMMAND_BACK}, + {8, XREMOTE_COMMAND_OK}, + {9, XREMOTE_COMMAND_UP}, + {10, XREMOTE_COMMAND_DOWN}, + {11, XREMOTE_COMMAND_LEFT}, + {12, XREMOTE_COMMAND_RIGHT}, + {13, XREMOTE_COMMAND_JUMP_FORWARD}, + {14, XREMOTE_COMMAND_JUMP_BACKWARD}, + {15, XREMOTE_COMMAND_FAST_FORWARD}, + {16, XREMOTE_COMMAND_FAST_BACKWARD}, + {17, XREMOTE_COMMAND_PLAY_PAUSE}, + {18, XREMOTE_COMMAND_PAUSE}, + {19, XREMOTE_COMMAND_PLAY}, + {20, XREMOTE_COMMAND_STOP}, + {21, XREMOTE_COMMAND_MUTE}, + {22, XREMOTE_COMMAND_MODE}, + {23, XREMOTE_COMMAND_VOL_UP}, + {24, XREMOTE_COMMAND_VOL_DOWN}, + {25, XREMOTE_COMMAND_NEXT_CHAN}, + {26, XREMOTE_COMMAND_PREV_CHAN}, {-1, NULL}}; const char* xremote_button_get_name(int index) { @@ -90,9 +91,7 @@ XRemoteView* void xremote_view_clear_context(XRemoteView* rview) { furi_assert(rview); - if(rview->context && rview->on_clear) rview->on_clear(rview->context); - rview->context = NULL; } @@ -134,16 +133,101 @@ View* xremote_view_get_view(XRemoteView* rview) { return rview->view; } +static InfraredRemoteButton* + infrared_remote_get_button_by_alt_name(InfraredRemote* remote, const char* name, bool try_low) { + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); + FuriString* header = furi_string_alloc(); + + FURI_LOG_I(XREMOTE_APP_TAG, "loading alt_names file: \'%s\'", XREMOTE_ALT_NAMES); + + InfraredRemoteButton* button = NULL; + char key[XREMOTE_NAME_MAX] = {0}; + bool key_found = false; + uint32_t version = 0; + + do { + /* Open file and read the header */ + if(!flipper_format_buffered_file_open_existing(ff, XREMOTE_ALT_NAMES)) break; + if(!flipper_format_read_header(ff, header, &version)) break; + if(!furi_string_equal(header, "XRemote Alt-Names") || (version != 1)) break; + + FuriString* value = furi_string_alloc(); + key_found = flipper_format_read_string(ff, name, value); + + if(!key_found) { + if(!try_low) break; + size_t i; + + /* Convert name to lowercase and try again */ + for(i = 0; name[i] != '\0' && i < sizeof(key) - 1; i++) { + key[i] = tolower(name[i]); + } + + key[i] = '\0'; + break; + } + + size_t start = 0; + size_t posit = furi_string_search_str(value, ",", start); + + if(posit == FURI_STRING_FAILURE) { + const char* alt_name_cstr = furi_string_get_cstr(value); + button = infrared_remote_get_button_by_name(remote, alt_name_cstr); + } else { + FuriString* alt_name = furi_string_alloc(); + + while(posit != FURI_STRING_FAILURE) { + furi_string_set_n(alt_name, value, start, posit - start); + const char* alt_name_cstr = furi_string_get_cstr(alt_name); + button = infrared_remote_get_button_by_name(remote, alt_name_cstr); + + furi_string_reset(alt_name); + if(button != NULL) break; + + start = posit + 1; // Move to the next position + posit = furi_string_search_str(value, ",", start); + } + + if(posit == FURI_STRING_FAILURE && button == NULL) { + size_t str_len = furi_string_utf8_length(value); + furi_string_set_n(alt_name, value, start, str_len - start); + const char* alt_name_cstr = furi_string_get_cstr(alt_name); + button = infrared_remote_get_button_by_name(remote, alt_name_cstr); + } + + furi_string_free(alt_name); + } + + } while(false); + + furi_record_close(RECORD_STORAGE); + furi_string_free(header); + flipper_format_free(ff); + + if(!key_found && try_low) return infrared_remote_get_button_by_alt_name(remote, key, false); + + return button; +} + InfraredRemoteButton* xremote_view_get_button_by_name(XRemoteView* rview, const char* name) { xremote_app_assert(rview->context, NULL); + xremote_app_assert(rview->app_ctx, NULL); + + XRemoteAppSettings* settings = rview->app_ctx->app_settings; XRemoteAppButtons* buttons = (XRemoteAppButtons*)rview->context; - return infrared_remote_get_button_by_name(buttons->remote, name); + InfraredRemoteButton* button = infrared_remote_get_button_by_name(buttons->remote, name); + + if(button == NULL && settings->alt_names) + button = infrared_remote_get_button_by_alt_name(buttons->remote, name, true); + + return button; } bool xremote_view_press_button(XRemoteView* rview, InfraredRemoteButton* button) { xremote_app_assert(button, false); - XRemoteAppSettings* settings = rview->app_ctx->app_settings; + XRemoteAppSettings* settings = rview->app_ctx->app_settings; InfraredSignal* signal = infrared_remote_button_get_signal(button); xremote_app_assert(signal, false); diff --git a/applications/external/xremote/views/xremote_common_view.h b/applications/external/xremote/views/xremote_common_view.h index a8842906..356cc843 100644 --- a/applications/external/xremote/views/xremote_common_view.h +++ b/applications/external/xremote/views/xremote_common_view.h @@ -22,10 +22,11 @@ #include "../infrared/infrared_remote.h" -#define XREMOTE_BUTTON_COUNT 26 -#define XREMOTE_NAME_MAX 16 +#define XREMOTE_BUTTON_COUNT 27 +#define XREMOTE_NAME_MAX 32 #define XREMOTE_COMMAND_POWER "Power" +#define XREMOTE_COMMAND_EJECT "Eject" #define XREMOTE_COMMAND_SETUP "Setup" #define XREMOTE_COMMAND_INPUT "Input" #define XREMOTE_COMMAND_MENU "Menu" diff --git a/applications/external/xremote/xremote.h b/applications/external/xremote/xremote.h index f79b1a8b..6e0e799a 100644 --- a/applications/external/xremote/xremote.h +++ b/applications/external/xremote/xremote.h @@ -9,7 +9,7 @@ #include "xremote_app.h" #define XREMOTE_VERSION_MAJ 1 -#define XREMOTE_VERSION_MIN 2 +#define XREMOTE_VERSION_MIN 3 #define XREMOTE_BUILD_NUMBER 0 /* Returns FAP_VERSION + XREMOTE_BUILD_NUMBER */ diff --git a/applications/external/xremote/xremote_app.c b/applications/external/xremote/xremote_app.c index 2f0908e4..84604efa 100644 --- a/applications/external/xremote/xremote_app.c +++ b/applications/external/xremote/xremote_app.c @@ -13,7 +13,6 @@ ////////////////////////////////////////////////////////////////////////////// #define XREMOTE_APP_SETTINGS APP_DATA_PATH("xremote.cfg") -#define TAG "XRemoteApp" #define XREMOTE_ORIENTATION_TEXT_HORIZONTAL "Horizontal" #define XREMOTE_ORIENTATION_TEXT_VERTICAL "Vertical" @@ -44,6 +43,10 @@ const char* xremote_app_get_exit_str(XRemoteAppExit exit_behavior) { return exit_behavior == XRemoteAppExitPress ? "Press" : "Hold"; } +const char* xremote_app_get_alt_names_str(uint8_t alt_names_index) { + return alt_names_index ? "On" : "Off"; +} + const char* xremote_app_get_orientation_str(ViewOrientation view_orientation) { return view_orientation == ViewOrientationHorizontal ? "Horizontal" : "Vertical"; } @@ -145,6 +148,49 @@ bool xremote_app_extension_store(XRemoteAppButtons* buttons, FuriString* path) { return success; } +bool xremote_app_alt_names_check_and_init() { + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* ff = flipper_format_file_alloc(storage); + bool success = false; + + do { + if(!flipper_format_file_open_new(ff, XREMOTE_ALT_NAMES)) break; + if(!flipper_format_write_header_cstr(ff, "XRemote Alt-Names", 1)) break; + if(!flipper_format_write_comment_cstr(ff, "")) break; + + if(!flipper_format_write_string_cstr(ff, "Power", "shutdown,off,on,standby")) break; + if(!flipper_format_write_string_cstr(ff, "Setup", "settings,config,cfg")) break; + if(!flipper_format_write_string_cstr(ff, "Input", "source,select")) break; + if(!flipper_format_write_string_cstr(ff, "Menu", "osd,gui")) break; + if(!flipper_format_write_string_cstr(ff, "List", "guide")) break; + if(!flipper_format_write_string_cstr(ff, "Info", "display")) break; + if(!flipper_format_write_string_cstr(ff, "Mode", "aspect,format")) break; + if(!flipper_format_write_string_cstr(ff, "Back", "return,exit")) break; + if(!flipper_format_write_string_cstr(ff, "Ok", "enter,select")) break; + if(!flipper_format_write_string_cstr(ff, "Up", "uparrow")) break; + if(!flipper_format_write_string_cstr(ff, "Down", "downarrow")) break; + if(!flipper_format_write_string_cstr(ff, "Left", "leftarrow")) break; + if(!flipper_format_write_string_cstr(ff, "Right", "rightarrow")) break; + if(!flipper_format_write_string_cstr(ff, "Mute", "silence,silent,unmute")) break; + if(!flipper_format_write_string_cstr(ff, "Vol_up", "vol+,volume+,volup,+")) break; + if(!flipper_format_write_string_cstr(ff, "Vol_dn", "vol-,volume-,voldown,-")) break; + if(!flipper_format_write_string_cstr(ff, "Ch_next", "ch+,channel+,chup")) break; + if(!flipper_format_write_string_cstr(ff, "Ch_prev", "ch-,channel-,chdown")) break; + if(!flipper_format_write_string_cstr(ff, "Next", "next,skip,ffwd")) break; + if(!flipper_format_write_string_cstr(ff, "Prev", "prev,back,rewind,rew")) break; + if(!flipper_format_write_string_cstr(ff, "Fast_fo", "fastfwd,fastforward,ff")) break; + if(!flipper_format_write_string_cstr(ff, "Fast_ba", "fastback,fastrewind,fb")) break; + if(!flipper_format_write_string_cstr(ff, "Play_pa", "playpause,play,pause")) break; + + success = true; + } while(false); + + furi_record_close(RECORD_STORAGE); + flipper_format_free(ff); + + return success; +} + void xremote_app_buttons_free(XRemoteAppButtons* buttons) { xremote_app_assert_void(buttons); infrared_remote_free(buttons->remote); @@ -183,7 +229,7 @@ XRemoteAppButtons* xremote_app_buttons_alloc() { XRemoteAppButtons* xremote_app_buttons_load(XRemoteAppContext* app_ctx) { /* Show file selection dialog (returns selected file path with app_ctx->file_path) */ - if(!xremote_app_browser_select_file(app_ctx, XREMOTE_APP_EXTENSION)) return NULL; + if(!xremote_app_context_select_file(app_ctx, XREMOTE_APP_EXTENSION)) return NULL; XRemoteAppButtons* buttons = xremote_app_buttons_alloc(); buttons->app_ctx = app_ctx; @@ -207,6 +253,7 @@ XRemoteAppSettings* xremote_app_settings_alloc() { settings->orientation = ViewOrientationHorizontal; settings->exit_behavior = XRemoteAppExitPress; settings->repeat_count = 2; + settings->alt_names = 1; return settings; } @@ -219,7 +266,7 @@ bool xremote_app_settings_store(XRemoteAppSettings* settings) { Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* ff = flipper_format_file_alloc(storage); - FURI_LOG_I(TAG, "store config file: \'%s\'", XREMOTE_APP_SETTINGS); + FURI_LOG_I(XREMOTE_APP_TAG, "store config file: \'%s\'", XREMOTE_APP_SETTINGS); bool success = false; do { @@ -238,6 +285,9 @@ bool xremote_app_settings_store(XRemoteAppSettings* settings) { value = settings->repeat_count; if(!flipper_format_write_uint32(ff, "repeat", &value, 1)) break; + value = settings->alt_names; + if(!flipper_format_write_uint32(ff, "altNames", &value, 1)) break; + success = true; } while(false); @@ -252,7 +302,7 @@ bool xremote_app_settings_load(XRemoteAppSettings* settings) { FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); FuriString* header = furi_string_alloc(); - FURI_LOG_I(TAG, "load config file: \'%s\'", XREMOTE_APP_SETTINGS); + FURI_LOG_I(XREMOTE_APP_TAG, "load config file: \'%s\'", XREMOTE_APP_SETTINGS); uint32_t version = 0; uint32_t value = 0; bool success = false; @@ -273,6 +323,9 @@ bool xremote_app_settings_load(XRemoteAppSettings* settings) { if(!flipper_format_read_uint32(ff, "repeat", &value, 1)) break; settings->repeat_count = value; + if(!flipper_format_read_uint32(ff, "altNames", &value, 1)) break; + settings->alt_names = value; + success = true; } while(false); @@ -300,6 +353,9 @@ XRemoteAppContext* xremote_app_context_alloc(void* arg) { ctx->app_settings = xremote_app_settings_alloc(); xremote_app_settings_load(ctx->app_settings); + /* Initialize alternative names */ + if(ctx->app_settings->alt_names) xremote_app_alt_names_check_and_init(); + /* Allocate and setup view dispatcher */ ctx->view_dispatcher = view_dispatcher_alloc(); view_dispatcher_enable_queue(ctx->view_dispatcher); @@ -326,24 +382,23 @@ void xremote_app_context_free(XRemoteAppContext* ctx) { free(ctx); } -bool xremote_app_browser_select_file(XRemoteAppContext* app_ctx, const char* extension) { +bool xremote_app_browser_select_file(FuriString** file_path, const char* extension) { DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); Storage* storage = furi_record_open(RECORD_STORAGE); storage_simply_mkdir(storage, XREMOTE_APP_FOLDER); - if(app_ctx->file_path == NULL) { - app_ctx->file_path = furi_string_alloc(); - furi_string_set(app_ctx->file_path, XREMOTE_APP_FOLDER); + if(*file_path == NULL) { + *file_path = furi_string_alloc(); + furi_string_set(*file_path, XREMOTE_APP_FOLDER); } /* Open file browser (view and dialogs are managed by the browser itself) */ DialogsFileBrowserOptions browser; dialog_file_browser_set_basic_options(&browser, extension, &I_IR_Icon_10x10); browser.base_path = XREMOTE_APP_FOLDER; - FuriString* path = app_ctx->file_path; /* Show file selection dialog (returns selected file path with file_path) */ - bool status = dialog_file_browser_show(dialogs, path, path, &browser); + bool status = dialog_file_browser_show(dialogs, *file_path, *file_path, &browser); /* Cleanup file loading context */ furi_record_close(RECORD_STORAGE); @@ -352,6 +407,11 @@ bool xremote_app_browser_select_file(XRemoteAppContext* app_ctx, const char* ext return status; } +bool xremote_app_context_select_file(XRemoteAppContext* app_ctx, const char* extension) { + if(app_ctx == NULL) return false; + return xremote_app_browser_select_file(&app_ctx->file_path, extension); +} + const char* xremote_app_context_get_exit_str(XRemoteAppContext* app_ctx) { XRemoteAppExit exit_behavior = app_ctx->app_settings->exit_behavior; return exit_behavior == XRemoteAppExitHold ? "Hold to exit" : "Press to exit"; diff --git a/applications/external/xremote/xremote_app.h b/applications/external/xremote/xremote_app.h index dbd64325..426c0a87 100644 --- a/applications/external/xremote/xremote_app.h +++ b/applications/external/xremote/xremote_app.h @@ -34,9 +34,13 @@ // XRemote generic functions and definitions ////////////////////////////////////////////////////////////////////////////// +#define XREMOTE_APP_TEXT_MAX 128 #define XREMOTE_APP_EXTENSION ".ir" +#define XREMOTE_APP_TAG "XRemoteApp" + #define XREMOTE_APP_FOLDER ANY_PATH("infrared") -#define XREMOTE_APP_TEXT_MAX 128 +#define XREMOTE_APP_SETTINGS APP_DATA_PATH("xremote.cfg") +#define XREMOTE_ALT_NAMES APP_DATA_PATH("alt_names.txt") #define xremote_app_assert_void(cond) \ if(!cond) return @@ -51,6 +55,7 @@ uint32_t xremote_app_get_exit_index(XRemoteAppExit exit_behavior); ViewOrientation xremote_app_get_orientation(uint8_t orientation_index); const char* xremote_app_get_orientation_str(ViewOrientation view_orientation); +const char* xremote_app_get_alt_names_str(uint8_t alt_names_index); uint32_t xremote_app_get_orientation_index(ViewOrientation view_orientation); ////////////////////////////////////////////////////////////////////////////// @@ -61,6 +66,7 @@ typedef struct { ViewOrientation orientation; XRemoteAppExit exit_behavior; uint32_t repeat_count; + uint32_t alt_names; } XRemoteAppSettings; XRemoteAppSettings* xremote_app_settings_alloc(); @@ -89,7 +95,8 @@ const char* xremote_app_context_get_exit_str(XRemoteAppContext* app_ctx); void xremote_app_context_notify_led(XRemoteAppContext* app_ctx); void xremote_app_notification_blink(NotificationApp* notifications); bool xremote_app_send_signal(XRemoteAppContext* app_ctx, InfraredSignal* signal); -bool xremote_app_browser_select_file(XRemoteAppContext* app_ctx, const char* extension); +bool xremote_app_context_select_file(XRemoteAppContext* app_ctx, const char* extension); +bool xremote_app_browser_select_file(FuriString** file_path, const char* extension); ////////////////////////////////////////////////////////////////////////////// // XRemote buttons and custom button pairs @@ -116,6 +123,7 @@ XRemoteAppButtons* xremote_app_buttons_load(XRemoteAppContext* app_ctx); bool xremote_app_extension_store(XRemoteAppButtons* buttons, FuriString* path); bool xremote_app_extension_load(XRemoteAppButtons* buttons, FuriString* path); +bool xremote_app_alt_names_check_and_init(); ////////////////////////////////////////////////////////////////////////////// // XRemote application factory diff --git a/applications/external/xremote/xremote_settings.c b/applications/external/xremote/xremote_settings.c index 3af88a58..7908c917 100644 --- a/applications/external/xremote/xremote_settings.c +++ b/applications/external/xremote/xremote_settings.c @@ -22,6 +22,9 @@ typedef struct { #define XREMOTE_REPEAT_TEXT "IR Msg Repeat" #define XREMOTE_REPEAT_MAX 128 +#define XREMOTE_ALT_NAMES_TEXT "Alt Names" +#define XREMOTE_ALT_NAMES_MAX 2 + static uint32_t xremote_settings_view_exit_callback(void* context) { UNUSED(context); return XRemoteViewSubmenu; @@ -63,6 +66,18 @@ static void infrared_settings_exit_changed(VariableItem* item) { xremote_app_settings_store(settings); } +static void infrared_settings_alt_names_changed(VariableItem* item) { + XRemoteSettingsContext* ctx = variable_item_get_context(item); + XRemoteAppSettings* settings = ctx->app_ctx->app_settings; + + settings->alt_names = variable_item_get_current_value_index(item); + const char* alt_names_str = xremote_app_get_alt_names_str(settings->alt_names); + + if(settings->alt_names) xremote_app_alt_names_check_and_init(); + variable_item_set_current_value_text(item, alt_names_str); + xremote_app_settings_store(settings); +} + static XRemoteSettingsContext* xremote_settings_context_alloc(XRemoteAppContext* app_ctx) { XRemoteSettingsContext* context = malloc(sizeof(XRemoteSettingsContext)); XRemoteAppSettings* settings = app_ctx->app_settings; @@ -121,6 +136,18 @@ static XRemoteSettingsContext* xremote_settings_context_alloc(XRemoteAppContext* variable_item_set_current_value_index(item, exit_index); variable_item_set_current_value_text(item, exit_str); + /* Add exit behavior to variable item list */ + item = variable_item_list_add( + context->item_list, + XREMOTE_ALT_NAMES_TEXT, + XREMOTE_ALT_NAMES_MAX, + infrared_settings_alt_names_changed, + context); + + /* Set exit behavior item index and string */ + variable_item_set_current_value_index(item, settings->alt_names); + variable_item_set_current_value_text(item, xremote_app_get_alt_names_str(settings->alt_names)); + return context; }