Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions applications/main/nfc/helpers/protocol_support/felica/felica.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#include "felica.h"
#include "felica_render.h"

#include <nfc/protocols/felica/felica_poller.h>

#include "nfc/nfc_app_i.h"

#include "../nfc_protocol_support_gui_common.h"

static void nfc_scene_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();
furi_string_cat_printf(
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, 64, furi_string_get_cstr(temp_str));

furi_string_free(temp_str);
}

static NfcCommand nfc_scene_read_poller_callback_felica(NfcGenericEvent event, void* context) {
furi_assert(event.protocol == NfcProtocolFelica);

NfcApp* instance = context;
const FelicaPollerEvent* felica_event = event.data;

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;
}

return NfcCommandContinue;
}

static void nfc_scene_read_on_enter_felica(NfcApp* instance) {
nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_felica, instance);
}

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);

widget_add_text_scroll_element(
instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str));

furi_string_free(temp_str);
}

static bool nfc_scene_info_on_event_felica(NfcApp* instance, uint32_t event) {
if(event == GuiButtonTypeRight) {
scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented);
return true;
}

return false;
}

static bool nfc_scene_saved_menu_on_event_felica(NfcApp* instance, uint32_t event) {
if(event == SubmenuIndexCommonEdit) {
scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid);
return true;
}

return false;
}

const NfcProtocolSupportBase nfc_protocol_support_felica = {
.features = NfcProtocolFeatureNone, // TODO: Implement better UID editing,

.scene_info =
{
.on_enter = nfc_scene_info_on_enter_felica,
.on_event = nfc_scene_info_on_event_felica,
},
.scene_read =
{
.on_enter = nfc_scene_read_on_enter_felica,
.on_event = NULL,
},
.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_felica,
.on_event = NULL,
},
.scene_saved_menu =
{
.on_enter = nfc_protocol_support_common_on_enter_empty,
.on_event = nfc_scene_saved_menu_on_event_felica,
},
.scene_emulate =
{
.on_enter = NULL,
.on_event = NULL,
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once

#include "../nfc_protocol_support_base.h"

extern const NfcProtocolSupportBase nfc_protocol_support_felica;
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "felica_render.h"

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, "\nPMm:");
for(size_t i = 0; i < FELICA_PMM_SIZE; ++i) {
furi_string_cat_printf(str, " %02X", data->pmm.data[i]);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include <nfc/protocols/felica/felica.h>

#include "../nfc_protocol_support_render_common.h"

void nfc_render_felica_info(
const FelicaData* data,
NfcProtocolFormatType format_type,
FuriString* str);
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "iso14443_3b/iso14443_3b.h"
#include "iso14443_4a/iso14443_4a.h"
#include "iso15693_3/iso15693_3.h"
#include "felica/felica.h"
#include "mf_ultralight/mf_ultralight.h"
#include "mf_classic/mf_classic.h"
#include "mf_desfire/mf_desfire.h"
Expand All @@ -13,6 +14,7 @@ const NfcProtocolSupportBase* nfc_protocol_support[NfcProtocolNum] = {
[NfcProtocolIso14443_3b] = &nfc_protocol_support_iso14443_3b,
[NfcProtocolIso14443_4a] = &nfc_protocol_support_iso14443_4a,
[NfcProtocolIso15693_3] = &nfc_protocol_support_iso15693_3,
[NfcProtocolFelica] = &nfc_protocol_support_felica,
[NfcProtocolMfUltralight] = &nfc_protocol_support_mf_ultralight,
[NfcProtocolMfClassic] = &nfc_protocol_support_mf_classic,
[NfcProtocolMfDesfire] = &nfc_protocol_support_mf_desfire,
Expand Down
2 changes: 0 additions & 2 deletions applications/main/nfc/nfc_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ NfcApp* nfc_app_alloc() {
instance->view_dispatcher, nfc_back_event_callback);

instance->nfc = nfc_alloc();
instance->scanner = nfc_scanner_alloc(instance->nfc);

instance->mf_ul_auth = mf_ultralight_auth_alloc();

Expand Down Expand Up @@ -147,7 +146,6 @@ void nfc_app_free(NfcApp* instance) {
}

nfc_free(instance->nfc);
nfc_scanner_free(instance->scanner);

mf_ultralight_auth_free(instance->mf_ul_auth);

Expand Down
1 change: 0 additions & 1 deletion applications/main/nfc/scenes/nfc_scene_delete.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ void nfc_scene_delete_on_enter(void* context) {
furi_string_set_str(temp_str, nfc_device_get_name(nfc->nfc_device, NfcDeviceNameTypeFull));
widget_add_string_element(
nfc->widget, 64, 34, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str));
widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, "NFC-A");
furi_string_free(temp_str);

view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
Expand Down
2 changes: 2 additions & 0 deletions applications/main/nfc/scenes/nfc_scene_detect.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ void nfc_scene_detect_on_enter(void* context) {

nfc_app_reset_detected_protocols(instance);

instance->scanner = nfc_scanner_alloc(instance->nfc);
nfc_scanner_start(instance->scanner, nfc_scene_detect_scan_callback, instance);

nfc_blink_detect_start(instance);
Expand Down Expand Up @@ -53,6 +54,7 @@ void nfc_scene_detect_on_exit(void* context) {
NfcApp* instance = context;

nfc_scanner_stop(instance->scanner);
nfc_scanner_free(instance->scanner);
popup_reset(instance->popup);

nfc_blink_stop(instance);
Expand Down
1 change: 1 addition & 0 deletions applications/main/nfc/scenes/nfc_scene_select_protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ void nfc_scene_select_protocol_on_enter(void* context) {
} else {
prefix = "Read as";
submenu_set_header(submenu, "Multi-protocol card");
notification_message(instance->notifications, &sequence_single_vibro);
}

for(size_t i = 0; i < instance->protocols_detected_num; i++) {
Expand Down
62 changes: 62 additions & 0 deletions firmware/targets/f7/furi_hal/f_hal_nfc.c
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,46 @@ FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate) {
st25r3916_write_reg(
handle, ST25R3916_REG_CORR_CONF2, ST25R3916_REG_CORR_CONF2_corr_s8);
}
} else if(mode == FHalNfcModeFelicaPoller) {
f_hal_nfc_configure_poller_common(handle);
// Enable Felica mode, AM modulation
st25r3916_change_reg_bits(
handle,
ST25R3916_REG_MODE,
ST25R3916_REG_MODE_om_mask | ST25R3916_REG_MODE_tr_am,
ST25R3916_REG_MODE_om_felica | ST25R3916_REG_MODE_tr_am_am);

// 10% ASK modulation
st25r3916_change_reg_bits(
handle,
ST25R3916_REG_TX_DRIVER,
ST25R3916_REG_TX_DRIVER_am_mod_mask,
ST25R3916_REG_TX_DRIVER_am_mod_10percent);

// Use regulator AM, resistive AM disabled
st25r3916_clear_reg_bits(
handle,
ST25R3916_REG_AUX_MOD,
ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am);

st25r3916_change_reg_bits(
handle,
ST25R3916_REG_BIT_RATE,
ST25R3916_REG_BIT_RATE_txrate_mask | ST25R3916_REG_BIT_RATE_rxrate_mask,
ST25R3916_REG_BIT_RATE_txrate_212 | ST25R3916_REG_BIT_RATE_rxrate_212);

// Receive configuration
st25r3916_write_reg(
handle,
ST25R3916_REG_RX_CONF1,
ST25R3916_REG_RX_CONF1_lp0 | ST25R3916_REG_RX_CONF1_hz_12_80khz);

// Correlator setup
st25r3916_write_reg(
handle,
ST25R3916_REG_CORR_CONF1,
ST25R3916_REG_CORR_CONF1_corr_s6 | ST25R3916_REG_CORR_CONF1_corr_s4 |
ST25R3916_REG_CORR_CONF1_corr_s3);
}

return error;
Expand All @@ -543,7 +583,29 @@ FHalNfcError f_hal_nfc_reset_mode() {
st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP);
// Set default value in mode register
st25r3916_write_reg(handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_om0);
st25r3916_write_reg(handle, ST25R3916_REG_STREAM_MODE, 0);

st25r3916_clear_reg_bits(handle, ST25R3916_REG_AUX, ST25R3916_REG_AUX_no_crc_rx);
st25r3916_clear_reg_bits(
handle,
ST25R3916_REG_BIT_RATE,
ST25R3916_REG_BIT_RATE_txrate_mask | ST25R3916_REG_BIT_RATE_rxrate_mask);

// Write default values
st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF1, 0);
st25r3916_write_reg(
handle,
ST25R3916_REG_RX_CONF2,
ST25R3916_REG_RX_CONF2_sqm_dyn | ST25R3916_REG_RX_CONF2_agc_en |
ST25R3916_REG_RX_CONF2_agc_m);

st25r3916_write_reg(
handle,
ST25R3916_REG_CORR_CONF1,
ST25R3916_REG_CORR_CONF1_corr_s7 | ST25R3916_REG_CORR_CONF1_corr_s4 |
ST25R3916_REG_CORR_CONF1_corr_s1 | ST25R3916_REG_CORR_CONF1_corr_s0);
st25r3916_write_reg(handle, ST25R3916_REG_CORR_CONF2, 0);

f_hal_nfca_listener_deinit();

return error;
Expand Down
4 changes: 2 additions & 2 deletions firmware/targets/f7/furi_hal/f_hal_nfc_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ static FHalNfcTimerConfig f_hal_nfc_timers[FHalNfcTimerCount] = {
.pin = &gpio_ext_pa6,
.timer = TIM17,
.bus = FuriHalBusTIM17,
.prescaler = 15,
.freq_khz = 4000U,
.prescaler = 31,
.freq_khz = 2000U,
.event = FHalNfcEventInternalTypeTimerBlockTxExpired,
.irq_id = FuriHalInterruptIdTim1TrgComTim17,
.irq_type = TIM1_TRG_COM_TIM17_IRQn,
Expand Down
2 changes: 1 addition & 1 deletion firmware/targets/furi_hal_include/f_hal_nfc.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ typedef enum {
FHalNfcModeIso14443bPoller,
FHalNfcModeIso14443bListener,

FHalNfcModeNfcfPoller,
FHalNfcModeFelicaPoller,
FHalNfcModeNfcfListener,

FHalNfcModeIso15693Poller,
Expand Down
52 changes: 52 additions & 0 deletions lib/nfc/helpers/felica_crc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include "felica_crc.h"

#include <furi/furi.h>

#define FELICA_CRC_POLY (0x1021U) // Polynomial: x^16 + x^12 + x^5 + 1
#define FELICA_CRC_INIT (0x0000U)

uint16_t felica_crc_calculate(const uint8_t* data, size_t length) {
uint16_t crc = FELICA_CRC_INIT;

for(size_t i = 0; i < length; i++) {
crc ^= ((uint16_t)data[i] << 8);
for(size_t j = 0; j < 8; j++) {
if(crc & 0x8000) {
crc <<= 1;
crc ^= FELICA_CRC_POLY;
} else {
crc <<= 1;
}
}
}

return (crc << 8) | (crc >> 8);
}

void felica_crc_append(BitBuffer* buf) {
const uint8_t* data = bit_buffer_get_data(buf);
const size_t data_size = bit_buffer_get_size_bytes(buf);

const uint16_t crc = felica_crc_calculate(data, data_size);
bit_buffer_append_bytes(buf, (const uint8_t*)&crc, FELICA_CRC_SIZE);
}

bool felica_crc_check(const BitBuffer* buf) {
const size_t data_size = bit_buffer_get_size_bytes(buf);
if(data_size <= FELICA_CRC_SIZE) return false;

uint16_t crc_received;
bit_buffer_write_bytes_mid(buf, &crc_received, data_size - FELICA_CRC_SIZE, FELICA_CRC_SIZE);

const uint8_t* data = bit_buffer_get_data(buf);
const uint16_t crc_calc = felica_crc_calculate(data, data_size - FELICA_CRC_SIZE);

return (crc_calc == crc_received);
}

void felica_crc_trim(BitBuffer* buf) {
const size_t data_size = bit_buffer_get_size_bytes(buf);
furi_assert(data_size > FELICA_CRC_SIZE);

bit_buffer_set_size_bytes(buf, data_size - FELICA_CRC_SIZE);
}
22 changes: 22 additions & 0 deletions lib/nfc/helpers/felica_crc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include <stdint.h>
#include <stddef.h>

#include "bit_buffer.h"

#ifdef __cplusplus
extern "C" {
#endif

#define FELICA_CRC_SIZE sizeof(uint16_t)

void felica_crc_append(BitBuffer* buf);

bool felica_crc_check(const BitBuffer* buf);

void felica_crc_trim(BitBuffer* buf);

#ifdef __cplusplus
}
#endif
3 changes: 3 additions & 0 deletions lib/nfc/nfc.c
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@ void nfc_config(Nfc* instance, NfcMode mode) {
f_hal_nfc_low_power_mode_stop();
f_hal_nfc_set_mode(FHalNfcModeIso15693Listener, FHalNfcBitrate26p48);
instance->config_state = NfcConfigurationStateDone;
} else if(mode == NfcModeFelicaPoller) {
f_hal_nfc_set_mode(FHalNfcModeFelicaPoller, FHalNfcBitrate106);
instance->config_state = NfcConfigurationStateDone;
}
}

Expand Down
Loading