Skip to content

Commit f4dc0ba

Browse files
committed
NFC Magic: Direct write to block 0 mode management added, code cleanup
1 parent 039a8d1 commit f4dc0ba

12 files changed

+335
-29
lines changed

nfc_magic/.catalog/changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
- Get revision, get config moved into main Gen4 menu
44
- New function: Set Gen4 card shadow mode
5+
- New function: Set Gen4 card direct write to block 0 mode
56
- Fixed: back button did not allow to exit from some scenes while the card is next to the Flipper HF RFID antenna
67

78
## 1.4

nfc_magic/lib/magic/protocols/gen4/gen4_poller.c

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ NfcCommand gen4_poller_request_mode_handler(Gen4Poller* instance) {
181181
instance->state = Gen4PollerStateGetRevision;
182182
} else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeSetShadowMode) {
183183
instance->state = Gen4PollerStateSetShadowMode;
184+
} else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeSetDirectWriteBlock0Mode) {
185+
instance->state = Gen4PollerStateSetDirectWriteBlock0;
184186
} else {
185187
instance->state = Gen4PollerStateFail;
186188
}
@@ -273,13 +275,13 @@ static NfcCommand gen4_poller_write_mf_classic(Gen4Poller* instance) {
273275
break;
274276
}
275277

276-
instance->config[6] = Gen4PollerShadowModeIgnore;
278+
instance->config[6] = Gen4PollerShadowModeDisabled;
277279
instance->config[24] = iso3_data->atqa[0];
278280
instance->config[25] = iso3_data->atqa[1];
279281
instance->config[26] = iso3_data->sak;
280282
instance->config[27] = 0x00;
281283
instance->config[28] = instance->total_blocks;
282-
instance->config[29] = 0x01;
284+
instance->config[29] = Gen4PollerDirectWriteBlock0ModeDeactivated;
283285

284286
Gen4PollerError error = gen4_poller_set_config(
285287
instance, instance->password, instance->config, sizeof(instance->config), false);
@@ -352,13 +354,13 @@ static NfcCommand gen4_poller_write_mf_ultralight(Gen4Poller* instance) {
352354
break;
353355
}
354356

355-
instance->config[6] = Gen4PollerShadowModeHighSpeedIgnore;
357+
instance->config[6] = Gen4PollerShadowModeHighSpeedDisabled;
356358
instance->config[24] = iso3_data->atqa[0];
357359
instance->config[25] = iso3_data->atqa[1];
358360
instance->config[26] = iso3_data->sak;
359361
instance->config[27] = 0x00;
360362
instance->config[28] = instance->total_blocks;
361-
instance->config[29] = 0x01;
363+
instance->config[29] = Gen4PollerDirectWriteBlock0ModeDeactivated;
362364

363365
Gen4PollerError error = gen4_poller_set_config(
364366
instance, instance->password, instance->config, sizeof(instance->config), false);
@@ -557,6 +559,25 @@ NfcCommand gen4_poller_set_shadow_mode_handler(Gen4Poller* instance) {
557559
return command;
558560
}
559561

562+
NfcCommand gen4_poller_set_direct_write_block_0_mode_handler(Gen4Poller* instance) {
563+
NfcCommand command = NfcCommandContinue;
564+
565+
do {
566+
Gen4PollerError error = gen4_poller_set_direct_write_block_0_mode(
567+
instance, instance->password, instance->direct_write_block_0_mode);
568+
569+
if(error != Gen4PollerErrorNone) {
570+
FURI_LOG_E(TAG, "Failed to set direct write to block 0 mode: %d", error);
571+
instance->state = Gen4PollerStateFail;
572+
break;
573+
}
574+
575+
instance->state = Gen4PollerStateSuccess;
576+
} while(false);
577+
578+
return command;
579+
}
580+
560581
NfcCommand gen4_poller_success_handler(Gen4Poller* instance) {
561582
NfcCommand command = NfcCommandContinue;
562583

@@ -592,6 +613,7 @@ static const Gen4PollerStateHandler gen4_poller_state_handlers[Gen4PollerStateNu
592613
[Gen4PollerStateGetCurrentConfig] = gen4_poller_get_current_cfg_handler,
593614
[Gen4PollerStateGetRevision] = gen4_poller_get_revision_handler,
594615
[Gen4PollerStateSetShadowMode] = gen4_poller_set_shadow_mode_handler,
616+
[Gen4PollerStateSetDirectWriteBlock0] = gen4_poller_set_direct_write_block_0_mode_handler,
595617
[Gen4PollerStateSuccess] = gen4_poller_success_handler,
596618
[Gen4PollerStateFail] = gen4_poller_fail_handler,
597619

nfc_magic/lib/magic/protocols/gen4/gen4_poller.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ typedef enum {
4242
Gen4PollerModeGetCfg,
4343
Gen4PollerModeGetRevision,
4444
Gen4PollerModeSetShadowMode,
45+
Gen4PollerModeSetDirectWriteBlock0Mode
4546
} Gen4PollerMode;
4647

4748
typedef struct {

nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.c

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#define GEN4_CMD_GET_REVISION (0xCC)
1414
#define GEN4_CMD_WRITE (0xCD)
1515
#define GEN4_CMD_READ (0xCE)
16+
#define GEN4_CMD_SET_DW_BLOCK_0 (0xCF)
1617
#define GEN4_CMD_SET_CFG (0xF0)
1718
#define GEN4_CMD_FUSE_CFG (0xF1)
1819
#define GEN4_CMD_SET_PWD (0xFE)
@@ -33,8 +34,10 @@ static Gen4PollerError gen4_poller_process_error(Iso14443_3aError error) {
3334
return ret;
3435
}
3536

36-
Gen4PollerError
37-
gen4_poller_set_shadow_mode(Gen4Poller* instance, uint32_t password, uint8_t mode) {
37+
Gen4PollerError gen4_poller_set_shadow_mode(
38+
Gen4Poller* instance,
39+
uint32_t password,
40+
Gen4PollerShadowMode mode) {
3841
Gen4PollerError ret = Gen4PollerErrorNone;
3942
bit_buffer_reset(instance->tx_buffer);
4043

@@ -68,6 +71,43 @@ Gen4PollerError
6871
return ret;
6972
}
7073

74+
Gen4PollerError gen4_poller_set_direct_write_block_0_mode(
75+
Gen4Poller* instance,
76+
uint32_t password,
77+
Gen4PollerDirectWriteBlock0Mode mode) {
78+
Gen4PollerError ret = Gen4PollerErrorNone;
79+
bit_buffer_reset(instance->tx_buffer);
80+
81+
do {
82+
uint8_t password_arr[4] = {};
83+
nfc_util_num2bytes(password, COUNT_OF(password_arr), password_arr);
84+
bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX);
85+
bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr));
86+
bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_SET_DW_BLOCK_0);
87+
bit_buffer_append_byte(instance->tx_buffer, mode);
88+
89+
Iso14443_3aError error = iso14443_3a_poller_send_standard_frame(
90+
instance->iso3_poller, instance->tx_buffer, instance->rx_buffer, GEN4_POLLER_MAX_FWT);
91+
92+
if(error != Iso14443_3aErrorNone) {
93+
ret = gen4_poller_process_error(error);
94+
break;
95+
}
96+
97+
// size_t rx_bytes = bit_buffer_get_size_bytes(instance->rx_buffer);
98+
// if(rx_bytes != SHD_MODE_RESPONSE_SIZE) {
99+
// ret = Gen4PollerErrorProtocol;
100+
// break;
101+
// }
102+
uint16_t response = bit_buffer_get_size_bytes(instance->rx_buffer);
103+
104+
FURI_LOG_D(TAG, "Card response: %X, Direct write to block 0 mode set: %u", response, mode);
105+
106+
} while(false);
107+
108+
return ret;
109+
}
110+
71111
Gen4PollerError
72112
gen4_poller_get_config(Gen4Poller* instance, uint32_t password, uint8_t* config_result) {
73113
Gen4PollerError ret = Gen4PollerErrorNone;

nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.h

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,23 @@ typedef enum {
3737
Gen4PollerShadowModePreWrite = 0x00,
3838
// written data can be read once before restored to original
3939
Gen4PollerShadowModeRestore = 0x01,
40-
// written data is discarded
41-
Gen4PollerShadowModeIgnore = 0x02,
40+
// shadow mode disabled
41+
Gen4PollerShadowModeDisabled = 0x02,
4242
// apparently for UL?
43-
Gen4PollerShadowModeHighSpeedIgnore = 0x03
43+
Gen4PollerShadowModeHighSpeedDisabled = 0x03,
44+
// work with new UMC. With old UMC is untested
45+
Gen4PollerShadowModeSplit = 0x04,
4446
} Gen4PollerShadowMode;
4547

48+
typedef enum {
49+
// gen2 card behavour
50+
Gen4PollerDirectWriteBlock0ModeActivated = 0x00,
51+
// common card behavour
52+
Gen4PollerDirectWriteBlock0ModeDeactivated = 0x01,
53+
// default mode. same behavour as Gen4PollerDirectWriteBlock0ModeActivate
54+
Gen4PollerDirectWriteBlock0ModeDefault = 0x02,
55+
} Gen4PollerDirectWriteBlock0Mode;
56+
4657
typedef enum {
4758
Gen4PollerStateIdle,
4859
Gen4PollerStateRequestMode,
@@ -55,6 +66,7 @@ typedef enum {
5566
Gen4PollerStateGetCurrentConfig,
5667
Gen4PollerStateGetRevision,
5768
Gen4PollerStateSetShadowMode,
69+
Gen4PollerStateSetDirectWriteBlock0,
5870

5971
Gen4PollerStateSuccess,
6072
Gen4PollerStateFail,
@@ -80,7 +92,8 @@ struct Gen4Poller {
8092

8193
uint8_t config[GEN4_POLLER_CONFIG_SIZE_MAX];
8294

83-
uint8_t shadow_mode;
95+
Gen4PollerShadowMode shadow_mode;
96+
Gen4PollerDirectWriteBlock0Mode direct_write_block_0_mode;
8497

8598
Gen4PollerEvent gen4_event;
8699
Gen4PollerEventData gen4_event_data;
@@ -111,7 +124,13 @@ Gen4PollerError
111124
Gen4PollerError
112125
gen4_poller_get_config(Gen4Poller* instance, uint32_t password, uint8_t* config_result);
113126

114-
Gen4PollerError gen4_poller_set_shadow_mode(Gen4Poller* instance, uint32_t password, uint8_t mode);
127+
Gen4PollerError
128+
gen4_poller_set_shadow_mode(Gen4Poller* instance, uint32_t password, Gen4PollerShadowMode mode);
129+
130+
Gen4PollerError gen4_poller_set_direct_write_block_0_mode(
131+
Gen4Poller* instance,
132+
uint32_t password,
133+
Gen4PollerDirectWriteBlock0Mode mode);
115134

116135
#ifdef __cplusplus
117136
}

nfc_magic/scenes/nfc_magic_scene_config.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ ADD_SCENE(nfc_magic, gen4_show_rev, Gen4ShowRev)
1212
ADD_SCENE(nfc_magic, gen4_show_cfg, Gen4ShowCfg)
1313
ADD_SCENE(nfc_magic, gen4_select_shd_mode, Gen4SelectShdMode)
1414
ADD_SCENE(nfc_magic, gen4_set_shd_mode, Gen4SetShdMode)
15+
ADD_SCENE(nfc_magic, gen4_select_direct_write_block_0_mode, Gen4SelectDirectWriteBlock0Mode)
16+
ADD_SCENE(nfc_magic, gen4_set_direct_write_block_0_mode, Gen4SetDirectWriteBlock0Mode)
1517
ADD_SCENE(nfc_magic, gen4_fail, Gen4Fail)
1618
ADD_SCENE(nfc_magic, wipe, Wipe)
1719
ADD_SCENE(nfc_magic, wipe_fail, WipeFail)

nfc_magic/scenes/nfc_magic_scene_gen4_menu.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ enum SubmenuIndex {
55
SubmenuIndexWrite,
66
SubmenuIndexChangePassword,
77
SubmenuIndexSetShadowMode,
8+
SubmenuIndexSetDirectWriteBlock0Mode,
89
SubmenuIndexGetRevision,
910
SubmenuIndexGetConfig,
1011
SubmenuIndexWipe,
@@ -34,6 +35,12 @@ void nfc_magic_scene_gen4_menu_on_enter(void* context) {
3435
SubmenuIndexSetShadowMode,
3536
nfc_magic_scene_gen4_menu_submenu_callback,
3637
instance);
38+
submenu_add_item(
39+
submenu,
40+
"Set Direct Write To Block 0 Mode",
41+
SubmenuIndexSetDirectWriteBlock0Mode,
42+
nfc_magic_scene_gen4_menu_submenu_callback,
43+
instance);
3744
submenu_add_item(
3845
submenu,
3946
"Get Revision",
@@ -79,6 +86,10 @@ bool nfc_magic_scene_gen4_menu_on_event(void* context, SceneManagerEvent event)
7986
} else if(event.event == SubmenuIndexSetShadowMode) {
8087
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SelectShdMode);
8188
consumed = true;
89+
} else if(event.event == SubmenuIndexSetDirectWriteBlock0Mode) {
90+
scene_manager_next_scene(
91+
instance->scene_manager, NfcMagicSceneGen4SelectDirectWriteBlock0Mode);
92+
consumed = true;
8293
}
8394

8495
scene_manager_set_scene_state(instance->scene_manager, NfcMagicSceneGen4Menu, event.event);
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#include "../nfc_magic_app_i.h"
2+
#include "furi_hal_rtc.h"
3+
#include "protocols/gen4/gen4_poller_i.h"
4+
5+
enum SubmenuIndex {
6+
SubmenuIndexActivate,
7+
SubmenuIndexDeactivate,
8+
SubmenuIndexDefault,
9+
};
10+
11+
void nfc_magic_scene_gen4_select_direct_write_block_0_mode_submenu_callback(
12+
void* context,
13+
uint32_t index) {
14+
NfcMagicApp* instance = context;
15+
16+
view_dispatcher_send_custom_event(instance->view_dispatcher, index);
17+
}
18+
19+
void nfc_magic_scene_gen4_select_direct_write_block_0_mode_on_enter(void* context) {
20+
NfcMagicApp* instance = context;
21+
22+
Submenu* submenu = instance->submenu;
23+
submenu_add_item(
24+
submenu,
25+
"Activate",
26+
SubmenuIndexActivate,
27+
nfc_magic_scene_gen4_select_direct_write_block_0_mode_submenu_callback,
28+
instance);
29+
submenu_add_item(
30+
submenu,
31+
"Deactivate",
32+
SubmenuIndexDeactivate,
33+
nfc_magic_scene_gen4_select_direct_write_block_0_mode_submenu_callback,
34+
instance);
35+
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
36+
submenu_add_item(
37+
submenu,
38+
"Default",
39+
SubmenuIndexDefault,
40+
nfc_magic_scene_gen4_select_direct_write_block_0_mode_submenu_callback,
41+
instance);
42+
}
43+
submenu_set_selected_item(
44+
submenu,
45+
scene_manager_get_scene_state(
46+
instance->scene_manager, NfcMagicSceneGen4SelectDirectWriteBlock0Mode));
47+
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewMenu);
48+
}
49+
50+
bool nfc_magic_scene_gen4_select_direct_write_block_0_mode_on_event(
51+
void* context,
52+
SceneManagerEvent event) {
53+
NfcMagicApp* instance = context;
54+
bool consumed = false;
55+
56+
if(event.type == SceneManagerEventTypeCustom) {
57+
if(event.event == SubmenuIndexActivate) {
58+
scene_manager_set_scene_state(
59+
instance->scene_manager,
60+
NfcMagicSceneGen4SetDirectWriteBlock0Mode,
61+
Gen4PollerDirectWriteBlock0ModeActivated);
62+
scene_manager_next_scene(
63+
instance->scene_manager, NfcMagicSceneGen4SetDirectWriteBlock0Mode);
64+
consumed = true;
65+
} else if(event.event == SubmenuIndexDeactivate) {
66+
scene_manager_set_scene_state(
67+
instance->scene_manager,
68+
NfcMagicSceneGen4SetDirectWriteBlock0Mode,
69+
Gen4PollerDirectWriteBlock0ModeDeactivated);
70+
scene_manager_next_scene(
71+
instance->scene_manager, NfcMagicSceneGen4SetDirectWriteBlock0Mode);
72+
consumed = true;
73+
} else if(event.event == SubmenuIndexDefault) {
74+
scene_manager_set_scene_state(
75+
instance->scene_manager,
76+
NfcMagicSceneGen4SetDirectWriteBlock0Mode,
77+
Gen4PollerDirectWriteBlock0ModeDefault);
78+
scene_manager_next_scene(
79+
instance->scene_manager, NfcMagicSceneGen4SetDirectWriteBlock0Mode);
80+
consumed = true;
81+
}
82+
scene_manager_set_scene_state(
83+
instance->scene_manager, NfcMagicSceneGen4SelectDirectWriteBlock0Mode, event.event);
84+
} else if(event.type == SceneManagerEventTypeBack) {
85+
consumed = scene_manager_search_and_switch_to_previous_scene(
86+
instance->scene_manager, NfcMagicSceneGen4ActionsMenu);
87+
}
88+
89+
return consumed;
90+
}
91+
92+
void nfc_magic_scene_gen4_select_direct_write_block_0_mode_on_exit(void* context) {
93+
NfcMagicApp* instance = context;
94+
95+
submenu_reset(instance->submenu);
96+
}

0 commit comments

Comments
 (0)