mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-10 06:54:19 +00:00
Merge remote-tracking branch 'origin/dev' into electra
This commit is contained in:
commit
d73832a5dd
30 changed files with 164 additions and 1428 deletions
25
CHANGELOG.md
25
CHANGELOG.md
|
@ -1,19 +1,37 @@
|
|||
## New changes
|
||||
* NFC: Temp fix for `iso14443_4_layer_decode_block` crash
|
||||
* NFC: CharlieCard parser (by @zacharyweiss)
|
||||
* SubGHz: FAAC RC XT - add 0xB button code on arrow buttons for programming mode
|
||||
* SubGHz: Add Manually - Sommer FM fixes
|
||||
* SubGHz: Enabled tx-rx state on unused gpio pin by default (**external amp option was removed and is enabled by default now**)
|
||||
* SubGHz: **Status output !TX/RX on the GDO2 CC1101 pin** (by @quen0n | PR #742)
|
||||
* SubGHz: Reworked saved settings (by @xMasterX and @Willy-JL)
|
||||
* Desktop: Fixes for animation unload (by @Willy-JL)
|
||||
* iButton: Updated DS1420 for latest ibutton changes
|
||||
* Misc: Allow no prefix usage of name_generator_make_detailed_datetime
|
||||
* Misc: Allow setting view dispatcher callbacks to NULL
|
||||
* Misc: Added `void` due to `-Wstrict-prototypes`
|
||||
* Misc: Some code cleanup and proper log levels in nfc parsers
|
||||
* Infrared: Allow external apps to use infrared settings (by @Willy-JL)
|
||||
* JS & HAL: Various fixes and FURI_HAL_RANDOM_MAX define added (by @Willy-JL)
|
||||
* JS: **BadUSB layout support** (by @Willy-JL)
|
||||
* JS: Module `widget` and path globals (by @jamisonderek)
|
||||
* JS: New Modules `widget`, `vgm` and path globals (by @jamisonderek)
|
||||
* Apps: NFC Magic - **Gen2 writing support, Gen4 NTAG password and PACK fixes** (by @Astrrra)
|
||||
* Apps: MFKey - **fixed crashes** (by @noproto)
|
||||
* Apps: MFKey - **fixed crashes**, add more free ram (by @noproto & @Willy-JL)
|
||||
* Apps: **Check out Apps updates by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev)
|
||||
* OFW PR 3616: NFC: Mf Desfire fix reading big files (by gornekich)
|
||||
* OFW: iButton: fix crash when deleting some keys
|
||||
* OFW: Desktop: cleanup error popups
|
||||
* OFW: Troika parser visual fixes
|
||||
* OFW: Fix the retry/exit confirmation prompts in iButton
|
||||
* OFW: nfc app: add legacy keys for plantain cards
|
||||
* OFW: GUI: Fix array out of bounds in menu exit
|
||||
* OFW: add support for S(WTX) request in iso14443_4a_poller
|
||||
* OFW: Mosgortrans parser output fixes
|
||||
* OFW: BLE: Add GapPairingNone support
|
||||
* OFW: iButton new UI
|
||||
* OFW: FuriHal: add ADC API
|
||||
* OFW: Mf Desfire multiple file rights support
|
||||
* OFW: **Felica poller** (NFC-F)
|
||||
* OFW: Desktop/Loader: Unload animations before loading FAPs
|
||||
* OFW: JS Documentation
|
||||
|
@ -49,8 +67,7 @@
|
|||
#### Known NFC post-refactor regressions list:
|
||||
- Mifare Mini clones reading is broken (original mini working fine) (OFW)
|
||||
- NFC CLI was removed with refactoring (OFW) (will be back soon)
|
||||
- Current list of affected apps: https://github.com/xMasterX/all-the-plugins/tree/dev/apps_broken_by_last_refactors
|
||||
- Also in app **Enhanced Sub-GHz Chat** - NFC part was temporarily removed to make app usable, NFC part of the app requires remaking it with new nfc stack
|
||||
- Mifare Nested not ported to latest API yet, `unlshd-065` is the latest version on old NFC API that works with "nested app"
|
||||
|
||||
----
|
||||
|
||||
|
|
|
@ -17,14 +17,21 @@ void ibutton_scene_delete_confirm_on_enter(void* context) {
|
|||
|
||||
ibutton_protocols_render_uid(ibutton->protocols, key, uid);
|
||||
|
||||
furi_string_cat_printf(
|
||||
uid,
|
||||
"\n%s %s",
|
||||
ibutton_protocols_get_manufacturer(ibutton->protocols, ibutton_key_get_protocol_id(key)),
|
||||
ibutton_protocols_get_name(ibutton->protocols, ibutton_key_get_protocol_id(key)));
|
||||
|
||||
furi_string_cat(tmp, uid);
|
||||
|
||||
furi_string_push_back(tmp, '\n');
|
||||
|
||||
const char* protocol =
|
||||
ibutton_protocols_get_name(ibutton->protocols, ibutton_key_get_protocol_id(key));
|
||||
const char* manufacturer =
|
||||
ibutton_protocols_get_manufacturer(ibutton->protocols, ibutton_key_get_protocol_id(key));
|
||||
|
||||
if(strcasecmp(protocol, manufacturer) != 0 && strcasecmp(manufacturer, "N/A") != 0) {
|
||||
furi_string_cat_printf(tmp, "%s ", manufacturer);
|
||||
}
|
||||
|
||||
furi_string_cat(tmp, protocol);
|
||||
|
||||
widget_add_text_box_element(
|
||||
widget, 0, 0, 128, 64, AlignCenter, AlignTop, furi_string_get_cstr(tmp), false);
|
||||
|
||||
|
|
|
@ -21,17 +21,14 @@ void ibutton_scene_emulate_on_enter(void* context) {
|
|||
|
||||
widget_add_icon_element(widget, 3, 10, &I_iButtonKey_49x44);
|
||||
|
||||
if(furi_string_empty(ibutton->file_path)) {
|
||||
furi_string_printf(
|
||||
tmp,
|
||||
"Unsaved\n%s",
|
||||
ibutton_protocols_get_name(ibutton->protocols, ibutton_key_get_protocol_id(key)));
|
||||
} else {
|
||||
furi_string_printf(tmp, "%s", ibutton->key_name);
|
||||
}
|
||||
furi_string_printf(
|
||||
tmp,
|
||||
"[%s]\n%s",
|
||||
ibutton_protocols_get_name(ibutton->protocols, ibutton_key_get_protocol_id(key)),
|
||||
furi_string_empty(ibutton->file_path) ? "Unsaved Key" : ibutton->key_name);
|
||||
|
||||
widget_add_text_box_element(
|
||||
widget, 52, 23, 75, 26, AlignCenter, AlignTop, furi_string_get_cstr(tmp), false);
|
||||
widget, 52, 24, 75, 40, AlignCenter, AlignTop, furi_string_get_cstr(tmp), true);
|
||||
|
||||
widget_add_string_multiline_element(
|
||||
widget, 88, 10, AlignCenter, AlignTop, FontPrimary, "Emulating");
|
||||
|
|
|
@ -10,12 +10,23 @@ void ibutton_scene_info_on_enter(void* context) {
|
|||
FuriString* tmp = furi_string_alloc();
|
||||
FuriString* brief_data = furi_string_alloc();
|
||||
|
||||
furi_string_printf(
|
||||
tmp,
|
||||
"Name:%s\n\e#%s %s\e#\n",
|
||||
ibutton->key_name,
|
||||
ibutton_protocols_get_manufacturer(ibutton->protocols, protocol_id),
|
||||
ibutton_protocols_get_name(ibutton->protocols, protocol_id));
|
||||
if((strcmp(
|
||||
ibutton_protocols_get_manufacturer(ibutton->protocols, protocol_id),
|
||||
ibutton_protocols_get_name(ibutton->protocols, protocol_id)) != 0) &&
|
||||
(strcmp(ibutton_protocols_get_manufacturer(ibutton->protocols, protocol_id), "N/A") != 0)) {
|
||||
furi_string_printf(
|
||||
tmp,
|
||||
"Name:%s\n\e#%s %s\e#\n",
|
||||
ibutton->key_name,
|
||||
ibutton_protocols_get_manufacturer(ibutton->protocols, protocol_id),
|
||||
ibutton_protocols_get_name(ibutton->protocols, protocol_id));
|
||||
} else {
|
||||
furi_string_printf(
|
||||
tmp,
|
||||
"Name:%s\n\e#%s\e#\n",
|
||||
ibutton->key_name,
|
||||
ibutton_protocols_get_name(ibutton->protocols, protocol_id));
|
||||
}
|
||||
|
||||
ibutton_protocols_render_brief_data(ibutton->protocols, key, brief_data);
|
||||
|
||||
|
|
|
@ -40,15 +40,14 @@ void ibutton_scene_write_on_enter(void* context) {
|
|||
|
||||
widget_add_icon_element(widget, 3, 10, &I_iButtonKey_49x44);
|
||||
|
||||
if(furi_string_empty(ibutton->file_path)) {
|
||||
furi_string_printf(
|
||||
tmp, "Unsaved\n%s", ibutton_protocols_get_name(ibutton->protocols, protocol_id));
|
||||
} else {
|
||||
furi_string_printf(tmp, "%s", ibutton->key_name);
|
||||
}
|
||||
furi_string_printf(
|
||||
tmp,
|
||||
"[%s]\n%s",
|
||||
ibutton_protocols_get_name(ibutton->protocols, protocol_id),
|
||||
furi_string_empty(ibutton->file_path) ? "Unsaved Key" : ibutton->key_name);
|
||||
|
||||
widget_add_text_box_element(
|
||||
widget, 52, 23, 75, 26, AlignCenter, AlignTop, furi_string_get_cstr(tmp), false);
|
||||
widget, 52, 24, 75, 40, AlignCenter, AlignTop, furi_string_get_cstr(tmp), true);
|
||||
|
||||
ibutton_worker_write_set_callback(worker, ibutton_scene_write_callback, ibutton);
|
||||
|
||||
|
|
|
@ -6,16 +6,15 @@ void lfrfid_scene_emulate_on_enter(void* context) {
|
|||
|
||||
FuriString* display_text = furi_string_alloc_set("\e#Emulating\e#\n");
|
||||
|
||||
if(furi_string_empty(app->file_name)) {
|
||||
furi_string_cat(display_text, "Unsaved\n");
|
||||
furi_string_cat(display_text, protocol_dict_get_name(app->dict, app->protocol_id));
|
||||
} else {
|
||||
furi_string_cat(display_text, app->file_name);
|
||||
}
|
||||
furi_string_cat_printf(
|
||||
display_text,
|
||||
"[%s]\n%s",
|
||||
protocol_dict_get_name(app->dict, app->protocol_id),
|
||||
furi_string_empty(app->file_name) ? "Unsaved Tag" : furi_string_get_cstr(app->file_name));
|
||||
|
||||
widget_add_icon_element(widget, 0, 0, &I_NFC_dolphin_emulation_51x64);
|
||||
widget_add_text_box_element(
|
||||
widget, 55, 16, 67, 48, AlignCenter, AlignTop, furi_string_get_cstr(display_text), true);
|
||||
widget, 51, 6, 79, 50, AlignCenter, AlignTop, furi_string_get_cstr(display_text), false);
|
||||
|
||||
furi_string_free(display_text);
|
||||
|
||||
|
|
|
@ -25,12 +25,18 @@ void lfrfid_scene_write_on_enter(void* context) {
|
|||
popup_set_header(popup, "Writing", 94, 16, AlignCenter, AlignTop);
|
||||
|
||||
if(!furi_string_empty(app->file_name)) {
|
||||
popup_set_text(popup, furi_string_get_cstr(app->file_name), 94, 29, AlignCenter, AlignTop);
|
||||
snprintf(
|
||||
app->text_store,
|
||||
LFRFID_TEXT_STORE_SIZE,
|
||||
"[%s]\n%s",
|
||||
protocol_dict_get_name(app->dict, app->protocol_id),
|
||||
furi_string_get_cstr(app->file_name));
|
||||
popup_set_text(popup, app->text_store, 94, 29, AlignCenter, AlignTop);
|
||||
} else {
|
||||
snprintf(
|
||||
app->text_store,
|
||||
LFRFID_TEXT_STORE_SIZE,
|
||||
"Unsaved\n%s",
|
||||
"[%s]\nUnsaved Tag",
|
||||
protocol_dict_get_name(app->dict, app->protocol_id));
|
||||
popup_set_text(popup, app->text_store, 94, 29, AlignCenter, AlignTop);
|
||||
}
|
||||
|
|
|
@ -22,8 +22,14 @@ void lfrfid_scene_write_and_set_pass_on_enter(void* context) {
|
|||
LfRfid* app = context;
|
||||
Popup* popup = app->popup;
|
||||
|
||||
popup_set_header(popup, "Writing\nwith password", 89, 30, AlignCenter, AlignTop);
|
||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
|
||||
popup_set_header(popup, "Writing\nwith\npassword", 94, 8, AlignCenter, AlignTop);
|
||||
popup_set_icon(popup, 0, 8, &I_NFC_manual_60x50);
|
||||
snprintf(
|
||||
app->text_store,
|
||||
LFRFID_TEXT_STORE_SIZE,
|
||||
"[%s]",
|
||||
protocol_dict_get_name(app->dict, app->protocol_id));
|
||||
popup_set_text(popup, app->text_store, 94, 45, AlignCenter, AlignTop);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
|
||||
|
||||
|
|
|
@ -1,121 +0,0 @@
|
|||
#include "mf_plus.h"
|
||||
#include "mf_plus_render.h"
|
||||
|
||||
#include <nfc/protocols/mf_plus/mf_plus_poller.h>
|
||||
|
||||
#include "nfc/nfc_app_i.h"
|
||||
|
||||
#include "../nfc_protocol_support_common.h"
|
||||
#include "../nfc_protocol_support_gui_common.h"
|
||||
#include "../iso14443_4a/iso14443_4a_i.h"
|
||||
|
||||
static void nfc_scene_info_on_enter_mf_plus(NfcApp* instance) {
|
||||
const NfcDevice* device = instance->nfc_device;
|
||||
const MfPlusData* data = nfc_device_get_data(device, NfcProtocolMfPlus);
|
||||
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
nfc_append_filename_string_when_present(instance, temp_str);
|
||||
furi_string_cat_printf(
|
||||
temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
|
||||
furi_string_replace(temp_str, "Mifare", "MIFARE");
|
||||
nfc_render_mf_plus_info(data, NfcProtocolFormatTypeFull, temp_str);
|
||||
|
||||
widget_add_text_scroll_element(
|
||||
instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str));
|
||||
|
||||
furi_string_free(temp_str);
|
||||
}
|
||||
static NfcCommand nfc_scene_read_poller_callback_mf_plus(NfcGenericEvent event, void* context) {
|
||||
furi_assert(event.protocol == NfcProtocolMfPlus);
|
||||
|
||||
NfcApp* instance = context;
|
||||
const MfPlusPollerEvent* mf_plus_event = event.event_data;
|
||||
|
||||
if(mf_plus_event->type == MfPlusPollerEventTypeReadSuccess) {
|
||||
nfc_device_set_data(
|
||||
instance->nfc_device, NfcProtocolMfPlus, nfc_poller_get_data(instance->poller));
|
||||
FURI_LOG_D(
|
||||
"MFP",
|
||||
"Read success: %s",
|
||||
nfc_device_get_name(instance->nfc_device, NfcDeviceNameTypeFull));
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess);
|
||||
return NfcCommandStop;
|
||||
}
|
||||
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
||||
static void nfc_scene_read_on_enter_mf_plus(NfcApp* instance) {
|
||||
nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_mf_plus, instance);
|
||||
}
|
||||
|
||||
static void nfc_scene_read_success_on_enter_mf_plus(NfcApp* instance) {
|
||||
const NfcDevice* device = instance->nfc_device;
|
||||
const MfPlusData* data = nfc_device_get_data(device, NfcProtocolMfPlus);
|
||||
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
furi_string_cat_printf(
|
||||
temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
|
||||
furi_string_replace(temp_str, "Mifare", "MIFARE");
|
||||
nfc_render_mf_plus_info(data, NfcProtocolFormatTypeShort, temp_str);
|
||||
|
||||
widget_add_text_scroll_element(
|
||||
instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str));
|
||||
|
||||
furi_string_free(temp_str);
|
||||
}
|
||||
|
||||
static void nfc_scene_emulate_on_enter_mf_plus(NfcApp* instance) {
|
||||
const Iso14443_4aData* iso14443_4a_data =
|
||||
nfc_device_get_data(instance->nfc_device, NfcProtocolIso14443_4a);
|
||||
|
||||
instance->listener =
|
||||
nfc_listener_alloc(instance->nfc, NfcProtocolIso14443_4a, iso14443_4a_data);
|
||||
nfc_listener_start(
|
||||
instance->listener, nfc_scene_emulate_listener_callback_iso14443_4a, instance);
|
||||
}
|
||||
|
||||
const NfcProtocolSupportBase nfc_protocol_support_mf_plus = {
|
||||
.features = NfcProtocolFeatureMoreInfo,
|
||||
|
||||
.scene_info =
|
||||
{
|
||||
.on_enter = nfc_scene_info_on_enter_mf_plus,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_more_info =
|
||||
{
|
||||
.on_enter = nfc_protocol_support_common_on_enter_empty,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_read =
|
||||
{
|
||||
.on_enter = nfc_scene_read_on_enter_mf_plus,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_read_menu =
|
||||
{
|
||||
.on_enter = nfc_protocol_support_common_on_enter_empty,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_read_success =
|
||||
{
|
||||
.on_enter = nfc_scene_read_success_on_enter_mf_plus,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_saved_menu =
|
||||
{
|
||||
.on_enter = nfc_protocol_support_common_on_enter_empty,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_save_name =
|
||||
{
|
||||
.on_enter = nfc_protocol_support_common_on_enter_empty,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_emulate =
|
||||
{
|
||||
.on_enter = nfc_scene_emulate_on_enter_mf_plus,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
};
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "../nfc_protocol_support_base.h"
|
||||
|
||||
extern const NfcProtocolSupportBase nfc_protocol_support_mf_plus;
|
|
@ -1,67 +0,0 @@
|
|||
#include "mf_plus_render.h"
|
||||
|
||||
#include "../iso14443_4a/iso14443_4a_render.h"
|
||||
|
||||
void nfc_render_mf_plus_info(
|
||||
const MfPlusData* data,
|
||||
NfcProtocolFormatType format_type,
|
||||
FuriString* str) {
|
||||
nfc_render_iso14443_4a_brief(mf_plus_get_base_data(data), str);
|
||||
|
||||
if(format_type != NfcProtocolFormatTypeFull) return;
|
||||
|
||||
furi_string_cat(str, "\n\e#ISO14443-4 data");
|
||||
nfc_render_iso14443_4a_extra(mf_plus_get_base_data(data), str);
|
||||
}
|
||||
|
||||
void nfc_render_mf_plus_data(const MfPlusData* data, FuriString* str) {
|
||||
nfc_render_mf_plus_version(&data->version, str);
|
||||
}
|
||||
|
||||
void nfc_render_mf_plus_version(const MfPlusVersion* data, FuriString* str) {
|
||||
furi_string_cat_printf(
|
||||
str,
|
||||
"%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
data->uid[0],
|
||||
data->uid[1],
|
||||
data->uid[2],
|
||||
data->uid[3],
|
||||
data->uid[4],
|
||||
data->uid[5],
|
||||
data->uid[6]);
|
||||
furi_string_cat_printf(
|
||||
str,
|
||||
"hw %02x type %02x sub %02x\n"
|
||||
" maj %02x min %02x\n"
|
||||
" size %02x proto %02x\n",
|
||||
data->hw_vendor,
|
||||
data->hw_type,
|
||||
data->hw_subtype,
|
||||
data->hw_major,
|
||||
data->hw_minor,
|
||||
data->hw_storage,
|
||||
data->hw_proto);
|
||||
furi_string_cat_printf(
|
||||
str,
|
||||
"sw %02x type %02x sub %02x\n"
|
||||
" maj %02x min %02x\n"
|
||||
" size %02x proto %02x\n",
|
||||
data->sw_vendor,
|
||||
data->sw_type,
|
||||
data->sw_subtype,
|
||||
data->sw_major,
|
||||
data->sw_minor,
|
||||
data->sw_storage,
|
||||
data->sw_proto);
|
||||
furi_string_cat_printf(
|
||||
str,
|
||||
"batch %02x:%02x:%02x:%02x:%02x\n"
|
||||
"week %d year %d\n",
|
||||
data->batch[0],
|
||||
data->batch[1],
|
||||
data->batch[2],
|
||||
data->batch[3],
|
||||
data->batch[4],
|
||||
data->prod_week,
|
||||
data->prod_year);
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <nfc/protocols/mf_plus/mf_plus.h>
|
||||
|
||||
#include "../nfc_protocol_support_render_common.h"
|
||||
|
||||
void nfc_render_mf_plus_info(
|
||||
const MfPlusData* data,
|
||||
NfcProtocolFormatType format_type,
|
||||
FuriString* str);
|
||||
|
||||
void nfc_render_mf_plus_data(const MfPlusData* data, FuriString* str);
|
||||
|
||||
void nfc_render_mf_plus_version(const MfPlusVersion* data, FuriString* str);
|
|
@ -17,7 +17,6 @@
|
|||
#include "felica/felica.h"
|
||||
#include "mf_ultralight/mf_ultralight.h"
|
||||
#include "mf_classic/mf_classic.h"
|
||||
#include "mf_plus/mf_plus.h"
|
||||
#include "mf_desfire/mf_desfire.h"
|
||||
#include "emv/emv.h"
|
||||
#include "slix/slix.h"
|
||||
|
@ -40,7 +39,6 @@ const NfcProtocolSupportBase* nfc_protocol_support[NfcProtocolNum] = {
|
|||
[NfcProtocolFelica] = &nfc_protocol_support_felica,
|
||||
[NfcProtocolMfUltralight] = &nfc_protocol_support_mf_ultralight,
|
||||
[NfcProtocolMfClassic] = &nfc_protocol_support_mf_classic,
|
||||
[NfcProtocolMfPlus] = &nfc_protocol_support_mf_plus,
|
||||
[NfcProtocolMfDesfire] = &nfc_protocol_support_mf_desfire,
|
||||
[NfcProtocolSlix] = &nfc_protocol_support_slix,
|
||||
[NfcProtocolSt25tb] = &nfc_protocol_support_st25tb,
|
||||
|
|
|
@ -15,13 +15,11 @@ struct HidMouseJiggler {
|
|||
typedef struct {
|
||||
bool connected;
|
||||
bool running;
|
||||
int interval_idx;
|
||||
uint8_t counter;
|
||||
int min_interval; // Minimum interval for random range
|
||||
int max_interval; // Maximum interval for random range
|
||||
HidTransport transport;
|
||||
} HidMouseJigglerModel;
|
||||
|
||||
const int intervals[6] = {500, 2000, 5000, 10000, 30000, 60000};
|
||||
|
||||
static void hid_mouse_jiggler_draw_callback(Canvas* canvas, void* context) {
|
||||
furi_assert(context);
|
||||
HidMouseJigglerModel* model = context;
|
||||
|
@ -35,22 +33,26 @@ static void hid_mouse_jiggler_draw_callback(Canvas* canvas, void* context) {
|
|||
}
|
||||
}
|
||||
|
||||
// Title "Mouse Jiggler"
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_aligned(canvas, 17, 2, AlignLeft, AlignTop, "Mouse Jiggler");
|
||||
|
||||
// Timeout
|
||||
elements_multiline_text(canvas, AlignLeft, 26, "Interval (ms):");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
if(model->interval_idx != 0) canvas_draw_icon(canvas, 74, 19, &I_ButtonLeft_4x7);
|
||||
if(model->interval_idx != (int)COUNT_OF(intervals) - 1)
|
||||
canvas_draw_icon(canvas, 80, 19, &I_ButtonRight_4x7);
|
||||
FuriString* interval_str = furi_string_alloc_printf("%d", intervals[model->interval_idx]);
|
||||
elements_multiline_text(canvas, 91, 26, furi_string_get_cstr(interval_str));
|
||||
furi_string_free(interval_str);
|
||||
// Display the current min interval in minutes
|
||||
canvas_set_font(canvas, FontSecondary); // Assuming there's a smaller font available
|
||||
FuriString* min_interval_str = furi_string_alloc_printf("Min: %d min", model->min_interval);
|
||||
elements_multiline_text_aligned(
|
||||
canvas, 0, 16, AlignLeft, AlignTop, furi_string_get_cstr(min_interval_str));
|
||||
furi_string_free(min_interval_str);
|
||||
|
||||
// Display the current max interval in minutes
|
||||
FuriString* max_interval_str = furi_string_alloc_printf("Max: %d min", model->max_interval);
|
||||
elements_multiline_text_aligned(
|
||||
canvas, 0, 28, AlignLeft, AlignTop, furi_string_get_cstr(max_interval_str));
|
||||
furi_string_free(max_interval_str);
|
||||
|
||||
// "Press Start to jiggle"
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text(canvas, AlignLeft, 40, "Press Start\nto jiggle");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_multiline_text(canvas, AlignLeft, 50, "Press Start\nto jiggle");
|
||||
|
||||
// Ok
|
||||
canvas_draw_icon(canvas, 63, 30, &I_Space_65x18);
|
||||
|
@ -79,11 +81,20 @@ static void hid_mouse_jiggler_timer_callback(void* context) {
|
|||
HidMouseJigglerModel * model,
|
||||
{
|
||||
if(model->running) {
|
||||
model->counter++;
|
||||
hid_hal_mouse_move(
|
||||
hid_mouse_jiggler->hid,
|
||||
(model->counter % 2 == 0) ? MOUSE_MOVE_SHORT : -MOUSE_MOVE_SHORT,
|
||||
0);
|
||||
// Generate a random interval in minutes and convert to milliseconds
|
||||
int randomIntervalMinutes =
|
||||
model->min_interval + rand() % (model->max_interval - model->min_interval + 1);
|
||||
|
||||
// Randomize the mouse movement distance and direction
|
||||
int move_x = (rand() % 2001) - 1000; // Randomly between -1000 and 1000
|
||||
int move_y = (rand() % 2001) - 1000; // Randomly between -1000 and 1000
|
||||
|
||||
// Perform the mouse move with the randomized values
|
||||
hid_hal_mouse_move(hid_mouse_jiggler->hid, move_x, move_y);
|
||||
|
||||
// Restart timer with the new random interval
|
||||
furi_timer_stop(hid_mouse_jiggler->timer);
|
||||
furi_timer_start(hid_mouse_jiggler->timer, randomIntervalMinutes * 60000);
|
||||
}
|
||||
},
|
||||
false);
|
||||
|
@ -105,23 +116,51 @@ static bool hid_mouse_jiggler_input_callback(InputEvent* event, void* context) {
|
|||
hid_mouse_jiggler->view,
|
||||
HidMouseJigglerModel * model,
|
||||
{
|
||||
if(event->type == InputTypePress && event->key == InputKeyOk) {
|
||||
model->running = !model->running;
|
||||
if(model->running) {
|
||||
furi_timer_stop(hid_mouse_jiggler->timer);
|
||||
furi_timer_start(hid_mouse_jiggler->timer, intervals[model->interval_idx]);
|
||||
};
|
||||
consumed = true;
|
||||
}
|
||||
if(event->type == InputTypePress && event->key == InputKeyRight && !model->running &&
|
||||
model->interval_idx < (int)COUNT_OF(intervals) - 1) {
|
||||
model->interval_idx++;
|
||||
consumed = true;
|
||||
}
|
||||
if(event->type == InputTypePress && event->key == InputKeyLeft && !model->running &&
|
||||
model->interval_idx > 0) {
|
||||
model->interval_idx--;
|
||||
consumed = true;
|
||||
if(event->type == InputTypePress) {
|
||||
switch(event->key) {
|
||||
case InputKeyOk:
|
||||
model->running = !model->running;
|
||||
if(model->running) {
|
||||
furi_timer_stop(hid_mouse_jiggler->timer);
|
||||
int randomIntervalMinutes =
|
||||
model->min_interval +
|
||||
rand() % (model->max_interval - model->min_interval + 1);
|
||||
furi_timer_start(hid_mouse_jiggler->timer, randomIntervalMinutes * 60000);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
case InputKeyUp:
|
||||
if(!model->running && model->min_interval < model->max_interval) {
|
||||
model->min_interval++; // Increment min interval by 1 minute
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
case InputKeyDown:
|
||||
if(!model->running && model->min_interval > 1) { // Minimum 1 minute
|
||||
model->min_interval--; // Decrement min interval by 1 minute
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
case InputKeyRight:
|
||||
if(!model->running && model->max_interval < 30) { // Maximum 30 minutes
|
||||
model->max_interval++; // Increment max interval by 1 minute
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
case InputKeyLeft:
|
||||
if(!model->running && model->max_interval > model->min_interval + 1) {
|
||||
model->max_interval--; // Decrement max interval by 1 minute
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
true);
|
||||
|
@ -149,8 +188,9 @@ HidMouseJiggler* hid_mouse_jiggler_alloc(Hid* hid) {
|
|||
hid_mouse_jiggler->view,
|
||||
HidMouseJigglerModel * model,
|
||||
{
|
||||
model->transport = hid->transport;
|
||||
model->interval_idx = 2;
|
||||
// Initialize the min and max interval values
|
||||
model->min_interval = 2; // 2 minutes
|
||||
model->max_interval = 15; // 15 minutes
|
||||
},
|
||||
true);
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
#include <gui/view.h>
|
||||
|
||||
#define MOUSE_MOVE_SHORT 5
|
||||
|
||||
typedef struct Hid Hid;
|
||||
typedef struct HidMouseJiggler HidMouseJiggler;
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ env.Append(
|
|||
File("protocols/iso14443_4b/iso14443_4b.h"),
|
||||
File("protocols/mf_ultralight/mf_ultralight.h"),
|
||||
File("protocols/mf_classic/mf_classic.h"),
|
||||
File("protocols/mf_plus/mf_plus.h"),
|
||||
File("protocols/mf_desfire/mf_desfire.h"),
|
||||
File("protocols/emv/emv.h"),
|
||||
File("protocols/slix/slix.h"),
|
||||
|
@ -34,7 +33,6 @@ env.Append(
|
|||
File("protocols/iso14443_4b/iso14443_4b_poller.h"),
|
||||
File("protocols/mf_ultralight/mf_ultralight_poller.h"),
|
||||
File("protocols/mf_classic/mf_classic_poller.h"),
|
||||
File("protocols/mf_plus/mf_plus_poller.h"),
|
||||
File("protocols/mf_desfire/mf_desfire_poller.h"),
|
||||
File("protocols/emv/emv_poller.h"),
|
||||
File("protocols/st25tb/st25tb_poller.h"),
|
||||
|
|
|
@ -1,189 +0,0 @@
|
|||
#include "mf_plus_i.h"
|
||||
|
||||
#include <bit_lib/bit_lib.h>
|
||||
#include <furi.h>
|
||||
|
||||
#define MF_PLUS_PROTOCOL_NAME "Mifare Plus"
|
||||
|
||||
static const char* mf_plus_type_strings[] = {
|
||||
[MfPlusTypeS] = "Plus S",
|
||||
[MfPlusTypeX] = "Plus X",
|
||||
[MfPlusTypeSE] = "Plus SE",
|
||||
[MfPlusTypeEV1] = "Plus EV1",
|
||||
[MfPlusTypeEV2] = "Plus EV2",
|
||||
[MfPlusTypePlus] = "Plus",
|
||||
[MfPlusTypeUnknown] = "Unknown",
|
||||
};
|
||||
|
||||
static const char* mf_plus_size_strings[] = {
|
||||
[MfPlusSize1K] = "1K",
|
||||
[MfPlusSize2K] = "2K",
|
||||
[MfPlusSize4K] = "4K",
|
||||
[MfPlusSizeUnknown] = "Unknown",
|
||||
};
|
||||
|
||||
static const char* mf_plus_security_level_strings[] = {
|
||||
[MfPlusSecurityLevel0] = "SL0",
|
||||
[MfPlusSecurityLevel1] = "SL1",
|
||||
[MfPlusSecurityLevel2] = "SL2",
|
||||
[MfPlusSecurityLevel3] = "SL3",
|
||||
[MfPlusSecurityLevelUnknown] = "Unknown",
|
||||
};
|
||||
|
||||
const NfcDeviceBase nfc_device_mf_plus = {
|
||||
.protocol_name = MF_PLUS_PROTOCOL_NAME,
|
||||
.alloc = (NfcDeviceAlloc)mf_plus_alloc,
|
||||
.free = (NfcDeviceFree)mf_plus_free,
|
||||
.reset = (NfcDeviceReset)mf_plus_reset,
|
||||
.copy = (NfcDeviceCopy)mf_plus_copy,
|
||||
.verify = (NfcDeviceVerify)mf_plus_verify,
|
||||
.load = (NfcDeviceLoad)mf_plus_load,
|
||||
.save = (NfcDeviceSave)mf_plus_save,
|
||||
.is_equal = (NfcDeviceEqual)mf_plus_is_equal,
|
||||
.get_name = (NfcDeviceGetName)mf_plus_get_device_name,
|
||||
.get_uid = (NfcDeviceGetUid)mf_plus_get_uid,
|
||||
.set_uid = (NfcDeviceSetUid)mf_plus_set_uid,
|
||||
.get_base_data = (NfcDeviceGetBaseData)mf_plus_get_base_data,
|
||||
};
|
||||
|
||||
MfPlusData* mf_plus_alloc(void) {
|
||||
MfPlusData* data = malloc(sizeof(MfPlusData));
|
||||
data->device_name = furi_string_alloc();
|
||||
data->iso14443_4a_data = iso14443_4a_alloc();
|
||||
|
||||
data->type = MfPlusTypeUnknown;
|
||||
data->security_level = MfPlusSecurityLevelUnknown;
|
||||
data->size = MfPlusSizeUnknown;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void mf_plus_free(MfPlusData* data) {
|
||||
furi_check(data);
|
||||
furi_string_free(data->device_name);
|
||||
iso14443_4a_free(data->iso14443_4a_data);
|
||||
free(data);
|
||||
}
|
||||
|
||||
void mf_plus_reset(MfPlusData* data) {
|
||||
furi_check(data);
|
||||
iso14443_4a_reset(data->iso14443_4a_data);
|
||||
|
||||
memset(&data->version, 0, sizeof(data->version));
|
||||
data->type = MfPlusTypeUnknown;
|
||||
data->security_level = MfPlusSecurityLevelUnknown;
|
||||
data->size = MfPlusSizeUnknown;
|
||||
}
|
||||
|
||||
void mf_plus_copy(MfPlusData* data, const MfPlusData* other) {
|
||||
furi_check(data);
|
||||
furi_check(other);
|
||||
iso14443_4a_copy(data->iso14443_4a_data, other->iso14443_4a_data);
|
||||
|
||||
data->version = other->version;
|
||||
data->type = other->type;
|
||||
data->security_level = other->security_level;
|
||||
data->size = other->size;
|
||||
}
|
||||
|
||||
bool mf_plus_verify(MfPlusData* data, const FuriString* device_type) {
|
||||
UNUSED(data);
|
||||
return furi_string_equal_str(device_type, MF_PLUS_PROTOCOL_NAME);
|
||||
}
|
||||
|
||||
bool mf_plus_load(MfPlusData* data, FlipperFormat* ff, uint32_t version) {
|
||||
furi_assert(data);
|
||||
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if(!iso14443_4a_load(data->iso14443_4a_data, ff, version)) break;
|
||||
if(!mf_plus_version_load(&data->version, ff)) break;
|
||||
if(!mf_plus_type_load(&data->type, ff)) break;
|
||||
if(!mf_plus_security_level_load(&data->security_level, ff)) break;
|
||||
if(!mf_plus_size_load(&data->size, ff)) break;
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool mf_plus_save(const MfPlusData* data, FlipperFormat* ff) {
|
||||
furi_assert(data);
|
||||
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if(!iso14443_4a_save(data->iso14443_4a_data, ff)) break;
|
||||
if(!flipper_format_write_comment_cstr(ff, MF_PLUS_PROTOCOL_NAME " specific data")) break;
|
||||
if(!mf_plus_version_save(&data->version, ff)) break;
|
||||
if(!mf_plus_type_save(&data->type, ff)) break;
|
||||
if(!mf_plus_security_level_save(&data->security_level, ff)) break;
|
||||
if(!mf_plus_size_save(&data->size, ff)) break;
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool mf_plus_is_equal(const MfPlusData* data, const MfPlusData* other) {
|
||||
furi_assert(data);
|
||||
furi_assert(other);
|
||||
bool equal = false;
|
||||
|
||||
do {
|
||||
if(!iso14443_4a_is_equal(data->iso14443_4a_data, other->iso14443_4a_data)) break;
|
||||
if(memcmp(&data->version, &other->version, sizeof(data->version)) != 0) break;
|
||||
if(data->security_level != other->security_level) break;
|
||||
if(data->type != other->type) break;
|
||||
if(data->size != other->size) break;
|
||||
equal = true;
|
||||
} while(false);
|
||||
|
||||
return equal;
|
||||
}
|
||||
|
||||
const char* mf_plus_get_device_name(const MfPlusData* data, NfcDeviceNameType name_type) {
|
||||
furi_check(data);
|
||||
|
||||
FuriString* full_name = furi_string_alloc();
|
||||
const char* name = NULL;
|
||||
|
||||
do {
|
||||
if(name_type == NfcDeviceNameTypeFull) {
|
||||
furi_string_reset(data->device_name);
|
||||
furi_string_cat_printf(
|
||||
data->device_name,
|
||||
"Mifare %s %s %s",
|
||||
mf_plus_type_strings[data->type], // Includes "Plus" for regular Mifare Plus cards
|
||||
mf_plus_size_strings[data->size],
|
||||
mf_plus_security_level_strings[data->security_level]);
|
||||
name = furi_string_get_cstr(data->device_name);
|
||||
FURI_LOG_D("Mifare Plus", "Full name: %s", name);
|
||||
} else if(name_type == NfcDeviceNameTypeShort) {
|
||||
name = "Mifare Plus";
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while(false);
|
||||
|
||||
furi_string_free(full_name);
|
||||
FURI_LOG_D("Mifare Plus", "Name: %s", name);
|
||||
return name;
|
||||
}
|
||||
|
||||
const uint8_t* mf_plus_get_uid(const MfPlusData* data, size_t* uid_len) {
|
||||
furi_assert(data);
|
||||
|
||||
return iso14443_4a_get_uid(data->iso14443_4a_data, uid_len);
|
||||
}
|
||||
|
||||
bool mf_plus_set_uid(MfPlusData* data, const uint8_t* uid, size_t uid_len) {
|
||||
furi_assert(data);
|
||||
|
||||
return iso14443_4a_set_uid(data->iso14443_4a_data, uid, uid_len);
|
||||
}
|
||||
Iso14443_4aData* mf_plus_get_base_data(const MfPlusData* data) {
|
||||
furi_check(data);
|
||||
return data->iso14443_4a_data;
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <lib/nfc/protocols/iso14443_4a/iso14443_4a.h>
|
||||
|
||||
#include <lib/toolbox/simple_array.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MF_PLUS_UID_SIZE (7)
|
||||
#define MF_PLUS_BATCH_SIZE (5)
|
||||
|
||||
#define MF_PLUS_CMD_GET_VERSION (0x60)
|
||||
|
||||
typedef enum {
|
||||
MfPlusErrorNone,
|
||||
MfPlusErrorUnknown,
|
||||
MfPlusErrorNotPresent,
|
||||
MfPlusErrorProtocol,
|
||||
MfPlusErrorAuth,
|
||||
MfPlusErrorPartialRead,
|
||||
MfPlusErrorTimeout,
|
||||
} MfPlusError;
|
||||
|
||||
typedef enum {
|
||||
MfPlusTypePlus,
|
||||
MfPlusTypeEV1,
|
||||
MfPlusTypeEV2,
|
||||
MfPlusTypeS,
|
||||
MfPlusTypeSE,
|
||||
MfPlusTypeX,
|
||||
|
||||
MfPlusTypeUnknown,
|
||||
MfPlusTypeNum,
|
||||
} MfPlusType;
|
||||
|
||||
typedef enum {
|
||||
MfPlusSize1K,
|
||||
MfPlusSize2K,
|
||||
MfPlusSize4K,
|
||||
|
||||
MfPlusSizeUnknown,
|
||||
MfPlusSizeNum,
|
||||
} MfPlusSize;
|
||||
|
||||
typedef enum {
|
||||
MfPlusSecurityLevel0,
|
||||
MfPlusSecurityLevel1,
|
||||
MfPlusSecurityLevel2,
|
||||
MfPlusSecurityLevel3,
|
||||
|
||||
MfPlusSecurityLevelUnknown,
|
||||
MfPlusSecurityLevelNum,
|
||||
} MfPlusSecurityLevel;
|
||||
|
||||
typedef struct {
|
||||
uint8_t hw_vendor;
|
||||
uint8_t hw_type;
|
||||
uint8_t hw_subtype;
|
||||
uint8_t hw_major;
|
||||
uint8_t hw_minor;
|
||||
uint8_t hw_storage;
|
||||
uint8_t hw_proto;
|
||||
|
||||
uint8_t sw_vendor;
|
||||
uint8_t sw_type;
|
||||
uint8_t sw_subtype;
|
||||
uint8_t sw_major;
|
||||
uint8_t sw_minor;
|
||||
uint8_t sw_storage;
|
||||
uint8_t sw_proto;
|
||||
|
||||
uint8_t uid[MF_PLUS_UID_SIZE];
|
||||
uint8_t batch[MF_PLUS_BATCH_SIZE];
|
||||
uint8_t prod_week;
|
||||
uint8_t prod_year;
|
||||
} MfPlusVersion;
|
||||
|
||||
typedef struct {
|
||||
Iso14443_4aData* iso14443_4a_data;
|
||||
MfPlusVersion version;
|
||||
MfPlusType type;
|
||||
MfPlusSize size;
|
||||
MfPlusSecurityLevel security_level;
|
||||
FuriString* device_name;
|
||||
} MfPlusData;
|
||||
|
||||
extern const NfcDeviceBase nfc_device_mf_plus;
|
||||
|
||||
MfPlusData* mf_plus_alloc(void);
|
||||
|
||||
void mf_plus_free(MfPlusData* data);
|
||||
|
||||
void mf_plus_reset(MfPlusData* data);
|
||||
|
||||
void mf_plus_copy(MfPlusData* data, const MfPlusData* other);
|
||||
|
||||
bool mf_plus_verify(MfPlusData* data, const FuriString* device_type);
|
||||
|
||||
bool mf_plus_load(MfPlusData* data, FlipperFormat* ff, uint32_t version);
|
||||
|
||||
bool mf_plus_save(const MfPlusData* data, FlipperFormat* ff);
|
||||
|
||||
bool mf_plus_is_equal(const MfPlusData* data, const MfPlusData* other);
|
||||
|
||||
const char* mf_plus_get_device_name(const MfPlusData* data, NfcDeviceNameType name_type);
|
||||
|
||||
const uint8_t* mf_plus_get_uid(const MfPlusData* data, size_t* uid_len);
|
||||
|
||||
bool mf_plus_set_uid(MfPlusData* data, const uint8_t* uid, size_t uid_len);
|
||||
|
||||
Iso14443_4aData* mf_plus_get_base_data(const MfPlusData* data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -1,216 +0,0 @@
|
|||
#include "mf_plus_i.h"
|
||||
|
||||
#define MF_PLUS_FFF_VERSION_KEY \
|
||||
MF_PLUS_FFF_PICC_PREFIX " " \
|
||||
"Version"
|
||||
|
||||
#define MF_PLUS_FFF_SECURITY_LEVEL_KEY "Security Level"
|
||||
#define MF_PLUS_FFF_CARD_TYPE_KEY "Card Type"
|
||||
#define MF_PLUS_FFF_MEMORY_SIZE_KEY "Memory Size"
|
||||
|
||||
bool mf_plus_version_parse(MfPlusVersion* data, const BitBuffer* buf) {
|
||||
const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfPlusVersion);
|
||||
|
||||
if(can_parse) {
|
||||
bit_buffer_write_bytes(buf, data, sizeof(MfPlusVersion));
|
||||
}
|
||||
|
||||
return can_parse;
|
||||
}
|
||||
|
||||
bool mf_plus_security_level_parse(MfPlusSecurityLevel* data, const BitBuffer* buf) {
|
||||
const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfPlusSecurityLevel);
|
||||
|
||||
if(can_parse) {
|
||||
bit_buffer_write_bytes(buf, data, sizeof(MfPlusSecurityLevel));
|
||||
}
|
||||
|
||||
return can_parse;
|
||||
}
|
||||
|
||||
bool mf_plus_type_parse(MfPlusType* data, const BitBuffer* buf) {
|
||||
const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfPlusType);
|
||||
|
||||
if(can_parse) {
|
||||
bit_buffer_write_bytes(buf, data, sizeof(MfPlusType));
|
||||
}
|
||||
|
||||
return can_parse;
|
||||
}
|
||||
|
||||
bool mf_plus_size_parse(MfPlusSize* data, const BitBuffer* buf) {
|
||||
const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfPlusSize);
|
||||
|
||||
if(can_parse) {
|
||||
bit_buffer_write_bytes(buf, data, sizeof(MfPlusSize));
|
||||
}
|
||||
|
||||
return can_parse;
|
||||
}
|
||||
|
||||
bool mf_plus_version_load(MfPlusVersion* data, FlipperFormat* ff) {
|
||||
return flipper_format_read_hex(
|
||||
ff, MF_PLUS_FFF_VERSION_KEY, (uint8_t*)data, sizeof(MfPlusVersion));
|
||||
}
|
||||
|
||||
bool mf_plus_security_level_load(MfPlusSecurityLevel* data, FlipperFormat* ff) {
|
||||
FuriString* security_level_string = furi_string_alloc();
|
||||
flipper_format_read_string(ff, MF_PLUS_FFF_SECURITY_LEVEL_KEY, security_level_string);
|
||||
|
||||
// Take the last character of the string
|
||||
char security_level_char = furi_string_get_char(
|
||||
security_level_string, furi_string_utf8_length(security_level_string) - 1);
|
||||
|
||||
switch(security_level_char) {
|
||||
case '0':
|
||||
*data = MfPlusSecurityLevel0;
|
||||
break;
|
||||
case '1':
|
||||
*data = MfPlusSecurityLevel1;
|
||||
break;
|
||||
case '2':
|
||||
*data = MfPlusSecurityLevel2;
|
||||
break;
|
||||
case '3':
|
||||
*data = MfPlusSecurityLevel3;
|
||||
break;
|
||||
default:
|
||||
*data = MfPlusSecurityLevelUnknown;
|
||||
break;
|
||||
}
|
||||
|
||||
furi_string_free(security_level_string);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mf_plus_type_load(MfPlusType* data, FlipperFormat* ff) {
|
||||
FuriString* type_string = furi_string_alloc();
|
||||
flipper_format_read_string(ff, MF_PLUS_FFF_CARD_TYPE_KEY, type_string);
|
||||
|
||||
if(furi_string_equal_str(type_string, "Mifare Plus")) {
|
||||
*data = MfPlusTypePlus;
|
||||
} else if(furi_string_equal_str(type_string, "Mifare Plus X")) {
|
||||
*data = MfPlusTypeX;
|
||||
} else if(furi_string_equal_str(type_string, "Mifare Plus S")) {
|
||||
*data = MfPlusTypeS;
|
||||
} else if(furi_string_equal_str(type_string, "Mifare Plus SE")) {
|
||||
*data = MfPlusTypeSE;
|
||||
} else if(furi_string_equal_str(type_string, "Mifare Plus EV1")) {
|
||||
*data = MfPlusTypeEV1;
|
||||
} else if(furi_string_equal_str(type_string, "Mifare Plus EV2")) {
|
||||
*data = MfPlusTypeEV2;
|
||||
} else {
|
||||
*data = MfPlusTypeUnknown;
|
||||
}
|
||||
|
||||
furi_string_free(type_string);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mf_plus_size_load(MfPlusSize* data, FlipperFormat* ff) {
|
||||
FuriString* size_string = furi_string_alloc();
|
||||
flipper_format_read_string(ff, MF_PLUS_FFF_MEMORY_SIZE_KEY, size_string);
|
||||
|
||||
if(furi_string_equal_str(size_string, "1K")) {
|
||||
*data = MfPlusSize1K;
|
||||
} else if(furi_string_equal_str(size_string, "2K")) {
|
||||
*data = MfPlusSize2K;
|
||||
} else if(furi_string_equal_str(size_string, "4K")) {
|
||||
*data = MfPlusSize4K;
|
||||
} else {
|
||||
*data = MfPlusSizeUnknown;
|
||||
}
|
||||
|
||||
furi_string_free(size_string);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mf_plus_version_save(const MfPlusVersion* data, FlipperFormat* ff) {
|
||||
return flipper_format_write_hex(
|
||||
ff, MF_PLUS_FFF_VERSION_KEY, (const uint8_t*)data, sizeof(MfPlusVersion));
|
||||
}
|
||||
|
||||
bool mf_plus_security_level_save(const MfPlusSecurityLevel* data, FlipperFormat* ff) {
|
||||
FuriString* security_level_string = furi_string_alloc();
|
||||
|
||||
switch(*data) {
|
||||
case MfPlusSecurityLevel0:
|
||||
furi_string_cat(security_level_string, "SL0");
|
||||
break;
|
||||
case MfPlusSecurityLevel1:
|
||||
furi_string_cat(security_level_string, "SL1");
|
||||
break;
|
||||
case MfPlusSecurityLevel2:
|
||||
furi_string_cat(security_level_string, "SL2");
|
||||
break;
|
||||
case MfPlusSecurityLevel3:
|
||||
furi_string_cat(security_level_string, "SL3");
|
||||
break;
|
||||
default:
|
||||
furi_string_cat(security_level_string, "Unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
flipper_format_write_string(ff, MF_PLUS_FFF_SECURITY_LEVEL_KEY, security_level_string);
|
||||
furi_string_free(security_level_string);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mf_plus_type_save(const MfPlusType* data, FlipperFormat* ff) {
|
||||
FuriString* type_string = furi_string_alloc();
|
||||
|
||||
switch(*data) {
|
||||
case MfPlusTypePlus:
|
||||
furi_string_cat(type_string, "Mifare Plus");
|
||||
break;
|
||||
case MfPlusTypeX:
|
||||
furi_string_cat(type_string, "Mifare Plus X");
|
||||
break;
|
||||
case MfPlusTypeS:
|
||||
furi_string_cat(type_string, "Mifare Plus S");
|
||||
break;
|
||||
case MfPlusTypeSE:
|
||||
furi_string_cat(type_string, "Mifare Plus SE");
|
||||
break;
|
||||
case MfPlusTypeEV1:
|
||||
furi_string_cat(type_string, "Mifare Plus EV1");
|
||||
break;
|
||||
case MfPlusTypeEV2:
|
||||
furi_string_cat(type_string, "Mifare Plus EV2");
|
||||
break;
|
||||
default:
|
||||
furi_string_cat(type_string, "Unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
flipper_format_write_string(ff, MF_PLUS_FFF_CARD_TYPE_KEY, type_string);
|
||||
furi_string_free(type_string);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mf_plus_size_save(const MfPlusSize* data, FlipperFormat* ff) {
|
||||
FuriString* size_string = furi_string_alloc();
|
||||
|
||||
switch(*data) {
|
||||
case MfPlusSize1K:
|
||||
furi_string_cat(size_string, "1K");
|
||||
break;
|
||||
case MfPlusSize2K:
|
||||
furi_string_cat(size_string, "2K");
|
||||
break;
|
||||
case MfPlusSize4K:
|
||||
furi_string_cat(size_string, "4K");
|
||||
break;
|
||||
default:
|
||||
furi_string_cat(size_string, "Unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
flipper_format_write_string(ff, MF_PLUS_FFF_MEMORY_SIZE_KEY, size_string);
|
||||
furi_string_free(size_string);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "mf_plus.h"
|
||||
|
||||
#define MF_PLUS_FFF_PICC_PREFIX "PICC"
|
||||
|
||||
bool mf_plus_version_parse(MfPlusVersion* data, const BitBuffer* buf);
|
||||
|
||||
bool mf_plus_security_level_parse(MfPlusSecurityLevel* data, const BitBuffer* buf);
|
||||
|
||||
bool mf_plus_type_parse(MfPlusType* data, const BitBuffer* buf);
|
||||
|
||||
bool mf_plus_size_parse(MfPlusSize* data, const BitBuffer* buf);
|
||||
|
||||
bool mf_plus_version_load(MfPlusVersion* data, FlipperFormat* ff);
|
||||
|
||||
bool mf_plus_security_level_load(MfPlusSecurityLevel* data, FlipperFormat* ff);
|
||||
|
||||
bool mf_plus_type_load(MfPlusType* data, FlipperFormat* ff);
|
||||
|
||||
bool mf_plus_size_load(MfPlusSize* data, FlipperFormat* ff);
|
||||
|
||||
bool mf_plus_version_save(const MfPlusVersion* data, FlipperFormat* ff);
|
||||
|
||||
bool mf_plus_security_level_save(const MfPlusSecurityLevel* data, FlipperFormat* ff);
|
||||
|
||||
bool mf_plus_type_save(const MfPlusType* data, FlipperFormat* ff);
|
||||
|
||||
bool mf_plus_size_save(const MfPlusSize* data, FlipperFormat* ff);
|
|
@ -1,367 +0,0 @@
|
|||
#include "mf_plus_poller_i.h"
|
||||
|
||||
#include <nfc/protocols/nfc_poller_base.h>
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define TAG "MfPlusPoller"
|
||||
|
||||
#define MF_PLUS_BUF_SIZE (64U)
|
||||
#define MF_PLUS_RESULT_BUF_SIZE (512U)
|
||||
|
||||
const char* mf_plus_ats_t1_tk_values[] = {
|
||||
"\xC1\x05\x2F\x2F\x00\x35\xC7", // Mifare Plus S
|
||||
"\xC1\x05\x2F\x2F\x01\xBC\xD6", // Mifare Plus X
|
||||
"\xC1\x05\x2F\x2F\x00\xF6\xD1", // Mifare Plus SE
|
||||
"\xC1\x05\x2F\x2F\x01\xF6\xD1", // Mifare Plus SE
|
||||
};
|
||||
|
||||
typedef NfcCommand (*MfPlusPollerReadHandler)(MfPlusPoller* instance);
|
||||
|
||||
const MfPlusData* mf_plus_poller_get_data(MfPlusPoller* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
return instance->data;
|
||||
}
|
||||
|
||||
bool mf_plus_poller_get_type_from_iso4(const Iso14443_4aData* iso4_data, MfPlusData* mf_plus_data) {
|
||||
furi_assert(iso4_data);
|
||||
furi_assert(mf_plus_data);
|
||||
|
||||
switch(iso4_data->iso14443_3a_data->sak) {
|
||||
case 0x08:
|
||||
if(memcmp(
|
||||
simple_array_get_data(iso4_data->ats_data.t1_tk),
|
||||
mf_plus_ats_t1_tk_values[0],
|
||||
simple_array_get_count(iso4_data->ats_data.t1_tk)) == 0) {
|
||||
// Mifare Plus S 2K SL1
|
||||
mf_plus_data->type = MfPlusTypeS;
|
||||
mf_plus_data->size = MfPlusSize2K;
|
||||
mf_plus_data->security_level = MfPlusSecurityLevel1;
|
||||
FURI_LOG_D(TAG, "Mifare Plus S 2K SL1");
|
||||
return true;
|
||||
} else if(
|
||||
memcmp(
|
||||
simple_array_get_data(iso4_data->ats_data.t1_tk),
|
||||
mf_plus_ats_t1_tk_values[1],
|
||||
simple_array_get_count(iso4_data->ats_data.t1_tk)) == 0) {
|
||||
// Mifare Plus X 2K SL1
|
||||
mf_plus_data->type = MfPlusTypeX;
|
||||
mf_plus_data->size = MfPlusSize2K;
|
||||
mf_plus_data->security_level = MfPlusSecurityLevel1;
|
||||
FURI_LOG_D(TAG, "Mifare Plus X 2K SL1");
|
||||
return true;
|
||||
} else if(
|
||||
memcmp(
|
||||
simple_array_get_data(iso4_data->ats_data.t1_tk),
|
||||
mf_plus_ats_t1_tk_values[2],
|
||||
simple_array_get_count(iso4_data->ats_data.t1_tk)) == 0 ||
|
||||
memcmp(
|
||||
simple_array_get_data(iso4_data->ats_data.t1_tk),
|
||||
mf_plus_ats_t1_tk_values[3],
|
||||
simple_array_get_count(iso4_data->ats_data.t1_tk)) == 0) {
|
||||
// Mifare Plus SE 1K SL1
|
||||
mf_plus_data->type = MfPlusTypeSE;
|
||||
mf_plus_data->size = MfPlusSize1K;
|
||||
mf_plus_data->security_level = MfPlusSecurityLevel1;
|
||||
FURI_LOG_D(TAG, "Mifare Plus SE 1K SL1");
|
||||
return true;
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Sak 08 but no known Mifare Plus type");
|
||||
return false;
|
||||
}
|
||||
case 0x18:
|
||||
if(memcmp(
|
||||
simple_array_get_data(iso4_data->ats_data.t1_tk),
|
||||
mf_plus_ats_t1_tk_values[0],
|
||||
simple_array_get_count(iso4_data->ats_data.t1_tk)) == 0) {
|
||||
// Mifare Plus S 4K SL1
|
||||
mf_plus_data->type = MfPlusTypeS;
|
||||
mf_plus_data->size = MfPlusSize4K;
|
||||
mf_plus_data->security_level = MfPlusSecurityLevel1;
|
||||
FURI_LOG_D(TAG, "Mifare Plus S 4K SL1");
|
||||
return true;
|
||||
} else if(
|
||||
memcmp(
|
||||
simple_array_get_data(iso4_data->ats_data.t1_tk),
|
||||
mf_plus_ats_t1_tk_values[1],
|
||||
simple_array_get_count(iso4_data->ats_data.t1_tk)) == 0) {
|
||||
// Mifare Plus X 4K SL1
|
||||
mf_plus_data->type = MfPlusTypeX;
|
||||
mf_plus_data->size = MfPlusSize4K;
|
||||
mf_plus_data->security_level = MfPlusSecurityLevel1;
|
||||
FURI_LOG_D(TAG, "Mifare Plus X 4K SL1");
|
||||
return true;
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Sak 18 but no known Mifare Plus type");
|
||||
return false;
|
||||
}
|
||||
case 0x20:
|
||||
if(memcmp(
|
||||
iso4_data->ats_data.t1_tk,
|
||||
mf_plus_ats_t1_tk_values[0],
|
||||
simple_array_get_count(iso4_data->ats_data.t1_tk)) == 0) {
|
||||
// Mifare Plus S 2/4K SL3
|
||||
mf_plus_data->type = MfPlusTypeS;
|
||||
mf_plus_data->security_level = MfPlusSecurityLevel3;
|
||||
|
||||
if(iso4_data->iso14443_3a_data->atqa[1] == 0x04) {
|
||||
// Mifare Plus S 2K SL3
|
||||
mf_plus_data->size = MfPlusSize2K;
|
||||
FURI_LOG_D(TAG, "Mifare Plus S 2K SL3");
|
||||
} else if(iso4_data->iso14443_3a_data->atqa[1] == 0x02) {
|
||||
// Mifare Plus S 4K SL3
|
||||
mf_plus_data->size = MfPlusSize4K;
|
||||
FURI_LOG_D(TAG, "Mifare Plus S 4K SL3");
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Sak 20 but no known Mifare Plus type (S)");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
} else if(
|
||||
memcmp(
|
||||
iso4_data->ats_data.t1_tk,
|
||||
mf_plus_ats_t1_tk_values[1],
|
||||
simple_array_get_count(iso4_data->ats_data.t1_tk)) == 0) {
|
||||
mf_plus_data->type = MfPlusTypeX;
|
||||
mf_plus_data->security_level = MfPlusSecurityLevel3;
|
||||
|
||||
if(iso4_data->iso14443_3a_data->atqa[1] == 0x04) {
|
||||
mf_plus_data->size = MfPlusSize2K;
|
||||
FURI_LOG_D(TAG, "Mifare Plus X 2K SL3");
|
||||
} else if(iso4_data->iso14443_3a_data->atqa[1] == 0x02) {
|
||||
mf_plus_data->size = MfPlusSize4K;
|
||||
FURI_LOG_D(TAG, "Mifare Plus X 4K SL3");
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Sak 20 but no known Mifare Plus type (X)");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Sak 20 but no known Mifare Plus type");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
FURI_LOG_D(TAG, "No known Mifare Plus type");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool mf_plus_poller_detect_type(MfPlusPoller* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
bool detected = false;
|
||||
|
||||
const Iso14443_4aData* iso14443_4a_data =
|
||||
iso14443_4a_poller_get_data(instance->iso14443_4a_poller);
|
||||
const MfPlusError error = mf_plus_poller_read_version(instance, &instance->data->version);
|
||||
if(error == MfPlusErrorNone) {
|
||||
FURI_LOG_D(TAG, "Read version success: %d", error);
|
||||
if(instance->data->version.hw_major == 0x02 || instance->data->version.hw_major == 0x82) {
|
||||
detected = true;
|
||||
if(iso14443_4a_data->iso14443_3a_data->sak == 0x10) {
|
||||
// Mifare Plus 2K SL2
|
||||
instance->data->type = MfPlusTypePlus;
|
||||
instance->data->size = MfPlusSize2K;
|
||||
instance->data->security_level = MfPlusSecurityLevel2;
|
||||
} else if(iso14443_4a_data->iso14443_3a_data->sak == 0x11) {
|
||||
// Mifare Plus 4K SL3
|
||||
instance->data->type = MfPlusTypePlus;
|
||||
instance->data->size = MfPlusSize4K;
|
||||
instance->data->security_level = MfPlusSecurityLevel3;
|
||||
} else {
|
||||
// Mifare Plus EV1/EV2
|
||||
|
||||
// Revision
|
||||
switch(instance->data->version.hw_major) {
|
||||
case 0x11:
|
||||
instance->data->type = MfPlusTypeEV1;
|
||||
break;
|
||||
case 0x22:
|
||||
instance->data->type = MfPlusTypeEV2;
|
||||
break;
|
||||
default:
|
||||
instance->data->type = MfPlusTypeUnknown;
|
||||
break;
|
||||
}
|
||||
|
||||
// Storage size
|
||||
switch(instance->data->version.hw_storage) {
|
||||
case 0x16:
|
||||
instance->data->size = MfPlusSize2K;
|
||||
break;
|
||||
case 0x18:
|
||||
instance->data->size = MfPlusSize4K;
|
||||
break;
|
||||
default:
|
||||
instance->data->size = MfPlusSizeUnknown;
|
||||
break;
|
||||
}
|
||||
|
||||
// Security level
|
||||
if(iso14443_4a_data->iso14443_3a_data->sak == 0x20) {
|
||||
// Mifare Plus EV1/2 SL3
|
||||
instance->data->security_level = MfPlusSecurityLevel3;
|
||||
} else {
|
||||
// Mifare Plus EV1/2 SL1
|
||||
instance->data->security_level = MfPlusSecurityLevel1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Read version error: %d", error);
|
||||
detected = mf_plus_poller_get_type_from_iso4(iso14443_4a_data, instance->data);
|
||||
}
|
||||
|
||||
return detected;
|
||||
}
|
||||
|
||||
MfPlusPoller* mf_plus_poller_alloc(Iso14443_4aPoller* iso14443_4a_poller) {
|
||||
furi_assert(iso14443_4a_poller);
|
||||
|
||||
MfPlusPoller* instance = malloc(sizeof(MfPlusPoller));
|
||||
furi_assert(instance);
|
||||
|
||||
instance->iso14443_4a_poller = iso14443_4a_poller;
|
||||
|
||||
instance->data = mf_plus_alloc();
|
||||
|
||||
instance->tx_buffer = bit_buffer_alloc(MF_PLUS_BUF_SIZE);
|
||||
instance->rx_buffer = bit_buffer_alloc(MF_PLUS_BUF_SIZE);
|
||||
instance->input_buffer = bit_buffer_alloc(MF_PLUS_BUF_SIZE);
|
||||
instance->result_buffer = bit_buffer_alloc(MF_PLUS_RESULT_BUF_SIZE);
|
||||
|
||||
instance->general_event.protocol = NfcProtocolMfPlus;
|
||||
instance->general_event.event_data = &instance->mfp_event;
|
||||
instance->general_event.instance = instance;
|
||||
|
||||
instance->mfp_event.data = &instance->mfp_event_data;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
static NfcCommand mf_plus_poller_handler_idle(MfPlusPoller* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
bit_buffer_reset(instance->input_buffer);
|
||||
bit_buffer_reset(instance->result_buffer);
|
||||
bit_buffer_reset(instance->tx_buffer);
|
||||
bit_buffer_reset(instance->rx_buffer);
|
||||
|
||||
iso14443_4a_copy(
|
||||
instance->data->iso14443_4a_data,
|
||||
iso14443_4a_poller_get_data(instance->iso14443_4a_poller));
|
||||
|
||||
instance->state = MfPlusPollerStateReadVersion;
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
||||
static NfcCommand mf_plus_poller_handler_read_version(MfPlusPoller* instance) {
|
||||
bool success = mf_plus_poller_detect_type(instance);
|
||||
if(success) {
|
||||
instance->state = MfPlusPollerStateReadSuccess;
|
||||
} else {
|
||||
instance->state = MfPlusPollerStateReadFailed;
|
||||
}
|
||||
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
||||
static NfcCommand mf_plus_poller_handler_read_failed(MfPlusPoller* instance) {
|
||||
furi_assert(instance);
|
||||
FURI_LOG_D(TAG, "Read failed");
|
||||
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
||||
instance->mfp_event.data->error = instance->error;
|
||||
NfcCommand command = instance->callback(instance->general_event, instance->context);
|
||||
instance->state = MfPlusPollerStateIdle;
|
||||
return command;
|
||||
}
|
||||
|
||||
static NfcCommand mf_plus_poller_handler_read_success(MfPlusPoller* instance) {
|
||||
furi_assert(instance);
|
||||
FURI_LOG_D(TAG, "Read success");
|
||||
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
||||
instance->mfp_event.type = MfPlusPollerEventTypeReadSuccess;
|
||||
NfcCommand command = instance->callback(instance->general_event, instance->context);
|
||||
return command;
|
||||
}
|
||||
|
||||
static const MfPlusPollerReadHandler mf_plus_poller_read_handler[MfPlusPollerStateNum] = {
|
||||
[MfPlusPollerStateIdle] = mf_plus_poller_handler_idle,
|
||||
[MfPlusPollerStateReadVersion] = mf_plus_poller_handler_read_version,
|
||||
[MfPlusPollerStateReadFailed] = mf_plus_poller_handler_read_failed,
|
||||
[MfPlusPollerStateReadSuccess] = mf_plus_poller_handler_read_success,
|
||||
};
|
||||
|
||||
static void mf_plus_poller_set_callback(
|
||||
MfPlusPoller* instance,
|
||||
NfcGenericCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
furi_assert(callback);
|
||||
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
static NfcCommand mf_plus_poller_run(NfcGenericEvent event, void* context) {
|
||||
furi_assert(event.protocol = NfcProtocolIso14443_4a);
|
||||
|
||||
MfPlusPoller* instance = context;
|
||||
furi_assert(instance);
|
||||
|
||||
const Iso14443_4aPollerEvent* iso14443_4a_event = event.event_data;
|
||||
furi_assert(iso14443_4a_event);
|
||||
|
||||
NfcCommand command = NfcCommandContinue;
|
||||
|
||||
if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) {
|
||||
command = mf_plus_poller_read_handler[instance->state](instance);
|
||||
} else if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeError) {
|
||||
instance->mfp_event.type = MfPlusPollerEventTypeReadFailed;
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
void mf_plus_poller_free(MfPlusPoller* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->data);
|
||||
|
||||
bit_buffer_free(instance->tx_buffer);
|
||||
bit_buffer_free(instance->rx_buffer);
|
||||
bit_buffer_free(instance->input_buffer);
|
||||
bit_buffer_free(instance->result_buffer);
|
||||
mf_plus_free(instance->data);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
static bool mf_plus_poller_detect(NfcGenericEvent event, void* context) {
|
||||
furi_assert(event.protocol = NfcProtocolIso14443_4a);
|
||||
|
||||
MfPlusPoller* instance = context;
|
||||
furi_assert(instance);
|
||||
|
||||
Iso14443_4aPollerEvent* iso14443_4a_event = event.event_data;
|
||||
furi_assert(iso14443_4a_event);
|
||||
|
||||
bool detected = false;
|
||||
|
||||
if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) {
|
||||
detected = mf_plus_poller_detect_type(instance);
|
||||
}
|
||||
|
||||
return detected;
|
||||
}
|
||||
|
||||
const NfcPollerBase mf_plus_poller = {
|
||||
.alloc = (NfcPollerAlloc)mf_plus_poller_alloc,
|
||||
.free = (NfcPollerFree)mf_plus_poller_free,
|
||||
.set_callback = (NfcPollerSetCallback)mf_plus_poller_set_callback,
|
||||
.run = (NfcPollerRun)mf_plus_poller_run,
|
||||
.detect = (NfcPollerDetect)mf_plus_poller_detect,
|
||||
.get_data = (NfcPollerGetData)mf_plus_poller_get_data,
|
||||
};
|
|
@ -1,55 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "mf_plus.h"
|
||||
|
||||
#include <lib/nfc/protocols/iso14443_4a/iso14443_4a.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief MIFARE Plus poller opaque type definition.
|
||||
*/
|
||||
typedef struct MfPlusPoller MfPlusPoller;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of possible MfPlus poller event types.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
MfPlusPollerEventTypeReadSuccess, /**< Card was read successfully. */
|
||||
MfPlusPollerEventTypeReadFailed, /**< Poller failed to read the card. */
|
||||
} MfPlusPollerEventType;
|
||||
|
||||
/**
|
||||
* @brief MIFARE Plus poller event data.
|
||||
*/
|
||||
typedef union {
|
||||
MfPlusError error; /**< Error code indicating card reading fail reason. */
|
||||
} MfPlusPollerEventData;
|
||||
|
||||
/**
|
||||
* @brief MIFARE Plus poller event structure.
|
||||
*
|
||||
* Upon emission of an event, an instance of this struct will be passed to the callback.
|
||||
*/
|
||||
typedef struct {
|
||||
MfPlusPollerEventType type; /**< Type of emitted event. */
|
||||
MfPlusPollerEventData* data; /**< Pointer to event specific data. */
|
||||
} MfPlusPollerEvent;
|
||||
|
||||
/**
|
||||
* @brief Read MfPlus card version.
|
||||
*
|
||||
* Must ONLY be used inside the callback function.
|
||||
*
|
||||
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||
* @param[out] data pointer to the MfPlusVersion structure to be filled with version data.
|
||||
* @return MfPlusErrorNone on success, an error code on failure.
|
||||
*/
|
||||
MfPlusError mf_plus_poller_read_version(MfPlusPoller* instance, MfPlusVersion* data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <nfc/protocols/nfc_poller_base.h>
|
||||
|
||||
extern const NfcPollerBase mf_plus_poller;
|
|
@ -1,73 +0,0 @@
|
|||
#include "mf_plus_poller_i.h"
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#include "mf_plus_i.h"
|
||||
|
||||
#define TAG "MfPlusPoller"
|
||||
|
||||
MfPlusError mf_plus_process_error(Iso14443_4aError error) {
|
||||
switch(error) {
|
||||
case Iso14443_4aErrorNone:
|
||||
return MfPlusErrorNone;
|
||||
case Iso14443_4aErrorNotPresent:
|
||||
return MfPlusErrorNotPresent;
|
||||
case Iso14443_4aErrorTimeout:
|
||||
return MfPlusErrorTimeout;
|
||||
default:
|
||||
return MfPlusErrorProtocol;
|
||||
}
|
||||
}
|
||||
|
||||
MfPlusError
|
||||
mf_plus_send_chunk(MfPlusPoller* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->iso14443_4a_poller);
|
||||
furi_assert(instance->tx_buffer);
|
||||
furi_assert(instance->rx_buffer);
|
||||
furi_assert(tx_buffer);
|
||||
furi_assert(rx_buffer);
|
||||
|
||||
MfPlusError error = MfPlusErrorNone;
|
||||
|
||||
do {
|
||||
Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block(
|
||||
instance->iso14443_4a_poller, tx_buffer, instance->rx_buffer);
|
||||
|
||||
if(iso14443_4a_error != Iso14443_4aErrorNone) {
|
||||
error = mf_plus_process_error(iso14443_4a_error);
|
||||
break;
|
||||
}
|
||||
|
||||
bit_buffer_reset(instance->tx_buffer);
|
||||
|
||||
if(bit_buffer_get_size_bytes(instance->rx_buffer) > sizeof(uint8_t)) {
|
||||
bit_buffer_copy_right(rx_buffer, instance->rx_buffer, sizeof(uint8_t));
|
||||
} else {
|
||||
bit_buffer_reset(rx_buffer);
|
||||
}
|
||||
} while(false);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
MfPlusError mf_plus_poller_read_version(MfPlusPoller* instance, MfPlusVersion* data) {
|
||||
furi_assert(instance);
|
||||
|
||||
bit_buffer_reset(instance->input_buffer);
|
||||
bit_buffer_append_byte(instance->input_buffer, MF_PLUS_CMD_GET_VERSION);
|
||||
|
||||
MfPlusError error;
|
||||
|
||||
do {
|
||||
error = mf_plus_send_chunk(instance, instance->input_buffer, instance->result_buffer);
|
||||
|
||||
if(error != MfPlusErrorNone) break;
|
||||
|
||||
if(!mf_plus_version_parse(data, instance->result_buffer)) {
|
||||
error = MfPlusErrorProtocol;
|
||||
}
|
||||
} while(false);
|
||||
|
||||
return error;
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "mf_plus_poller.h"
|
||||
|
||||
#include <lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MF_PLUS_FWT_FC (60000)
|
||||
|
||||
typedef enum {
|
||||
MfPlusCardStateDetected,
|
||||
MfPlusCardStateLost,
|
||||
} MfPlusCardState;
|
||||
|
||||
typedef enum {
|
||||
MfPlusPollerStateIdle,
|
||||
MfPlusPollerStateReadVersion,
|
||||
MfPlusPollerStateReadFailed,
|
||||
MfPlusPollerStateReadSuccess,
|
||||
|
||||
MfPlusPollerStateNum,
|
||||
} MfPlusPollerState;
|
||||
|
||||
struct MfPlusPoller {
|
||||
Iso14443_4aPoller* iso14443_4a_poller;
|
||||
|
||||
MfPlusData* data;
|
||||
MfPlusPollerState state;
|
||||
|
||||
BitBuffer* tx_buffer;
|
||||
BitBuffer* rx_buffer;
|
||||
BitBuffer* input_buffer;
|
||||
BitBuffer* result_buffer;
|
||||
|
||||
MfPlusError error;
|
||||
NfcGenericEvent general_event;
|
||||
MfPlusPollerEvent mfp_event;
|
||||
MfPlusPollerEventData mfp_event_data;
|
||||
NfcGenericCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
MfPlusError mf_plus_process_error(Iso14443_4aError error);
|
||||
|
||||
MfPlusPoller* mf_plus_poller_alloc(Iso14443_4aPoller* iso14443_4a_poller);
|
||||
|
||||
void mf_plus_poller_free(MfPlusPoller* instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -20,7 +20,6 @@
|
|||
#include <nfc/protocols/felica/felica.h>
|
||||
#include <nfc/protocols/mf_ultralight/mf_ultralight.h>
|
||||
#include <nfc/protocols/mf_classic/mf_classic.h>
|
||||
#include <nfc/protocols/mf_plus/mf_plus.h>
|
||||
#include <nfc/protocols/mf_desfire/mf_desfire.h>
|
||||
#include <nfc/protocols/emv/emv.h>
|
||||
#include <nfc/protocols/slix/slix_device_defs.h>
|
||||
|
@ -41,7 +40,6 @@ const NfcDeviceBase* nfc_devices[NfcProtocolNum] = {
|
|||
[NfcProtocolFelica] = &nfc_device_felica,
|
||||
[NfcProtocolMfUltralight] = &nfc_device_mf_ultralight,
|
||||
[NfcProtocolMfClassic] = &nfc_device_mf_classic,
|
||||
[NfcProtocolMfPlus] = &nfc_device_mf_plus,
|
||||
[NfcProtocolMfDesfire] = &nfc_device_mf_desfire,
|
||||
[NfcProtocolSlix] = &nfc_device_slix,
|
||||
[NfcProtocolSt25tb] = &nfc_device_st25tb,
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include <nfc/protocols/felica/felica_poller_defs.h>
|
||||
#include <nfc/protocols/mf_ultralight/mf_ultralight_poller_defs.h>
|
||||
#include <nfc/protocols/mf_classic/mf_classic_poller_defs.h>
|
||||
#include <nfc/protocols/mf_plus/mf_plus_poller_defs.h>
|
||||
#include <nfc/protocols/mf_desfire/mf_desfire_poller_defs.h>
|
||||
#include <nfc/protocols/emv/emv_poller_defs.h>
|
||||
#include <nfc/protocols/slix/slix_poller_defs.h>
|
||||
|
@ -23,7 +22,6 @@ const NfcPollerBase* nfc_pollers_api[NfcProtocolNum] = {
|
|||
[NfcProtocolFelica] = &nfc_poller_felica,
|
||||
[NfcProtocolMfUltralight] = &mf_ultralight_poller,
|
||||
[NfcProtocolMfClassic] = &mf_classic_poller,
|
||||
[NfcProtocolMfPlus] = &mf_plus_poller,
|
||||
[NfcProtocolMfDesfire] = &mf_desfire_poller,
|
||||
[NfcProtocolSlix] = &nfc_poller_slix,
|
||||
[NfcProtocolSt25tb] = &nfc_poller_st25tb,
|
||||
|
|
|
@ -63,7 +63,6 @@ static const NfcProtocol nfc_protocol_iso14443_3b_children_protocol[] = {
|
|||
/** List of ISO14443-4A child protocols. */
|
||||
static const NfcProtocol nfc_protocol_iso14443_4a_children_protocol[] = {
|
||||
NfcProtocolMfDesfire,
|
||||
NfcProtocolMfPlus,
|
||||
NfcProtocolEmv,
|
||||
};
|
||||
|
||||
|
@ -132,12 +131,6 @@ static const NfcProtocolTreeNode nfc_protocol_nodes[NfcProtocolNum] = {
|
|||
.children_num = 0,
|
||||
.children_protocol = NULL,
|
||||
},
|
||||
[NfcProtocolMfPlus] =
|
||||
{
|
||||
.parent_protocol = NfcProtocolIso14443_4a,
|
||||
.children_num = 0,
|
||||
.children_protocol = NULL,
|
||||
},
|
||||
[NfcProtocolMfDesfire] =
|
||||
{
|
||||
.parent_protocol = NfcProtocolIso14443_4a,
|
||||
|
|
|
@ -184,7 +184,6 @@ typedef enum {
|
|||
NfcProtocolFelica,
|
||||
NfcProtocolMfUltralight,
|
||||
NfcProtocolMfClassic,
|
||||
NfcProtocolMfPlus,
|
||||
NfcProtocolMfDesfire,
|
||||
NfcProtocolSlix,
|
||||
NfcProtocolSt25tb,
|
||||
|
|
|
@ -154,8 +154,6 @@ Header,+,lib/nfc/protocols/mf_classic/mf_classic_poller.h,,
|
|||
Header,+,lib/nfc/protocols/mf_classic/mf_classic_poller_sync.h,,
|
||||
Header,+,lib/nfc/protocols/mf_desfire/mf_desfire.h,,
|
||||
Header,+,lib/nfc/protocols/mf_desfire/mf_desfire_poller.h,,
|
||||
Header,+,lib/nfc/protocols/mf_plus/mf_plus.h,,
|
||||
Header,+,lib/nfc/protocols/mf_plus/mf_plus_poller.h,,
|
||||
Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight.h,,
|
||||
Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h,,
|
||||
Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h,,
|
||||
|
@ -2548,19 +2546,6 @@ Function,+,mf_desfire_save,_Bool,"const MfDesfireData*, FlipperFormat*"
|
|||
Function,+,mf_desfire_send_chunks,MfDesfireError,"MfDesfirePoller*, const BitBuffer*, BitBuffer*"
|
||||
Function,+,mf_desfire_set_uid,_Bool,"MfDesfireData*, const uint8_t*, size_t"
|
||||
Function,+,mf_desfire_verify,_Bool,"MfDesfireData*, const FuriString*"
|
||||
Function,+,mf_plus_alloc,MfPlusData*,
|
||||
Function,+,mf_plus_copy,void,"MfPlusData*, const MfPlusData*"
|
||||
Function,+,mf_plus_free,void,MfPlusData*
|
||||
Function,+,mf_plus_get_base_data,Iso14443_4aData*,const MfPlusData*
|
||||
Function,+,mf_plus_get_device_name,const char*,"const MfPlusData*, NfcDeviceNameType"
|
||||
Function,+,mf_plus_get_uid,const uint8_t*,"const MfPlusData*, size_t*"
|
||||
Function,+,mf_plus_is_equal,_Bool,"const MfPlusData*, const MfPlusData*"
|
||||
Function,+,mf_plus_load,_Bool,"MfPlusData*, FlipperFormat*, uint32_t"
|
||||
Function,+,mf_plus_poller_read_version,MfPlusError,"MfPlusPoller*, MfPlusVersion*"
|
||||
Function,+,mf_plus_reset,void,MfPlusData*
|
||||
Function,+,mf_plus_save,_Bool,"const MfPlusData*, FlipperFormat*"
|
||||
Function,+,mf_plus_set_uid,_Bool,"MfPlusData*, const uint8_t*, size_t"
|
||||
Function,+,mf_plus_verify,_Bool,"MfPlusData*, const FuriString*"
|
||||
Function,+,mf_ultralight_alloc,MfUltralightData*,
|
||||
Function,+,mf_ultralight_copy,void,"MfUltralightData*, const MfUltralightData*"
|
||||
Function,+,mf_ultralight_detect_protocol,_Bool,const Iso14443_3aData*
|
||||
|
@ -3874,7 +3859,6 @@ Variable,-,nfc_device_emv,const NfcDeviceBase,
|
|||
Variable,-,nfc_device_felica,const NfcDeviceBase,
|
||||
Variable,-,nfc_device_mf_classic,const NfcDeviceBase,
|
||||
Variable,-,nfc_device_mf_desfire,const NfcDeviceBase,
|
||||
Variable,-,nfc_device_mf_plus,const NfcDeviceBase,
|
||||
Variable,-,nfc_device_mf_ultralight,const NfcDeviceBase,
|
||||
Variable,-,nfc_device_st25tb,const NfcDeviceBase,
|
||||
Variable,+,sequence_audiovisual_alert,const NotificationSequence,
|
||||
|
|
|
Loading…
Reference in a new issue