1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-13 05:06:30 +04:00

Merge remote-tracking branch 'upstream/dev' into feat/unirf-protocols

This commit is contained in:
Daniel
2022-08-18 01:46:57 +02:00
177 changed files with 3247 additions and 1397 deletions

View File

@@ -1,7 +1,10 @@
### New changes ### New changes
* Fix qFlipper and other apps causes flipper crash while trying to interact with files - see commit `b2bd13` * Wifi Marauder app update (by @0xchocolate)
* NRF24 Sniffer update * Updated Universal remote assets (by @Amec0e)
* Other fixes * Fixed music player
* Fixed typos in subghz encoders
* OFW: New NFC info screens
* OFW: U2F fixes
**Note: Prefer installing using web updater or by self update package, all needed assets will be installed** **Note: Prefer installing using web updater or by self update package, all needed assets will be installed**

View File

@@ -83,6 +83,8 @@ See changelog in releases for latest updates!
## [- BadUSB: how to add new keyboard layouts](https://github.com/dummy-decoy/flipperzero_badusb_kl) ## [- BadUSB: how to add new keyboard layouts](https://github.com/dummy-decoy/flipperzero_badusb_kl)
## [- How to change Flipper name](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/CustomFlipperName.md)
### **Plugins** ### **Plugins**
## [- Configure UniversalRF Remix App](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/UniRFRemix.md) ## [- Configure UniversalRF Remix App](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/UniRFRemix.md)
@@ -121,7 +123,7 @@ See changelog in releases for latest updates!
# Where I can find IR, SubGhz, ... files, DBs, and other stuff? # Where I can find IR, SubGhz, ... files, DBs, and other stuff?
## [Awesome Flipper Zero - Github](https://github.com/djsime1/awesome-flipperzero) ## [Awesome Flipper Zero - Github](https://github.com/djsime1/awesome-flipperzero)
## [UberGuidoZ Playground - Large collection of files - Github](https://github.com/UberGuidoZ/Flipper) ## [UberGuidoZ Playground - Large collection of files - Github](https://github.com/UberGuidoZ/Flipper)
## [CAME, NICE, PT-2240, PT-2262 - SubGHz fixed code bruteforce](https://github.com/tobiabocchi/flipperzero-bruteforce) ## [CAME-12bit, NICE-12bit, Linear-10bit, PT-2240 - SubGHz fixed code bruteforce](https://github.com/tobiabocchi/flipperzero-bruteforce)
<br> <br>
<br> <br>

View File

@@ -5,6 +5,7 @@
#include <gui/modules/empty_screen.h> #include <gui/modules/empty_screen.h>
#include <m-string.h> #include <m-string.h>
#include <furi_hal_version.h> #include <furi_hal_version.h>
#include <furi_hal_region.h>
#include <furi_hal_bt.h> #include <furi_hal_bt.h>
typedef DialogMessageButton (*AboutDialogScreen)(DialogsApp* dialogs, DialogMessage* message); typedef DialogMessageButton (*AboutDialogScreen)(DialogsApp* dialogs, DialogMessage* message);
@@ -114,12 +115,13 @@ static DialogMessageButton hw_version_screen(DialogsApp* dialogs, DialogMessage*
string_cat_printf( string_cat_printf(
buffer, buffer,
"%d.F%dB%dC%d %s %s\n", "%d.F%dB%dC%d %s:%s %s\n",
furi_hal_version_get_hw_version(), furi_hal_version_get_hw_version(),
furi_hal_version_get_hw_target(), furi_hal_version_get_hw_target(),
furi_hal_version_get_hw_body(), furi_hal_version_get_hw_body(),
furi_hal_version_get_hw_connect(), furi_hal_version_get_hw_connect(),
furi_hal_version_get_hw_region_name(), furi_hal_version_get_hw_region_name(),
furi_hal_region_get_name(),
my_name ? my_name : "Unknown"); my_name ? my_name : "Unknown");
string_cat_printf(buffer, "Serial Number:\n"); string_cat_printf(buffer, "Serial Number:\n");

View File

@@ -32,14 +32,14 @@ void AccessorApp::run(void) {
} }
AccessorApp::AccessorApp() { AccessorApp::AccessorApp() {
notification = static_cast<NotificationApp*>(furi_record_open("notification")); notification = static_cast<NotificationApp*>(furi_record_open(RECORD_NOTIFICATION));
onewire_host = onewire_host_alloc(); onewire_host = onewire_host_alloc();
furi_hal_power_enable_otg(); furi_hal_power_enable_otg();
} }
AccessorApp::~AccessorApp() { AccessorApp::~AccessorApp() {
furi_hal_power_disable_otg(); furi_hal_power_disable_otg();
furi_record_close("notification"); furi_record_close(RECORD_NOTIFICATION);
onewire_host_free(onewire_host); onewire_host_free(onewire_host);
} }

View File

@@ -15,7 +15,7 @@ AccessorAppViewManager::AccessorAppViewManager() {
popup = popup_alloc(); popup = popup_alloc();
add_view(ViewType::Popup, popup_get_view(popup)); add_view(ViewType::Popup, popup_get_view(popup));
gui = static_cast<Gui*>(furi_record_open("gui")); gui = static_cast<Gui*>(furi_record_open(RECORD_GUI));
view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen); view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen);
// set previous view callback for all views // set previous view callback for all views
@@ -31,6 +31,7 @@ AccessorAppViewManager::~AccessorAppViewManager() {
view_dispatcher, static_cast<uint32_t>(AccessorAppViewManager::ViewType::Popup)); view_dispatcher, static_cast<uint32_t>(AccessorAppViewManager::ViewType::Popup));
// free view modules // free view modules
furi_record_close(RECORD_GUI);
submenu_free(submenu); submenu_free(submenu);
popup_free(popup); popup_free(popup);

View File

@@ -18,6 +18,8 @@ typedef struct {
typedef void (*FlipperOnStartHook)(void); typedef void (*FlipperOnStartHook)(void);
extern const char* FLIPPER_AUTORUN_APP_NAME;
/* Services list /* Services list
* Spawned on startup * Spawned on startup
*/ */

View File

@@ -64,7 +64,7 @@ uint16_t archive_favorites_count(void* context) {
break; break;
} }
if(!string_size(buffer)) { if(!string_size(buffer)) {
break; continue; // Skip empty lines
} }
++lines; ++lines;
} }
@@ -93,7 +93,7 @@ static bool archive_favourites_rescan() {
break; break;
} }
if(!string_size(buffer)) { if(!string_size(buffer)) {
break; continue;
} }
if(string_search(buffer, "/app:") == 0) { if(string_search(buffer, "/app:") == 0) {
@@ -152,7 +152,7 @@ bool archive_favorites_read(void* context) {
break; break;
} }
if(!string_size(buffer)) { if(!string_size(buffer)) {
break; continue;
} }
if(string_search(buffer, "/app:") == 0) { if(string_search(buffer, "/app:") == 0) {
@@ -215,7 +215,7 @@ bool archive_favorites_delete(const char* format, ...) {
break; break;
} }
if(!string_size(buffer)) { if(!string_size(buffer)) {
break; continue;
} }
if(string_search(buffer, filename)) { if(string_search(buffer, filename)) {
@@ -259,7 +259,7 @@ bool archive_is_favorite(const char* format, ...) {
break; break;
} }
if(!string_size(buffer)) { if(!string_size(buffer)) {
break; continue;
} }
if(!string_search(buffer, filename)) { if(!string_search(buffer, filename)) {
found = true; found = true;
@@ -299,7 +299,7 @@ bool archive_favorites_rename(const char* src, const char* dst) {
break; break;
} }
if(!string_size(buffer)) { if(!string_size(buffer)) {
break; continue;
} }
archive_file_append( archive_file_append(

View File

@@ -423,7 +423,7 @@ int32_t barcode_UPCA_generator_app(void* p) {
view_port_input_callback_set(view_port, input_callback, event_queue); view_port_input_callback_set(view_port, input_callback, event_queue);
// Open GUI and register view_port // Open GUI and register view_port
Gui* gui = furi_record_open("gui"); Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen); gui_add_view_port(gui, view_port, GuiLayerFullscreen);
PluginEvent event; PluginEvent event;
@@ -537,7 +537,7 @@ int32_t barcode_UPCA_generator_app(void* p) {
view_port_enabled_set(view_port, false); view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port); gui_remove_view_port(gui, view_port);
furi_record_close("gui"); furi_record_close(RECORD_GUI);
view_port_free(view_port); view_port_free(view_port);
furi_message_queue_free(event_queue); furi_message_queue_free(event_queue);

View File

@@ -15,7 +15,7 @@
void cli_command_device_info_callback(const char* key, const char* value, bool last, void* context) { void cli_command_device_info_callback(const char* key, const char* value, bool last, void* context) {
UNUSED(context); UNUSED(context);
UNUSED(last); UNUSED(last);
printf("%-24s: %s\r\n", key, value); printf("%-30s: %s\r\n", key, value);
} }
/* /*

View File

@@ -96,7 +96,7 @@ int32_t clock_app(void* p) {
furi_timer_start(timer, furi_kernel_get_tick_frequency()); furi_timer_start(timer, furi_kernel_get_tick_frequency());
// Open GUI and register view_port // Open GUI and register view_port
Gui* gui = furi_record_open("gui"); Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen); gui_add_view_port(gui, view_port, GuiLayerFullscreen);
// Main loop // Main loop
@@ -137,7 +137,7 @@ int32_t clock_app(void* p) {
furi_timer_free(timer); furi_timer_free(timer);
view_port_enabled_set(view_port, false); view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port); gui_remove_view_port(gui, view_port);
furi_record_close("gui"); furi_record_close(RECORD_GUI);
view_port_free(view_port); view_port_free(view_port);
furi_message_queue_free(event_queue); furi_message_queue_free(event_queue);
delete_mutex(&state_mutex); delete_mutex(&state_mutex);

View File

@@ -333,7 +333,7 @@ int32_t dec_hex_converter_app(void* p) {
view_port_input_callback_set(view_port, dec_hex_converter_input_callback, event_queue); view_port_input_callback_set(view_port, dec_hex_converter_input_callback, event_queue);
// open GUI and register view_port // open GUI and register view_port
Gui* gui = furi_record_open("gui"); Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen); gui_add_view_port(gui, view_port, GuiLayerFullscreen);
dec_hex_converter_init(dec_hex_converter_state); dec_hex_converter_init(dec_hex_converter_state);
@@ -394,7 +394,7 @@ int32_t dec_hex_converter_app(void* p) {
view_port_enabled_set(view_port, false); view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port); gui_remove_view_port(gui, view_port);
furi_record_close("gui"); furi_record_close(RECORD_GUI);
view_port_free(view_port); view_port_free(view_port);
furi_message_queue_free(event_queue); furi_message_queue_free(event_queue);
delete_mutex(&state_mutex); delete_mutex(&state_mutex);

View File

@@ -36,12 +36,13 @@ void desktop_debug_render(Canvas* canvas, void* model) {
snprintf( snprintf(
buffer, buffer,
sizeof(buffer), sizeof(buffer),
"%d.F%dB%dC%d %s %s", "%d.F%dB%dC%d %s:%s %s",
furi_hal_version_get_hw_version(), furi_hal_version_get_hw_version(),
furi_hal_version_get_hw_target(), furi_hal_version_get_hw_target(),
furi_hal_version_get_hw_body(), furi_hal_version_get_hw_body(),
furi_hal_version_get_hw_connect(), furi_hal_version_get_hw_connect(),
furi_hal_version_get_hw_region_name(), furi_hal_version_get_hw_region_name(),
furi_hal_region_get_name(),
my_name ? my_name : "Unknown"); my_name ? my_name : "Unknown");
canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer); canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer);

View File

@@ -377,7 +377,7 @@ int32_t esp8266_deauth_app(void* p) {
view_port_input_callback_set(view_port, esp8266_deauth_module_input_callback, event_queue); view_port_input_callback_set(view_port, esp8266_deauth_module_input_callback, event_queue);
// Open GUI and register view_port // Open GUI and register view_port
Gui* gui = furi_record_open("gui"); Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen); gui_add_view_port(gui, view_port, GuiLayerFullscreen);
//notification_message(app->notification, &sequence_set_only_blue_255); //notification_message(app->notification, &sequence_set_only_blue_255);
@@ -511,7 +511,7 @@ int32_t esp8266_deauth_app(void* p) {
gui_remove_view_port(gui, view_port); gui_remove_view_port(gui, view_port);
// Close gui record // Close gui record
furi_record_close("gui"); furi_record_close(RECORD_GUI);
furi_record_close("notification"); furi_record_close("notification");
app->m_gui = NULL; app->m_gui = NULL;

View File

@@ -162,6 +162,19 @@ void widget_add_text_box_element(
widget_add_element(widget, text_box_element); widget_add_element(widget, text_box_element);
} }
void widget_add_text_scroll_element(
Widget* widget,
uint8_t x,
uint8_t y,
uint8_t width,
uint8_t height,
const char* text) {
furi_assert(widget);
WidgetElement* text_scroll_element =
widget_element_text_scroll_create(x, y, width, height, text);
widget_add_element(widget, text_scroll_element);
}
void widget_add_button_element( void widget_add_button_element(
Widget* widget, Widget* widget,
GuiButtonType button_type, GuiButtonType button_type,

View File

@@ -105,6 +105,27 @@ void widget_add_text_box_element(
const char* text, const char* text,
bool strip_to_dots); bool strip_to_dots);
/** Add Text Scroll Element
*
* @param widget Widget instance
* @param x x coordinate
* @param y y coordinate
* @param width width to fit text
* @param height height to fit text
* @param[in] text Formatted text. Default format: align left, Secondary font.
* The following formats are available:
* "\e#Bold text" - sets bold font before until next '\n' symbol
* "\ecBold text" - sets center horizontal align before until next '\n' symbol
* "\erBold text" - sets right horizontal align before until next '\n' symbol
*/
void widget_add_text_scroll_element(
Widget* widget,
uint8_t x,
uint8_t y,
uint8_t width,
uint8_t height,
const char* text);
/** Add Button Element /** Add Button Element
* *
* @param widget Widget instance * @param widget Widget instance

View File

@@ -29,6 +29,7 @@ struct WidgetElement {
// generic model holder // generic model holder
void* model; void* model;
FuriMutex* model_mutex;
// pointer to widget that hold our element // pointer to widget that hold our element
Widget* parent; Widget* parent;
@@ -80,3 +81,10 @@ WidgetElement* widget_element_frame_create(
uint8_t width, uint8_t width,
uint8_t height, uint8_t height,
uint8_t radius); uint8_t radius);
WidgetElement* widget_element_text_scroll_create(
uint8_t x,
uint8_t y,
uint8_t width,
uint8_t height,
const char* text);

View File

@@ -0,0 +1,245 @@
#include "widget_element_i.h"
#include <m-string.h>
#include <gui/elements.h>
#include <m-array.h>
#define WIDGET_ELEMENT_TEXT_SCROLL_BAR_OFFSET (4)
typedef struct {
Font font;
Align horizontal;
string_t text;
} TextScrollLineArray;
ARRAY_DEF(TextScrollLineArray, TextScrollLineArray, M_POD_OPLIST)
typedef struct {
TextScrollLineArray_t line_array;
uint8_t x;
uint8_t y;
uint8_t width;
uint8_t height;
string_t text;
uint8_t scroll_pos_total;
uint8_t scroll_pos_current;
bool text_formatted;
} WidgetElementTextScrollModel;
static bool
widget_element_text_scroll_process_ctrl_symbols(TextScrollLineArray* line, string_t text) {
bool processed = false;
do {
if(string_get_char(text, 0) != '\e') break;
char ctrl_symbol = string_get_char(text, 1);
if(ctrl_symbol == 'c') {
line->horizontal = AlignCenter;
} else if(ctrl_symbol == 'r') {
line->horizontal = AlignRight;
} else if(ctrl_symbol == '#') {
line->font = FontPrimary;
}
string_right(text, 2);
processed = true;
} while(false);
return processed;
}
void widget_element_text_scroll_add_line(WidgetElement* element, TextScrollLineArray* line) {
WidgetElementTextScrollModel* model = element->model;
TextScrollLineArray new_line;
new_line.font = line->font;
new_line.horizontal = line->horizontal;
string_init_set(new_line.text, line->text);
TextScrollLineArray_push_back(model->line_array, new_line);
}
static void widget_element_text_scroll_fill_lines(Canvas* canvas, WidgetElement* element) {
WidgetElementTextScrollModel* model = element->model;
TextScrollLineArray line_tmp;
bool all_text_processed = false;
string_init(line_tmp.text);
bool reached_new_line = true;
uint16_t total_height = 0;
while(!all_text_processed) {
if(reached_new_line) {
// Set default line properties
line_tmp.font = FontSecondary;
line_tmp.horizontal = AlignLeft;
string_reset(line_tmp.text);
// Process control symbols
while(widget_element_text_scroll_process_ctrl_symbols(&line_tmp, model->text))
;
}
// Set canvas font
canvas_set_font(canvas, line_tmp.font);
CanvasFontParameters* params = canvas_get_font_params(canvas, line_tmp.font);
total_height += params->height;
if(total_height > model->height) {
model->scroll_pos_total++;
}
uint8_t line_width = 0;
uint16_t char_i = 0;
while(true) {
char next_char = string_get_char(model->text, char_i++);
if(next_char == '\0') {
string_push_back(line_tmp.text, '\0');
widget_element_text_scroll_add_line(element, &line_tmp);
total_height += params->leading_default - params->height;
all_text_processed = true;
break;
} else if(next_char == '\n') {
string_push_back(line_tmp.text, '\0');
widget_element_text_scroll_add_line(element, &line_tmp);
string_right(model->text, char_i);
total_height += params->leading_default - params->height;
reached_new_line = true;
break;
} else {
line_width += canvas_glyph_width(canvas, next_char);
if(line_width > model->width) {
string_push_back(line_tmp.text, '\0');
widget_element_text_scroll_add_line(element, &line_tmp);
string_right(model->text, char_i - 1);
string_reset(line_tmp.text);
total_height += params->leading_default - params->height;
reached_new_line = false;
break;
} else {
string_push_back(line_tmp.text, next_char);
}
}
}
}
string_clear(line_tmp.text);
}
static void widget_element_text_scroll_draw(Canvas* canvas, WidgetElement* element) {
furi_assert(canvas);
furi_assert(element);
furi_mutex_acquire(element->model_mutex, FuriWaitForever);
WidgetElementTextScrollModel* model = element->model;
if(!model->text_formatted) {
widget_element_text_scroll_fill_lines(canvas, element);
model->text_formatted = true;
}
uint8_t y = model->y;
uint8_t x = model->x;
uint16_t curr_line = 0;
if(TextScrollLineArray_size(model->line_array)) {
TextScrollLineArray_it_t it;
for(TextScrollLineArray_it(it, model->line_array); !TextScrollLineArray_end_p(it);
TextScrollLineArray_next(it), curr_line++) {
if(curr_line < model->scroll_pos_current) continue;
TextScrollLineArray* line = TextScrollLineArray_ref(it);
CanvasFontParameters* params = canvas_get_font_params(canvas, line->font);
if(y + params->descender > model->y + model->height) break;
canvas_set_font(canvas, line->font);
if(line->horizontal == AlignLeft) {
x = model->x;
} else if(line->horizontal == AlignCenter) {
x = (model->x + model->width) / 2;
} else if(line->horizontal == AlignRight) {
x = model->x + model->width;
}
canvas_draw_str_aligned(
canvas, x, y, line->horizontal, AlignTop, string_get_cstr(line->text));
y += params->leading_default;
}
// Draw scroll bar
if(model->scroll_pos_total > 1) {
elements_scrollbar_pos(
canvas,
model->x + model->width + WIDGET_ELEMENT_TEXT_SCROLL_BAR_OFFSET,
model->y,
model->height,
model->scroll_pos_current,
model->scroll_pos_total);
}
}
furi_mutex_release(element->model_mutex);
}
static bool widget_element_text_scroll_input(InputEvent* event, WidgetElement* element) {
furi_assert(event);
furi_assert(element);
furi_mutex_acquire(element->model_mutex, FuriWaitForever);
WidgetElementTextScrollModel* model = element->model;
bool consumed = false;
if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) {
if(event->key == InputKeyUp) {
if(model->scroll_pos_current > 0) {
model->scroll_pos_current--;
}
consumed = true;
} else if(event->key == InputKeyDown) {
if((model->scroll_pos_total > 1) &&
(model->scroll_pos_current < model->scroll_pos_total - 1)) {
model->scroll_pos_current++;
}
consumed = true;
}
}
furi_mutex_release(element->model_mutex);
return consumed;
}
static void widget_element_text_scroll_free(WidgetElement* text_scroll) {
furi_assert(text_scroll);
WidgetElementTextScrollModel* model = text_scroll->model;
TextScrollLineArray_it_t it;
for(TextScrollLineArray_it(it, model->line_array); !TextScrollLineArray_end_p(it);
TextScrollLineArray_next(it)) {
TextScrollLineArray* line = TextScrollLineArray_ref(it);
string_clear(line->text);
}
TextScrollLineArray_clear(model->line_array);
string_clear(model->text);
free(text_scroll->model);
furi_mutex_free(text_scroll->model_mutex);
free(text_scroll);
}
WidgetElement* widget_element_text_scroll_create(
uint8_t x,
uint8_t y,
uint8_t width,
uint8_t height,
const char* text) {
furi_assert(text);
// Allocate and init model
WidgetElementTextScrollModel* model = malloc(sizeof(WidgetElementTextScrollModel));
model->x = x;
model->y = y;
model->width = width - WIDGET_ELEMENT_TEXT_SCROLL_BAR_OFFSET;
model->height = height;
model->scroll_pos_current = 0;
model->scroll_pos_total = 1;
TextScrollLineArray_init(model->line_array);
string_init_set_str(model->text, text);
WidgetElement* text_scroll = malloc(sizeof(WidgetElement));
text_scroll->parent = NULL;
text_scroll->draw = widget_element_text_scroll_draw;
text_scroll->input = widget_element_text_scroll_input;
text_scroll->free = widget_element_text_scroll_free;
text_scroll->model = model;
text_scroll->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
return text_scroll;
}

View File

@@ -16,6 +16,7 @@ HIDApp::~HIDApp() {
void HIDApp::run(void* _args) { void HIDApp::run(void* _args) {
UNUSED(_args); UNUSED(_args);
view_controller.attach_to_gui(ViewDispatcherTypeFullscreen);
scene_controller.add_scene(SceneType::Read, new HIDAppSceneRead()); scene_controller.add_scene(SceneType::Read, new HIDAppSceneRead());
scene_controller.add_scene(SceneType::ReadSuccess, new HIDAppSceneReadSuccess()); scene_controller.add_scene(SceneType::ReadSuccess, new HIDAppSceneReadSuccess());
scene_controller.process(100, SceneType::Read); scene_controller.process(100, SceneType::Read);

View File

@@ -87,6 +87,8 @@ static void ibutton_rpc_command_callback(RpcAppSystemEvent event, void* context)
if(event == RpcAppEventSessionClose) { if(event == RpcAppEventSessionClose) {
view_dispatcher_send_custom_event( view_dispatcher_send_custom_event(
ibutton->view_dispatcher, iButtonCustomEventRpcSessionClose); ibutton->view_dispatcher, iButtonCustomEventRpcSessionClose);
rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL);
ibutton->rpc_ctx = NULL;
} else if(event == RpcAppEventAppExit) { } else if(event == RpcAppEventAppExit) {
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcExit); view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcExit);
} else if(event == RpcAppEventLoadFile) { } else if(event == RpcAppEventLoadFile) {

View File

@@ -29,7 +29,7 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
if(event.event == iButtonCustomEventRpcLoad) { if(event.event == iButtonCustomEventRpcLoad) {
const char* arg = rpc_system_app_get_data(ibutton->rpc_ctx); const char* arg = rpc_system_app_get_data(ibutton->rpc_ctx);
bool result = false; bool result = false;
if(arg) { if(arg && (string_empty_p(ibutton->file_path))) {
string_set_str(ibutton->file_path, arg); string_set_str(ibutton->file_path, arg);
if(ibutton_load_key_data(ibutton, ibutton->file_path, false)) { if(ibutton_load_key_data(ibutton, ibutton->file_path, false)) {
ibutton_worker_emulate_start(ibutton->key_worker, ibutton->key); ibutton_worker_emulate_start(ibutton->key_worker, ibutton->key);
@@ -51,17 +51,17 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
string_clear(key_name); string_clear(key_name);
result = true; result = true;
} else {
string_reset(ibutton->file_path);
} }
} }
rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventLoadFile, result); rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventLoadFile, result);
} else if(event.event == iButtonCustomEventRpcExit) { } else if(event.event == iButtonCustomEventRpcExit) {
rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventAppExit, true); rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventAppExit, true);
ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop); scene_manager_stop(ibutton->scene_manager);
view_dispatcher_stop(ibutton->view_dispatcher); view_dispatcher_stop(ibutton->view_dispatcher);
} else if(event.event == iButtonCustomEventRpcSessionClose) { } else if(event.event == iButtonCustomEventRpcSessionClose) {
rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL); scene_manager_stop(ibutton->scene_manager);
ibutton->rpc_ctx = NULL;
ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop);
view_dispatcher_stop(ibutton->view_dispatcher); view_dispatcher_stop(ibutton->view_dispatcher);
} }
} }

View File

@@ -46,6 +46,8 @@ static void infrared_rpc_command_callback(RpcAppSystemEvent event, void* context
if(event == RpcAppEventSessionClose) { if(event == RpcAppEventSessionClose) {
view_dispatcher_send_custom_event( view_dispatcher_send_custom_event(
infrared->view_dispatcher, InfraredCustomEventTypeRpcSessionClose); infrared->view_dispatcher, InfraredCustomEventTypeRpcSessionClose);
rpc_system_app_set_callback(infrared->rpc_ctx, NULL, NULL);
infrared->rpc_ctx = NULL;
} else if(event == RpcAppEventAppExit) { } else if(event == RpcAppEventAppExit) {
view_dispatcher_send_custom_event( view_dispatcher_send_custom_event(
infrared->view_dispatcher, InfraredCustomEventTypeRpcExit); infrared->view_dispatcher, InfraredCustomEventTypeRpcExit);
@@ -293,6 +295,13 @@ bool infrared_rename_current_remote(Infrared* infrared, const char* name) {
} }
void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) { void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) {
if(infrared->app_state.is_transmitting) {
FURI_LOG_D(INFRARED_LOG_TAG, "Transmitter is already active");
return;
} else {
infrared->app_state.is_transmitting = true;
}
if(infrared_signal_is_raw(signal)) { if(infrared_signal_is_raw(signal)) {
InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal);
infrared_worker_set_raw_signal(infrared->worker, raw->timings, raw->timings_size); infrared_worker_set_raw_signal(infrared->worker, raw->timings, raw->timings_size);
@@ -302,8 +311,11 @@ void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) {
} }
DOLPHIN_DEED(DolphinDeedIrSend); DOLPHIN_DEED(DolphinDeedIrSend);
infrared_worker_tx_start(infrared->worker);
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend); infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend);
infrared_worker_tx_set_get_signal_callback(
infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared);
infrared_worker_tx_start(infrared->worker);
} }
void infrared_tx_start_button_index(Infrared* infrared, size_t button_index) { void infrared_tx_start_button_index(Infrared* infrared, size_t button_index) {
@@ -322,7 +334,16 @@ void infrared_tx_start_received(Infrared* infrared) {
} }
void infrared_tx_stop(Infrared* infrared) { void infrared_tx_stop(Infrared* infrared) {
if(!infrared->app_state.is_transmitting) {
FURI_LOG_D(INFRARED_LOG_TAG, "Transmitter is already stopped");
return;
} else {
infrared->app_state.is_transmitting = false;
}
infrared_worker_tx_stop(infrared->worker); infrared_worker_tx_stop(infrared->worker);
infrared_worker_tx_set_get_signal_callback(infrared->worker, NULL, NULL);
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop); infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop);
} }

View File

@@ -43,6 +43,7 @@
#define INFRARED_APP_EXTENSION ".ir" #define INFRARED_APP_EXTENSION ".ir"
#define INFRARED_DEFAULT_REMOTE_NAME "Remote" #define INFRARED_DEFAULT_REMOTE_NAME "Remote"
#define INFRARED_LOG_TAG "InfraredApp"
typedef enum { typedef enum {
InfraredButtonIndexNone = -1, InfraredButtonIndexNone = -1,
@@ -63,6 +64,7 @@ typedef enum {
typedef struct { typedef struct {
bool is_learning_new_remote; bool is_learning_new_remote;
bool is_debug_enabled; bool is_debug_enabled;
bool is_transmitting;
InfraredEditTarget edit_target : 8; InfraredEditTarget edit_target : 8;
InfraredEditMode edit_mode : 8; InfraredEditMode edit_mode : 8;
int32_t current_button_index; int32_t current_button_index;

View File

@@ -2,11 +2,6 @@
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
typedef enum {
InfraredSceneLearnSuccessStateIdle = 0,
InfraredSceneLearnSuccessStateSending = 1,
} InfraredSceneLearnSuccessState;
static void static void
infrared_scene_learn_success_dialog_result_callback(DialogExResult result, void* context) { infrared_scene_learn_success_dialog_result_callback(DialogExResult result, void* context) {
Infrared* infrared = context; Infrared* infrared = context;
@@ -21,9 +16,6 @@ void infrared_scene_learn_success_on_enter(void* context) {
DOLPHIN_DEED(DolphinDeedIrLearnSuccess); DOLPHIN_DEED(DolphinDeedIrLearnSuccess);
infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn); infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn);
infrared_worker_tx_set_get_signal_callback(
infrared->worker, infrared_worker_tx_get_signal_steady_callback, context);
if(infrared_signal_is_raw(signal)) { if(infrared_signal_is_raw(signal)) {
InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal);
dialog_ex_set_header(dialog_ex, "Unknown", 95, 10, AlignCenter, AlignCenter); dialog_ex_set_header(dialog_ex, "Unknown", 95, 10, AlignCenter, AlignCenter);
@@ -63,57 +55,42 @@ void infrared_scene_learn_success_on_enter(void* context) {
dialog_ex_set_context(dialog_ex, context); dialog_ex_set_context(dialog_ex, context);
dialog_ex_enable_extended_events(dialog_ex); dialog_ex_enable_extended_events(dialog_ex);
scene_manager_set_scene_state(
infrared->scene_manager, InfraredSceneLearnSuccess, InfraredSceneLearnSuccessStateIdle);
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewDialogEx); view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewDialogEx);
} }
bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent event) { bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent event) {
Infrared* infrared = context; Infrared* infrared = context;
SceneManager* scene_manager = infrared->scene_manager; SceneManager* scene_manager = infrared->scene_manager;
uint32_t scene_state = scene_manager_get_scene_state(scene_manager, InfraredSceneLearnSuccess); const bool is_transmitter_idle = !infrared->app_state.is_transmitting;
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeTick) { if(event.type == SceneManagerEventTypeTick) {
if(scene_state == InfraredSceneLearnSuccessStateIdle) { if(is_transmitter_idle) {
infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn); infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn);
} }
consumed = true; consumed = true;
} else if(event.type == SceneManagerEventTypeBack) { } else if(event.type == SceneManagerEventTypeBack) {
if(scene_state == InfraredSceneLearnSuccessStateIdle) { if(is_transmitter_idle) {
scene_manager_next_scene(scene_manager, InfraredSceneAskBack); scene_manager_next_scene(scene_manager, InfraredSceneAskBack);
} }
consumed = true; consumed = true;
} else if(event.type == SceneManagerEventTypeCustom) { } else if(event.type == SceneManagerEventTypeCustom) {
if(event.event == DialogExResultLeft) { if(event.event == DialogExResultLeft) {
if(scene_state == InfraredSceneLearnSuccessStateIdle) { if(is_transmitter_idle) {
scene_manager_next_scene(scene_manager, InfraredSceneAskRetry); scene_manager_next_scene(scene_manager, InfraredSceneAskRetry);
} }
consumed = true; consumed = true;
} else if(event.event == DialogExResultRight) { } else if(event.event == DialogExResultRight) {
if(scene_state == InfraredSceneLearnSuccessStateIdle) { if(is_transmitter_idle) {
scene_manager_next_scene(scene_manager, InfraredSceneLearnEnterName); scene_manager_next_scene(scene_manager, InfraredSceneLearnEnterName);
} }
consumed = true; consumed = true;
} else if(event.event == DialogExPressCenter) { } else if(event.event == DialogExPressCenter) {
if(scene_state == InfraredSceneLearnSuccessStateIdle) { infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff);
scene_manager_set_scene_state(
scene_manager,
InfraredSceneLearnSuccess,
InfraredSceneLearnSuccessStateSending);
infrared_tx_start_received(infrared); infrared_tx_start_received(infrared);
infrared_play_notification_message(
infrared, InfraredNotificationMessageBlinkStartSend);
}
consumed = true; consumed = true;
} else if(event.event == DialogExReleaseCenter) { } else if(event.event == DialogExReleaseCenter) {
if(scene_state == InfraredSceneLearnSuccessStateSending) {
scene_manager_set_scene_state(
scene_manager, InfraredSceneLearnSuccess, InfraredSceneLearnSuccessStateIdle);
infrared_tx_stop(infrared); infrared_tx_stop(infrared);
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop);
infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff);
}
consumed = true; consumed = true;
} }
} }
@@ -123,9 +100,6 @@ bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent even
void infrared_scene_learn_success_on_exit(void* context) { void infrared_scene_learn_success_on_exit(void* context) {
Infrared* infrared = context; Infrared* infrared = context;
InfraredWorker* worker = infrared->worker;
dialog_ex_reset(infrared->dialog_ex); dialog_ex_reset(infrared->dialog_ex);
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop);
infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff); infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff);
infrared_worker_tx_set_get_signal_callback(worker, NULL, NULL);
} }

View File

@@ -31,9 +31,6 @@ void infrared_scene_remote_on_enter(void* context) {
ButtonMenu* button_menu = infrared->button_menu; ButtonMenu* button_menu = infrared->button_menu;
SceneManager* scene_manager = infrared->scene_manager; SceneManager* scene_manager = infrared->scene_manager;
infrared_worker_tx_set_get_signal_callback(
infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared);
size_t button_count = infrared_remote_get_button_count(remote); size_t button_count = infrared_remote_get_button_count(remote);
for(size_t i = 0; i < button_count; ++i) { for(size_t i = 0; i < button_count; ++i) {
InfraredRemoteButton* button = infrared_remote_get_button(remote, i); InfraredRemoteButton* button = infrared_remote_get_button(remote, i);
@@ -73,12 +70,17 @@ void infrared_scene_remote_on_enter(void* context) {
bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) { bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) {
Infrared* infrared = context; Infrared* infrared = context;
SceneManager* scene_manager = infrared->scene_manager; SceneManager* scene_manager = infrared->scene_manager;
const bool is_transmitter_idle = !infrared->app_state.is_transmitting;
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeBack) { if(event.type == SceneManagerEventTypeBack) {
if(is_transmitter_idle) {
const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart};
consumed = scene_manager_search_and_switch_to_previous_scene_one_of( consumed = scene_manager_search_and_switch_to_previous_scene_one_of(
scene_manager, possible_scenes, COUNT_OF(possible_scenes)); scene_manager, possible_scenes, COUNT_OF(possible_scenes));
} else {
consumed = true;
}
} else if(event.type == SceneManagerEventTypeCustom) { } else if(event.type == SceneManagerEventTypeCustom) {
const uint16_t custom_type = infrared_custom_event_get_type(event.event); const uint16_t custom_type = infrared_custom_event_get_type(event.event);
const int16_t button_index = infrared_custom_event_get_value(event.event); const int16_t button_index = infrared_custom_event_get_value(event.event);
@@ -92,6 +94,7 @@ bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) {
consumed = true; consumed = true;
} else if(custom_type == InfraredCustomEventTypeMenuSelected) { } else if(custom_type == InfraredCustomEventTypeMenuSelected) {
furi_assert(button_index < 0); furi_assert(button_index < 0);
if(is_transmitter_idle) {
scene_manager_set_scene_state( scene_manager_set_scene_state(
scene_manager, InfraredSceneRemote, (unsigned)button_index); scene_manager, InfraredSceneRemote, (unsigned)button_index);
if(button_index == ButtonIndexPlus) { if(button_index == ButtonIndexPlus) {
@@ -102,6 +105,10 @@ bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) {
scene_manager_next_scene(scene_manager, InfraredSceneEdit); scene_manager_next_scene(scene_manager, InfraredSceneEdit);
consumed = true; consumed = true;
} }
} else {
consumed = true;
}
} }
} }
@@ -110,7 +117,5 @@ bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) {
void infrared_scene_remote_on_exit(void* context) { void infrared_scene_remote_on_exit(void* context) {
Infrared* infrared = context; Infrared* infrared = context;
infrared_tx_stop(infrared);
infrared_worker_tx_set_get_signal_callback(infrared->worker, NULL, NULL);
button_menu_reset(infrared->button_menu); button_menu_reset(infrared->button_menu);
} }

View File

@@ -1,20 +1,28 @@
#include "../infrared_i.h" #include "../infrared_i.h"
#include "gui/canvas.h" #include "gui/canvas.h"
typedef enum {
InfraredRpcStateIdle,
InfraredRpcStateLoaded,
InfraredRpcStateSending,
} InfraredRpcState;
void infrared_scene_rpc_on_enter(void* context) { void infrared_scene_rpc_on_enter(void* context) {
Infrared* infrared = context; Infrared* infrared = context;
Popup* popup = infrared->popup; Popup* popup = infrared->popup;
popup_set_header(popup, "Infrared", 82, 28, AlignCenter, AlignBottom); popup_set_header(popup, "Infrared", 89, 42, AlignCenter, AlignBottom);
popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop); popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop);
popup_set_icon(popup, 2, 14, &I_Warning_30x23); // TODO: icon popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61);
popup_set_context(popup, context); popup_set_context(popup, context);
popup_set_callback(popup, infrared_popup_closed_callback); popup_set_callback(popup, infrared_popup_closed_callback);
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup); view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup);
scene_manager_set_scene_state(infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateIdle);
notification_message(infrared->notifications, &sequence_display_backlight_on); notification_message(infrared->notifications, &sequence_display_backlight_on);
} }
@@ -24,6 +32,8 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
consumed = true; consumed = true;
InfraredRpcState state =
scene_manager_get_scene_state(infrared->scene_manager, InfraredSceneRpc);
if(event.event == InfraredCustomEventTypeBackPressed) { if(event.event == InfraredCustomEventTypeBackPressed) {
view_dispatcher_stop(infrared->view_dispatcher); view_dispatcher_stop(infrared->view_dispatcher);
} else if(event.event == InfraredCustomEventTypePopupClosed) { } else if(event.event == InfraredCustomEventTypePopupClosed) {
@@ -31,39 +41,49 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) {
} else if(event.event == InfraredCustomEventTypeRpcLoad) { } else if(event.event == InfraredCustomEventTypeRpcLoad) {
bool result = false; bool result = false;
const char* arg = rpc_system_app_get_data(infrared->rpc_ctx); const char* arg = rpc_system_app_get_data(infrared->rpc_ctx);
if(arg) { if(arg && (state == InfraredRpcStateIdle)) {
string_set_str(infrared->file_path, arg); string_set_str(infrared->file_path, arg);
result = infrared_remote_load(infrared->remote, infrared->file_path); result = infrared_remote_load(infrared->remote, infrared->file_path);
infrared_worker_tx_set_get_signal_callback( if(result) {
infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared); scene_manager_set_scene_state(
infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateLoaded);
}
} }
const char* remote_name = infrared_remote_get_name(infrared->remote); const char* remote_name = infrared_remote_get_name(infrared->remote);
infrared_text_store_set(infrared, 0, "loaded\n%s", remote_name); infrared_text_store_set(infrared, 0, "loaded\n%s", remote_name);
popup_set_text( popup_set_text(
infrared->popup, infrared->text_store[0], 82, 32, AlignCenter, AlignTop); infrared->popup, infrared->text_store[0], 89, 44, AlignCenter, AlignTop);
rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventLoadFile, result); rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventLoadFile, result);
} else if(event.event == InfraredCustomEventTypeRpcButtonPress) { } else if(event.event == InfraredCustomEventTypeRpcButtonPress) {
bool result = false; bool result = false;
const char* arg = rpc_system_app_get_data(infrared->rpc_ctx); const char* arg = rpc_system_app_get_data(infrared->rpc_ctx);
if(arg) { if(arg && (state == InfraredRpcStateLoaded)) {
size_t button_index = 0; size_t button_index = 0;
if(infrared_remote_find_button_by_name(infrared->remote, arg, &button_index)) { if(infrared_remote_find_button_by_name(infrared->remote, arg, &button_index)) {
infrared_tx_start_button_index(infrared, button_index); infrared_tx_start_button_index(infrared, button_index);
result = true; result = true;
scene_manager_set_scene_state(
infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateSending);
} }
} }
rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, result); rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, result);
} else if(event.event == InfraredCustomEventTypeRpcButtonRelease) { } else if(event.event == InfraredCustomEventTypeRpcButtonRelease) {
bool result = false;
if(state == InfraredRpcStateSending) {
infrared_tx_stop(infrared); infrared_tx_stop(infrared);
rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, true); result = true;
scene_manager_set_scene_state(
infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateLoaded);
}
rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, result);
} else if(event.event == InfraredCustomEventTypeRpcExit) { } else if(event.event == InfraredCustomEventTypeRpcExit) {
scene_manager_stop(infrared->scene_manager);
view_dispatcher_stop(infrared->view_dispatcher); view_dispatcher_stop(infrared->view_dispatcher);
rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventAppExit, true); rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventAppExit, true);
} else if(event.event == InfraredCustomEventTypeRpcSessionClose) { } else if(event.event == InfraredCustomEventTypeRpcSessionClose) {
rpc_system_app_set_callback(infrared->rpc_ctx, NULL, NULL); scene_manager_stop(infrared->scene_manager);
infrared->rpc_ctx = NULL;
view_dispatcher_stop(infrared->view_dispatcher); view_dispatcher_stop(infrared->view_dispatcher);
} }
} }
@@ -72,6 +92,9 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) {
void infrared_scene_rpc_on_exit(void* context) { void infrared_scene_rpc_on_exit(void* context) {
Infrared* infrared = context; Infrared* infrared = context;
if(scene_manager_get_scene_state(infrared->scene_manager, InfraredSceneRpc) ==
InfraredRpcStateSending) {
infrared_tx_stop(infrared); infrared_tx_stop(infrared);
}
popup_reset(infrared->popup); popup_reset(infrared->popup);
} }

View File

@@ -11,7 +11,7 @@ void infrared_scene_universal_audio_on_enter(void* context) {
infrared_brute_force_set_db_filename(brute_force, EXT_PATH("infrared/assets/audio.ir")); infrared_brute_force_set_db_filename(brute_force, EXT_PATH("infrared/assets/audio.ir"));
//TODO Improve Audio universal remote //TODO Improve Audio universal remote
button_panel_reserve(button_panel, 2, 1); button_panel_reserve(button_panel, 2, 2);
uint32_t i = 0; uint32_t i = 0;
button_panel_add_item( button_panel_add_item(
button_panel, button_panel,
@@ -37,8 +37,33 @@ void infrared_scene_universal_audio_on_enter(void* context) {
infrared_scene_universal_common_item_callback, infrared_scene_universal_common_item_callback,
context); context);
infrared_brute_force_add_record(brute_force, i++, "MUTE"); infrared_brute_force_add_record(brute_force, i++, "MUTE");
button_panel_add_item(
button_panel,
i,
0,
1,
3,
64,
&I_Vol_up_25x27,
&I_Vol_up_hvr_25x27,
infrared_scene_universal_common_item_callback,
context);
infrared_brute_force_add_record(brute_force, i++, "VOL+");
button_panel_add_item(
button_panel,
i,
1,
1,
36,
64,
&I_Vol_down_25x27,
&I_Vol_down_hvr_25x27,
infrared_scene_universal_common_item_callback,
context);
infrared_brute_force_add_record(brute_force, i++, "VOL-");
button_panel_add_label(button_panel, 4, 11, FontSecondary, "Audio remote"); button_panel_add_label(button_panel, 5, 11, FontSecondary, "Audio remote");
button_panel_add_label(button_panel, 17, 60, FontSecondary, "Volume");
view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical); view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical);
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack);

View File

@@ -56,6 +56,9 @@ static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) {
LfRfidApp::Event event; LfRfidApp::Event event;
event.type = LfRfidApp::EventType::RpcSessionClose; event.type = LfRfidApp::EventType::RpcSessionClose;
app->view_controller.send_event(&event); app->view_controller.send_event(&event);
// Detach RPC
rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL);
app->rpc_ctx = NULL;
} else if(rpc_event == RpcAppEventAppExit) { } else if(rpc_event == RpcAppEventAppExit) {
LfRfidApp::Event event; LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Exit; event.type = LfRfidApp::EventType::Exit;
@@ -80,16 +83,19 @@ void LfRfidApp::run(void* _args) {
rpc_ctx = (RpcAppSystem*)rpc_ctx_ptr; rpc_ctx = (RpcAppSystem*)rpc_ctx_ptr;
rpc_system_app_set_callback(rpc_ctx, rpc_command_callback, this); rpc_system_app_set_callback(rpc_ctx, rpc_command_callback, this);
rpc_system_app_send_started(rpc_ctx); rpc_system_app_send_started(rpc_ctx);
view_controller.attach_to_gui(ViewDispatcherTypeDesktop);
scene_controller.add_scene(SceneType::Rpc, new LfRfidAppSceneRpc()); scene_controller.add_scene(SceneType::Rpc, new LfRfidAppSceneRpc());
scene_controller.process(100, SceneType::Rpc); scene_controller.process(100, SceneType::Rpc);
} else { } else {
string_set_str(file_path, args); string_set_str(file_path, args);
load_key_data(file_path, &worker.key, true); load_key_data(file_path, &worker.key, true);
view_controller.attach_to_gui(ViewDispatcherTypeFullscreen);
scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate()); scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate());
scene_controller.process(100, SceneType::Emulate); scene_controller.process(100, SceneType::Emulate);
} }
} else { } else {
view_controller.attach_to_gui(ViewDispatcherTypeFullscreen);
scene_controller.add_scene(SceneType::Start, new LfRfidAppSceneStart()); scene_controller.add_scene(SceneType::Start, new LfRfidAppSceneStart());
scene_controller.add_scene(SceneType::Read, new LfRfidAppSceneRead()); scene_controller.add_scene(SceneType::Read, new LfRfidAppSceneRead());
scene_controller.add_scene(SceneType::RetryConfirm, new LfRfidAppSceneRetryConfirm()); scene_controller.add_scene(SceneType::RetryConfirm, new LfRfidAppSceneRetryConfirm());

View File

@@ -101,5 +101,4 @@ public:
bool save_key_data(string_t path, RfidKey* key); bool save_key_data(string_t path, RfidKey* key);
void make_app_folder(); void make_app_folder();
//bool rpc_command_callback(RpcAppSystemEvent event, const char* arg, void* context);
}; };

View File

@@ -6,9 +6,9 @@
void LfRfidAppSceneRpc::on_enter(LfRfidApp* app, bool /* need_restore */) { void LfRfidAppSceneRpc::on_enter(LfRfidApp* app, bool /* need_restore */) {
auto popup = app->view_controller.get<PopupVM>(); auto popup = app->view_controller.get<PopupVM>();
popup->set_header("LF RFID", 89, 30, AlignCenter, AlignTop); popup->set_header("LF RFID", 89, 42, AlignCenter, AlignBottom);
popup->set_text("RPC mode", 89, 43, AlignCenter, AlignTop); popup->set_text("RPC mode", 89, 44, AlignCenter, AlignTop);
popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61); popup->set_icon(0, 12, &I_RFIDDolphinSend_97x61);
app->view_controller.switch_to<PopupVM>(); app->view_controller.switch_to<PopupVM>();
@@ -27,33 +27,25 @@ bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
app->view_controller.send_event(&view_event); app->view_controller.send_event(&view_event);
rpc_system_app_confirm(app->rpc_ctx, RpcAppEventAppExit, true); rpc_system_app_confirm(app->rpc_ctx, RpcAppEventAppExit, true);
} else if(event->type == LfRfidApp::EventType::RpcSessionClose) { } else if(event->type == LfRfidApp::EventType::RpcSessionClose) {
// Detach RPC
rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL);
app->rpc_ctx = NULL;
consumed = true; consumed = true;
LfRfidApp::Event view_event; LfRfidApp::Event view_event;
view_event.type = LfRfidApp::EventType::Back; view_event.type = LfRfidApp::EventType::Back;
app->view_controller.send_event(&view_event); app->view_controller.send_event(&view_event);
} else if(event->type == LfRfidApp::EventType::EmulateStart) {
auto popup = app->view_controller.get<PopupVM>();
consumed = true;
emulating = true;
app->text_store.set("emulating\n%s", app->worker.key.get_name());
popup->set_text(app->text_store.text, 89, 43, AlignCenter, AlignTop);
notification_message(app->notification, &sequence_blink_start_magenta);
} else if(event->type == LfRfidApp::EventType::RpcLoadFile) { } else if(event->type == LfRfidApp::EventType::RpcLoadFile) {
const char* arg = rpc_system_app_get_data(app->rpc_ctx); const char* arg = rpc_system_app_get_data(app->rpc_ctx);
consumed = true;
bool result = false; bool result = false;
if(arg) { if(arg && !emulating) {
string_set_str(app->file_path, arg); string_set_str(app->file_path, arg);
if(app->load_key_data(app->file_path, &(app->worker.key), false)) { if(app->load_key_data(app->file_path, &(app->worker.key), false)) {
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::EmulateStart;
app->view_controller.send_event(&event);
app->worker.start_emulate(); app->worker.start_emulate();
emulating = true;
auto popup = app->view_controller.get<PopupVM>();
app->text_store.set("emulating\n%s", app->worker.key.get_name());
popup->set_text(app->text_store.text, 89, 44, AlignCenter, AlignTop);
notification_message(app->notification, &sequence_blink_start_magenta);
result = true; result = true;
} }
} }

View File

@@ -41,7 +41,7 @@ bool LfRfidAppSceneWrite::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
case RfidWorker::WriteResult::NotWritable: case RfidWorker::WriteResult::NotWritable:
if(!card_not_supported) { if(!card_not_supported) {
auto popup = app->view_controller.get<PopupVM>(); auto popup = app->view_controller.get<PopupVM>();
popup->set_icon(72, 14, &I_DolphinFirstStart8_56x51); popup->set_icon(72, 17, &I_DolphinCommon_56x48);
popup->set_header("Still trying to write...", 64, 3, AlignCenter, AlignTop); popup->set_header("Still trying to write...", 64, 3, AlignCenter, AlignTop);
popup->set_text( popup->set_text(
"Make sure this\ncard is writable\nand not\nprotected.", "Make sure this\ncard is writable\nand not\nprotected.",

View File

@@ -10,6 +10,7 @@ LfRfidDebugApp::~LfRfidDebugApp() {
} }
void LfRfidDebugApp::run() { void LfRfidDebugApp::run() {
view_controller.attach_to_gui(ViewDispatcherTypeFullscreen);
scene_controller.add_scene(SceneType::Start, new LfRfidDebugAppSceneStart()); scene_controller.add_scene(SceneType::Start, new LfRfidDebugAppSceneStart());
scene_controller.add_scene(SceneType::TuneScene, new LfRfidDebugAppSceneTune()); scene_controller.add_scene(SceneType::TuneScene, new LfRfidDebugAppSceneTune());
scene_controller.process(100); scene_controller.process(100);

View File

@@ -5,6 +5,6 @@ App(
entry_point="loader_srv", entry_point="loader_srv",
cdefines=["SRV_LOADER"], cdefines=["SRV_LOADER"],
requires=["gui"], requires=["gui"],
stack_size=1 * 1024, stack_size=2 * 1024,
order=90, order=90,
) )

View File

@@ -503,9 +503,9 @@ int32_t loader_srv(void* p) {
furi_record_create(RECORD_LOADER, loader_instance); furi_record_create(RECORD_LOADER, loader_instance);
#ifdef LOADER_AUTOSTART if(FLIPPER_AUTORUN_APP_NAME && strlen(FLIPPER_AUTORUN_APP_NAME)) {
loader_start(loader_instance, LOADER_AUTOSTART, NULL); loader_start(loader_instance, FLIPPER_AUTORUN_APP_NAME, NULL);
#endif }
while(1) { while(1) {
uint32_t flags = uint32_t flags =

View File

@@ -240,10 +240,10 @@ int32_t mousejacker_app(void* p) {
view_port_input_callback_set(view_port, input_callback, event_queue); view_port_input_callback_set(view_port, input_callback, event_queue);
// Open GUI and register view_port // Open GUI and register view_port
Gui* gui = furi_record_open("gui"); Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen); gui_add_view_port(gui, view_port, GuiLayerFullscreen);
Storage* storage = furi_record_open("storage"); Storage* storage = furi_record_open(RECORD_STORAGE);
storage_common_mkdir(storage, MOUSEJACKER_APP_PATH_FOLDER); storage_common_mkdir(storage, MOUSEJACKER_APP_PATH_FOLDER);
Stream* file_stream = file_stream_alloc(storage); Stream* file_stream = file_stream_alloc(storage);
@@ -329,8 +329,8 @@ int32_t mousejacker_app(void* p) {
furi_hal_spi_release(nrf24_HANDLE); furi_hal_spi_release(nrf24_HANDLE);
view_port_enabled_set(view_port, false); view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port); gui_remove_view_port(gui, view_port);
furi_record_close("gui"); furi_record_close(RECORD_GUI);
furi_record_close("storage"); furi_record_close(RECORD_STORAGE);
view_port_free(view_port); view_port_free(view_port);
furi_message_queue_free(event_queue); furi_message_queue_free(event_queue);

View File

@@ -30,7 +30,7 @@ typedef struct {
typedef struct { typedef struct {
MusicPlayerModel* model; MusicPlayerModel* model;
FuriMutex* model_mutex; FuriMutex** model_mutex;
FuriMessageQueue* input_queue; FuriMessageQueue* input_queue;
@@ -256,7 +256,7 @@ MusicPlayer* music_player_alloc() {
instance->model = malloc(sizeof(MusicPlayerModel)); instance->model = malloc(sizeof(MusicPlayerModel));
memset(instance->model->duration_history, 0xff, MUSIC_PLAYER_SEMITONE_HISTORY_SIZE); memset(instance->model->duration_history, 0xff, MUSIC_PLAYER_SEMITONE_HISTORY_SIZE);
memset(instance->model->semitone_history, 0xff, MUSIC_PLAYER_SEMITONE_HISTORY_SIZE); memset(instance->model->semitone_history, 0xff, MUSIC_PLAYER_SEMITONE_HISTORY_SIZE);
instance->model->volume = 1; instance->model->volume = 3;
instance->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal); instance->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal);

View File

@@ -79,7 +79,7 @@ static int32_t music_player_worker_thread_callback(void* context) {
furi_hal_speaker_stop(); furi_hal_speaker_stop();
furi_hal_speaker_start(frequency, volume); furi_hal_speaker_start(frequency, volume);
while(instance->should_work && furi_get_tick() < next_tick) { while(instance->should_work && furi_get_tick() < next_tick) {
volume *= 1.0000000; volume *= 0.9945679;
furi_hal_speaker_set_volume(volume); furi_hal_speaker_set_volume(volume);
furi_delay_ms(2); furi_delay_ms(2);
} }

View File

@@ -21,6 +21,8 @@ static void nfc_rpc_command_callback(RpcAppSystemEvent event, void* context) {
if(event == RpcAppEventSessionClose) { if(event == RpcAppEventSessionClose) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcSessionClose); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcSessionClose);
rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL);
nfc->rpc_ctx = NULL;
} else if(event == RpcAppEventAppExit) { } else if(event == RpcAppEventAppExit) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
} else if(event == RpcAppEventLoadFile) { } else if(event == RpcAppEventLoadFile) {
@@ -87,11 +89,6 @@ Nfc* nfc_alloc() {
nfc->widget = widget_alloc(); nfc->widget = widget_alloc();
view_dispatcher_add_view(nfc->view_dispatcher, NfcViewWidget, widget_get_view(nfc->widget)); view_dispatcher_add_view(nfc->view_dispatcher, NfcViewWidget, widget_get_view(nfc->widget));
// Bank Card
nfc->bank_card = bank_card_alloc();
view_dispatcher_add_view(
nfc->view_dispatcher, NfcViewBankCard, bank_card_get_view(nfc->bank_card));
// Mifare Classic Dict Attack // Mifare Classic Dict Attack
nfc->dict_attack = dict_attack_alloc(); nfc->dict_attack = dict_attack_alloc();
view_dispatcher_add_view( view_dispatcher_add_view(
@@ -157,10 +154,6 @@ void nfc_free(Nfc* nfc) {
view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewWidget); view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewWidget);
widget_free(nfc->widget); widget_free(nfc->widget);
// Bank Card
view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewBankCard);
bank_card_free(nfc->bank_card);
// Mifare Classic Dict Attack // Mifare Classic Dict Attack
view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDictAttack); view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDictAttack);
dict_attack_free(nfc->dict_attack); dict_attack_free(nfc->dict_attack);

View File

@@ -25,8 +25,8 @@
#include <lib/nfc/nfc_worker.h> #include <lib/nfc/nfc_worker.h>
#include <lib/nfc/nfc_device.h> #include <lib/nfc/nfc_device.h>
#include <lib/nfc/helpers/mf_classic_dict.h> #include <lib/nfc/helpers/mf_classic_dict.h>
#include <lib/nfc/parsers/nfc_supported_card.h>
#include "views/bank_card.h"
#include "views/dict_attack.h" #include "views/dict_attack.h"
#include <nfc/scenes/nfc_scene.h> #include <nfc/scenes/nfc_scene.h>
@@ -70,7 +70,6 @@ struct Nfc {
ByteInput* byte_input; ByteInput* byte_input;
TextBox* text_box; TextBox* text_box;
Widget* widget; Widget* widget;
BankCard* bank_card;
DictAttack* dict_attack; DictAttack* dict_attack;
const NfcGenerator* generator; const NfcGenerator* generator;
@@ -85,7 +84,6 @@ typedef enum {
NfcViewByteInput, NfcViewByteInput,
NfcViewTextBox, NfcViewTextBox,
NfcViewWidget, NfcViewWidget,
NfcViewBankCard,
NfcViewDictAttack, NfcViewDictAttack,
} NfcView; } NfcView;

View File

@@ -12,7 +12,10 @@ ADD_SCENE(nfc, save_name, SaveName)
ADD_SCENE(nfc, save_success, SaveSuccess) ADD_SCENE(nfc, save_success, SaveSuccess)
ADD_SCENE(nfc, file_select, FileSelect) ADD_SCENE(nfc, file_select, FileSelect)
ADD_SCENE(nfc, emulate_uid, EmulateUid) ADD_SCENE(nfc, emulate_uid, EmulateUid)
ADD_SCENE(nfc, nfca_read_success, NfcaReadSuccess)
ADD_SCENE(nfc, nfca_menu, NfcaMenu)
ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess)
ADD_SCENE(nfc, mf_ultralight_data, MfUltralightData)
ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu)
ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate) ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate)
ADD_SCENE(nfc, mf_ultralight_read_auth, MfUltralightReadAuth) ADD_SCENE(nfc, mf_ultralight_read_auth, MfUltralightReadAuth)
@@ -25,13 +28,13 @@ ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu)
ADD_SCENE(nfc, mf_desfire_data, MfDesfireData) ADD_SCENE(nfc, mf_desfire_data, MfDesfireData)
ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp)
ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess) ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess)
ADD_SCENE(nfc, mf_classic_info, MfClassicInfo)
ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu) ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu)
ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate) ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate)
ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys) ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys)
ADD_SCENE(nfc, mf_classic_keys_add, MfClassicKeysAdd) ADD_SCENE(nfc, mf_classic_keys_add, MfClassicKeysAdd)
ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack)
ADD_SCENE(nfc, emv_read_success, EmvReadSuccess) ADD_SCENE(nfc, emv_read_success, EmvReadSuccess)
ADD_SCENE(nfc, emv_menu, EmvMenu)
ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence) ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence)
ADD_SCENE(nfc, device_info, DeviceInfo) ADD_SCENE(nfc, device_info, DeviceInfo)
ADD_SCENE(nfc, delete, Delete) ADD_SCENE(nfc, delete, Delete)
@@ -45,3 +48,4 @@ ADD_SCENE(nfc, rpc, Rpc)
ADD_SCENE(nfc, exit_confirm, ExitConfirm) ADD_SCENE(nfc, exit_confirm, ExitConfirm)
ADD_SCENE(nfc, retry_confirm, RetryConfirm) ADD_SCENE(nfc, retry_confirm, RetryConfirm)
ADD_SCENE(nfc, detect_reader, DetectReader) ADD_SCENE(nfc, detect_reader, DetectReader)
ADD_SCENE(nfc, nfc_data_info, NfcDataInfo)

View File

@@ -9,58 +9,43 @@ void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void
void nfc_scene_delete_on_enter(void* context) { void nfc_scene_delete_on_enter(void* context) {
Nfc* nfc = context; Nfc* nfc = context;
FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
// Setup Custom Widget view // Setup Custom Widget view
char temp_str[64]; string_t temp_str;
snprintf(temp_str, sizeof(temp_str), "\e#Delete %s?\e#", nfc->dev->dev_name); string_init(temp_str);
string_printf(temp_str, "\e#Delete %s?\e#", nfc->dev->dev_name);
widget_add_text_box_element( widget_add_text_box_element(
nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, temp_str, false); nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, string_get_cstr(temp_str), false);
widget_add_button_element( widget_add_button_element(
nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_delete_widget_callback, nfc); nfc->widget, GuiButtonTypeLeft, "Cancel", nfc_scene_delete_widget_callback, nfc);
widget_add_button_element( widget_add_button_element(
nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc); nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc);
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
if(data->uid_len == 4) {
snprintf(
temp_str,
sizeof(temp_str),
"UID: %02X %02X %02X %02X",
data->uid[0],
data->uid[1],
data->uid[2],
data->uid[3]);
} else if(data->uid_len == 7) {
snprintf(
temp_str,
sizeof(temp_str),
"UID: %02X %02X %02X %02X %02X %02X %02X",
data->uid[0],
data->uid[1],
data->uid[2],
data->uid[3],
data->uid[4],
data->uid[5],
data->uid[6]);
}
widget_add_string_element(nfc->widget, 64, 23, AlignCenter, AlignTop, FontSecondary, temp_str);
const char* protocol_name = NULL; string_set_str(temp_str, "UID:");
for(size_t i = 0; i < nfc_data->uid_len; i++) {
string_cat_printf(temp_str, " %02X", nfc_data->uid[i]);
}
widget_add_string_element(
nfc->widget, 64, 24, AlignCenter, AlignTop, FontSecondary, string_get_cstr(temp_str));
NfcProtocol protocol = nfc->dev->dev_data.protocol; NfcProtocol protocol = nfc->dev->dev_data.protocol;
if(protocol == NfcDeviceProtocolEMV) { if(protocol == NfcDeviceProtocolEMV) {
protocol_name = nfc_guess_protocol(protocol); string_set_str(temp_str, "EMV bank card");
} else if(protocol == NfcDeviceProtocolMifareUl) { } else if(protocol == NfcDeviceProtocolMifareUl) {
protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false); string_set_str(temp_str, nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, true));
} else if(protocol == NfcDeviceProtocolMifareClassic) {
string_set_str(temp_str, nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type));
} else if(protocol == NfcDeviceProtocolMifareDesfire) {
string_set_str(temp_str, "MIFARE DESFire");
} else {
string_set_str(temp_str, "Unknown ISO tag");
} }
if(protocol_name) {
widget_add_string_element( widget_add_string_element(
nfc->widget, 10, 33, AlignLeft, AlignTop, FontSecondary, protocol_name); nfc->widget, 64, 34, AlignCenter, AlignTop, FontSecondary, string_get_cstr(temp_str));
} widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, "NFC-A");
// TODO change dinamically string_clear(temp_str);
widget_add_string_element(nfc->widget, 118, 33, AlignRight, AlignTop, FontSecondary, "NFC-A");
snprintf(temp_str, sizeof(temp_str), "SAK: %02X", data->sak);
widget_add_string_element(nfc->widget, 10, 43, AlignLeft, AlignTop, FontSecondary, temp_str);
snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]);
widget_add_string_element(nfc->widget, 118, 43, AlignRight, AlignTop, FontSecondary, temp_str);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
} }
@@ -71,7 +56,7 @@ bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) { if(event.event == GuiButtonTypeLeft) {
return scene_manager_previous_scene(nfc->scene_manager); consumed = scene_manager_previous_scene(nfc->scene_manager);
} else if(event.event == GuiButtonTypeRight) { } else if(event.event == GuiButtonTypeRight) {
if(nfc_device_delete(nfc->dev, true)) { if(nfc_device_delete(nfc->dev, true)) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess); scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess);

View File

@@ -26,7 +26,7 @@ bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventViewExit) { if(event.event == NfcCustomEventViewExit) {
consumed = scene_manager_search_and_switch_to_previous_scene( consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneStart); nfc->scene_manager, NfcSceneFileSelect);
} }
} }
return consumed; return consumed;

View File

@@ -1,11 +1,6 @@
#include "../nfc_i.h" #include "../nfc_i.h"
#include "../helpers/nfc_emv_parser.h" #include "../helpers/nfc_emv_parser.h"
enum {
NfcSceneDeviceInfoUid,
NfcSceneDeviceInfoData,
};
void nfc_scene_device_info_widget_callback(GuiButtonType result, InputType type, void* context) { void nfc_scene_device_info_widget_callback(GuiButtonType result, InputType type, void* context) {
Nfc* nfc = context; Nfc* nfc = context;
if(type == InputTypeShort) { if(type == InputTypeShort) {
@@ -13,197 +8,65 @@ void nfc_scene_device_info_widget_callback(GuiButtonType result, InputType type,
} }
} }
void nfc_scene_device_info_dialog_callback(DialogExResult result, void* context) {
Nfc* nfc = context;
if(result == DialogExResultLeft) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
}
}
void nfc_scene_device_info_bank_card_callback(GuiButtonType result, InputType type, void* context) {
UNUSED(result);
Nfc* nfc = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
}
}
void nfc_scene_device_info_on_enter(void* context) { void nfc_scene_device_info_on_enter(void* context) {
Nfc* nfc = context; Nfc* nfc = context;
NfcDeviceData* dev_data = &nfc->dev->dev_data;
bool data_display_supported = (nfc->dev->format == NfcDeviceSaveFormatUid) || string_t temp_str;
(nfc->dev->format == NfcDeviceSaveFormatMifareUl) || string_init(temp_str);
(nfc->dev->format == NfcDeviceSaveFormatMifareDesfire) ||
(nfc->dev->format == NfcDeviceSaveFormatBankCard);
// Setup Custom Widget view
widget_add_text_box_element(
nfc->widget, 0, 0, 128, 22, AlignCenter, AlignTop, nfc->dev->dev_name, false);
widget_add_button_element(
nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_device_info_widget_callback, nfc);
if(data_display_supported) {
widget_add_button_element(
nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc);
}
char temp_str[32];
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
if(data->uid_len == 4) {
snprintf(
temp_str,
sizeof(temp_str),
"UID: %02X %02X %02X %02X",
data->uid[0],
data->uid[1],
data->uid[2],
data->uid[3]);
} else if(data->uid_len == 7) {
snprintf(
temp_str,
sizeof(temp_str),
"UID: %02X %02X %02X %02X %02X %02X %02X",
data->uid[0],
data->uid[1],
data->uid[2],
data->uid[3],
data->uid[4],
data->uid[5],
data->uid[6]);
}
widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, temp_str);
const char* protocol_name = NULL; if(dev_data->protocol == NfcDeviceProtocolEMV) {
NfcProtocol protocol = nfc->dev->dev_data.protocol; EmvData* emv_data = &dev_data->emv_data;
if(protocol == NfcDeviceProtocolEMV || protocol == NfcDeviceProtocolMifareDesfire) { string_printf(temp_str, "\e#%s\n", emv_data->name);
protocol_name = nfc_guess_protocol(protocol); for(uint8_t i = 0; i < emv_data->number_len; i += 2) {
} else if(protocol == NfcDeviceProtocolMifareUl) { string_cat_printf(temp_str, "%02X%02X ", emv_data->number[i], emv_data->number[i + 1]);
protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false);
} else if(protocol == NfcDeviceProtocolMifareClassic) {
protocol_name = nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type);
} }
if(protocol_name) { string_strim(temp_str);
widget_add_string_element(
nfc->widget, 10, 32, AlignLeft, AlignTop, FontSecondary, protocol_name);
}
// TODO change dinamically
widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A");
snprintf(temp_str, sizeof(temp_str), "SAK: %02X", data->sak);
widget_add_string_element(nfc->widget, 10, 42, AlignLeft, AlignTop, FontSecondary, temp_str);
snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]);
widget_add_string_element(nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, temp_str);
// Setup Data View // Add expiration date
if(nfc->dev->format == NfcDeviceSaveFormatUid) {
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_left_button_text(dialog_ex, "Back");
dialog_ex_set_text(dialog_ex, "No data", 64, 32, AlignCenter, AlignCenter);
dialog_ex_set_context(dialog_ex, nfc);
dialog_ex_set_result_callback(dialog_ex, nfc_scene_device_info_dialog_callback);
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
TextBox* text_box = nfc->text_box;
text_box_set_font(text_box, TextBoxFontHex);
for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) {
if(!(i % 8) && i) {
string_push_back(nfc->text_box_store, '\n');
}
string_cat_printf(
nfc->text_box_store, "%02X%02X ", mf_ul_data->data[i], mf_ul_data->data[i + 1]);
}
text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareDesfire) {
MifareDesfireData* mf_df_data = &nfc->dev->dev_data.mf_df_data;
uint16_t n_apps = 0;
uint16_t n_files = 0;
for(MifareDesfireApplication* app = mf_df_data->app_head; app; app = app->next) {
n_apps++;
for(MifareDesfireFile* file = app->file_head; file; file = file->next) {
n_files++;
}
}
nfc_text_store_set(
nfc,
"%d application%s, %d file%s",
n_apps,
n_apps == 1 ? "" : "s",
n_files,
n_files == 1 ? "" : "s");
widget_add_string_element(
nfc->widget, 64, 17, AlignCenter, AlignBottom, FontSecondary, nfc->text_store);
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
EmvData* emv_data = &nfc->dev->dev_data.emv_data;
BankCard* bank_card = nfc->bank_card;
bank_card_set_name(bank_card, emv_data->name);
bank_card_set_number(bank_card, emv_data->number, emv_data->number_len);
bank_card_set_back_callback(bank_card, nfc_scene_device_info_bank_card_callback, nfc);
if(emv_data->exp_mon) { if(emv_data->exp_mon) {
bank_card_set_exp_date(bank_card, emv_data->exp_mon, emv_data->exp_year); string_cat_printf(temp_str, "\nExp: %02X/%02X", emv_data->exp_mon, emv_data->exp_year);
} }
string_t display_str; // Parse currency code
string_init(display_str); if((emv_data->currency_code)) {
if(emv_data->country_code) { string_t currency_name;
string_init(currency_name);
if(nfc_emv_parser_get_currency_name(
nfc->dev->storage, emv_data->currency_code, currency_name)) {
string_cat_printf(temp_str, "\nCur: %s ", string_get_cstr(currency_name));
}
string_clear(currency_name);
}
// Parse country code
if((emv_data->country_code)) {
string_t country_name; string_t country_name;
string_init(country_name); string_init(country_name);
if(nfc_emv_parser_get_country_name( if(nfc_emv_parser_get_country_name(
nfc->dev->storage, emv_data->country_code, country_name)) { nfc->dev->storage, emv_data->country_code, country_name)) {
string_printf(display_str, "Reg:%s", string_get_cstr(country_name)); string_cat_printf(temp_str, "Reg: %s", string_get_cstr(country_name));
bank_card_set_country_name(bank_card, string_get_cstr(display_str));
} }
string_clear(country_name); string_clear(country_name);
} }
if(emv_data->currency_code) { } else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) {
string_t currency_name; string_set(temp_str, nfc->dev->dev_data.parsed_data);
string_init(currency_name);
if(nfc_emv_parser_get_currency_name(
nfc->dev->storage, emv_data->country_code, currency_name)) {
string_printf(display_str, "Cur:%s", string_get_cstr(currency_name));
bank_card_set_currency_name(bank_card, string_get_cstr(display_str));
} }
string_clear(currency_name);
} widget_add_text_scroll_element(nfc->widget, 0, 0, 128, 52, string_get_cstr(temp_str));
string_clear(display_str); string_clear(temp_str);
}
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid); widget_add_button_element(
nfc->widget, GuiButtonTypeRight, "More", nfc_scene_device_info_widget_callback, nfc);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
} }
bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context; Nfc* nfc = context;
bool consumed = false; bool consumed = false;
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDeviceInfo);
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if((state == NfcSceneDeviceInfoUid) && (event.event == GuiButtonTypeLeft)) { if(event.event == GuiButtonTypeRight) {
consumed = scene_manager_previous_scene(nfc->scene_manager); scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo);
} else if((state == NfcSceneDeviceInfoUid) && (event.event == GuiButtonTypeRight)) {
if(nfc->dev->format == NfcDeviceSaveFormatUid) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
consumed = true;
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
consumed = true;
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewBankCard);
consumed = true;
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareDesfire) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData);
consumed = true;
}
} else if(state == NfcSceneDeviceInfoData && event.event == NfcCustomEventViewExit) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
if(state == NfcSceneDeviceInfoData) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
consumed = true; consumed = true;
} }
} }
@@ -215,12 +78,4 @@ void nfc_scene_device_info_on_exit(void* context) {
// Clear views // Clear views
widget_reset(nfc->widget); widget_reset(nfc->widget);
if(nfc->dev->format == NfcDeviceSaveFormatUid) {
dialog_ex_reset(nfc->dialog_ex);
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
text_box_reset(nfc->text_box);
string_reset(nfc->text_box_store);
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
bank_card_clear(nfc->bank_card);
}
} }

View File

@@ -0,0 +1,54 @@
#include "../nfc_i.h"
enum SubmenuIndex {
SubmenuIndexSave,
SubmenuIndexInfo,
};
void nfc_scene_emv_menu_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
}
void nfc_scene_emv_menu_on_enter(void* context) {
Nfc* nfc = context;
Submenu* submenu = nfc->submenu;
submenu_add_item(submenu, "Save", SubmenuIndexSave, nfc_scene_emv_menu_submenu_callback, nfc);
submenu_add_item(submenu, "Info", SubmenuIndexInfo, nfc_scene_emv_menu_submenu_callback, nfc);
submenu_set_selected_item(
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmvMenu));
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
}
bool nfc_scene_emv_menu_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexSave) {
nfc->dev->format = NfcDeviceSaveFormatBankCard;
// Clear device name
nfc_device_set_name(nfc->dev, "");
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
consumed = true;
} else if(event.event == SubmenuIndexInfo) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo);
consumed = true;
}
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneEmvMenu, event.event);
} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_previous_scene(nfc->scene_manager);
}
return consumed;
}
void nfc_scene_emv_menu_on_exit(void* context) {
Nfc* nfc = context;
// Clear view
submenu_reset(nfc->submenu);
}

View File

@@ -15,85 +15,48 @@ void nfc_scene_emv_read_success_widget_callback(
void nfc_scene_emv_read_success_on_enter(void* context) { void nfc_scene_emv_read_success_on_enter(void* context) {
Nfc* nfc = context; Nfc* nfc = context;
EmvData* emv_data = &nfc->dev->dev_data.emv_data; EmvData* emv_data = &nfc->dev->dev_data.emv_data;
FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
DOLPHIN_DEED(DolphinDeedNfcReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
// Setup Custom Widget view // Setup Custom Widget view
// Add frame
widget_add_frame_element(nfc->widget, 0, 0, 128, 64, 6);
// Add buttons
widget_add_button_element( widget_add_button_element(
nfc->widget, GuiButtonTypeLeft, "Retry", nfc_scene_emv_read_success_widget_callback, nfc); nfc->widget, GuiButtonTypeLeft, "Retry", nfc_scene_emv_read_success_widget_callback, nfc);
widget_add_button_element( widget_add_button_element(
nfc->widget, GuiButtonTypeRight, "Save", nfc_scene_emv_read_success_widget_callback, nfc); nfc->widget, GuiButtonTypeRight, "More", nfc_scene_emv_read_success_widget_callback, nfc);
// Add card name
widget_add_string_element( string_t temp_str;
nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev->dev_data.emv_data.name); string_init_printf(temp_str, "\e#%s\n", emv_data->name);
// Add card number
string_t pan_str;
string_init(pan_str);
for(uint8_t i = 0; i < emv_data->number_len; i += 2) { for(uint8_t i = 0; i < emv_data->number_len; i += 2) {
string_cat_printf(pan_str, "%02X%02X ", emv_data->number[i], emv_data->number[i + 1]); string_cat_printf(temp_str, "%02X%02X ", emv_data->number[i], emv_data->number[i + 1]);
} }
string_strim(pan_str); string_strim(temp_str);
widget_add_string_element(
nfc->widget, 64, 13, AlignCenter, AlignTop, FontSecondary, string_get_cstr(pan_str));
string_clear(pan_str);
// Parse country code
string_t country_name;
string_init(country_name);
if((emv_data->country_code) &&
nfc_emv_parser_get_country_name(nfc->dev->storage, emv_data->country_code, country_name)) {
string_t disp_country;
string_init_printf(disp_country, "Reg:%s", country_name);
widget_add_string_element(
nfc->widget, 7, 23, AlignLeft, AlignTop, FontSecondary, string_get_cstr(disp_country));
string_clear(disp_country);
}
string_clear(country_name);
// Parse currency code
string_t currency_name;
string_init(currency_name);
if((emv_data->currency_code) &&
nfc_emv_parser_get_currency_name(
nfc->dev->storage, emv_data->currency_code, currency_name)) {
string_t disp_currency;
string_init_printf(disp_currency, "Cur:%s", currency_name);
widget_add_string_element(
nfc->widget,
121,
23,
AlignRight,
AlignTop,
FontSecondary,
string_get_cstr(disp_currency));
string_clear(disp_currency);
}
string_clear(currency_name);
char temp_str[32];
// Add ATQA
snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", nfc_data->atqa[0], nfc_data->atqa[1]);
widget_add_string_element(nfc->widget, 121, 32, AlignRight, AlignTop, FontSecondary, temp_str);
// Add UID
snprintf(
temp_str,
sizeof(temp_str),
"UID: %02X %02X %02X %02X",
nfc_data->uid[0],
nfc_data->uid[1],
nfc_data->uid[2],
nfc_data->uid[3]);
widget_add_string_element(nfc->widget, 7, 42, AlignLeft, AlignTop, FontSecondary, temp_str);
// Add SAK
snprintf(temp_str, sizeof(temp_str), "SAK: %02X", nfc_data->sak);
widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, temp_str);
// Add expiration date // Add expiration date
if(emv_data->exp_mon) { if(emv_data->exp_mon) {
char exp_str[16]; string_cat_printf(temp_str, "\nExp: %02X/%02X", emv_data->exp_mon, emv_data->exp_year);
snprintf(
exp_str, sizeof(exp_str), "Exp: %02X/%02X", emv_data->exp_mon, emv_data->exp_year);
widget_add_string_element(nfc->widget, 7, 32, AlignLeft, AlignTop, FontSecondary, exp_str);
} }
// Parse currency code
if((emv_data->currency_code)) {
string_t currency_name;
string_init(currency_name);
if(nfc_emv_parser_get_currency_name(
nfc->dev->storage, emv_data->currency_code, currency_name)) {
string_cat_printf(temp_str, "\nCur: %s ", string_get_cstr(currency_name));
}
string_clear(currency_name);
}
// Parse country code
if((emv_data->country_code)) {
string_t country_name;
string_init(country_name);
if(nfc_emv_parser_get_country_name(
nfc->dev->storage, emv_data->country_code, country_name)) {
string_cat_printf(temp_str, "Reg: %s", string_get_cstr(country_name));
}
string_clear(country_name);
}
widget_add_text_scroll_element(nfc->widget, 0, 0, 128, 52, string_get_cstr(temp_str));
string_clear(temp_str);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
} }
@@ -107,10 +70,7 @@ bool nfc_scene_emv_read_success_on_event(void* context, SceneManagerEvent event)
scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm);
consumed = true; consumed = true;
} else if(event.event == GuiButtonTypeRight) { } else if(event.event == GuiButtonTypeRight) {
// Clear device name scene_manager_next_scene(nfc->scene_manager, NfcSceneEmvMenu);
nfc_device_set_name(nfc->dev, "");
nfc->dev->format = NfcDeviceSaveFormatBankCard;
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
consumed = true; consumed = true;
} }
} else if(event.type == SceneManagerEventTypeBack) { } else if(event.type == SceneManagerEventTypeBack) {

View File

@@ -6,6 +6,7 @@ void nfc_scene_file_select_on_enter(void* context) {
// Process file_select return // Process file_select return
nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc);
if(nfc_file_select(nfc->dev)) { if(nfc_file_select(nfc->dev)) {
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, 0);
scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu); scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu);
} else { } else {
scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart);

View File

@@ -1,72 +0,0 @@
#include "../nfc_i.h"
void nfc_scene_mf_classic_info_widget_callback(GuiButtonType result, InputType type, void* context) {
furi_assert(context);
Nfc* nfc = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
}
void nfc_scene_mf_classic_info_on_enter(void* context) {
Nfc* nfc = context;
NfcDeviceData* dev_data = &nfc->dev->dev_data;
MfClassicData* mf_data = &dev_data->mf_classic_data;
string_t str_tmp;
string_init(str_tmp);
// Setup view
Widget* widget = nfc->widget;
widget_add_string_element(
widget, 0, 0, AlignLeft, AlignTop, FontSecondary, mf_classic_get_type_str(mf_data->type));
widget_add_string_element(
widget, 0, 11, AlignLeft, AlignTop, FontSecondary, "ISO 14443-3 (Type A)");
string_printf(str_tmp, "UID:");
for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) {
string_cat_printf(str_tmp, " %02X", dev_data->nfc_data.uid[i]);
}
widget_add_string_element(
widget, 0, 22, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp));
string_printf(
str_tmp,
"ATQA: %02X %02X SAK: %02X",
dev_data->nfc_data.atqa[0],
dev_data->nfc_data.atqa[1],
dev_data->nfc_data.sak);
widget_add_string_element(
widget, 0, 33, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp));
uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type);
uint8_t keys_total = sectors_total * 2;
uint8_t keys_found = 0;
uint8_t sectors_read = 0;
mf_classic_get_read_sectors_and_keys(mf_data, &sectors_read, &keys_found);
string_printf(str_tmp, "Keys Found: %d/%d", keys_found, keys_total);
widget_add_string_element(
widget, 0, 44, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp));
string_printf(str_tmp, "Sectors Read: %d/%d", sectors_read, sectors_total);
widget_add_string_element(
widget, 0, 55, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp));
string_clear(str_tmp);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
}
bool nfc_scene_mf_classic_info_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_previous_scene(nfc->scene_manager);
}
return consumed;
}
void nfc_scene_mf_classic_info_on_exit(void* context) {
Nfc* nfc = context;
// Clear view
widget_reset(nfc->widget);
}

View File

@@ -34,6 +34,7 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) {
widget_add_string_element(nfc->widget, 0, 32, AlignLeft, AlignTop, FontSecondary, temp_str); widget_add_string_element(nfc->widget, 0, 32, AlignLeft, AlignTop, FontSecondary, temp_str);
widget_add_button_element( widget_add_button_element(
nfc->widget, GuiButtonTypeCenter, "Add", nfc_scene_mf_classic_keys_widget_callback, nfc); nfc->widget, GuiButtonTypeCenter, "Add", nfc_scene_mf_classic_keys_widget_callback, nfc);
widget_add_icon_element(nfc->widget, 90, 12, &I_Keychain);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
} }

View File

@@ -50,7 +50,7 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event)
} else if(event.event == SubmenuIndexInfo) { } else if(event.event == SubmenuIndexInfo) {
scene_manager_set_scene_state( scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexInfo); nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexInfo);
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicInfo); scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo);
consumed = true; consumed = true;
} }
} else if(event.type == SceneManagerEventTypeBack) { } else if(event.type == SceneManagerEventTypeBack) {

View File

@@ -17,8 +17,6 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) {
Nfc* nfc = context; Nfc* nfc = context;
NfcDeviceData* dev_data = &nfc->dev->dev_data; NfcDeviceData* dev_data = &nfc->dev->dev_data;
MfClassicData* mf_data = &dev_data->mf_classic_data; MfClassicData* mf_data = &dev_data->mf_classic_data;
string_t str_tmp;
string_init(str_tmp);
DOLPHIN_DEED(DolphinDeedNfcReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
@@ -29,48 +27,27 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) {
widget_add_button_element( widget_add_button_element(
widget, GuiButtonTypeRight, "More", nfc_scene_mf_classic_read_success_widget_callback, nfc); widget, GuiButtonTypeRight, "More", nfc_scene_mf_classic_read_success_widget_callback, nfc);
string_t temp_str;
if(string_size(nfc->dev->dev_data.parsed_data)) { if(string_size(nfc->dev->dev_data.parsed_data)) {
widget_add_text_box_element( string_init_set(temp_str, nfc->dev->dev_data.parsed_data);
nfc->widget,
0,
0,
128,
32,
AlignLeft,
AlignTop,
string_get_cstr(nfc->dev->dev_data.parsed_data),
true);
} else { } else {
widget_add_string_element( string_init_printf(temp_str, "\e#%s\n", nfc_mf_classic_type(mf_data->type));
widget, string_cat_printf(temp_str, "UID:");
0,
0,
AlignLeft,
AlignTop,
FontSecondary,
mf_classic_get_type_str(mf_data->type));
widget_add_string_element(
widget, 0, 11, AlignLeft, AlignTop, FontSecondary, "ISO 14443-3 (Type A)");
string_printf(str_tmp, "UID:");
for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) { for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) {
string_cat_printf(str_tmp, " %02X", dev_data->nfc_data.uid[i]); string_cat_printf(temp_str, " %02X", dev_data->nfc_data.uid[i]);
} }
widget_add_string_element(
widget, 0, 22, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp));
uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type); uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type);
uint8_t keys_total = sectors_total * 2; uint8_t keys_total = sectors_total * 2;
uint8_t keys_found = 0; uint8_t keys_found = 0;
uint8_t sectors_read = 0; uint8_t sectors_read = 0;
mf_classic_get_read_sectors_and_keys(mf_data, &sectors_read, &keys_found); mf_classic_get_read_sectors_and_keys(mf_data, &sectors_read, &keys_found);
string_printf(str_tmp, "Keys Found: %d/%d", keys_found, keys_total); string_cat_printf(temp_str, "\nKeys Found: %d/%d", keys_found, keys_total);
widget_add_string_element( string_cat_printf(temp_str, "\nSectors Read: %d/%d", sectors_read, sectors_total);
widget, 0, 33, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp));
string_printf(str_tmp, "Sectors Read: %d/%d", sectors_read, sectors_total);
widget_add_string_element(
widget, 0, 44, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp));
} }
string_clear(str_tmp); widget_add_text_scroll_element(widget, 0, 0, 128, 52, string_get_cstr(temp_str));
string_clear(temp_str);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
} }

View File

@@ -2,6 +2,8 @@
enum SubmenuIndex { enum SubmenuIndex {
SubmenuIndexSave, SubmenuIndexSave,
SubmenuIndexEmulateUid,
SubmenuIndexInfo,
}; };
void nfc_scene_mf_desfire_menu_submenu_callback(void* context, uint32_t index) { void nfc_scene_mf_desfire_menu_submenu_callback(void* context, uint32_t index) {
@@ -16,6 +18,15 @@ void nfc_scene_mf_desfire_menu_on_enter(void* context) {
submenu_add_item( submenu_add_item(
submenu, "Save", SubmenuIndexSave, nfc_scene_mf_desfire_menu_submenu_callback, nfc); submenu, "Save", SubmenuIndexSave, nfc_scene_mf_desfire_menu_submenu_callback, nfc);
submenu_add_item(
submenu,
"Emulate UID",
SubmenuIndexEmulateUid,
nfc_scene_mf_desfire_menu_submenu_callback,
nfc);
submenu_add_item(
submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_desfire_menu_submenu_callback, nfc);
submenu_set_selected_item( submenu_set_selected_item(
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireMenu)); nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireMenu));
@@ -35,6 +46,12 @@ bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event)
nfc_device_set_name(nfc->dev, ""); nfc_device_set_name(nfc->dev, "");
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
consumed = true; consumed = true;
} else if(event.event == SubmenuIndexEmulateUid) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
consumed = true;
} else if(event.event == SubmenuIndexInfo) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo);
consumed = true;
} }
} }

View File

@@ -1,91 +1,86 @@
#include "../nfc_i.h" #include "../nfc_i.h"
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
#define NFC_SCENE_READ_SUCCESS_SHIFT " " void nfc_scene_mf_desfire_read_success_widget_callback(
GuiButtonType result,
enum { InputType type,
MfDesfireReadSuccessStateShowUID, void* context) {
MfDesfireReadSuccessStateShowData,
};
void nfc_scene_mf_desfire_read_success_dialog_callback(DialogExResult result, void* context) {
Nfc* nfc = context; Nfc* nfc = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result); view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
} }
}
void nfc_scene_mf_desfire_read_success_on_enter(void* context) { void nfc_scene_mf_desfire_read_success_on_enter(void* context) {
Nfc* nfc = context; Nfc* nfc = context;
FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
DialogEx* dialog_ex = nfc->dialog_ex; Widget* widget = nfc->widget;
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_center_button_text(dialog_ex, "Data"); // Prepare string for data display
dialog_ex_set_right_button_text(dialog_ex, "More"); string_t temp_str;
dialog_ex_set_icon(dialog_ex, 8, 16, &I_Medium_chip_22x21); string_init_printf(temp_str, "\e#MIFARE DESfire\n");
string_cat_printf(temp_str, "UID:");
for(size_t i = 0; i < nfc_data->uid_len; i++) {
string_cat_printf(temp_str, " %02X", nfc_data->uid[i]);
}
uint32_t bytes_total = 1 << (data->version.sw_storage >> 1);
uint32_t bytes_free = data->free_memory ? data->free_memory->bytes : 0;
string_cat_printf(temp_str, "\n%d", bytes_total);
if(data->version.sw_storage & 1) {
string_push_back(temp_str, '+');
}
string_cat_printf(temp_str, " bytes, %d bytes free\n", bytes_free);
uint16_t n_apps = 0; uint16_t n_apps = 0;
uint16_t n_files = 0; uint16_t n_files = 0;
for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { for(MifareDesfireApplication* app = data->app_head; app; app = app->next) {
n_apps++; n_apps++;
for(MifareDesfireFile* file = app->file_head; file; file = file->next) { for(MifareDesfireFile* file = app->file_head; file; file = file->next) {
n_files++; n_files++;
} }
} }
string_cat_printf(temp_str, "%d Application", n_apps);
if(n_apps != 1) {
string_push_back(temp_str, 's');
}
string_cat_printf(temp_str, ", %d file", n_files);
if(n_files != 1) {
string_push_back(temp_str, 's');
}
// TODO rework info view // Add text scroll element
nfc_text_store_set( widget_add_text_scroll_element(widget, 0, 0, 128, 52, string_get_cstr(temp_str));
nfc, string_clear(temp_str);
NFC_SCENE_READ_SUCCESS_SHIFT "Mifare DESFire\n" NFC_SCENE_READ_SUCCESS_SHIFT
"%d%s bytes\n" NFC_SCENE_READ_SUCCESS_SHIFT "%d bytes free\n"
"%d application%s, %d file%s",
1 << (data->version.sw_storage >> 1),
(data->version.sw_storage & 1) ? "+" : "",
data->free_memory ? data->free_memory->bytes : 0,
n_apps,
n_apps == 1 ? "" : "s",
n_files,
n_files == 1 ? "" : "s");
dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 6, AlignLeft, AlignTop);
dialog_ex_set_context(dialog_ex, nfc);
dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_desfire_read_success_dialog_callback);
scene_manager_set_scene_state( // Add button elements
nfc->scene_manager, NfcSceneMfDesfireReadSuccess, MfDesfireReadSuccessStateShowUID); widget_add_button_element(
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); widget, GuiButtonTypeLeft, "Retry", nfc_scene_mf_desfire_read_success_widget_callback, nfc);
widget_add_button_element(
widget, GuiButtonTypeRight, "More", nfc_scene_mf_desfire_read_success_widget_callback, nfc);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
} }
bool nfc_scene_mf_desfire_read_success_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_mf_desfire_read_success_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context; Nfc* nfc = context;
bool consumed = false; bool consumed = false;
uint32_t state =
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireReadSuccess);
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultLeft) { if(event.event == GuiButtonTypeLeft) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm);
consumed = true; consumed = true;
} else if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultCenter) { } else if(event.event == GuiButtonTypeRight) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData);
consumed = true;
} else if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultRight) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireMenu); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireMenu);
consumed = true; consumed = true;
} }
} else if(event.type == SceneManagerEventTypeBack) { } else if(event.type == SceneManagerEventTypeBack) {
if(state == MfDesfireReadSuccessStateShowData) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
scene_manager_set_scene_state(
nfc->scene_manager,
NfcSceneMfDesfireReadSuccess,
MfDesfireReadSuccessStateShowUID);
consumed = true;
} else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm);
consumed = true; consumed = true;
} }
}
return consumed; return consumed;
} }
@@ -94,5 +89,5 @@ void nfc_scene_mf_desfire_read_success_on_exit(void* context) {
Nfc* nfc = context; Nfc* nfc = context;
// Clean dialog // Clean dialog
dialog_ex_reset(nfc->dialog_ex); widget_reset(nfc->widget);
} }

View File

@@ -0,0 +1,32 @@
#include "../nfc_i.h"
void nfc_scene_mf_ultralight_data_on_enter(void* context) {
Nfc* nfc = context;
MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data;
TextBox* text_box = nfc->text_box;
text_box_set_font(text_box, TextBoxFontHex);
for(uint16_t i = 0; i < data->data_size; i += 2) {
if(!(i % 8) && i) {
string_push_back(nfc->text_box_store, '\n');
}
string_cat_printf(nfc->text_box_store, "%02X%02X ", data->data[i], data->data[i + 1]);
}
text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
}
bool nfc_scene_mf_ultralight_data_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void nfc_scene_mf_ultralight_data_on_exit(void* context) {
Nfc* nfc = context;
// Clean view
text_box_reset(nfc->text_box);
string_reset(nfc->text_box_store);
}

View File

@@ -4,6 +4,7 @@ enum SubmenuIndex {
SubmenuIndexUnlock, SubmenuIndexUnlock,
SubmenuIndexSave, SubmenuIndexSave,
SubmenuIndexEmulate, SubmenuIndexEmulate,
SubmenuIndexInfo,
}; };
void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index) { void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index) {
@@ -33,6 +34,9 @@ void nfc_scene_mf_ultralight_menu_on_enter(void* context) {
SubmenuIndexEmulate, SubmenuIndexEmulate,
nfc_scene_mf_ultralight_menu_submenu_callback, nfc_scene_mf_ultralight_menu_submenu_callback,
nfc); nfc);
submenu_add_item(
submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_ultralight_menu_submenu_callback, nfc);
submenu_set_selected_item( submenu_set_selected_item(
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu)); nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu));
@@ -56,6 +60,9 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even
} else if(event.event == SubmenuIndexUnlock) { } else if(event.event == SubmenuIndexUnlock) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
consumed = true; consumed = true;
} else if(event.event == SubmenuIndexInfo) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo);
consumed = true;
} }
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu, event.event); scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu, event.event);

View File

@@ -43,7 +43,7 @@ void nfc_scene_mf_ultralight_read_auth_set_state(Nfc* nfc, NfcSceneMfUlReadState
22, 22,
AlignLeft, AlignLeft,
AlignTop); AlignTop);
popup_set_icon(nfc->popup, 73, 17, &I_DolphinFirstStart8_56x51); popup_set_icon(nfc->popup, 73, 20, &I_DolphinCommon_56x48);
} }
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth, state); scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth, state);
} }

View File

@@ -1,11 +1,6 @@
#include "../nfc_i.h" #include "../nfc_i.h"
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
enum {
ReadMifareUlStateShowInfo,
ReadMifareUlStateShowData,
};
void nfc_scene_mf_ultralight_read_success_widget_callback( void nfc_scene_mf_ultralight_read_success_widget_callback(
GuiButtonType result, GuiButtonType result,
InputType type, InputType type,
@@ -31,12 +26,6 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) {
"Retry", "Retry",
nfc_scene_mf_ultralight_read_success_widget_callback, nfc_scene_mf_ultralight_read_success_widget_callback,
nfc); nfc);
widget_add_button_element(
widget,
GuiButtonTypeCenter,
"Data",
nfc_scene_mf_ultralight_read_success_widget_callback,
nfc);
widget_add_button_element( widget_add_button_element(
widget, widget,
GuiButtonTypeRight, GuiButtonTypeRight,
@@ -44,72 +33,39 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) {
nfc_scene_mf_ultralight_read_success_widget_callback, nfc_scene_mf_ultralight_read_success_widget_callback,
nfc); nfc);
widget_add_string_element( string_t temp_str;
widget, 0, 0, AlignLeft, AlignTop, FontSecondary, nfc_mf_ul_type(mf_ul_data->type, true)); string_init_printf(temp_str, "\e#%s\n", nfc_mf_ul_type(mf_ul_data->type, true));
string_t data_str; string_cat_printf(temp_str, "UID:");
string_init_printf(data_str, "UID:");
for(size_t i = 0; i < data->uid_len; i++) { for(size_t i = 0; i < data->uid_len; i++) {
string_cat_printf(data_str, " %02X", data->uid[i]); string_cat_printf(temp_str, " %02X", data->uid[i]);
}
widget_add_string_element(
widget, 0, 13, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str));
string_printf(
data_str, "Pages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4);
widget_add_string_element(
widget, 0, 24, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str));
if(mf_ul_data->data_read != mf_ul_data->data_size) {
widget_add_string_element(
widget, 0, 35, AlignLeft, AlignTop, FontSecondary, "Password-protected pages!");
}
string_clear(data_str);
// Setup TextBox view
TextBox* text_box = nfc->text_box;
text_box_set_font(text_box, TextBoxFontHex);
for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) {
if(!(i % 8) && i) {
string_push_back(nfc->text_box_store, '\n');
} }
string_cat_printf( string_cat_printf(
nfc->text_box_store, "%02X%02X ", mf_ul_data->data[i], mf_ul_data->data[i + 1]); temp_str, "\nPages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4);
if(mf_ul_data->data_read != mf_ul_data->data_size) {
string_cat_printf(temp_str, "\nPassword-protected pages!");
} }
text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); widget_add_text_scroll_element(widget, 0, 0, 128, 52, string_get_cstr(temp_str));
string_clear(temp_str);
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowInfo);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
} }
bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context; Nfc* nfc = context;
bool consumed = false; bool consumed = false;
uint32_t state =
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadSuccess);
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeLeft) { if(event.event == GuiButtonTypeLeft) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm);
consumed = true; consumed = true;
} else if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeRight) { } else if(event.event == GuiButtonTypeRight) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu);
consumed = true; consumed = true;
} else if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeCenter) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowData);
consumed = true;
} }
} else if(event.type == SceneManagerEventTypeBack) { } else if(event.type == SceneManagerEventTypeBack) {
if(state == ReadMifareUlStateShowData) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowInfo);
consumed = true;
} else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm);
consumed = true; consumed = true;
} }
}
return consumed; return consumed;
} }
@@ -117,8 +73,6 @@ bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEv
void nfc_scene_mf_ultralight_read_success_on_exit(void* context) { void nfc_scene_mf_ultralight_read_success_on_exit(void* context) {
Nfc* nfc = context; Nfc* nfc = context;
// Clean views // Clean view
widget_reset(nfc->widget); widget_reset(nfc->widget);
text_box_reset(nfc->text_box);
string_reset(nfc->text_box_store);
} }

View File

@@ -16,7 +16,7 @@ void nfc_scene_mf_ultralight_unlock_warn_on_enter(void* context) {
dialog_ex_set_header(dialog_ex, "Risky function!", 64, 4, AlignCenter, AlignTop); dialog_ex_set_header(dialog_ex, "Risky function!", 64, 4, AlignCenter, AlignTop);
dialog_ex_set_text( dialog_ex_set_text(
dialog_ex, "Wrong password\ncan block your\ncard.", 4, 18, AlignLeft, AlignTop); dialog_ex, "Wrong password\ncan block your\ncard.", 4, 18, AlignLeft, AlignTop);
dialog_ex_set_icon(dialog_ex, 73, 17, &I_DolphinFirstStart8_56x51); dialog_ex_set_icon(dialog_ex, 73, 20, &I_DolphinCommon_56x48);
dialog_ex_set_center_button_text(dialog_ex, "OK"); dialog_ex_set_center_button_text(dialog_ex, "OK");
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);

View File

@@ -0,0 +1,133 @@
#include "../nfc_i.h"
void nfc_scene_nfc_data_info_widget_callback(GuiButtonType result, InputType type, void* context) {
Nfc* nfc = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
}
void nfc_scene_nfc_data_info_on_enter(void* context) {
Nfc* nfc = context;
Widget* widget = nfc->widget;
FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
NfcDeviceData* dev_data = &nfc->dev->dev_data;
NfcProtocol protocol = dev_data->protocol;
uint8_t text_scroll_height = 0;
if((protocol == NfcDeviceProtocolMifareDesfire) || (protocol == NfcDeviceProtocolMifareUl)) {
widget_add_button_element(
widget, GuiButtonTypeRight, "More", nfc_scene_nfc_data_info_widget_callback, nfc);
text_scroll_height = 52;
} else {
text_scroll_height = 64;
}
string_t temp_str;
string_init(temp_str);
// Set name if present
if(nfc->dev->dev_name[0] != '\0') {
string_printf(temp_str, "\ec%s\n", nfc->dev->dev_name);
}
// Set tag type
if(protocol == NfcDeviceProtocolEMV) {
string_cat_printf(temp_str, "\e#EMV Bank Card\n");
} else if(protocol == NfcDeviceProtocolMifareUl) {
string_cat_printf(temp_str, "\e#%s\n", nfc_mf_ul_type(dev_data->mf_ul_data.type, true));
} else if(protocol == NfcDeviceProtocolMifareClassic) {
string_cat_printf(
temp_str, "\e#%s\n", nfc_mf_classic_type(dev_data->mf_classic_data.type));
} else if(protocol == NfcDeviceProtocolMifareDesfire) {
string_cat_printf(temp_str, "\e#MIFARE DESfire\n");
} else {
string_cat_printf(temp_str, "\e#Unknown ISO tag\n");
}
// Set tag iso data
char iso_type = FURI_BIT(nfc_data->sak, 5) ? '4' : '3';
string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type);
string_cat_printf(temp_str, "UID:");
for(size_t i = 0; i < nfc_data->uid_len; i++) {
string_cat_printf(temp_str, " %02X", nfc_data->uid[i]);
}
string_cat_printf(temp_str, "\nATQA: %02X %02X ", nfc_data->atqa[1], nfc_data->atqa[0]);
string_cat_printf(temp_str, " SAK: %02X", nfc_data->sak);
// Set application specific data
if(protocol == NfcDeviceProtocolMifareDesfire) {
MifareDesfireData* data = &dev_data->mf_df_data;
uint32_t bytes_total = 1 << (data->version.sw_storage >> 1);
uint32_t bytes_free = data->free_memory ? data->free_memory->bytes : 0;
string_cat_printf(temp_str, "\n%d", bytes_total);
if(data->version.sw_storage & 1) {
string_push_back(temp_str, '+');
}
string_cat_printf(temp_str, " bytes, %d bytes free\n", bytes_free);
uint16_t n_apps = 0;
uint16_t n_files = 0;
for(MifareDesfireApplication* app = data->app_head; app; app = app->next) {
n_apps++;
for(MifareDesfireFile* file = app->file_head; file; file = file->next) {
n_files++;
}
}
string_cat_printf(temp_str, "%d Application", n_apps);
if(n_apps != 1) {
string_push_back(temp_str, 's');
}
string_cat_printf(temp_str, ", %d file", n_files);
if(n_files != 1) {
string_push_back(temp_str, 's');
}
} else if(protocol == NfcDeviceProtocolMifareUl) {
MfUltralightData* data = &dev_data->mf_ul_data;
string_cat_printf(
temp_str, "\nPages Read %d/%d", data->data_read / 4, data->data_size / 4);
if(data->data_size > data->data_read) {
string_cat_printf(temp_str, "\nPassword-protected");
}
} else if(protocol == NfcDeviceProtocolMifareClassic) {
MfClassicData* data = &dev_data->mf_classic_data;
uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type);
uint8_t keys_total = sectors_total * 2;
uint8_t keys_found = 0;
uint8_t sectors_read = 0;
mf_classic_get_read_sectors_and_keys(data, &sectors_read, &keys_found);
string_cat_printf(temp_str, "\nKeys Found %d/%d", keys_found, keys_total);
string_cat_printf(temp_str, "\nSectors Read %d/%d", sectors_read, sectors_total);
}
// Add text scroll widget
widget_add_text_scroll_element(
widget, 0, 0, 128, text_scroll_height, string_get_cstr(temp_str));
string_clear(temp_str);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
}
bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
NfcProtocol protocol = nfc->dev->dev_data.protocol;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeRight) {
if(protocol == NfcDeviceProtocolMifareDesfire) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireApp);
consumed = true;
} else if(protocol == NfcDeviceProtocolMifareUl) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightData);
consumed = true;
}
}
}
return consumed;
}
void nfc_scene_nfc_data_info_on_exit(void* context) {
Nfc* nfc = context;
widget_reset(nfc->widget);
}

View File

@@ -0,0 +1,62 @@
#include "../nfc_i.h"
enum SubmenuIndex {
SubmenuIndexSaveUid,
SubmenuIndexEmulateUid,
SubmenuIndexInfo,
};
void nfc_scene_nfca_menu_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
}
void nfc_scene_nfca_menu_on_enter(void* context) {
Nfc* nfc = context;
Submenu* submenu = nfc->submenu;
submenu_add_item(
submenu, "Save UID", SubmenuIndexSaveUid, nfc_scene_nfca_menu_submenu_callback, nfc);
submenu_add_item(
submenu, "Emulate UID", SubmenuIndexEmulateUid, nfc_scene_nfca_menu_submenu_callback, nfc);
submenu_add_item(submenu, "Info", SubmenuIndexInfo, nfc_scene_nfca_menu_submenu_callback, nfc);
submenu_set_selected_item(
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcaMenu));
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
}
bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexSaveUid) {
nfc->dev->format = NfcDeviceSaveFormatUid;
// Clear device name
nfc_device_set_name(nfc->dev, "");
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
consumed = true;
} else if(event.event == SubmenuIndexEmulateUid) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
consumed = true;
} else if(event.event == SubmenuIndexInfo) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo);
consumed = true;
}
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcaMenu, event.event);
} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_previous_scene(nfc->scene_manager);
}
return consumed;
}
void nfc_scene_nfca_menu_on_exit(void* context) {
Nfc* nfc = context;
// Clear view
submenu_reset(nfc->submenu);
}

View File

@@ -0,0 +1,72 @@
#include "../nfc_i.h"
#include <dolphin/dolphin.h>
void nfc_scene_nfca_read_success_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
furi_assert(context);
Nfc* nfc = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
}
void nfc_scene_nfca_read_success_on_enter(void* context) {
Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
// Setup view
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
Widget* widget = nfc->widget;
string_t temp_str;
string_init_set_str(temp_str, "\e#Unknown ISO tag\n");
char iso_type = FURI_BIT(data->sak, 5) ? '4' : '3';
string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type);
string_cat_printf(temp_str, "UID:");
for(size_t i = 0; i < data->uid_len; i++) {
string_cat_printf(temp_str, " %02X", data->uid[i]);
}
string_cat_printf(temp_str, "\nATQA: %02X %02X ", data->atqa[1], data->atqa[0]);
string_cat_printf(temp_str, " SAK: %02X", data->sak);
widget_add_text_scroll_element(widget, 0, 0, 128, 52, string_get_cstr(temp_str));
string_clear(temp_str);
widget_add_button_element(
widget, GuiButtonTypeLeft, "Retry", nfc_scene_nfca_read_success_widget_callback, nfc);
widget_add_button_element(
widget, GuiButtonTypeRight, "More", nfc_scene_nfca_read_success_widget_callback, nfc);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
}
bool nfc_scene_nfca_read_success_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm);
consumed = true;
} else if(event.event == GuiButtonTypeRight) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaMenu);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm);
consumed = true;
}
return consumed;
}
void nfc_scene_nfca_read_success_on_exit(void* context) {
Nfc* nfc = context;
// Clear view
widget_reset(nfc->widget);
}

View File

@@ -59,11 +59,14 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if((event.event == NfcWorkerEventReadUidNfcB) || if((event.event == NfcWorkerEventReadUidNfcB) ||
(event.event == NfcWorkerEventReadUidNfcF) || (event.event == NfcWorkerEventReadUidNfcF) ||
(event.event == NfcWorkerEventReadUidNfcV) || (event.event == NfcWorkerEventReadUidNfcV)) {
(event.event == NfcWorkerEventReadUidNfcA)) {
notification_message(nfc->notifications, &sequence_success); notification_message(nfc->notifications, &sequence_success);
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess);
consumed = true; consumed = true;
} else if(event.event == NfcWorkerEventReadUidNfcA) {
notification_message(nfc->notifications, &sequence_success);
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess);
consumed = true;
} else if(event.event == NfcWorkerEventReadMfUltralight) { } else if(event.event == NfcWorkerEventReadMfUltralight) {
notification_message(nfc->notifications, &sequence_success); notification_message(nfc->notifications, &sequence_success);
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess);

View File

@@ -16,44 +16,26 @@ void nfc_scene_read_card_success_widget_callback(
void nfc_scene_read_card_success_on_enter(void* context) { void nfc_scene_read_card_success_on_enter(void* context) {
Nfc* nfc = context; Nfc* nfc = context;
string_t data_str; string_t temp_str;
string_t uid_str; string_init(temp_str);
string_init(data_str);
string_init(uid_str);
DOLPHIN_DEED(DolphinDeedNfcReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
// Setup view // Setup view
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
Widget* widget = nfc->widget; Widget* widget = nfc->widget;
string_set_str(data_str, nfc_get_dev_type(data->type)); string_set_str(temp_str, nfc_get_dev_type(data->type));
string_set_str(uid_str, "UID:"); widget_add_string_element(
widget, 64, 12, AlignCenter, AlignBottom, FontPrimary, string_get_cstr(temp_str));
string_set_str(temp_str, "UID:");
for(uint8_t i = 0; i < data->uid_len; i++) { for(uint8_t i = 0; i < data->uid_len; i++) {
string_cat_printf(uid_str, " %02X", data->uid[i]); string_cat_printf(temp_str, " %02X", data->uid[i]);
} }
widget_add_string_element(
widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(temp_str));
widget_add_button_element( widget_add_button_element(
widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc); widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc);
if(data->type == FuriHalNfcTypeA) {
widget_add_button_element(
widget, GuiButtonTypeRight, "Save", nfc_scene_read_card_success_widget_callback, nfc);
widget_add_icon_element(widget, 8, 13, &I_Medium_chip_22x21);
widget_add_string_element(
widget, 37, 12, AlignLeft, AlignBottom, FontPrimary, string_get_cstr(data_str));
string_printf(
data_str, "ATQA: %02X%02X\nSAK: %02X", data->atqa[0], data->atqa[1], data->sak);
widget_add_string_multiline_element(
widget, 37, 16, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str));
widget_add_string_element(
widget, 64, 46, AlignCenter, AlignBottom, FontSecondary, string_get_cstr(uid_str));
} else {
widget_add_string_element(
widget, 64, 12, AlignCenter, AlignBottom, FontPrimary, string_get_cstr(data_str));
widget_add_string_element(
widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(uid_str));
}
string_clear(data_str); string_clear(temp_str);
string_clear(uid_str);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
} }
@@ -65,11 +47,6 @@ bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) { if(event.event == GuiButtonTypeLeft) {
consumed = scene_manager_previous_scene(nfc->scene_manager); consumed = scene_manager_previous_scene(nfc->scene_manager);
} else if(event.event == GuiButtonTypeRight) {
nfc->dev->format = NfcDeviceSaveFormatUid;
nfc_device_set_name(nfc->dev, "");
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
consumed = true;
} }
} }
return consumed; return consumed;

View File

@@ -4,10 +4,10 @@ void nfc_scene_rpc_on_enter(void* context) {
Nfc* nfc = context; Nfc* nfc = context;
Popup* popup = nfc->popup; Popup* popup = nfc->popup;
popup_set_header(popup, "NFC", 82, 28, AlignCenter, AlignBottom); popup_set_header(popup, "NFC", 89, 42, AlignCenter, AlignBottom);
popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop); popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop);
popup_set_icon(popup, 2, 14, &I_Warning_30x23); // TODO: icon popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
@@ -31,13 +31,11 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) {
consumed = true; consumed = true;
if(event.event == NfcCustomEventViewExit) { if(event.event == NfcCustomEventViewExit) {
rpc_system_app_confirm(nfc->rpc_ctx, RpcAppEventAppExit, true); rpc_system_app_confirm(nfc->rpc_ctx, RpcAppEventAppExit, true);
scene_manager_stop(nfc->scene_manager);
view_dispatcher_stop(nfc->view_dispatcher); view_dispatcher_stop(nfc->view_dispatcher);
nfc_blink_stop(nfc);
} else if(event.event == NfcCustomEventRpcSessionClose) { } else if(event.event == NfcCustomEventRpcSessionClose) {
rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL); scene_manager_stop(nfc->scene_manager);
nfc->rpc_ctx = NULL;
view_dispatcher_stop(nfc->view_dispatcher); view_dispatcher_stop(nfc->view_dispatcher);
nfc_blink_stop(nfc);
} else if(event.event == NfcCustomEventRpcLoad) { } else if(event.event == NfcCustomEventRpcLoad) {
bool result = false; bool result = false;
const char* arg = rpc_system_app_get_data(nfc->rpc_ctx); const char* arg = rpc_system_app_get_data(nfc->rpc_ctx);
@@ -66,7 +64,7 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) {
nfc_blink_start(nfc); nfc_blink_start(nfc);
nfc_text_store_set(nfc, "emulating\n%s", nfc->dev->dev_name); nfc_text_store_set(nfc, "emulating\n%s", nfc->dev->dev_name);
popup_set_text(popup, nfc->text_store, 82, 32, AlignCenter, AlignTop); popup_set_text(popup, nfc->text_store, 89, 44, AlignCenter, AlignTop);
} }
} }

View File

@@ -44,8 +44,6 @@ void nfc_scene_saved_menu_on_enter(void* context) {
} }
submenu_add_item( submenu_add_item(
submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc);
submenu_set_selected_item(
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu));
if(nfc->dev->shadow_file_exist) { if(nfc->dev->shadow_file_exist) {
submenu_add_item( submenu_add_item(
submenu, submenu,
@@ -58,12 +56,15 @@ void nfc_scene_saved_menu_on_enter(void* context) {
submenu, "Rename", SubmenuIndexRename, nfc_scene_saved_menu_submenu_callback, nfc); submenu, "Rename", SubmenuIndexRename, nfc_scene_saved_menu_submenu_callback, nfc);
submenu_add_item( submenu_add_item(
submenu, "Delete", SubmenuIndexDelete, nfc_scene_saved_menu_submenu_callback, nfc); submenu, "Delete", SubmenuIndexDelete, nfc_scene_saved_menu_submenu_callback, nfc);
submenu_set_selected_item(
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu));
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
} }
bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context; Nfc* nfc = context;
NfcDeviceData* dev_data = &nfc->dev->dev_data;
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
@@ -87,7 +88,18 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneDelete); scene_manager_next_scene(nfc->scene_manager, NfcSceneDelete);
consumed = true; consumed = true;
} else if(event.event == SubmenuIndexInfo) { } else if(event.event == SubmenuIndexInfo) {
bool application_info_present = false;
if(dev_data->protocol == NfcDeviceProtocolEMV) {
application_info_present = true;
} else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) {
application_info_present = nfc_supported_card_verify_and_parse(dev_data);
}
if(application_info_present) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo);
} else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo);
}
consumed = true; consumed = true;
} else if(event.event == SubmenuIndexRestoreOriginal) { } else if(event.event == SubmenuIndexRestoreOriginal) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneRestoreOriginalConfirm); scene_manager_next_scene(nfc->scene_manager, NfcSceneRestoreOriginalConfirm);

View File

@@ -1,80 +0,0 @@
#include "bank_card.h"
#include "../helpers/nfc_emv_parser.h"
#include <m-string.h>
struct BankCard {
Widget* widget;
};
BankCard* bank_card_alloc() {
BankCard* bank_card = malloc(sizeof(BankCard));
bank_card->widget = widget_alloc();
return bank_card;
}
void bank_card_free(BankCard* bank_card) {
furi_assert(bank_card);
widget_free(bank_card->widget);
free(bank_card);
}
View* bank_card_get_view(BankCard* bank_card) {
furi_assert(bank_card);
return widget_get_view(bank_card->widget);
}
void bank_card_clear(BankCard* bank_card) {
furi_assert(bank_card);
widget_reset(bank_card->widget);
}
void bank_card_set_name(BankCard* bank_card, char* name) {
furi_assert(bank_card);
furi_assert(name);
widget_add_string_element(
bank_card->widget, 64, 6, AlignCenter, AlignTop, FontSecondary, name);
}
void bank_card_set_number(BankCard* bank_card, uint8_t* number, uint8_t len) {
furi_assert(bank_card);
furi_assert(number);
string_t num_str;
string_init(num_str);
for(uint8_t i = 0; i < len; i += 2) {
string_cat_printf(num_str, "%02X%02X ", number[i], number[i + 1]);
}
// Add number
widget_add_string_element(
bank_card->widget, 64, 32, AlignCenter, AlignTop, FontSecondary, string_get_cstr(num_str));
string_clear(num_str);
// Add icon
widget_add_icon_element(bank_card->widget, 8, 15, &I_Detailed_chip_17x13);
// Add frame
widget_add_frame_element(bank_card->widget, 0, 0, 128, 64, 6);
}
void bank_card_set_back_callback(BankCard* bank_card, ButtonCallback callback, void* context) {
furi_assert(bank_card);
furi_assert(callback);
widget_add_button_element(bank_card->widget, GuiButtonTypeLeft, "Back", callback, context);
}
void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year) {
furi_assert(bank_card);
char exp_date_str[16];
snprintf(exp_date_str, sizeof(exp_date_str), "Exp: %02X/%02X", mon, year);
widget_add_string_element(
bank_card->widget, 122, 54, AlignRight, AlignBottom, FontSecondary, exp_date_str);
}
void bank_card_set_country_name(BankCard* bank_card, const char* country_name) {
furi_assert(bank_card);
widget_add_string_element(
bank_card->widget, 120, 18, AlignRight, AlignTop, FontSecondary, country_name);
}
void bank_card_set_currency_name(BankCard* bank_card, const char* currency_name) {
furi_assert(bank_card);
widget_add_string_element(
bank_card->widget, 31, 18, AlignLeft, AlignTop, FontSecondary, currency_name);
}

View File

@@ -1,26 +0,0 @@
#pragma once
#include <stdint.h>
#include <gui/view.h>
#include <gui/modules/widget.h>
typedef struct BankCard BankCard;
BankCard* bank_card_alloc();
void bank_card_free(BankCard* bank_card);
void bank_card_clear(BankCard* bank_card);
View* bank_card_get_view(BankCard* bank_card);
void bank_card_set_back_callback(BankCard* bank_card, ButtonCallback callback, void* context);
void bank_card_set_name(BankCard* bank_card, char* name);
void bank_card_set_number(BankCard* bank_card, uint8_t* number, uint8_t len);
void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year);
void bank_card_set_country_name(BankCard* bank_card, const char* country_name);
void bank_card_set_currency_name(BankCard* bank_card, const char* currency_name);

View File

@@ -297,36 +297,44 @@ static void rpc_system_storage_read_process(const PB_Main* request, void* contex
const char* path = request->content.storage_read_request.path; const char* path = request->content.storage_read_request.path;
Storage* fs_api = furi_record_open(RECORD_STORAGE); Storage* fs_api = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(fs_api); File* file = storage_file_alloc(fs_api);
bool result = false; bool fs_operation_success = storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING);
if(storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING)) { if(fs_operation_success) {
size_t size_left = storage_file_size(file); size_t size_left = storage_file_size(file);
do { do {
response->command_id = request->command_id; response->command_id = request->command_id;
response->which_content = PB_Main_storage_read_response_tag; response->which_content = PB_Main_storage_read_response_tag;
response->command_status = PB_CommandStatus_OK; response->command_status = PB_CommandStatus_OK;
response->content.storage_read_response.has_file = true;
response->content.storage_read_response.file.data =
malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(MIN(size_left, MAX_DATA_SIZE)));
uint8_t* buffer = response->content.storage_read_response.file.data->bytes;
uint16_t* read_size_msg = &response->content.storage_read_response.file.data->size;
size_t read_size = MIN(size_left, MAX_DATA_SIZE); size_t read_size = MIN(size_left, MAX_DATA_SIZE);
*read_size_msg = storage_file_read(file, buffer, read_size); if(read_size) {
size_left -= read_size; response->content.storage_read_response.has_file = true;
result = (*read_size_msg == read_size); response->content.storage_read_response.file.data =
malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(read_size));
uint8_t* buffer = &response->content.storage_read_response.file.data->bytes[0];
uint16_t* read_size_msg = &response->content.storage_read_response.file.data->size;
if(result) { *read_size_msg = storage_file_read(file, buffer, read_size);
response->has_next = (size_left > 0); size_left -= *read_size_msg;
fs_operation_success = (*read_size_msg == read_size);
response->has_next = fs_operation_success && (size_left > 0);
} else {
response->content.storage_read_response.file.data =
malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(0));
response->content.storage_read_response.file.data->size = 0;
response->content.storage_read_response.has_file = true;
response->has_next = false;
fs_operation_success = true;
}
if(fs_operation_success) {
rpc_send_and_release(session, response); rpc_send_and_release(session, response);
} }
} while((size_left != 0) && result); } while((size_left != 0) && fs_operation_success);
if(!result) {
rpc_send_and_release_empty(
session, request->command_id, rpc_system_storage_get_file_error(file));
} }
} else {
if(!fs_operation_success) {
rpc_send_and_release_empty( rpc_send_and_release_empty(
session, request->command_id, rpc_system_storage_get_file_error(file)); session, request->command_id, rpc_system_storage_get_file_error(file));
} }
@@ -349,7 +357,7 @@ static void rpc_system_storage_write_process(const PB_Main* request, void* conte
RpcSession* session = rpc_storage->session; RpcSession* session = rpc_storage->session;
furi_assert(session); furi_assert(session);
bool result = true; bool fs_operation_success = true;
if(!path_contains_only_ascii(request->content.storage_write_request.path)) { if(!path_contains_only_ascii(request->content.storage_write_request.path)) {
rpc_storage->current_command_id = request->command_id; rpc_storage->current_command_id = request->command_id;
@@ -370,28 +378,34 @@ static void rpc_system_storage_write_process(const PB_Main* request, void* conte
rpc_storage->current_command_id = request->command_id; rpc_storage->current_command_id = request->command_id;
rpc_storage->state = RpcStorageStateWriting; rpc_storage->state = RpcStorageStateWriting;
const char* path = request->content.storage_write_request.path; const char* path = request->content.storage_write_request.path;
result = storage_file_open(rpc_storage->file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS); fs_operation_success =
storage_file_open(rpc_storage->file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS);
} }
File* file = rpc_storage->file; File* file = rpc_storage->file;
bool send_response = false;
if(result) { if(fs_operation_success) {
if(request->content.storage_write_request.has_file &&
request->content.storage_write_request.file.data &&
request->content.storage_write_request.file.data->size) {
uint8_t* buffer = request->content.storage_write_request.file.data->bytes; uint8_t* buffer = request->content.storage_write_request.file.data->bytes;
size_t buffer_size = request->content.storage_write_request.file.data->size; size_t buffer_size = request->content.storage_write_request.file.data->size;
uint16_t written_size = storage_file_write(file, buffer, buffer_size); uint16_t written_size = storage_file_write(file, buffer, buffer_size);
result = (written_size == buffer_size); fs_operation_success = (written_size == buffer_size);
if(result && !request->has_next) {
rpc_send_and_release_empty(
session, rpc_storage->current_command_id, PB_CommandStatus_OK);
rpc_system_storage_reset_state(rpc_storage, session, false);
}
} }
if(!result) { send_response = !request->has_next;
rpc_send_and_release_empty( }
session, rpc_storage->current_command_id, rpc_system_storage_get_file_error(file));
PB_CommandStatus command_status = PB_CommandStatus_OK;
if(!fs_operation_success) {
send_response = true;
command_status = rpc_system_storage_get_file_error(file);
}
if(send_response) {
rpc_send_and_release_empty(session, rpc_storage->current_command_id, command_status);
rpc_system_storage_reset_state(rpc_storage, session, false); rpc_system_storage_reset_state(rpc_storage, session, false);
} }
} }

View File

@@ -102,7 +102,7 @@ int32_t sentry_safe_app(void* p) {
view_port_input_callback_set(view_port, sentry_safe_input_callback, event_queue); view_port_input_callback_set(view_port, sentry_safe_input_callback, event_queue);
// Open GUI and register view_port // Open GUI and register view_port
Gui* gui = furi_record_open("gui"); Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen); gui_add_view_port(gui, view_port, GuiLayerFullscreen);
Event event; Event event;
@@ -156,7 +156,7 @@ int32_t sentry_safe_app(void* p) {
view_port_enabled_set(view_port, false); view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port); gui_remove_view_port(gui, view_port);
furi_record_close("gui"); furi_record_close(RECORD_GUI);
view_port_free(view_port); view_port_free(view_port);
furi_message_queue_free(event_queue); furi_message_queue_free(event_queue);
delete_mutex(&state_mutex); delete_mutex(&state_mutex);

View File

@@ -369,7 +369,7 @@ SpectrumAnalyzer* spectrum_analyzer_alloc() {
view_port_input_callback_set(instance->view_port, spectrum_analyzer_input_callback, instance); view_port_input_callback_set(instance->view_port, spectrum_analyzer_input_callback, instance);
// Open GUI and register view_port // Open GUI and register view_port
instance->gui = furi_record_open("gui"); instance->gui = furi_record_open(RECORD_GUI);
gui_add_view_port(instance->gui, instance->view_port, GuiLayerFullscreen); gui_add_view_port(instance->gui, instance->view_port, GuiLayerFullscreen);
return instance; return instance;
@@ -378,7 +378,7 @@ SpectrumAnalyzer* spectrum_analyzer_alloc() {
void spectrum_analyzer_free(SpectrumAnalyzer* instance) { void spectrum_analyzer_free(SpectrumAnalyzer* instance) {
// view_port_enabled_set(view_port, false); // view_port_enabled_set(view_port, false);
gui_remove_view_port(instance->gui, instance->view_port); gui_remove_view_port(instance->gui, instance->view_port);
furi_record_close("gui"); furi_record_close(RECORD_GUI);
view_port_free(instance->view_port); view_port_free(instance->view_port);
spectrum_analyzer_worker_free(instance->worker); spectrum_analyzer_worker_free(instance->worker);

View File

@@ -274,11 +274,12 @@ static void storage_cli_read_chunks(Cli* cli, string_t path, string_t args) {
if(parsed_count == EOF || parsed_count != 1) { if(parsed_count == EOF || parsed_count != 1) {
storage_cli_print_usage(); storage_cli_print_usage();
} else if(storage_file_open(file, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { } else if(storage_file_open(file, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
uint8_t* data = malloc(buffer_size);
uint64_t file_size = storage_file_size(file); uint64_t file_size = storage_file_size(file);
printf("Size: %lu\r\n", (uint32_t)file_size); printf("Size: %lu\r\n", (uint32_t)file_size);
if(buffer_size) {
uint8_t* data = malloc(buffer_size);
while(file_size > 0) { while(file_size > 0) {
printf("\r\nReady?\r\n"); printf("\r\nReady?\r\n");
cli_getc(cli); cli_getc(cli);
@@ -289,9 +290,10 @@ static void storage_cli_read_chunks(Cli* cli, string_t path, string_t args) {
} }
file_size -= read_size; file_size -= read_size;
} }
free(data);
}
printf("\r\n"); printf("\r\n");
free(data);
} else { } else {
storage_cli_print_error(storage_file_get_error(file)); storage_cli_print_error(storage_file_get_error(file));
} }
@@ -315,6 +317,7 @@ static void storage_cli_write_chunk(Cli* cli, string_t path, string_t args) {
if(storage_file_open(file, string_get_cstr(path), FSAM_WRITE, FSOM_OPEN_APPEND)) { if(storage_file_open(file, string_get_cstr(path), FSAM_WRITE, FSOM_OPEN_APPEND)) {
printf("Ready\r\n"); printf("Ready\r\n");
if(buffer_size) {
uint8_t* buffer = malloc(buffer_size); uint8_t* buffer = malloc(buffer_size);
for(uint32_t i = 0; i < buffer_size; i++) { for(uint32_t i = 0; i < buffer_size; i++) {
@@ -328,6 +331,7 @@ static void storage_cli_write_chunk(Cli* cli, string_t path, string_t args) {
} }
free(buffer); free(buffer);
}
} else { } else {
storage_cli_print_error(storage_file_get_error(file)); storage_cli_print_error(storage_file_get_error(file));
} }

View File

@@ -122,7 +122,7 @@ void storage_settings_scene_benchmark_on_enter(void* context) {
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx); view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
if(sd_status != FSE_OK) { if(sd_status != FSE_OK) {
dialog_ex_set_icon(dialog_ex, 72, 14, &I_DolphinFirstStart8_56x51); dialog_ex_set_icon(dialog_ex, 72, 17, &I_DolphinCommon_56x48);
dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop); dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop);
dialog_ex_set_text( dialog_ex_set_text(
dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop); dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop);

View File

@@ -14,7 +14,7 @@ void storage_settings_scene_format_confirm_on_enter(void* context) {
FS_Error sd_status = storage_sd_status(app->fs_api); FS_Error sd_status = storage_sd_status(app->fs_api);
if(sd_status == FSE_NOT_READY) { if(sd_status == FSE_NOT_READY) {
dialog_ex_set_icon(dialog_ex, 72, 14, &I_DolphinFirstStart8_56x51); dialog_ex_set_icon(dialog_ex, 72, 17, &I_DolphinCommon_56x48);
dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop); dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop);
dialog_ex_set_text( dialog_ex_set_text(
dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop); dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop);

View File

@@ -47,7 +47,7 @@ void storage_settings_scene_formatting_on_enter(void* context) {
dialog_ex_set_text( dialog_ex_set_text(
dialog_ex, storage_error_get_desc(error), 64, 32, AlignCenter, AlignCenter); dialog_ex, storage_error_get_desc(error), 64, 32, AlignCenter, AlignCenter);
} else { } else {
dialog_ex_set_icon(dialog_ex, 72, 14, &I_DolphinFirstStart8_56x51); dialog_ex_set_icon(dialog_ex, 72, 17, &I_DolphinCommon_56x48);
dialog_ex_set_header(dialog_ex, "Format\ncomplete!", 14, 15, AlignLeft, AlignTop); dialog_ex_set_header(dialog_ex, "Format\ncomplete!", 14, 15, AlignLeft, AlignTop);
} }
dialog_ex_set_center_button_text(dialog_ex, "OK"); dialog_ex_set_center_button_text(dialog_ex, "OK");

View File

@@ -18,7 +18,7 @@ void storage_settings_scene_sd_info_on_enter(void* context) {
dialog_ex_set_result_callback(dialog_ex, storage_settings_scene_sd_info_dialog_callback); dialog_ex_set_result_callback(dialog_ex, storage_settings_scene_sd_info_dialog_callback);
if(sd_status != FSE_OK) { if(sd_status != FSE_OK) {
dialog_ex_set_icon(dialog_ex, 72, 14, &I_DolphinFirstStart8_56x51); dialog_ex_set_icon(dialog_ex, 72, 17, &I_DolphinCommon_56x48);
dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop); dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop);
dialog_ex_set_text( dialog_ex_set_text(
dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop); dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop);

View File

@@ -14,7 +14,7 @@ void storage_settings_scene_unmount_confirm_on_enter(void* context) {
FS_Error sd_status = storage_sd_status(app->fs_api); FS_Error sd_status = storage_sd_status(app->fs_api);
if(sd_status == FSE_NOT_READY) { if(sd_status == FSE_NOT_READY) {
dialog_ex_set_icon(dialog_ex, 72, 14, &I_DolphinFirstStart8_56x51); dialog_ex_set_icon(dialog_ex, 72, 17, &I_DolphinCommon_56x48);
dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop); dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop);
dialog_ex_set_text( dialog_ex_set_text(
dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop); dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop);

View File

@@ -13,7 +13,7 @@ void storage_settings_scene_unmounted_on_enter(void* context) {
DialogEx* dialog_ex = app->dialog_ex; DialogEx* dialog_ex = app->dialog_ex;
dialog_ex_set_center_button_text(dialog_ex, "OK"); dialog_ex_set_center_button_text(dialog_ex, "OK");
dialog_ex_set_icon(dialog_ex, 72, 14, &I_DolphinFirstStart8_56x51); dialog_ex_set_icon(dialog_ex, 72, 17, &I_DolphinCommon_56x48);
if(error == FSE_OK) { if(error == FSE_OK) {
dialog_ex_set_header(dialog_ex, "SD Card Unmounted", 64, 3, AlignCenter, AlignTop); dialog_ex_set_header(dialog_ex, "SD Card Unmounted", 64, 3, AlignCenter, AlignTop);

View File

@@ -16,7 +16,7 @@ void subghz_scene_need_saving_on_enter(void* context) {
SubGhz* subghz = context; SubGhz* subghz = context;
widget_add_string_multiline_element( widget_add_string_multiline_element(
subghz->widget, 64, 13, AlignCenter, AlignCenter, FontPrimary, "Exit to Sub-Ghz menu?"); subghz->widget, 64, 13, AlignCenter, AlignCenter, FontPrimary, "Exit to Sub-GHz menu?");
widget_add_string_multiline_element( widget_add_string_multiline_element(
subghz->widget, subghz->widget,
64, 64,

View File

@@ -100,7 +100,7 @@ static void subghz_scene_receiver_config_set_preset(VariableItem* item) {
subghz_setting_get_preset_data_size(subghz->setting, index)); subghz_setting_get_preset_data_size(subghz->setting, index));
} }
static void subghz_scene_receiver_config_set_hopping_runing(VariableItem* item) { static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item); SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item); uint8_t index = variable_item_get_current_value_index(item);
@@ -176,7 +176,7 @@ void subghz_scene_receiver_config_on_enter(void* context) {
subghz->variable_item_list, subghz->variable_item_list,
"Hopping:", "Hopping:",
HOPPING_COUNT, HOPPING_COUNT,
subghz_scene_receiver_config_set_hopping_runing, subghz_scene_receiver_config_set_hopping_running,
subghz); subghz);
value_index = subghz_scene_receiver_config_hopper_value_index( value_index = subghz_scene_receiver_config_hopper_value_index(
subghz->txrx->hopper_state, hopping_value, HOPPING_COUNT, subghz); subghz->txrx->hopper_state, hopping_value, HOPPING_COUNT, subghz);

View File

@@ -101,7 +101,7 @@ void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) {
subghz); subghz);
} }
} else { } else {
widget_add_icon_element(subghz->widget, 32, 12, &I_DolphinFirstStart7_61x51); widget_add_icon_element(subghz->widget, 37, 15, &I_DolphinCommon_56x48);
widget_add_string_element( widget_add_string_element(
subghz->widget, 13, 8, AlignLeft, AlignBottom, FontSecondary, "Error history parse."); subghz->widget, 13, 8, AlignLeft, AlignBottom, FontSecondary, "Error history parse.");
} }

View File

@@ -1,16 +1,23 @@
#include "../subghz_i.h" #include "../subghz_i.h"
typedef enum {
SubGhzRpcStateIdle,
SubGhzRpcStateLoaded,
} SubGhzRpcState;
void subghz_scene_rpc_on_enter(void* context) { void subghz_scene_rpc_on_enter(void* context) {
SubGhz* subghz = context; SubGhz* subghz = context;
Popup* popup = subghz->popup; Popup* popup = subghz->popup;
popup_set_header(popup, "Sub-GHz", 82, 28, AlignCenter, AlignBottom); popup_set_header(popup, "Sub-GHz", 89, 42, AlignCenter, AlignBottom);
popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop); popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop);
popup_set_icon(popup, 2, 14, &I_Warning_30x23); // TODO: icon popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61);
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdPopup); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdPopup);
scene_manager_set_scene_state(subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle);
notification_message(subghz->notifications, &sequence_display_backlight_on); notification_message(subghz->notifications, &sequence_display_backlight_on);
} }
@@ -18,28 +25,21 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
SubGhz* subghz = context; SubGhz* subghz = context;
Popup* popup = subghz->popup; Popup* popup = subghz->popup;
bool consumed = false; bool consumed = false;
SubGhzRpcState state = scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneRpc);
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
consumed = true; consumed = true;
if(event.event == SubGhzCustomEventSceneExit) { if(event.event == SubGhzCustomEventSceneExit) {
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { scene_manager_stop(subghz->scene_manager);
subghz_tx_stop(subghz);
subghz_sleep(subghz);
}
view_dispatcher_stop(subghz->view_dispatcher); view_dispatcher_stop(subghz->view_dispatcher);
rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventAppExit, true); rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventAppExit, true);
} else if(event.event == SubGhzCustomEventSceneRpcSessionClose) { } else if(event.event == SubGhzCustomEventSceneRpcSessionClose) {
rpc_system_app_set_callback(subghz->rpc_ctx, NULL, NULL); scene_manager_stop(subghz->scene_manager);
subghz->rpc_ctx = NULL; view_dispatcher_stop(subghz->view_dispatcher);
subghz_blink_stop(subghz);
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
subghz_tx_stop(subghz);
subghz_sleep(subghz);
}
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneExit);
} else if(event.event == SubGhzCustomEventSceneRpcButtonPress) { } else if(event.event == SubGhzCustomEventSceneRpcButtonPress) {
bool result = false; bool result = false;
if(subghz->txrx->txrx_state == SubGhzTxRxStateSleep) { if((subghz->txrx->txrx_state == SubGhzTxRxStateSleep) &&
(state == SubGhzRpcStateLoaded)) {
subghz_blink_start(subghz); subghz_blink_start(subghz);
result = subghz_tx_start(subghz, subghz->txrx->fff_data); result = subghz_tx_start(subghz, subghz->txrx->fff_data);
result = true; result = true;
@@ -57,8 +57,10 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
} else if(event.event == SubGhzCustomEventSceneRpcLoad) { } else if(event.event == SubGhzCustomEventSceneRpcLoad) {
bool result = false; bool result = false;
const char* arg = rpc_system_app_get_data(subghz->rpc_ctx); const char* arg = rpc_system_app_get_data(subghz->rpc_ctx);
if(arg) { if(arg && (state == SubGhzRpcStateIdle)) {
if(subghz_key_load(subghz, arg, false)) { if(subghz_key_load(subghz, arg, false)) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateLoaded);
string_set_str(subghz->file_path, arg); string_set_str(subghz->file_path, arg);
result = true; result = true;
string_t file_name; string_t file_name;
@@ -70,7 +72,7 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
SUBGHZ_MAX_LEN_NAME, SUBGHZ_MAX_LEN_NAME,
"loaded\n%s", "loaded\n%s",
string_get_cstr(file_name)); string_get_cstr(file_name));
popup_set_text(popup, subghz->file_name_tmp, 82, 32, AlignCenter, AlignTop); popup_set_text(popup, subghz->file_name_tmp, 89, 44, AlignCenter, AlignTop);
string_clear(file_name); string_clear(file_name);
} }
@@ -83,6 +85,13 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
void subghz_scene_rpc_on_exit(void* context) { void subghz_scene_rpc_on_exit(void* context) {
SubGhz* subghz = context; SubGhz* subghz = context;
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
subghz_tx_stop(subghz);
subghz_sleep(subghz);
subghz_blink_stop(subghz);
}
Popup* popup = subghz->popup; Popup* popup = subghz->popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);

View File

@@ -11,7 +11,7 @@ void subghz_scene_show_error_sub_on_enter(void* context) {
// Setup view // Setup view
Popup* popup = subghz->popup; Popup* popup = subghz->popup;
popup_set_icon(popup, 72, 14, &I_DolphinFirstStart8_56x51); popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48);
popup_set_header(popup, string_get_cstr(subghz->error_str), 14, 15, AlignLeft, AlignTop); popup_set_header(popup, string_get_cstr(subghz->error_str), 14, 15, AlignLeft, AlignTop);
popup_set_timeout(popup, 1500); popup_set_timeout(popup, 1500);
popup_set_context(popup, subghz); popup_set_context(popup, subghz);

View File

@@ -11,9 +11,14 @@ void subghz_scene_show_only_rx_on_enter(void* context) {
// Setup view // Setup view
Popup* popup = subghz->popup; Popup* popup = subghz->popup;
popup_set_icon(popup, 67, 12, &I_DolphinFirstStart7_61x51);
popup_set_text( const char* header_text = "Transmission is blocked";
popup, "This frequency is\noutside of default\nrange", 38, 40, AlignCenter, AlignBottom); const char* message_text = "This frequency is\noutside of default\nrange";
popup_set_header(popup, header_text, 63, 3, AlignCenter, AlignTop);
popup_set_text(popup, message_text, 0, 17, AlignLeft, AlignTop);
popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48);
popup_set_timeout(popup, 1500); popup_set_timeout(popup, 1500);
popup_set_context(popup, subghz); popup_set_context(popup, subghz);
popup_set_callback(popup, subghz_scene_show_only_rx_popup_callback); popup_set_callback(popup, subghz_scene_show_only_rx_popup_callback);

View File

@@ -32,6 +32,8 @@ static void subghz_rpc_command_callback(RpcAppSystemEvent event, void* context)
if(event == RpcAppEventSessionClose) { if(event == RpcAppEventSessionClose) {
view_dispatcher_send_custom_event( view_dispatcher_send_custom_event(
subghz->view_dispatcher, SubGhzCustomEventSceneRpcSessionClose); subghz->view_dispatcher, SubGhzCustomEventSceneRpcSessionClose);
rpc_system_app_set_callback(subghz->rpc_ctx, NULL, NULL);
subghz->rpc_ctx = NULL;
} else if(event == RpcAppEventAppExit) { } else if(event == RpcAppEventAppExit) {
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneExit); view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneExit);
} else if(event == RpcAppEventLoadFile) { } else if(event == RpcAppEventLoadFile) {

View File

@@ -219,17 +219,13 @@ void subghz_dialog_message_show_only_rx(SubGhz* subghz) {
DialogsApp* dialogs = subghz->dialogs; DialogsApp* dialogs = subghz->dialogs;
DialogMessage* message = dialog_message_alloc(); DialogMessage* message = dialog_message_alloc();
dialog_message_set_header(message, "Transmission is blocked", 63, 3, AlignCenter, AlignTop); const char* header_text = "Transmission is blocked";
const char* message_text = "Frequency\nis outside of\ndefault range.\nCheck docs.";
dialog_message_set_text( dialog_message_set_header(message, header_text, 63, 3, AlignCenter, AlignTop);
message, dialog_message_set_text(message, message_text, 0, 17, AlignLeft, AlignTop);
"Frequency\nis outside of\ndefault range.\nCheck docs.",
3,
17,
AlignLeft,
AlignTop);
dialog_message_set_icon(message, &I_DolphinFirstStart8_56x51, 72, 14); dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17);
dialog_message_show(dialogs, message); dialog_message_show(dialogs, message);
dialog_message_free(message); dialog_message_free(message);
@@ -296,7 +292,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
if(!strcmp(string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) { if(!strcmp(string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) {
//Todo add Custom_preset_module //Todo add Custom_preset_module
//delete peset if it already exists //delete preset if it already exists
subghz_setting_delete_custom_preset( subghz_setting_delete_custom_preset(
subghz->setting, string_get_cstr(subghz->txrx->preset->name)); subghz->setting, string_get_cstr(subghz->txrx->preset->name));
//load custom preset from file //load custom preset from file

View File

@@ -373,7 +373,7 @@ int32_t tetris_game_app() {
view_port_input_callback_set(view_port, tetris_game_input_callback, event_queue); view_port_input_callback_set(view_port, tetris_game_input_callback, event_queue);
// Open GUI and register view_port // Open GUI and register view_port
Gui* gui = furi_record_open("gui"); Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen); gui_add_view_port(gui, view_port, GuiLayerFullscreen);
tetris_state->timer = tetris_state->timer =
@@ -460,7 +460,7 @@ int32_t tetris_game_app() {
furi_timer_free(tetris_state->timer); furi_timer_free(tetris_state->timer);
view_port_enabled_set(view_port, false); view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port); gui_remove_view_port(gui, view_port);
furi_record_close("gui"); furi_record_close(RECORD_GUI);
view_port_free(view_port); view_port_free(view_port);
furi_message_queue_free(event_queue); furi_message_queue_free(event_queue);
delete_mutex(&state_mutex); delete_mutex(&state_mutex);

View File

@@ -327,7 +327,7 @@ int32_t tictactoe_game_app(void* p) {
tictactoe_state_init(tictactoe_state); tictactoe_state_init(tictactoe_state);
// Open GUI and register view_port // Open GUI and register view_port
Gui* gui = furi_record_open("gui"); Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen); gui_add_view_port(gui, view_port, GuiLayerFullscreen);
GameEvent event; GameEvent event;
@@ -373,7 +373,7 @@ int32_t tictactoe_game_app(void* p) {
furi_timer_free(tictactoe_state->timer); furi_timer_free(tictactoe_state->timer);
view_port_enabled_set(view_port, false); view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port); gui_remove_view_port(gui, view_port);
furi_record_close("gui"); furi_record_close(RECORD_GUI);
view_port_free(view_port); view_port_free(view_port);
furi_message_queue_free(event_queue); furi_message_queue_free(event_queue);
delete_mutex(&state_mutex); delete_mutex(&state_mutex);

View File

@@ -4,6 +4,7 @@
#include "u2f_data.h" #include "u2f_data.h"
#include <furi_hal.h> #include <furi_hal.h>
#include <furi_hal_random.h> #include <furi_hal_random.h>
#include <littlefs/lfs_util.h> // for lfs_tobe32
#include "toolbox/sha256.h" #include "toolbox/sha256.h"
#include "toolbox/hmac_sha256.h" #include "toolbox/hmac_sha256.h"
@@ -256,6 +257,7 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) {
uint8_t flags = 0; uint8_t flags = 0;
uint8_t hash[32]; uint8_t hash[32];
uint8_t signature[64]; uint8_t signature[64];
uint32_t be_u2f_counter;
if(u2f_data_check(false) == false) { if(u2f_data_check(false) == false) {
U2F->ready = false; U2F->ready = false;
@@ -275,11 +277,14 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) {
} }
U2F->user_present = false; U2F->user_present = false;
// The 4 byte counter is represented in big endian. Increment it before use
be_u2f_counter = lfs_tobe32(U2F->counter + 1);
// Generate hash // Generate hash
sha256_start(&sha_ctx); sha256_start(&sha_ctx);
sha256_update(&sha_ctx, req->app_id, 32); sha256_update(&sha_ctx, req->app_id, 32);
sha256_update(&sha_ctx, &flags, 1); sha256_update(&sha_ctx, &flags, 1);
sha256_update(&sha_ctx, (uint8_t*)&(U2F->counter), 4); sha256_update(&sha_ctx, (uint8_t*)&(be_u2f_counter), 4);
sha256_update(&sha_ctx, req->challenge, 32); sha256_update(&sha_ctx, req->challenge, 32);
sha256_finish(&sha_ctx, hash); sha256_finish(&sha_ctx, hash);
@@ -309,12 +314,12 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) {
uECC_sign(priv_key, hash, 32, signature, U2F->p_curve); uECC_sign(priv_key, hash, 32, signature, U2F->p_curve);
resp->user_present = flags; resp->user_present = flags;
resp->counter = U2F->counter; resp->counter = be_u2f_counter;
uint8_t signature_len = u2f_der_encode_signature(resp->signature, signature); uint8_t signature_len = u2f_der_encode_signature(resp->signature, signature);
memcpy(resp->signature + signature_len, state_no_error, 2); memcpy(resp->signature + signature_len, state_no_error, 2);
FURI_LOG_D(TAG, "Counter: %lu", U2F->counter);
U2F->counter++; U2F->counter++;
FURI_LOG_D(TAG, "Counter: %lu", U2F->counter);
u2f_data_cnt_write(U2F->counter); u2f_data_cnt_write(U2F->counter);
if(U2F->callback != NULL) U2F->callback(U2fNotifyAuthSuccess, U2F->context); if(U2F->callback != NULL) U2F->callback(U2fNotifyAuthSuccess, U2F->context);

View File

@@ -1,5 +1,5 @@
#include <furi.h> #include <furi.h>
#include "u2f_hid.h" #include "u2f_data.h"
#include <furi_hal.h> #include <furi_hal.h>
#include <storage/storage.h> #include <storage/storage.h>
#include <furi_hal_random.h> #include <furi_hal_random.h>
@@ -28,7 +28,8 @@
#define U2F_DEVICE_KEY_VERSION 1 #define U2F_DEVICE_KEY_VERSION 1
#define U2F_COUNTER_FILE_TYPE "Flipper U2F Counter File" #define U2F_COUNTER_FILE_TYPE "Flipper U2F Counter File"
#define U2F_COUNTER_VERSION 1 #define U2F_COUNTER_VERSION 2
#define U2F_COUNTER_VERSION_OLD 1
#define U2F_COUNTER_CONTROL_VAL 0xAA5500FF #define U2F_COUNTER_CONTROL_VAL 0xAA5500FF
@@ -359,6 +360,7 @@ bool u2f_data_cnt_read(uint32_t* cnt_val) {
furi_assert(cnt_val); furi_assert(cnt_val);
bool state = false; bool state = false;
bool old_counter = false;
uint8_t iv[16]; uint8_t iv[16];
U2fCounterData cnt; U2fCounterData cnt;
uint8_t cnt_encr[48]; uint8_t cnt_encr[48];
@@ -376,9 +378,16 @@ bool u2f_data_cnt_read(uint32_t* cnt_val) {
FURI_LOG_E(TAG, "Missing or incorrect header"); FURI_LOG_E(TAG, "Missing or incorrect header");
break; break;
} }
if(strcmp(string_get_cstr(filetype), U2F_COUNTER_FILE_TYPE) != 0 || if(strcmp(string_get_cstr(filetype), U2F_COUNTER_FILE_TYPE) != 0) {
version != U2F_COUNTER_VERSION) { FURI_LOG_E(TAG, "Type mismatch");
FURI_LOG_E(TAG, "Type or version mismatch"); break;
}
if(version == U2F_COUNTER_VERSION_OLD) {
// Counter is from previous U2F app version with endianness bug
FURI_LOG_W(TAG, "Counter from old version");
old_counter = true;
} else if(version != U2F_COUNTER_VERSION) {
FURI_LOG_E(TAG, "Version mismatch");
break; break;
} }
if(!flipper_format_read_hex(flipper_format, "IV", iv, 16)) { if(!flipper_format_read_hex(flipper_format, "IV", iv, 16)) {
@@ -409,6 +418,13 @@ bool u2f_data_cnt_read(uint32_t* cnt_val) {
flipper_format_free(flipper_format); flipper_format_free(flipper_format);
furi_record_close(RECORD_STORAGE); furi_record_close(RECORD_STORAGE);
string_clear(filetype); string_clear(filetype);
if(old_counter && state) {
// Change counter endianness and rewrite counter file
*cnt_val = __REV(cnt.counter);
state = u2f_data_cnt_write(*cnt_val);
}
return state; return state;
} }

View File

@@ -13,7 +13,7 @@
#define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo") #define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo")
#define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s") #define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s")
#define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub") #define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub")
#define TEST_RANDOM_COUNT_PARSE 158 #define TEST_RANDOM_COUNT_PARSE 188
#define TEST_TIMEOUT 10000 #define TEST_TIMEOUT 10000
static SubGhzEnvironment* environment_handler; static SubGhzEnvironment* environment_handler;
@@ -404,6 +404,14 @@ MU_TEST(subghz_decoder_phoenix_v2_test) {
"Test decoder " SUBGHZ_PROTOCOL_PHOENIX_V2_NAME " error\r\n"); "Test decoder " SUBGHZ_PROTOCOL_PHOENIX_V2_NAME " error\r\n");
} }
MU_TEST(subghz_decoder_honeywell_wdb_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/honeywell_wdb_raw.sub"),
SUBGHZ_PROTOCOL_HONEYWELL_WDB_NAME),
"Test decoder " SUBGHZ_PROTOCOL_HONEYWELL_WDB_NAME " error\r\n");
}
//test encoders //test encoders
MU_TEST(subghz_encoder_princeton_test) { MU_TEST(subghz_encoder_princeton_test) {
mu_assert( mu_assert(
@@ -501,6 +509,12 @@ MU_TEST(subghz_encoder_phoenix_v2_test) {
"Test encoder " SUBGHZ_PROTOCOL_PHOENIX_V2_NAME " error\r\n"); "Test encoder " SUBGHZ_PROTOCOL_PHOENIX_V2_NAME " error\r\n");
} }
MU_TEST(subghz_encoder_honeywell_wdb_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/honeywell_wdb.sub")),
"Test encoder " SUBGHZ_PROTOCOL_HONEYWELL_WDB_NAME " error\r\n");
}
MU_TEST(subghz_random_test) { MU_TEST(subghz_random_test) {
mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n"); mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n");
} }
@@ -537,6 +551,7 @@ MU_TEST_SUITE(subghz) {
MU_RUN_TEST(subghz_decoder_bett_test); MU_RUN_TEST(subghz_decoder_bett_test);
MU_RUN_TEST(subghz_decoder_doitrand_test); MU_RUN_TEST(subghz_decoder_doitrand_test);
MU_RUN_TEST(subghz_decoder_phoenix_v2_test); MU_RUN_TEST(subghz_decoder_phoenix_v2_test);
MU_RUN_TEST(subghz_decoder_honeywell_wdb_test);
MU_RUN_TEST(subghz_encoder_princeton_test); MU_RUN_TEST(subghz_encoder_princeton_test);
MU_RUN_TEST(subghz_encoder_came_test); MU_RUN_TEST(subghz_encoder_came_test);
@@ -554,6 +569,7 @@ MU_TEST_SUITE(subghz) {
MU_RUN_TEST(subghz_encoder_bett_test); MU_RUN_TEST(subghz_encoder_bett_test);
MU_RUN_TEST(subghz_encoder_doitrand_test); MU_RUN_TEST(subghz_encoder_doitrand_test);
MU_RUN_TEST(subghz_encoder_phoenix_v2_test); MU_RUN_TEST(subghz_encoder_phoenix_v2_test);
MU_RUN_TEST(subghz_encoder_honeywell_wdb_test);
MU_RUN_TEST(subghz_random_test); MU_RUN_TEST(subghz_random_test);
subghz_test_deinit(); subghz_test_deinit();

View File

@@ -96,7 +96,7 @@ static WavPlayerApp* app_alloc() {
WavPlayerApp* app = malloc(sizeof(WavPlayerApp)); WavPlayerApp* app = malloc(sizeof(WavPlayerApp));
app->samples_count_half = 1024 * 4; app->samples_count_half = 1024 * 4;
app->samples_count = app->samples_count_half * 2; app->samples_count = app->samples_count_half * 2;
app->storage = furi_record_open("storage"); app->storage = furi_record_open(RECORD_STORAGE);
app->stream = file_stream_alloc(app->storage); app->stream = file_stream_alloc(app->storage);
app->parser = wav_parser_alloc(); app->parser = wav_parser_alloc();
app->sample_buffer = malloc(sizeof(uint16_t) * app->samples_count); app->sample_buffer = malloc(sizeof(uint16_t) * app->samples_count);
@@ -106,7 +106,7 @@ static WavPlayerApp* app_alloc() {
app->volume = 10.0f; app->volume = 10.0f;
app->play = true; app->play = true;
app->gui = furi_record_open("gui"); app->gui = furi_record_open(RECORD_GUI);
app->view_dispatcher = view_dispatcher_alloc(); app->view_dispatcher = view_dispatcher_alloc();
app->view = wav_player_view_alloc(); app->view = wav_player_view_alloc();
@@ -124,14 +124,14 @@ static void app_free(WavPlayerApp* app) {
view_dispatcher_remove_view(app->view_dispatcher, 0); view_dispatcher_remove_view(app->view_dispatcher, 0);
view_dispatcher_free(app->view_dispatcher); view_dispatcher_free(app->view_dispatcher);
wav_player_view_free(app->view); wav_player_view_free(app->view);
furi_record_close("gui"); furi_record_close(RECORD_GUI);
furi_message_queue_free(app->queue); furi_message_queue_free(app->queue);
free(app->tmp_buffer); free(app->tmp_buffer);
free(app->sample_buffer); free(app->sample_buffer);
wav_parser_free(app->parser); wav_parser_free(app->parser);
stream_free(app->stream); stream_free(app->stream);
furi_record_close("storage"); furi_record_close(RECORD_STORAGE);
notification_message(app->notification, &sequence_display_backlight_enforce_auto); notification_message(app->notification, &sequence_display_backlight_enforce_auto);
furi_record_close("notification"); furi_record_close("notification");
@@ -296,11 +296,11 @@ int32_t wav_player_app(void* p) {
UNUSED(p); UNUSED(p);
WavPlayerApp* app = app_alloc(); WavPlayerApp* app = app_alloc();
Storage* storage = furi_record_open("storage"); Storage* storage = furi_record_open(RECORD_STORAGE);
if(!storage_simply_mkdir(storage, WAVPLAYER_FOLDER)) { if(!storage_simply_mkdir(storage, WAVPLAYER_FOLDER)) {
FURI_LOG_E(TAG, "Could not create folder %s", WAVPLAYER_FOLDER); FURI_LOG_E(TAG, "Could not create folder %s", WAVPLAYER_FOLDER);
} }
furi_record_close("storage"); furi_record_close(RECORD_STORAGE);
app_run(app); app_run(app);
app_free(app); app_free(app);

View File

@@ -8,7 +8,7 @@ void wifi_marauder_console_output_handle_rx_data_cb(uint8_t* buf, size_t len, vo
app->text_box_store_strlen += len; app->text_box_store_strlen += len;
if(app->text_box_store_strlen >= WIFI_MARAUDER_TEXT_BOX_STORE_SIZE - 1) { if(app->text_box_store_strlen >= WIFI_MARAUDER_TEXT_BOX_STORE_SIZE - 1) {
string_right(app->text_box_store, app->text_box_store_strlen / 2); string_right(app->text_box_store, app->text_box_store_strlen / 2);
app->text_box_store_strlen = string_size(app->text_box_store); app->text_box_store_strlen = string_size(app->text_box_store) + len;
} }
// Null-terminate buf and append to text box store // Null-terminate buf and append to text box store
@@ -32,10 +32,23 @@ void wifi_marauder_scene_console_output_on_enter(void* context) {
if(app->is_command) { if(app->is_command) {
string_reset(app->text_box_store); string_reset(app->text_box_store);
app->text_box_store_strlen = 0; app->text_box_store_strlen = 0;
} else { // "View Log" menu action if(0 == strncmp("help", app->selected_tx_string, strlen("help"))) {
text_box_set_text(app->text_box, string_get_cstr(app->text_box_store)); const char* help_msg =
"For app support/feedback,\nreach out to me:\n@cococode#6011 (discord)\n0xchocolate (github)\n";
string_cat_str(app->text_box_store, help_msg);
app->text_box_store_strlen += strlen(help_msg);
} }
if(app->show_stopscan_tip) {
const char* help_msg = "Press BACK to send stopscan\n";
string_cat_str(app->text_box_store, help_msg);
app->text_box_store_strlen += strlen(help_msg);
}
}
// Set starting text - for "View Log", this will just be what was already in the text box store
text_box_set_text(app->text_box, string_get_cstr(app->text_box_store));
scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneConsoleOutput, 0); scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneConsoleOutput, 0);
view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewConsoleOutput); view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewConsoleOutput);

View File

@@ -1,67 +1,138 @@
#include "../wifi_marauder_app_i.h" #include "../wifi_marauder_app_i.h"
#define NUM_MENU_ITEMS (29)
// For each command, define whether additional arguments are needed // For each command, define whether additional arguments are needed
// (enabling text input to fill them out), and whether the console // (enabling text input to fill them out), and whether the console
// text box should focus at the start of the output or the end // text box should focus at the start of the output or the end
#define INPUT_ARGS (true) typedef enum { NO_ARGS = 0, INPUT_ARGS, TOGGLE_ARGS } InputArgs;
#define NO_ARGS (false)
#define FOCUS_CONSOLE_START (true)
#define FOCUS_CONSOLE_END (false)
struct WifiMarauderItem {
const char* item_string;
bool needs_keyboard;
bool focus_console_start;
};
const struct WifiMarauderItem items[NUM_MENU_ITEMS] = { typedef enum { FOCUS_CONSOLE_END = 0, FOCUS_CONSOLE_START, FOCUS_CONSOLE_TOGGLE } FocusConsole;
{"View Log (start)", NO_ARGS, FOCUS_CONSOLE_START},
{"View Log (end)", NO_ARGS, FOCUS_CONSOLE_END}, #define SHOW_STOPSCAN_TIP (true)
{"attack -t beacon -l", NO_ARGS, FOCUS_CONSOLE_END}, #define NO_TIP (false)
{"attack -t beacon -r", NO_ARGS, FOCUS_CONSOLE_END},
{"attack -t beacon -a", NO_ARGS, FOCUS_CONSOLE_END}, #define MAX_OPTIONS (6)
{"attack -t deauth", NO_ARGS, FOCUS_CONSOLE_END}, typedef struct {
{"attack -t probe", NO_ARGS, FOCUS_CONSOLE_END}, const char* item_string;
{"attack -t rickroll", NO_ARGS, FOCUS_CONSOLE_END}, const char* options_menu[MAX_OPTIONS];
{"channel", NO_ARGS, FOCUS_CONSOLE_END}, int num_options_menu;
{"channel -s", INPUT_ARGS, FOCUS_CONSOLE_END}, const char* actual_commands[MAX_OPTIONS];
{"clearlist -a", NO_ARGS, FOCUS_CONSOLE_END}, InputArgs needs_keyboard;
{"clearlist -s", NO_ARGS, FOCUS_CONSOLE_END}, FocusConsole focus_console;
{"help", NO_ARGS, FOCUS_CONSOLE_START}, bool show_stopscan_tip;
{"list -a", NO_ARGS, FOCUS_CONSOLE_START}, } WifiMarauderItem;
{"list -s", NO_ARGS, FOCUS_CONSOLE_START},
{"reboot", NO_ARGS, FOCUS_CONSOLE_END}, // NUM_MENU_ITEMS defined in wifi_marauder_app_i.h - if you add an entry here, increment it!
{"scanap", NO_ARGS, FOCUS_CONSOLE_END}, const WifiMarauderItem items[NUM_MENU_ITEMS] = {
{"select -a", INPUT_ARGS, FOCUS_CONSOLE_END}, {"View Log from", {"start", "end"}, 2, {"", ""}, NO_ARGS, FOCUS_CONSOLE_TOGGLE, NO_TIP},
{"select -s", INPUT_ARGS, FOCUS_CONSOLE_END}, {"Scan AP", {""}, 1, {"scanap"}, NO_ARGS, FOCUS_CONSOLE_END, SHOW_STOPSCAN_TIP},
{"sniffbeacon", NO_ARGS, FOCUS_CONSOLE_END}, {"SSID",
{"sniffdeauth", NO_ARGS, FOCUS_CONSOLE_END}, {"add random", "add name", "remove"},
{"sniffesp", NO_ARGS, FOCUS_CONSOLE_END}, 3,
{"sniffpmkid", NO_ARGS, FOCUS_CONSOLE_END}, {"ssid -a -g", "ssid -a -n", "ssid -r"},
{"sniffpmkid -c", INPUT_ARGS, FOCUS_CONSOLE_END}, INPUT_ARGS,
{"sniffpwn", NO_ARGS, FOCUS_CONSOLE_END}, FOCUS_CONSOLE_START,
{"ssid -a -g", INPUT_ARGS, FOCUS_CONSOLE_END}, NO_TIP},
{"ssid -a -n", INPUT_ARGS, FOCUS_CONSOLE_END}, {"List", {"ap", "ssid"}, 2, {"list -a", "list -s"}, NO_ARGS, FOCUS_CONSOLE_START, NO_TIP},
{"ssid -r", INPUT_ARGS, FOCUS_CONSOLE_END}, {"Select", {"ap", "ssid"}, 2, {"select -a", "select -s"}, INPUT_ARGS, FOCUS_CONSOLE_END, NO_TIP},
{"update -w", NO_ARGS, FOCUS_CONSOLE_END}, {"Clear List",
{"ap", "ssid"},
2,
{"clearlist -a", "clearlist -s"},
NO_ARGS,
FOCUS_CONSOLE_END,
NO_TIP},
{"Attack",
{"deauth", "probe", "rickroll"},
3,
{"attack -t deauth", "attack -t probe", "attack -t rickroll"},
NO_ARGS,
FOCUS_CONSOLE_END,
SHOW_STOPSCAN_TIP},
{"Beacon Spam",
{"ap list", "ssid list", "random"},
3,
{"attack -t beacon -a", "attack -t beacon -l", "attack -t beacon -r"},
NO_ARGS,
FOCUS_CONSOLE_END,
SHOW_STOPSCAN_TIP},
{"Sniff",
{"beacon", "deauth", "esp", "pmkid", "pwn"},
5,
{"sniffbeacon", "sniffdeauth", "sniffesp", "sniffpmkid", "sniffpwn"},
NO_ARGS,
FOCUS_CONSOLE_END,
SHOW_STOPSCAN_TIP},
{"Sniff PMKID on channel",
{""},
1,
{"sniffpmkid -c"},
INPUT_ARGS,
FOCUS_CONSOLE_END,
SHOW_STOPSCAN_TIP},
{"Channel",
{"get", "set"},
2,
{"channel", "channel -s"},
TOGGLE_ARGS,
FOCUS_CONSOLE_END,
NO_TIP},
{"Settings",
{"display", "restore", "ForcePMKID", "ForceProbe", "SavePCAP", "other"},
6,
{"settings",
"settings -r",
"settings -s ForcePMKID enable",
"settings -s ForceProbe enable",
"settings -s SavePCAP enable",
"settings -s"},
TOGGLE_ARGS,
FOCUS_CONSOLE_START,
NO_TIP},
{"Update", {""}, 1, {"update -w"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP},
{"Reboot", {""}, 1, {"reboot"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP},
{"Help", {""}, 1, {"help"}, NO_ARGS, FOCUS_CONSOLE_START, SHOW_STOPSCAN_TIP},
}; };
static void wifi_marauder_scene_start_var_list_enter_callback(void* context, uint32_t index) { static void wifi_marauder_scene_start_var_list_enter_callback(void* context, uint32_t index) {
furi_assert(context); furi_assert(context);
WifiMarauderApp* app = context; WifiMarauderApp* app = context;
app->selected_tx_string = items[index].item_string;
app->is_command = (2 <= index); furi_assert(index < NUM_MENU_ITEMS);
const WifiMarauderItem* item = &items[index];
const int selected_option_index = app->selected_option_index[index];
furi_assert(selected_option_index < item->num_options_menu);
app->selected_tx_string = item->actual_commands[selected_option_index];
app->is_command = (1 <= index);
app->is_custom_tx_string = false; app->is_custom_tx_string = false;
app->selected_menu_index = index; app->selected_menu_index = index;
app->focus_console_start = items[index].focus_console_start; app->focus_console_start = (item->focus_console == FOCUS_CONSOLE_TOGGLE) ?
if(items[index].needs_keyboard) { (selected_option_index == 0) :
item->focus_console;
app->show_stopscan_tip = item->show_stopscan_tip;
bool needs_keyboard = (item->needs_keyboard == TOGGLE_ARGS) ? (selected_option_index != 0) :
item->needs_keyboard;
if(needs_keyboard) {
view_dispatcher_send_custom_event(app->view_dispatcher, WifiMarauderEventStartKeyboard); view_dispatcher_send_custom_event(app->view_dispatcher, WifiMarauderEventStartKeyboard);
} else { } else {
view_dispatcher_send_custom_event(app->view_dispatcher, WifiMarauderEventStartConsole); view_dispatcher_send_custom_event(app->view_dispatcher, WifiMarauderEventStartConsole);
} }
} }
static void wifi_marauder_scene_start_var_list_change_callback(VariableItem* item) {
furi_assert(item);
WifiMarauderApp* app = variable_item_get_context(item);
furi_assert(app);
const WifiMarauderItem* menu_item = &items[app->selected_menu_index];
uint8_t item_index = variable_item_get_current_value_index(item);
furi_assert(item_index < menu_item->num_options_menu);
variable_item_set_current_value_text(item, menu_item->options_menu[item_index]);
app->selected_option_index[app->selected_menu_index] = item_index;
}
void wifi_marauder_scene_start_on_enter(void* context) { void wifi_marauder_scene_start_on_enter(void* context) {
WifiMarauderApp* app = context; WifiMarauderApp* app = context;
VariableItemList* var_item_list = app->var_item_list; VariableItemList* var_item_list = app->var_item_list;
@@ -69,9 +140,17 @@ void wifi_marauder_scene_start_on_enter(void* context) {
variable_item_list_set_enter_callback( variable_item_list_set_enter_callback(
var_item_list, wifi_marauder_scene_start_var_list_enter_callback, app); var_item_list, wifi_marauder_scene_start_var_list_enter_callback, app);
// TODO: organize menu VariableItem* item;
for(int i = 0; i < NUM_MENU_ITEMS; ++i) { for(int i = 0; i < NUM_MENU_ITEMS; ++i) {
variable_item_list_add(var_item_list, items[i].item_string, 0, NULL, NULL); item = variable_item_list_add(
var_item_list,
items[i].item_string,
items[i].num_options_menu,
wifi_marauder_scene_start_var_list_change_callback,
app);
variable_item_set_current_value_index(item, app->selected_option_index[i]);
variable_item_set_current_value_text(
item, items[i].options_menu[app->selected_option_index[i]]);
} }
variable_item_list_set_selected_item( variable_item_list_set_selected_item(
@@ -96,6 +175,9 @@ bool wifi_marauder_scene_start_on_event(void* context, SceneManagerEvent event)
scene_manager_next_scene(app->scene_manager, WifiMarauderAppViewConsoleOutput); scene_manager_next_scene(app->scene_manager, WifiMarauderAppViewConsoleOutput);
} }
consumed = true; consumed = true;
} else if(event.type == SceneManagerEventTypeTick) {
app->selected_menu_index = variable_item_list_get_selected_item_index(app->var_item_list);
consumed = true;
} }
return consumed; return consumed;

View File

@@ -24,7 +24,20 @@ void wifi_marauder_scene_text_input_on_enter(void* context) {
// Setup view // Setup view
TextInput* text_input = app->text_input; TextInput* text_input = app->text_input;
// Add help message to header
if(0 == strncmp("ssid -a -g", app->selected_tx_string, strlen("ssid -a -g"))) {
text_input_set_header_text(text_input, "Enter # SSIDs to generate");
} else if(0 == strncmp("ssid -a -n", app->selected_tx_string, strlen("ssid -a -n"))) {
text_input_set_header_text(text_input, "Enter SSID name to add");
} else if(0 == strncmp("ssid -r", app->selected_tx_string, strlen("ssid -r"))) {
text_input_set_header_text(text_input, "Remove target from SSID list");
} else if(0 == strncmp("select -a", app->selected_tx_string, strlen("select -a"))) {
text_input_set_header_text(text_input, "Add target from AP list");
} else if(0 == strncmp("select -s", app->selected_tx_string, strlen("select -s"))) {
text_input_set_header_text(text_input, "Add target from SSID list");
} else {
text_input_set_header_text(text_input, "Add command arguments"); text_input_set_header_text(text_input, "Add command arguments");
}
text_input_set_result_callback( text_input_set_result_callback(
text_input, text_input,
wifi_marauder_scene_text_input_callback, wifi_marauder_scene_text_input_callback,

View File

@@ -24,7 +24,7 @@ static void wifi_marauder_app_tick_event_callback(void* context) {
WifiMarauderApp* wifi_marauder_app_alloc() { WifiMarauderApp* wifi_marauder_app_alloc() {
WifiMarauderApp* app = malloc(sizeof(WifiMarauderApp)); WifiMarauderApp* app = malloc(sizeof(WifiMarauderApp));
app->gui = furi_record_open("gui"); app->gui = furi_record_open(RECORD_GUI);
app->view_dispatcher = view_dispatcher_alloc(); app->view_dispatcher = view_dispatcher_alloc();
app->scene_manager = scene_manager_alloc(&wifi_marauder_scene_handlers, app); app->scene_manager = scene_manager_alloc(&wifi_marauder_scene_handlers, app);
@@ -46,6 +46,10 @@ WifiMarauderApp* wifi_marauder_app_alloc() {
WifiMarauderAppViewVarItemList, WifiMarauderAppViewVarItemList,
variable_item_list_get_view(app->var_item_list)); variable_item_list_get_view(app->var_item_list));
for(int i = 0; i < NUM_MENU_ITEMS; ++i) {
app->selected_option_index[i] = 0;
}
app->text_box = text_box_alloc(); app->text_box = text_box_alloc();
view_dispatcher_add_view( view_dispatcher_add_view(
app->view_dispatcher, WifiMarauderAppViewConsoleOutput, text_box_get_view(app->text_box)); app->view_dispatcher, WifiMarauderAppViewConsoleOutput, text_box_get_view(app->text_box));
@@ -79,7 +83,7 @@ void wifi_marauder_app_free(WifiMarauderApp* app) {
wifi_marauder_uart_free(app->uart); wifi_marauder_uart_free(app->uart);
// Close records // Close records
furi_record_close("gui"); furi_record_close(RECORD_GUI);
free(app); free(app);
} }

View File

@@ -12,6 +12,8 @@
#include <gui/modules/text_input.h> #include <gui/modules/text_input.h>
#include <gui/modules/variable_item_list.h> #include <gui/modules/variable_item_list.h>
#define NUM_MENU_ITEMS (15)
#define WIFI_MARAUDER_TEXT_BOX_STORE_SIZE (4096) #define WIFI_MARAUDER_TEXT_BOX_STORE_SIZE (4096)
#define WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE (512) #define WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE (512)
@@ -31,10 +33,12 @@ struct WifiMarauderApp {
WifiMarauderUart* uart; WifiMarauderUart* uart;
int selected_menu_index; int selected_menu_index;
int selected_option_index[NUM_MENU_ITEMS];
const char* selected_tx_string; const char* selected_tx_string;
bool is_command; bool is_command;
bool is_custom_tx_string; bool is_custom_tx_string;
bool focus_console_start; bool focus_console_start;
bool show_stopscan_tip;
}; };
// Supported commands: // Supported commands:

View File

@@ -685,7 +685,7 @@ int32_t wifi_scanner_app(void* p) {
view_port_input_callback_set(view_port, wifi_module_input_callback, event_queue); view_port_input_callback_set(view_port, wifi_module_input_callback, event_queue);
// Open GUI and register view_port // Open GUI and register view_port
Gui* gui = furi_record_open("gui"); Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen); gui_add_view_port(gui, view_port, GuiLayerFullscreen);
//notification_message(app->notification, &sequence_set_only_blue_255); //notification_message(app->notification, &sequence_set_only_blue_255);
@@ -831,7 +831,7 @@ int32_t wifi_scanner_app(void* p) {
gui_remove_view_port(gui, view_port); gui_remove_view_port(gui, view_port);
// Close gui record // Close gui record
furi_record_close("gui"); furi_record_close(RECORD_GUI);
furi_record_close("notification"); furi_record_close("notification");
app->m_gui = NULL; app->m_gui = NULL;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Some files were not shown because too many files have changed in this diff Show More