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
19 changes: 19 additions & 0 deletions lib/nfc/nfc.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

#define NFC_MAX_BUFFER_SIZE (256)

#define NFC_FELICA_LISTENER_RESPONSE_TIME_A_FC (512 * 64)
#define NFC_FELICA_LISTENER_RESPONSE_TIME_B_FC (256 * 64)

typedef enum {
NfcStateIdle,
NfcStateRunning,
Expand Down Expand Up @@ -661,4 +664,20 @@ NfcError nfc_felica_listener_set_sensf_res_data(
return nfc_process_hal_error(error);
}

void nfc_felica_listener_timer_anticol_start(Nfc* instance, uint8_t target_time_slot) {
furi_check(instance);

furi_hal_nfc_timer_block_tx_start(
NFC_FELICA_LISTENER_RESPONSE_TIME_A_FC +
target_time_slot * NFC_FELICA_LISTENER_RESPONSE_TIME_B_FC);
}

void nfc_felica_listener_timer_anticol_stop(Nfc* instance) {
furi_check(instance);

if(furi_hal_nfc_timer_block_tx_is_running()) {
furi_hal_nfc_timer_block_tx_stop();
}
}

#endif // FW_CFG_unit_tests
18 changes: 18 additions & 0 deletions lib/nfc/nfc.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,24 @@ NfcError nfc_felica_listener_set_sensf_res_data(
*/
NfcError nfc_iso15693_listener_tx_sof(Nfc* instance);

/**
* @brief Start the timer used for manual FeliCa collision resolution in listener mode.
*
* This blocks TX until the desired Time Slot, and should be called as soon as the listener
* determines that a collision resolution needs to be handled manually.
*
* @param[in, out] instance instance pointer to the instance to be configured.
* @param[in] target_time_slot Target Time Slot number. Should be a value within the range of 0-15 (double-inclusive).
*/
void nfc_felica_listener_timer_anticol_start(Nfc* instance, uint8_t target_time_slot);

/**
* @brief Cancel the timer used for manual FeliCa collision resolution in listener mode.
*
* @param[in, out] instance instance pointer to the instance to be configured.
*/
void nfc_felica_listener_timer_anticol_stop(Nfc* instance);

#ifdef __cplusplus
}
#endif
10 changes: 10 additions & 0 deletions lib/nfc/nfc_mock.c
Original file line number Diff line number Diff line change
Expand Up @@ -518,4 +518,14 @@ NfcError nfc_felica_listener_set_sensf_res_data(
return NfcErrorNone;
}

void nfc_felica_listener_timer_anticol_start(Nfc* instance, uint8_t target_time_slot) {
furi_check(instance);

UNUSED(target_time_slot);
}

void nfc_felica_listener_timer_anticol_stop(Nfc* instance) {
furi_check(instance);
}

#endif
3 changes: 2 additions & 1 deletion lib/nfc/protocols/felica/felica.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ extern "C" {
#define FELICA_FDT_POLL_FC (10000U)
#define FELICA_POLL_POLL_MIN_US (1280U)

#define FELICA_FDT_LISTEN_FC (1172)
#define FELICA_FDT_LISTEN_FC (0)

#define FELICA_SYSTEM_CODE_CODE (0xFFFFU)
#define FELICA_TIME_SLOT_1 (0x00U)
Expand All @@ -58,6 +58,7 @@ typedef enum {
FelicaErrorWrongCrc,
FelicaErrorProtocol,
FelicaErrorTimeout,
FelicaErrorFeatureUnsupported,
} FelicaError;

typedef struct {
Expand Down
93 changes: 92 additions & 1 deletion lib/nfc/protocols/felica/felica_listener.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,20 @@
#include <furi_hal_nfc.h>

#define FELICA_LISTENER_MAX_BUFFER_SIZE (128)
#define FELICA_LISTENER_CMD_POLLING (0x00U)
#define FELICA_LISTENER_RESPONSE_POLLING (0x01U)
#define FELICA_LISTENER_RESPONSE_CODE_READ (0x07)
#define FELICA_LISTENER_RESPONSE_CODE_WRITE (0x09)

#define FELICA_LISTENER_REQUEST_NONE (0x00U)
#define FELICA_LISTENER_REQUEST_SYSTEM_CODE (0x01U)
#define FELICA_LISTENER_REQUEST_PERFORMANCE (0x02U)

#define FELICA_LISTENER_SYSTEM_CODE_NDEF (__builtin_bswap16(0x12FCU))
#define FELICA_LISTENER_SYSTEM_CODE_LITES (__builtin_bswap16(0x88B4U))

#define FELICA_LISTENER_PERFORMANCE_VALUE (__builtin_bswap16(0x0083U))

#define TAG "FelicaListener"

FelicaListener* felica_listener_alloc(Nfc* nfc, FelicaData* data) {
Expand Down Expand Up @@ -151,6 +162,70 @@ static FelicaError felica_listener_process_request(
}
}

static void felica_listener_populate_polling_response_header(
FelicaListener* instance,
FelicaListenerPollingResponseHeader* resp) {
resp->idm = instance->data->idm;
resp->pmm = instance->data->pmm;
resp->response_code = FELICA_LISTENER_RESPONSE_POLLING;
}

static bool felica_listener_check_system_code(
const FelicaListenerGenericRequest* const generic_request,
uint16_t code) {
return (
generic_request->polling.system_code == code ||
generic_request->polling.system_code == (code | 0x00FFU) ||
generic_request->polling.system_code == (code | 0xFF00U));
}

static uint16_t felica_listener_get_response_system_code(
FelicaListener* instance,
const FelicaListenerGenericRequest* const generic_request) {
uint16_t resp_system_code = FELICA_SYSTEM_CODE_CODE;
if(felica_listener_check_system_code(generic_request, FELICA_LISTENER_SYSTEM_CODE_NDEF) &&
instance->data->data.fs.mc.data[FELICA_MC_SYS_OP] == 1) {
// NDEF
resp_system_code = FELICA_LISTENER_SYSTEM_CODE_NDEF;
} else if(felica_listener_check_system_code(
generic_request, FELICA_LISTENER_SYSTEM_CODE_LITES)) {
// Lite-S
resp_system_code = FELICA_LISTENER_SYSTEM_CODE_LITES;
}
return resp_system_code;
}

static FelicaError felica_listener_process_system_code(
FelicaListener* instance,
const FelicaListenerGenericRequest* const generic_request) {
FelicaError result = FelicaErrorFeatureUnsupported;
do {
uint16_t resp_system_code =
felica_listener_get_response_system_code(instance, generic_request);
if(resp_system_code == FELICA_SYSTEM_CODE_CODE) break;

FelicaListenerPollingResponse* resp = malloc(sizeof(FelicaListenerPollingResponse));
felica_listener_populate_polling_response_header(instance, &resp->header);

resp->header.length = sizeof(FelicaListenerPollingResponse);
if(generic_request->polling.request_code == FELICA_LISTENER_REQUEST_SYSTEM_CODE) {
resp->optional_request_data = resp_system_code;
} else if(generic_request->polling.request_code == FELICA_LISTENER_REQUEST_PERFORMANCE) {
resp->optional_request_data = FELICA_LISTENER_PERFORMANCE_VALUE;
} else {
resp->header.length = sizeof(FelicaListenerPollingResponseHeader);
}

bit_buffer_reset(instance->tx_buffer);
bit_buffer_append_bytes(instance->tx_buffer, (uint8_t*)resp, resp->header.length);
free(resp);

result = felica_listener_frame_exchange(instance, instance->tx_buffer);
} while(false);

return result;
}

NfcCommand felica_listener_run(NfcGenericEvent event, void* context) {
furi_assert(context);
furi_assert(event.protocol == NfcProtocolInvalid);
Expand Down Expand Up @@ -187,7 +262,23 @@ NfcCommand felica_listener_run(NfcGenericEvent event, void* context) {
break;
}

if(!felica_listener_check_idm(instance, &request->header.idm)) {
if(request->header.code == FELICA_LISTENER_CMD_POLLING) {
// Will always respond at Time Slot 0 for now.
nfc_felica_listener_timer_anticol_start(instance->nfc, 0);
if(request->polling.system_code != FELICA_SYSTEM_CODE_CODE) {
FelicaError error = felica_listener_process_system_code(instance, request);
if(error == FelicaErrorFeatureUnsupported) {
command = NfcCommandReset;
} else if(error != FelicaErrorNone) {
FURI_LOG_E(
TAG, "Error when handling Polling with System Code: %2X", error);
}
break;
} else {
FURI_LOG_E(TAG, "Hardware Polling command leaking through");
break;
}
} else if(!felica_listener_check_idm(instance, &request->header.idm)) {
FURI_LOG_E(TAG, "Wrong IDm");
break;
}
Expand Down
13 changes: 0 additions & 13 deletions lib/nfc/protocols/felica/felica_listener_i.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,6 @@
#define FELICA_WCNT_MC2_00_WARNING_BEGIN_VALUE (0x00001027U)
#define FELICA_WCNT_MC2_00_WARNING_END_VALUE (0x00FFFDFFU)

#define FELICA_MC_SP_REG_ALL_RW_BYTES_0_1 (0U)
#define FELICA_MC_ALL_BYTE (2U)
#define FELICA_MC_SYS_OP (3U)
#define FELICA_MC_RF_PRM (4U)
#define FELICA_MC_CKCKV_W_MAC_A (5U)
#define FELICA_MC_SP_REG_R_RESTR_BYTES_6_7 (6U)
#define FELICA_MC_SP_REG_W_RESTR_BYTES_8_9 (8U)
#define FELICA_MC_SP_REG_W_MAC_A_BYTES_10_11 (10U)
#define FELICA_MC_STATE_W_MAC_A (12U)
#define FELICA_MC_RESERVED_13 (13U)
#define FELICA_MC_RESERVED_14 (14U)
#define FELICA_MC_RESERVED_15 (15U)

#define FELICA_MC_BYTE_GET(data, byte) (data->data.fs.mc.data[byte])
#define FELICA_SYSTEM_BLOCK_RO_ACCESS(data) (FELICA_MC_BYTE_GET(data, FELICA_MC_ALL_BYTE) == 0x00)
#define FELICA_SYSTEM_BLOCK_RW_ACCESS(data) (FELICA_MC_BYTE_GET(data, FELICA_MC_ALL_BYTE) == 0xFF)
Expand Down
37 changes: 36 additions & 1 deletion lib/nfc/protocols/felica/felica_listener_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,50 @@
#define FELICA_LISTENER_WRITE_BLOCK_COUNT_MAX (2U)
#define FELICA_LISTENER_WRITE_BLOCK_COUNT_MIN (1U)

#define FELICA_MC_SP_REG_ALL_RW_BYTES_0_1 (0U)
#define FELICA_MC_ALL_BYTE (2U)
#define FELICA_MC_SYS_OP (3U)
#define FELICA_MC_RF_PRM (4U)
#define FELICA_MC_CKCKV_W_MAC_A (5U)
#define FELICA_MC_SP_REG_R_RESTR_BYTES_6_7 (6U)
#define FELICA_MC_SP_REG_W_RESTR_BYTES_8_9 (8U)
#define FELICA_MC_SP_REG_W_MAC_A_BYTES_10_11 (10U)
#define FELICA_MC_STATE_W_MAC_A (12U)
#define FELICA_MC_RESERVED_13 (13U)
#define FELICA_MC_RESERVED_14 (14U)
#define FELICA_MC_RESERVED_15 (15U)

typedef enum {
Felica_ListenerStateIdle,
Felica_ListenerStateActivated,
} FelicaListenerState;

typedef struct FURI_PACKED {
uint8_t code;
uint16_t system_code;
uint8_t request_code;
uint8_t time_slot;
} FelicaListenerPollingHeader;

typedef struct {
uint8_t length;
uint8_t response_code;
FelicaIDm idm;
FelicaPMm pmm;
} FelicaListenerPollingResponseHeader;

typedef struct FURI_PACKED {
FelicaListenerPollingResponseHeader header;
uint16_t optional_request_data;
} FelicaListenerPollingResponse;

/** Generic Felica request same for both read and write operations. */
typedef struct {
uint8_t length;
FelicaCommandHeader header;
union {
FelicaCommandHeader header;
FelicaListenerPollingHeader polling;
};
} FelicaListenerGenericRequest;

/** Generic request but with list of requested elements. */
Expand Down
2 changes: 1 addition & 1 deletion targets/f18/api_symbols.csv
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,86.0,,
Version,+,86.1,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
Header,+,applications/services/cli/cli.h,,
Expand Down
4 changes: 3 additions & 1 deletion targets/f7/api_symbols.csv
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,86.0,,
Version,+,86.1,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
Expand Down Expand Up @@ -2859,6 +2859,8 @@ Function,+,nfc_device_set_data,void,"NfcDevice*, NfcProtocol, const NfcDeviceDat
Function,+,nfc_device_set_loading_callback,void,"NfcDevice*, NfcLoadingCallback, void*"
Function,+,nfc_device_set_uid,_Bool,"NfcDevice*, const uint8_t*, size_t"
Function,+,nfc_felica_listener_set_sensf_res_data,NfcError,"Nfc*, const uint8_t*, const uint8_t, const uint8_t*, const uint8_t, const uint16_t"
Function,+,nfc_felica_listener_timer_anticol_start,void,"Nfc*, uint8_t"
Function,+,nfc_felica_listener_timer_anticol_stop,void,Nfc*
Function,+,nfc_free,void,Nfc*
Function,+,nfc_iso14443a_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t"
Function,+,nfc_iso14443a_listener_tx_custom_parity,NfcError,"Nfc*, const BitBuffer*"
Expand Down
3 changes: 1 addition & 2 deletions targets/f7/furi_hal/furi_hal_nfc_felica.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#include "furi_hal_nfc_i.h"
#include "furi_hal_nfc_tech_i.h"

// Prevent FDT timer from starting
#define FURI_HAL_NFC_FELICA_LISTENER_FDT_COMP_FC (INT32_MAX)
#define FURI_HAL_NFC_FELICA_LISTENER_FDT_COMP_FC (0)

#define FURI_HAL_FELICA_COMMUNICATION_PERFORMANCE (0x0083U)
#define FURI_HAL_FELICA_RESPONSE_CODE (0x01)
Expand Down
Loading