mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-11 06:09:08 -07:00
Merge branch 'dev' into zlo/allocator-playground
This commit is contained in:
@@ -177,6 +177,14 @@ static bool subghz_device_cc1101_ext_check_init(void) {
|
||||
furi_hal_gpio_init(
|
||||
subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
// Reset GDO2 (!TX/RX) to floating state
|
||||
cc1101_status = cc1101_write_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHighImpedance);
|
||||
if(cc1101_status.CHIP_RDYn != 0) {
|
||||
//timeout or error
|
||||
break;
|
||||
}
|
||||
|
||||
// Go to sleep
|
||||
cc1101_status = cc1101_shutdown(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
if(cc1101_status.CHIP_RDYn != 0) {
|
||||
@@ -385,6 +393,9 @@ void subghz_device_cc1101_ext_reset(void) {
|
||||
// Warning: push pull cc1101 clock output on GD0
|
||||
cc1101_write_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance);
|
||||
// Reset GDO2 (!TX/RX) to floating state
|
||||
cc1101_write_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHighImpedance);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
}
|
||||
|
||||
@@ -394,6 +405,9 @@ void subghz_device_cc1101_ext_idle(void) {
|
||||
//waiting for the chip to switch to IDLE mode
|
||||
furi_check(cc1101_wait_status_state(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101StateIDLE, 10000));
|
||||
// Reset GDO2 (!TX/RX) to floating state
|
||||
cc1101_write_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHighImpedance);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
}
|
||||
|
||||
@@ -403,6 +417,10 @@ void subghz_device_cc1101_ext_rx(void) {
|
||||
//waiting for the chip to switch to Rx mode
|
||||
furi_check(
|
||||
cc1101_wait_status_state(subghz_device_cc1101_ext->spi_bus_handle, CC1101StateRX, 10000));
|
||||
// Go GDO2 (!TX/RX) to high (RX state)
|
||||
cc1101_write_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
|
||||
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
}
|
||||
|
||||
@@ -413,6 +431,8 @@ bool subghz_device_cc1101_ext_tx(void) {
|
||||
//waiting for the chip to switch to Tx mode
|
||||
furi_check(
|
||||
cc1101_wait_status_state(subghz_device_cc1101_ext->spi_bus_handle, CC1101StateTX, 10000));
|
||||
// Go GDO2 (!TX/RX) to low (TX state)
|
||||
cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
21
applications/main/nfc/helpers/felica_auth.c
Normal file
21
applications/main/nfc/helpers/felica_auth.c
Normal file
@@ -0,0 +1,21 @@
|
||||
#include "felica_auth.h"
|
||||
|
||||
FelicaAuthenticationContext* felica_auth_alloc() {
|
||||
FelicaAuthenticationContext* instance = malloc(sizeof(FelicaAuthenticationContext));
|
||||
memset(instance->card_key.data, 0, FELICA_DATA_BLOCK_SIZE);
|
||||
instance->skip_auth = true;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void felica_auth_free(FelicaAuthenticationContext* instance) {
|
||||
furi_assert(instance);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void felica_auth_reset(FelicaAuthenticationContext* instance) {
|
||||
furi_assert(instance);
|
||||
memset(instance->card_key.data, 0, FELICA_DATA_BLOCK_SIZE);
|
||||
instance->skip_auth = true;
|
||||
instance->auth_status.external = 0;
|
||||
instance->auth_status.internal = 0;
|
||||
}
|
||||
17
applications/main/nfc/helpers/felica_auth.h
Normal file
17
applications/main/nfc/helpers/felica_auth.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <lib/nfc/protocols/felica/felica.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
FelicaAuthenticationContext* felica_auth_alloc();
|
||||
|
||||
void felica_auth_free(FelicaAuthenticationContext* instance);
|
||||
|
||||
void felica_auth_reset(FelicaAuthenticationContext* instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -7,6 +7,11 @@
|
||||
|
||||
#include "../nfc_protocol_support_common.h"
|
||||
#include "../nfc_protocol_support_gui_common.h"
|
||||
#include "../nfc_protocol_support_unlock_helper.h"
|
||||
|
||||
enum {
|
||||
SubmenuIndexUnlock = SubmenuIndexCommonMax,
|
||||
};
|
||||
|
||||
static void nfc_scene_info_on_enter_felica(NfcApp* instance) {
|
||||
const NfcDevice* device = instance->nfc_device;
|
||||
@@ -18,6 +23,35 @@ static void nfc_scene_info_on_enter_felica(NfcApp* instance) {
|
||||
temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
|
||||
nfc_render_felica_info(data, NfcProtocolFormatTypeFull, temp_str);
|
||||
|
||||
widget_add_text_scroll_element(
|
||||
instance->widget, 0, 0, 128, 48, furi_string_get_cstr(temp_str));
|
||||
|
||||
widget_add_button_element(
|
||||
instance->widget,
|
||||
GuiButtonTypeRight,
|
||||
"More",
|
||||
nfc_protocol_support_common_widget_callback,
|
||||
instance);
|
||||
furi_string_free(temp_str);
|
||||
}
|
||||
|
||||
static bool nfc_scene_info_on_event_felica(NfcApp* instance, SceneManagerEvent event) {
|
||||
if(event.type == SceneManagerEventTypeCustom && event.event == GuiButtonTypeRight) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneMoreInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void nfc_scene_more_info_on_enter_felica(NfcApp* instance) {
|
||||
const NfcDevice* device = instance->nfc_device;
|
||||
const FelicaData* data = nfc_device_get_data(device, NfcProtocolFelica);
|
||||
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
|
||||
nfc_render_felica_dump(data, temp_str);
|
||||
|
||||
widget_add_text_scroll_element(
|
||||
instance->widget, 0, 0, 128, 64, furi_string_get_cstr(temp_str));
|
||||
|
||||
@@ -29,29 +63,75 @@ static NfcCommand nfc_scene_read_poller_callback_felica(NfcGenericEvent event, v
|
||||
|
||||
NfcApp* instance = context;
|
||||
const FelicaPollerEvent* felica_event = event.event_data;
|
||||
NfcCommand command = NfcCommandContinue;
|
||||
|
||||
if(felica_event->type == FelicaPollerEventTypeReady) {
|
||||
nfc_device_set_data(
|
||||
instance->nfc_device, NfcProtocolFelica, nfc_poller_get_data(instance->poller));
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess);
|
||||
return NfcCommandStop;
|
||||
command = NfcCommandStop;
|
||||
} else if(
|
||||
felica_event->type == FelicaPollerEventTypeError ||
|
||||
felica_event->type == FelicaPollerEventTypeIncomplete) {
|
||||
nfc_device_set_data(
|
||||
instance->nfc_device, NfcProtocolFelica, nfc_poller_get_data(instance->poller));
|
||||
view_dispatcher_send_custom_event(
|
||||
instance->view_dispatcher, NfcCustomEventPollerIncomplete);
|
||||
command = NfcCommandStop;
|
||||
} else if(felica_event->type == FelicaPollerEventTypeRequestAuthContext) {
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventCardDetected);
|
||||
FelicaAuthenticationContext* ctx = felica_event->data->auth_context;
|
||||
ctx->skip_auth = instance->felica_auth->skip_auth;
|
||||
memcpy(ctx->card_key.data, instance->felica_auth->card_key.data, FELICA_DATA_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
return NfcCommandContinue;
|
||||
return command;
|
||||
}
|
||||
|
||||
static void nfc_scene_read_on_enter_felica(NfcApp* instance) {
|
||||
nfc_unlock_helper_setup_from_state(instance);
|
||||
nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_felica, instance);
|
||||
}
|
||||
|
||||
bool nfc_scene_read_on_event_felica(NfcApp* instance, SceneManagerEvent event) {
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventCardDetected) {
|
||||
nfc_unlock_helper_card_detected_handler(instance);
|
||||
} else if(event.event == NfcCustomEventPollerIncomplete) {
|
||||
notification_message(instance->notifications, &sequence_semi_success);
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess);
|
||||
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void nfc_scene_read_success_on_enter_felica(NfcApp* instance) {
|
||||
const NfcDevice* device = instance->nfc_device;
|
||||
const FelicaData* data = nfc_device_get_data(device, NfcProtocolFelica);
|
||||
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
furi_string_cat_printf(
|
||||
temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
|
||||
nfc_render_felica_info(data, NfcProtocolFormatTypeShort, temp_str);
|
||||
|
||||
if(!scene_manager_has_previous_scene(instance->scene_manager, NfcSceneFelicaUnlockWarn)) {
|
||||
furi_string_cat_printf(
|
||||
temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
|
||||
nfc_render_felica_info(data, NfcProtocolFormatTypeShort, temp_str);
|
||||
} else {
|
||||
bool all_unlocked = data->blocks_read == data->blocks_total;
|
||||
furi_string_cat_printf(
|
||||
temp_str,
|
||||
"\e#%s\n",
|
||||
all_unlocked ? "All Blocks Are Unlocked" : "Some Blocks Are Locked");
|
||||
nfc_render_felica_idm(data, NfcProtocolFormatTypeShort, temp_str);
|
||||
uint8_t* ck_data = instance->felica_auth->card_key.data;
|
||||
furi_string_cat_printf(temp_str, "Key:");
|
||||
for(uint8_t i = 0; i < 7; i++) {
|
||||
furi_string_cat_printf(temp_str, " %02X", ck_data[i]);
|
||||
if(i == 6) furi_string_cat_printf(temp_str, "...");
|
||||
}
|
||||
nfc_render_felica_blocks_count(data, temp_str, false);
|
||||
}
|
||||
felica_auth_reset(instance->felica_auth);
|
||||
|
||||
widget_add_text_scroll_element(
|
||||
instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str));
|
||||
@@ -74,23 +154,50 @@ static void nfc_scene_emulate_on_enter_felica(NfcApp* instance) {
|
||||
nfc_listener_start(instance->listener, NULL, NULL);
|
||||
}
|
||||
|
||||
static void nfc_scene_read_menu_on_enter_felica(NfcApp* instance) {
|
||||
const FelicaData* data = nfc_device_get_data(instance->nfc_device, NfcProtocolFelica);
|
||||
if(data->blocks_read != data->blocks_total) {
|
||||
submenu_add_item(
|
||||
instance->submenu,
|
||||
"Unlock",
|
||||
SubmenuIndexUnlock,
|
||||
nfc_protocol_support_common_submenu_callback,
|
||||
instance);
|
||||
}
|
||||
}
|
||||
|
||||
static bool nfc_scene_read_menu_on_event_felica(NfcApp* instance, SceneManagerEvent event) {
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexUnlock) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneFelicaKeyInput);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const NfcProtocolSupportBase nfc_protocol_support_felica = {
|
||||
.features = NfcProtocolFeatureEmulateUid,
|
||||
|
||||
.scene_info =
|
||||
{
|
||||
.on_enter = nfc_scene_info_on_enter_felica,
|
||||
.on_event = nfc_scene_info_on_event_felica,
|
||||
},
|
||||
.scene_more_info =
|
||||
{
|
||||
.on_enter = nfc_scene_more_info_on_enter_felica,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_read =
|
||||
{
|
||||
.on_enter = nfc_scene_read_on_enter_felica,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
.on_event = nfc_scene_read_on_event_felica,
|
||||
},
|
||||
.scene_read_menu =
|
||||
{
|
||||
.on_enter = nfc_protocol_support_common_on_enter_empty,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
.on_enter = nfc_scene_read_menu_on_enter_felica,
|
||||
.on_event = nfc_scene_read_menu_on_event_felica,
|
||||
},
|
||||
.scene_read_success =
|
||||
{
|
||||
|
||||
@@ -1,19 +1,107 @@
|
||||
#include "felica_render.h"
|
||||
|
||||
void nfc_render_felica_blocks_count(
|
||||
const FelicaData* data,
|
||||
FuriString* str,
|
||||
bool render_auth_notification) {
|
||||
furi_string_cat_printf(str, "\nBlocks Read: %u/%u", data->blocks_read, data->blocks_total);
|
||||
if(render_auth_notification && data->blocks_read != data->blocks_total) {
|
||||
furi_string_cat_printf(str, "\nAuth-protected blocks!");
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_render_felica_idm(
|
||||
const FelicaData* data,
|
||||
NfcProtocolFormatType format_type,
|
||||
FuriString* str) {
|
||||
furi_string_cat_printf(str, (format_type == NfcProtocolFormatTypeFull) ? "IDm:\n" : "IDm:");
|
||||
|
||||
for(size_t i = 0; i < FELICA_IDM_SIZE; i++) {
|
||||
furi_string_cat_printf(
|
||||
str,
|
||||
(format_type == NfcProtocolFormatTypeFull) ? "%02X " : " %02X",
|
||||
data->idm.data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_render_felica_info(
|
||||
const FelicaData* data,
|
||||
NfcProtocolFormatType format_type,
|
||||
FuriString* str) {
|
||||
furi_string_cat_printf(str, "IDm:");
|
||||
|
||||
for(size_t i = 0; i < FELICA_IDM_SIZE; i++) {
|
||||
furi_string_cat_printf(str, " %02X", data->idm.data[i]);
|
||||
if(format_type == NfcProtocolFormatTypeFull) {
|
||||
furi_string_cat_printf(str, "Tech: JIS X 6319-4,\nISO 18092 [NFC-F]\n");
|
||||
}
|
||||
|
||||
nfc_render_felica_idm(data, format_type, str);
|
||||
|
||||
if(format_type == NfcProtocolFormatTypeFull) {
|
||||
furi_string_cat_printf(str, "\nPMm:");
|
||||
furi_string_cat_printf(str, "\nPMm:\n");
|
||||
for(size_t i = 0; i < FELICA_PMM_SIZE; ++i) {
|
||||
furi_string_cat_printf(str, " %02X", data->pmm.data[i]);
|
||||
furi_string_cat_printf(str, "%02X ", data->pmm.data[i]);
|
||||
}
|
||||
}
|
||||
nfc_render_felica_blocks_count(data, str, true);
|
||||
}
|
||||
|
||||
static void nfc_render_felica_block_name(
|
||||
const char* name,
|
||||
FuriString* str,
|
||||
uint8_t prefix_separator_cnt,
|
||||
uint8_t suffix_separator_cnt) {
|
||||
for(uint8_t i = 0; i < prefix_separator_cnt; i++) {
|
||||
furi_string_cat_printf(str, ":");
|
||||
}
|
||||
furi_string_cat_printf(str, "[ %s ]", name);
|
||||
for(uint8_t i = 0; i < suffix_separator_cnt; i++) {
|
||||
furi_string_cat_printf(str, ":");
|
||||
}
|
||||
}
|
||||
|
||||
static void nfc_render_felica_block_data(const FelicaBlock* block, FuriString* str) {
|
||||
furi_string_cat_printf(str, "\nSF1=%02X; SF2=%02X\n", block->SF1, block->SF2);
|
||||
for(size_t j = 0; j < FELICA_DATA_BLOCK_SIZE; j++) {
|
||||
if((j != 0) && (j % 8 == 0)) furi_string_cat_printf(str, "\n");
|
||||
furi_string_cat_printf(str, "%02X ", block->data[j]);
|
||||
}
|
||||
furi_string_cat_printf(str, "\n");
|
||||
}
|
||||
|
||||
static void nfc_render_felica_block(
|
||||
const FelicaBlock* block,
|
||||
FuriString* str,
|
||||
const char* name,
|
||||
uint8_t prefix_separator_cnt,
|
||||
uint8_t suffix_separator_cnt) {
|
||||
nfc_render_felica_block_name(name, str, prefix_separator_cnt, suffix_separator_cnt);
|
||||
nfc_render_felica_block_data(block, str);
|
||||
}
|
||||
|
||||
void nfc_render_felica_dump(const FelicaData* data, FuriString* str) {
|
||||
FuriString* name = furi_string_alloc();
|
||||
for(size_t i = 0; i < 14; i++) {
|
||||
furi_string_printf(name, "S_PAD%d", i);
|
||||
uint8_t suf_cnt = 18;
|
||||
if(i == 1) {
|
||||
suf_cnt = 19;
|
||||
} else if((i == 10) || (i == 12) || (i == 13)) {
|
||||
suf_cnt = 16;
|
||||
}
|
||||
nfc_render_felica_block(
|
||||
&data->data.fs.spad[i], str, furi_string_get_cstr(name), 20, suf_cnt);
|
||||
}
|
||||
furi_string_free(name);
|
||||
nfc_render_felica_block(&data->data.fs.reg, str, "REG", 23, 23);
|
||||
nfc_render_felica_block(&data->data.fs.rc, str, "RC", 25, 25);
|
||||
nfc_render_felica_block(&data->data.fs.mac, str, "MAC", 23, 23);
|
||||
nfc_render_felica_block(&data->data.fs.id, str, "ID", 25, 25);
|
||||
nfc_render_felica_block(&data->data.fs.d_id, str, "D_ID", 22, 24);
|
||||
nfc_render_felica_block(&data->data.fs.ser_c, str, "SER_C", 20, 21);
|
||||
nfc_render_felica_block(&data->data.fs.sys_c, str, "SYS_C", 20, 21);
|
||||
nfc_render_felica_block(&data->data.fs.ckv, str, "CKV", 23, 23);
|
||||
nfc_render_felica_block(&data->data.fs.ck, str, "CK", 25, 25);
|
||||
nfc_render_felica_block(&data->data.fs.mc, str, "MC", 25, 24);
|
||||
nfc_render_felica_block(&data->data.fs.wcnt, str, "WCNT", 22, 20);
|
||||
nfc_render_felica_block(&data->data.fs.mac_a, str, "MAC_A", 20, 20);
|
||||
nfc_render_felica_block(&data->data.fs.state, str, "STATE", 20, 21);
|
||||
nfc_render_felica_block(&data->data.fs.crc_check, str, "CRC_CHCK", 15, 17);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,19 @@
|
||||
|
||||
#include "../nfc_protocol_support_render_common.h"
|
||||
|
||||
void nfc_render_felica_blocks_count(
|
||||
const FelicaData* data,
|
||||
FuriString* str,
|
||||
bool render_auth_notification);
|
||||
|
||||
void nfc_render_felica_info(
|
||||
const FelicaData* data,
|
||||
NfcProtocolFormatType format_type,
|
||||
FuriString* str);
|
||||
|
||||
void nfc_render_felica_dump(const FelicaData* data, FuriString* str);
|
||||
|
||||
void nfc_render_felica_idm(
|
||||
const FelicaData* data,
|
||||
NfcProtocolFormatType format_type,
|
||||
FuriString* str);
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "../nfc_protocol_support_common.h"
|
||||
#include "../nfc_protocol_support_gui_common.h"
|
||||
#include "../nfc_protocol_support_unlock_helper.h"
|
||||
|
||||
enum {
|
||||
SubmenuIndexUnlock = SubmenuIndexCommonMax,
|
||||
@@ -157,48 +158,15 @@ static NfcCommand
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
||||
enum {
|
||||
NfcSceneMfUltralightReadMenuStateCardSearch,
|
||||
NfcSceneMfUltralightReadMenuStateCardFound,
|
||||
};
|
||||
|
||||
static void nfc_scene_read_setup_view(NfcApp* instance) {
|
||||
Popup* popup = instance->popup;
|
||||
popup_reset(popup);
|
||||
uint32_t state = scene_manager_get_scene_state(instance->scene_manager, NfcSceneRead);
|
||||
|
||||
if(state == NfcSceneMfUltralightReadMenuStateCardSearch) {
|
||||
popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50);
|
||||
popup_set_header(instance->popup, "Unlocking", 97, 15, AlignCenter, AlignTop);
|
||||
popup_set_text(
|
||||
instance->popup, "Hold card next\nto Flipper's back", 94, 27, AlignCenter, AlignTop);
|
||||
} else {
|
||||
popup_set_header(instance->popup, "Don't move", 85, 27, AlignCenter, AlignTop);
|
||||
popup_set_icon(instance->popup, 12, 20, &A_Loading_24);
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup);
|
||||
}
|
||||
|
||||
static void nfc_scene_read_on_enter_mf_ultralight(NfcApp* instance) {
|
||||
bool unlocking =
|
||||
scene_manager_has_previous_scene(instance->scene_manager, NfcSceneMfUltralightUnlockWarn);
|
||||
|
||||
uint32_t state = unlocking ? NfcSceneMfUltralightReadMenuStateCardSearch :
|
||||
NfcSceneMfUltralightReadMenuStateCardFound;
|
||||
|
||||
scene_manager_set_scene_state(instance->scene_manager, NfcSceneRead, state);
|
||||
|
||||
nfc_scene_read_setup_view(instance);
|
||||
nfc_unlock_helper_setup_from_state(instance);
|
||||
nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_mf_ultralight, instance);
|
||||
}
|
||||
|
||||
bool nfc_scene_read_on_event_mf_ultralight(NfcApp* instance, SceneManagerEvent event) {
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventCardDetected) {
|
||||
scene_manager_set_scene_state(
|
||||
instance->scene_manager, NfcSceneRead, NfcSceneMfUltralightReadMenuStateCardFound);
|
||||
nfc_scene_read_setup_view(instance);
|
||||
nfc_unlock_helper_card_detected_handler(instance);
|
||||
} else if((event.event == NfcCustomEventPollerIncomplete)) {
|
||||
notification_message(instance->notifications, &sequence_semi_success);
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess);
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "nfc_protocol_support_unlock_helper.h"
|
||||
|
||||
static void nfc_scene_read_setup_view(NfcApp* instance) {
|
||||
Popup* popup = instance->popup;
|
||||
popup_reset(popup);
|
||||
uint32_t state = scene_manager_get_scene_state(instance->scene_manager, NfcSceneRead);
|
||||
|
||||
if(state == NfcSceneReadMenuStateCardSearch) {
|
||||
popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50);
|
||||
popup_set_header(instance->popup, "Unlocking", 97, 15, AlignCenter, AlignTop);
|
||||
popup_set_text(
|
||||
instance->popup, "Hold card next\nto Flipper's back", 94, 27, AlignCenter, AlignTop);
|
||||
} else {
|
||||
popup_set_header(instance->popup, "Don't move", 85, 27, AlignCenter, AlignTop);
|
||||
popup_set_icon(instance->popup, 12, 20, &A_Loading_24);
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup);
|
||||
}
|
||||
|
||||
void nfc_unlock_helper_setup_from_state(NfcApp* instance) {
|
||||
bool unlocking =
|
||||
scene_manager_has_previous_scene(
|
||||
instance->scene_manager, NfcSceneMfUltralightUnlockWarn) ||
|
||||
scene_manager_has_previous_scene(instance->scene_manager, NfcSceneFelicaUnlockWarn);
|
||||
|
||||
uint32_t state = unlocking ? NfcSceneReadMenuStateCardSearch : NfcSceneReadMenuStateCardFound;
|
||||
|
||||
scene_manager_set_scene_state(instance->scene_manager, NfcSceneRead, state);
|
||||
|
||||
nfc_scene_read_setup_view(instance);
|
||||
}
|
||||
|
||||
void nfc_unlock_helper_card_detected_handler(NfcApp* instance) {
|
||||
scene_manager_set_scene_state(
|
||||
instance->scene_manager, NfcSceneRead, NfcSceneReadMenuStateCardFound);
|
||||
nfc_scene_read_setup_view(instance);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "nfc/nfc_app_i.h"
|
||||
|
||||
typedef enum {
|
||||
NfcSceneReadMenuStateCardSearch,
|
||||
NfcSceneReadMenuStateCardFound,
|
||||
} NfcSceneUnlockReadState;
|
||||
|
||||
void nfc_unlock_helper_setup_from_state(NfcApp* instance);
|
||||
void nfc_unlock_helper_card_detected_handler(NfcApp* instance);
|
||||
@@ -50,6 +50,7 @@ NfcApp* nfc_app_alloc(void) {
|
||||
|
||||
instance->nfc = nfc_alloc();
|
||||
|
||||
instance->felica_auth = felica_auth_alloc();
|
||||
instance->mf_ul_auth = mf_ultralight_auth_alloc();
|
||||
instance->slix_unlock = slix_unlock_alloc();
|
||||
instance->mfc_key_cache = mf_classic_key_cache_alloc();
|
||||
@@ -141,6 +142,7 @@ void nfc_app_free(NfcApp* instance) {
|
||||
|
||||
nfc_free(instance->nfc);
|
||||
|
||||
felica_auth_free(instance->felica_auth);
|
||||
mf_ultralight_auth_free(instance->mf_ul_auth);
|
||||
slix_unlock_free(instance->slix_unlock);
|
||||
mf_classic_key_cache_free(instance->mfc_key_cache);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "helpers/mfkey32_logger.h"
|
||||
#include "helpers/mf_classic_key_cache.h"
|
||||
#include "helpers/nfc_supported_cards.h"
|
||||
#include "helpers/felica_auth.h"
|
||||
#include "helpers/slix_unlock.h"
|
||||
|
||||
#include <dialogs/dialogs.h>
|
||||
@@ -129,6 +130,7 @@ struct NfcApp {
|
||||
NfcScanner* scanner;
|
||||
NfcListener* listener;
|
||||
|
||||
FelicaAuthenticationContext* felica_auth;
|
||||
MfUltralightAuth* mf_ul_auth;
|
||||
SlixUnlock* slix_unlock;
|
||||
NfcMfClassicDictAttackContext nfc_dict_context;
|
||||
|
||||
@@ -33,6 +33,8 @@ ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu)
|
||||
ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn)
|
||||
ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput)
|
||||
ADD_SCENE(nfc, mf_ultralight_capture_pass, MfUltralightCapturePass)
|
||||
ADD_SCENE(nfc, felica_key_input, FelicaKeyInput)
|
||||
ADD_SCENE(nfc, felica_unlock_warn, FelicaUnlockWarn)
|
||||
|
||||
ADD_SCENE(nfc, mf_desfire_more_info, MfDesfireMoreInfo)
|
||||
ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp)
|
||||
|
||||
46
applications/main/nfc/scenes/nfc_scene_felica_key_input.c
Normal file
46
applications/main/nfc/scenes/nfc_scene_felica_key_input.c
Normal file
@@ -0,0 +1,46 @@
|
||||
#include "../nfc_app_i.h"
|
||||
|
||||
void nfc_scene_felica_key_input_byte_input_callback(void* context) {
|
||||
NfcApp* nfc = context;
|
||||
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
|
||||
}
|
||||
|
||||
void nfc_scene_felica_key_input_on_enter(void* context) {
|
||||
NfcApp* nfc = context;
|
||||
|
||||
// Setup view
|
||||
ByteInput* byte_input = nfc->byte_input;
|
||||
byte_input_set_header_text(byte_input, "Enter key in hex");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
nfc_scene_felica_key_input_byte_input_callback,
|
||||
NULL,
|
||||
nfc,
|
||||
nfc->felica_auth->card_key.data,
|
||||
FELICA_DATA_BLOCK_SIZE);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput);
|
||||
}
|
||||
|
||||
bool nfc_scene_felica_key_input_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcApp* nfc = context;
|
||||
UNUSED(event);
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventByteInputDone) {
|
||||
nfc->felica_auth->skip_auth = false;
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaUnlockWarn);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_felica_key_input_on_exit(void* context) {
|
||||
NfcApp* nfc = context;
|
||||
|
||||
// Clear view
|
||||
byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||
byte_input_set_header_text(nfc->byte_input, "");
|
||||
}
|
||||
59
applications/main/nfc/scenes/nfc_scene_felica_unlock_warn.c
Normal file
59
applications/main/nfc/scenes/nfc_scene_felica_unlock_warn.c
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "../nfc_app_i.h"
|
||||
|
||||
void nfc_scene_felica_unlock_warn_dialog_callback(DialogExResult result, void* context) {
|
||||
NfcApp* nfc = context;
|
||||
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void nfc_scene_felica_unlock_warn_on_enter(void* context) {
|
||||
NfcApp* nfc = context;
|
||||
|
||||
const char* message = "Risky Action!";
|
||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
||||
dialog_ex_set_context(dialog_ex, nfc);
|
||||
dialog_ex_set_result_callback(dialog_ex, nfc_scene_felica_unlock_warn_dialog_callback);
|
||||
|
||||
dialog_ex_set_header(dialog_ex, message, 64, 0, AlignCenter, AlignTop);
|
||||
|
||||
FuriString* str = furi_string_alloc();
|
||||
furi_string_cat_printf(str, "Unlock with key: ");
|
||||
for(uint8_t i = 0; i < FELICA_DATA_BLOCK_SIZE; i++)
|
||||
furi_string_cat_printf(str, "%02X ", nfc->felica_auth->card_key.data[i]);
|
||||
furi_string_cat_printf(str, "?");
|
||||
|
||||
nfc_text_store_set(nfc, furi_string_get_cstr(str));
|
||||
furi_string_free(str);
|
||||
|
||||
dialog_ex_set_text(dialog_ex, nfc->text_store, 0, 12, AlignLeft, AlignTop);
|
||||
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Cancel");
|
||||
dialog_ex_set_right_button_text(dialog_ex, "Unlock");
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
||||
}
|
||||
|
||||
bool nfc_scene_felica_unlock_warn_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcApp* nfc = context;
|
||||
UNUSED(event);
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == DialogExResultRight) {
|
||||
nfc->felica_auth->skip_auth = false;
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
|
||||
consumed = true;
|
||||
} else if(event.event == DialogExResultLeft) {
|
||||
scene_manager_previous_scene(nfc->scene_manager);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_felica_unlock_warn_on_exit(void* context) {
|
||||
NfcApp* nfc = context;
|
||||
|
||||
dialog_ex_reset(nfc->dialog_ex);
|
||||
nfc_text_store_clear(nfc);
|
||||
}
|
||||
@@ -32,10 +32,12 @@ static void desktop_loader_callback(const void* message, void* context) {
|
||||
Desktop* desktop = context;
|
||||
const LoaderEvent* event = message;
|
||||
|
||||
if(event->type == LoaderEventTypeApplicationStarted) {
|
||||
if(event->type == LoaderEventTypeApplicationBeforeLoad) {
|
||||
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalBeforeAppStarted);
|
||||
furi_check(furi_semaphore_acquire(desktop->animation_semaphore, 3000) == FuriStatusOk);
|
||||
} else if(event->type == LoaderEventTypeApplicationStopped) {
|
||||
} else if(
|
||||
event->type == LoaderEventTypeApplicationLoadFailed ||
|
||||
event->type == LoaderEventTypeApplicationStopped) {
|
||||
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAfterAppFinished);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,23 +62,18 @@ static void
|
||||
#endif
|
||||
|
||||
static void desktop_scene_main_open_app_or_profile(Desktop* desktop, FavoriteApp* application) {
|
||||
bool load_ok = false;
|
||||
if(strlen(application->name_or_path) > 0) {
|
||||
if(loader_start(desktop->loader, application->name_or_path, NULL, NULL) ==
|
||||
LoaderStatusOk) {
|
||||
load_ok = true;
|
||||
}
|
||||
}
|
||||
if(!load_ok) {
|
||||
loader_start(desktop->loader, "Passport", NULL, NULL);
|
||||
loader_start_detached_with_gui_error(desktop->loader, application->name_or_path, NULL);
|
||||
} else {
|
||||
loader_start_detached_with_gui_error(desktop->loader, "Passport", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void desktop_scene_main_start_favorite(Desktop* desktop, FavoriteApp* application) {
|
||||
if(strlen(application->name_or_path) > 0) {
|
||||
loader_start_with_gui_error(desktop->loader, application->name_or_path, NULL);
|
||||
loader_start_detached_with_gui_error(desktop->loader, application->name_or_path, NULL);
|
||||
} else {
|
||||
loader_start(desktop->loader, LOADER_APPLICATIONS_NAME, NULL, NULL);
|
||||
loader_start_detached_with_gui_error(desktop->loader, LOADER_APPLICATIONS_NAME, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +136,7 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
|
||||
break;
|
||||
|
||||
case DesktopMainEventOpenPowerOff: {
|
||||
loader_start(desktop->loader, "Power", "off", NULL);
|
||||
loader_start_detached_with_gui_error(desktop->loader, "Power", "off");
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -47,13 +47,8 @@ LoaderStatus
|
||||
return result.value;
|
||||
}
|
||||
|
||||
LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const char* args) {
|
||||
furi_check(loader);
|
||||
furi_check(name);
|
||||
|
||||
FuriString* error_message = furi_string_alloc();
|
||||
LoaderStatus status = loader_start(loader, name, args, error_message);
|
||||
|
||||
static void
|
||||
loader_show_gui_error(LoaderStatus status, const char* name, FuriString* error_message) {
|
||||
if(status == LoaderStatusErrorUnknownApp &&
|
||||
loader_find_external_application_by_name(name) != NULL) {
|
||||
// Special case for external apps
|
||||
@@ -86,11 +81,31 @@ LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const
|
||||
dialog_message_free(message);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
}
|
||||
}
|
||||
|
||||
LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const char* args) {
|
||||
furi_check(loader);
|
||||
furi_check(name);
|
||||
|
||||
FuriString* error_message = furi_string_alloc();
|
||||
LoaderStatus status = loader_start(loader, name, args, error_message);
|
||||
loader_show_gui_error(status, name, error_message);
|
||||
furi_string_free(error_message);
|
||||
return status;
|
||||
}
|
||||
|
||||
void loader_start_detached_with_gui_error(Loader* loader, const char* name, const char* args) {
|
||||
furi_check(loader);
|
||||
furi_check(name);
|
||||
|
||||
LoaderMessage message = {
|
||||
.type = LoaderMessageTypeStartByNameDetachedWithGuiError,
|
||||
.start.name = strdup(name),
|
||||
.start.args = args ? strdup(args) : NULL,
|
||||
};
|
||||
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
|
||||
}
|
||||
|
||||
bool loader_lock(Loader* loader) {
|
||||
furi_check(loader);
|
||||
|
||||
@@ -166,11 +181,7 @@ static void loader_thread_state_callback(FuriThreadState thread_state, void* con
|
||||
|
||||
Loader* loader = context;
|
||||
|
||||
if(thread_state == FuriThreadStateRunning) {
|
||||
LoaderEvent event;
|
||||
event.type = LoaderEventTypeApplicationStarted;
|
||||
furi_pubsub_publish(loader->pubsub, &event);
|
||||
} else if(thread_state == FuriThreadStateStopped) {
|
||||
if(thread_state == FuriThreadStateStopped) {
|
||||
LoaderMessage message;
|
||||
message.type = LoaderMessageTypeAppClosed;
|
||||
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
|
||||
@@ -255,6 +266,9 @@ static void loader_start_internal_app(
|
||||
const FlipperInternalApplication* app,
|
||||
const char* args) {
|
||||
FURI_LOG_I(TAG, "Starting %s", app->name);
|
||||
LoaderEvent event;
|
||||
event.type = LoaderEventTypeApplicationBeforeLoad;
|
||||
furi_pubsub_publish(loader->pubsub, &event);
|
||||
|
||||
// store args
|
||||
furi_assert(loader->app.args == NULL);
|
||||
@@ -309,6 +323,9 @@ static LoaderStatus loader_start_external_app(
|
||||
const char* args,
|
||||
FuriString* error_message) {
|
||||
LoaderStatus status = loader_make_success_status(error_message);
|
||||
LoaderEvent event;
|
||||
event.type = LoaderEventTypeApplicationBeforeLoad;
|
||||
furi_pubsub_publish(loader->pubsub, &event);
|
||||
|
||||
do {
|
||||
loader->app.fap = flipper_application_alloc(storage, firmware_api_interface);
|
||||
@@ -356,6 +373,8 @@ static LoaderStatus loader_start_external_app(
|
||||
if(status != LoaderStatusOk) {
|
||||
flipper_application_free(loader->app.fap);
|
||||
loader->app.fap = NULL;
|
||||
event.type = LoaderEventTypeApplicationLoadFailed;
|
||||
furi_pubsub_publish(loader->pubsub, &event);
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -528,6 +547,16 @@ int32_t loader_srv(void* p) {
|
||||
loader, message.start.name, message.start.args, message.start.error_message);
|
||||
api_lock_unlock(message.api_lock);
|
||||
break;
|
||||
case LoaderMessageTypeStartByNameDetachedWithGuiError: {
|
||||
FuriString* error_message = furi_string_alloc();
|
||||
LoaderStatus status = loader_do_start_by_name(
|
||||
loader, message.start.name, message.start.args, error_message);
|
||||
loader_show_gui_error(status, message.start.name, error_message);
|
||||
if(message.start.name) free((void*)message.start.name);
|
||||
if(message.start.args) free((void*)message.start.args);
|
||||
furi_string_free(error_message);
|
||||
break;
|
||||
}
|
||||
case LoaderMessageTypeShowMenu:
|
||||
loader_do_menu_show(loader);
|
||||
break;
|
||||
|
||||
@@ -18,7 +18,8 @@ typedef enum {
|
||||
} LoaderStatus;
|
||||
|
||||
typedef enum {
|
||||
LoaderEventTypeApplicationStarted,
|
||||
LoaderEventTypeApplicationBeforeLoad,
|
||||
LoaderEventTypeApplicationLoadFailed,
|
||||
LoaderEventTypeApplicationStopped
|
||||
} LoaderEventType;
|
||||
|
||||
@@ -32,7 +33,7 @@ typedef struct {
|
||||
* @param[in] name application name or id
|
||||
* @param[in] args application arguments
|
||||
* @param[out] error_message detailed error message, can be NULL
|
||||
* @return LoaderStatus
|
||||
* @return LoaderStatus
|
||||
*/
|
||||
LoaderStatus
|
||||
loader_start(Loader* instance, const char* name, const char* args, FuriString* error_message);
|
||||
@@ -42,11 +43,19 @@ LoaderStatus
|
||||
* @param[in] instance loader instance
|
||||
* @param[in] name application name or id
|
||||
* @param[in] args application arguments
|
||||
* @return LoaderStatus
|
||||
* @return LoaderStatus
|
||||
*/
|
||||
LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const char* args);
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Start application detached with GUI error message
|
||||
* @param[in] instance loader instance
|
||||
* @param[in] name application name or id
|
||||
* @param[in] args application arguments
|
||||
*/
|
||||
void loader_start_detached_with_gui_error(Loader* loader, const char* name, const char* args);
|
||||
|
||||
/**
|
||||
* @brief Lock application start
|
||||
* @param[in] instance loader instance
|
||||
* @return true on success
|
||||
|
||||
@@ -30,6 +30,7 @@ typedef enum {
|
||||
LoaderMessageTypeLock,
|
||||
LoaderMessageTypeUnlock,
|
||||
LoaderMessageTypeIsLocked,
|
||||
LoaderMessageTypeStartByNameDetachedWithGuiError,
|
||||
} LoaderMessageType;
|
||||
|
||||
typedef struct {
|
||||
|
||||
Reference in New Issue
Block a user