* mf classic listener: fix write block * nfc: go to idle state instead of sleep * lib nfc: fix documentation
		
			
				
	
	
		
			666 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			666 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#ifndef FW_CFG_unit_tests
 | 
						|
 | 
						|
#include "nfc.h"
 | 
						|
 | 
						|
#include <furi_hal_nfc.h>
 | 
						|
#include <furi/furi.h>
 | 
						|
 | 
						|
#define TAG "Nfc"
 | 
						|
 | 
						|
#define NFC_MAX_BUFFER_SIZE (256)
 | 
						|
 | 
						|
typedef enum {
 | 
						|
    NfcStateIdle,
 | 
						|
    NfcStateRunning,
 | 
						|
} NfcState;
 | 
						|
 | 
						|
typedef enum {
 | 
						|
    NfcPollerStateStart,
 | 
						|
    NfcPollerStateReady,
 | 
						|
    NfcPollerStateReset,
 | 
						|
    NfcPollerStateStop,
 | 
						|
 | 
						|
    NfcPollerStateNum,
 | 
						|
} NfcPollerState;
 | 
						|
 | 
						|
typedef enum {
 | 
						|
    NfcCommStateIdle,
 | 
						|
    NfcCommStateWaitBlockTxTimer,
 | 
						|
    NfcCommStateReadyTx,
 | 
						|
    NfcCommStateWaitTxEnd,
 | 
						|
    NfcCommStateWaitRxStart,
 | 
						|
    NfcCommStateWaitRxEnd,
 | 
						|
    NfcCommStateFailed,
 | 
						|
} NfcCommState;
 | 
						|
 | 
						|
typedef enum {
 | 
						|
    NfcConfigurationStateIdle,
 | 
						|
    NfcConfigurationStateDone,
 | 
						|
} NfcConfigurationState;
 | 
						|
 | 
						|
struct Nfc {
 | 
						|
    NfcState state;
 | 
						|
    NfcPollerState poller_state;
 | 
						|
    NfcCommState comm_state;
 | 
						|
    NfcConfigurationState config_state;
 | 
						|
    NfcMode mode;
 | 
						|
 | 
						|
    uint32_t fdt_listen_fc;
 | 
						|
    uint32_t mask_rx_time_fc;
 | 
						|
    uint32_t fdt_poll_fc;
 | 
						|
    uint32_t fdt_poll_poll_us;
 | 
						|
    uint32_t guard_time_us;
 | 
						|
    NfcEventCallback callback;
 | 
						|
    void* context;
 | 
						|
 | 
						|
    uint8_t tx_buffer[NFC_MAX_BUFFER_SIZE];
 | 
						|
    size_t tx_bits;
 | 
						|
    uint8_t rx_buffer[NFC_MAX_BUFFER_SIZE];
 | 
						|
    size_t rx_bits;
 | 
						|
 | 
						|
    FuriThread* worker_thread;
 | 
						|
};
 | 
						|
 | 
						|
typedef bool (*NfcWorkerPollerStateHandler)(Nfc* instance);
 | 
						|
 | 
						|
static const FuriHalNfcTech nfc_tech_table[NfcModeNum][NfcTechNum] = {
 | 
						|
    [NfcModePoller] =
 | 
						|
        {
 | 
						|
            [NfcTechIso14443a] = FuriHalNfcTechIso14443a,
 | 
						|
            [NfcTechIso14443b] = FuriHalNfcTechIso14443b,
 | 
						|
            [NfcTechIso15693] = FuriHalNfcTechIso15693,
 | 
						|
            [NfcTechFelica] = FuriHalNfcTechFelica,
 | 
						|
        },
 | 
						|
    [NfcModeListener] =
 | 
						|
        {
 | 
						|
            [NfcTechIso14443a] = FuriHalNfcTechIso14443a,
 | 
						|
            [NfcTechIso14443b] = FuriHalNfcTechInvalid,
 | 
						|
            [NfcTechIso15693] = FuriHalNfcTechIso15693,
 | 
						|
            [NfcTechFelica] = FuriHalNfcTechFelica,
 | 
						|
        },
 | 
						|
};
 | 
						|
 | 
						|
static NfcError nfc_process_hal_error(FuriHalNfcError error) {
 | 
						|
    NfcError ret = NfcErrorNone;
 | 
						|
 | 
						|
    switch(error) {
 | 
						|
    case FuriHalNfcErrorNone:
 | 
						|
        ret = NfcErrorNone;
 | 
						|
        break;
 | 
						|
    case FuriHalNfcErrorIncompleteFrame:
 | 
						|
        ret = NfcErrorIncompleteFrame;
 | 
						|
        break;
 | 
						|
    case FuriHalNfcErrorDataFormat:
 | 
						|
        ret = NfcErrorDataFormat;
 | 
						|
        break;
 | 
						|
 | 
						|
    default:
 | 
						|
        ret = NfcErrorInternal;
 | 
						|
    }
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
static int32_t nfc_worker_listener(void* context) {
 | 
						|
    furi_assert(context);
 | 
						|
 | 
						|
    Nfc* instance = context;
 | 
						|
    furi_assert(instance->callback);
 | 
						|
    furi_assert(instance->config_state == NfcConfigurationStateDone);
 | 
						|
 | 
						|
    instance->state = NfcStateRunning;
 | 
						|
 | 
						|
    furi_hal_nfc_event_start();
 | 
						|
 | 
						|
    NfcEventData event_data = {};
 | 
						|
    event_data.buffer = bit_buffer_alloc(NFC_MAX_BUFFER_SIZE);
 | 
						|
    NfcEvent nfc_event = {.data = event_data};
 | 
						|
    NfcCommand command = NfcCommandContinue;
 | 
						|
 | 
						|
    while(true) {
 | 
						|
        FuriHalNfcEvent event = furi_hal_nfc_listener_wait_event(FURI_HAL_NFC_EVENT_WAIT_FOREVER);
 | 
						|
        if(event & FuriHalNfcEventAbortRequest) {
 | 
						|
            nfc_event.type = NfcEventTypeUserAbort;
 | 
						|
            instance->callback(nfc_event, instance->context);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        if(event & FuriHalNfcEventFieldOn) {
 | 
						|
            nfc_event.type = NfcEventTypeFieldOn;
 | 
						|
            instance->callback(nfc_event, instance->context);
 | 
						|
        }
 | 
						|
        if(event & FuriHalNfcEventFieldOff) {
 | 
						|
            nfc_event.type = NfcEventTypeFieldOff;
 | 
						|
            instance->callback(nfc_event, instance->context);
 | 
						|
            furi_hal_nfc_listener_idle();
 | 
						|
        }
 | 
						|
        if(event & FuriHalNfcEventListenerActive) {
 | 
						|
            nfc_event.type = NfcEventTypeListenerActivated;
 | 
						|
            instance->callback(nfc_event, instance->context);
 | 
						|
        }
 | 
						|
        if(event & FuriHalNfcEventRxEnd) {
 | 
						|
            furi_hal_nfc_timer_block_tx_start(instance->fdt_listen_fc);
 | 
						|
 | 
						|
            nfc_event.type = NfcEventTypeRxEnd;
 | 
						|
            furi_hal_nfc_listener_rx(
 | 
						|
                instance->rx_buffer, sizeof(instance->rx_buffer), &instance->rx_bits);
 | 
						|
            bit_buffer_copy_bits(event_data.buffer, instance->rx_buffer, instance->rx_bits);
 | 
						|
            command = instance->callback(nfc_event, instance->context);
 | 
						|
            if(command == NfcCommandStop) {
 | 
						|
                break;
 | 
						|
            } else if(command == NfcCommandReset) {
 | 
						|
                furi_hal_nfc_listener_enable_rx();
 | 
						|
            } else if(command == NfcCommandSleep) {
 | 
						|
                furi_hal_nfc_listener_idle();
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    furi_hal_nfc_reset_mode();
 | 
						|
    instance->config_state = NfcConfigurationStateIdle;
 | 
						|
 | 
						|
    bit_buffer_free(event_data.buffer);
 | 
						|
    furi_hal_nfc_low_power_mode_start();
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
bool nfc_worker_poller_start_handler(Nfc* instance) {
 | 
						|
    furi_hal_nfc_poller_field_on();
 | 
						|
    if(instance->guard_time_us) {
 | 
						|
        furi_hal_nfc_timer_block_tx_start_us(instance->guard_time_us);
 | 
						|
        FuriHalNfcEvent event = furi_hal_nfc_poller_wait_event(FURI_HAL_NFC_EVENT_WAIT_FOREVER);
 | 
						|
        furi_assert(event & FuriHalNfcEventTimerBlockTxExpired);
 | 
						|
    }
 | 
						|
    instance->poller_state = NfcPollerStateReady;
 | 
						|
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
bool nfc_worker_poller_ready_handler(Nfc* instance) {
 | 
						|
    NfcCommand command = NfcCommandContinue;
 | 
						|
 | 
						|
    NfcEvent event = {.type = NfcEventTypePollerReady};
 | 
						|
    command = instance->callback(event, instance->context);
 | 
						|
    if(command == NfcCommandReset) {
 | 
						|
        instance->poller_state = NfcPollerStateReset;
 | 
						|
    } else if(command == NfcCommandStop) {
 | 
						|
        instance->poller_state = NfcPollerStateStop;
 | 
						|
    }
 | 
						|
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
bool nfc_worker_poller_reset_handler(Nfc* instance) {
 | 
						|
    furi_hal_nfc_low_power_mode_start();
 | 
						|
    furi_delay_ms(100);
 | 
						|
    furi_hal_nfc_low_power_mode_stop();
 | 
						|
    instance->poller_state = NfcPollerStateStart;
 | 
						|
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
bool nfc_worker_poller_stop_handler(Nfc* instance) {
 | 
						|
    furi_hal_nfc_reset_mode();
 | 
						|
    instance->config_state = NfcConfigurationStateIdle;
 | 
						|
 | 
						|
    furi_hal_nfc_low_power_mode_start();
 | 
						|
    // Wait after field is off some time to reset tag power
 | 
						|
    furi_delay_ms(10);
 | 
						|
    instance->poller_state = NfcPollerStateStart;
 | 
						|
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
static const NfcWorkerPollerStateHandler nfc_worker_poller_state_handlers[NfcPollerStateNum] = {
 | 
						|
    [NfcPollerStateStart] = nfc_worker_poller_start_handler,
 | 
						|
    [NfcPollerStateReady] = nfc_worker_poller_ready_handler,
 | 
						|
    [NfcPollerStateReset] = nfc_worker_poller_reset_handler,
 | 
						|
    [NfcPollerStateStop] = nfc_worker_poller_stop_handler,
 | 
						|
};
 | 
						|
 | 
						|
static int32_t nfc_worker_poller(void* context) {
 | 
						|
    furi_assert(context);
 | 
						|
 | 
						|
    Nfc* instance = context;
 | 
						|
    furi_assert(instance->callback);
 | 
						|
    instance->state = NfcStateRunning;
 | 
						|
    instance->poller_state = NfcPollerStateStart;
 | 
						|
 | 
						|
    furi_hal_nfc_event_start();
 | 
						|
 | 
						|
    bool exit = false;
 | 
						|
    while(!exit) {
 | 
						|
        exit = nfc_worker_poller_state_handlers[instance->poller_state](instance);
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
Nfc* nfc_alloc() {
 | 
						|
    furi_check(furi_hal_nfc_acquire() == FuriHalNfcErrorNone);
 | 
						|
 | 
						|
    Nfc* instance = malloc(sizeof(Nfc));
 | 
						|
    instance->state = NfcStateIdle;
 | 
						|
    instance->comm_state = NfcCommStateIdle;
 | 
						|
    instance->config_state = NfcConfigurationStateIdle;
 | 
						|
 | 
						|
    instance->worker_thread = furi_thread_alloc();
 | 
						|
    furi_thread_set_name(instance->worker_thread, "NfcWorker");
 | 
						|
    furi_thread_set_context(instance->worker_thread, instance);
 | 
						|
    furi_thread_set_priority(instance->worker_thread, FuriThreadPriorityHighest);
 | 
						|
    furi_thread_set_stack_size(instance->worker_thread, 8 * 1024);
 | 
						|
 | 
						|
    return instance;
 | 
						|
}
 | 
						|
 | 
						|
void nfc_free(Nfc* instance) {
 | 
						|
    furi_assert(instance);
 | 
						|
    furi_assert(instance->state == NfcStateIdle);
 | 
						|
 | 
						|
    furi_thread_free(instance->worker_thread);
 | 
						|
    free(instance);
 | 
						|
 | 
						|
    furi_hal_nfc_release();
 | 
						|
}
 | 
						|
 | 
						|
void nfc_config(Nfc* instance, NfcMode mode, NfcTech tech) {
 | 
						|
    furi_assert(instance);
 | 
						|
    furi_assert(mode < NfcModeNum);
 | 
						|
    furi_assert(tech < NfcTechNum);
 | 
						|
    furi_assert(instance->config_state == NfcConfigurationStateIdle);
 | 
						|
 | 
						|
    FuriHalNfcTech hal_tech = nfc_tech_table[mode][tech];
 | 
						|
    if(hal_tech == FuriHalNfcTechInvalid) {
 | 
						|
        furi_crash("Unsupported mode for given tech");
 | 
						|
    }
 | 
						|
    FuriHalNfcMode hal_mode = (mode == NfcModePoller) ? FuriHalNfcModePoller :
 | 
						|
                                                        FuriHalNfcModeListener;
 | 
						|
    furi_hal_nfc_low_power_mode_stop();
 | 
						|
    furi_hal_nfc_set_mode(hal_mode, hal_tech);
 | 
						|
 | 
						|
    instance->mode = mode;
 | 
						|
    instance->config_state = NfcConfigurationStateDone;
 | 
						|
}
 | 
						|
 | 
						|
void nfc_set_fdt_poll_fc(Nfc* instance, uint32_t fdt_poll_fc) {
 | 
						|
    furi_assert(instance);
 | 
						|
    instance->fdt_poll_fc = fdt_poll_fc;
 | 
						|
}
 | 
						|
 | 
						|
void nfc_set_fdt_listen_fc(Nfc* instance, uint32_t fdt_listen_fc) {
 | 
						|
    furi_assert(instance);
 | 
						|
    instance->fdt_listen_fc = fdt_listen_fc;
 | 
						|
}
 | 
						|
 | 
						|
void nfc_set_fdt_poll_poll_us(Nfc* instance, uint32_t fdt_poll_poll_us) {
 | 
						|
    furi_assert(instance);
 | 
						|
    instance->fdt_poll_poll_us = fdt_poll_poll_us;
 | 
						|
}
 | 
						|
 | 
						|
void nfc_set_guard_time_us(Nfc* instance, uint32_t guard_time_us) {
 | 
						|
    furi_assert(instance);
 | 
						|
    instance->guard_time_us = guard_time_us;
 | 
						|
}
 | 
						|
 | 
						|
void nfc_set_mask_receive_time_fc(Nfc* instance, uint32_t mask_rx_time_fc) {
 | 
						|
    furi_assert(instance);
 | 
						|
    instance->mask_rx_time_fc = mask_rx_time_fc;
 | 
						|
}
 | 
						|
 | 
						|
void nfc_start(Nfc* instance, NfcEventCallback callback, void* context) {
 | 
						|
    furi_assert(instance);
 | 
						|
    furi_assert(instance->worker_thread);
 | 
						|
    furi_assert(callback);
 | 
						|
    furi_assert(instance->config_state == NfcConfigurationStateDone);
 | 
						|
 | 
						|
    instance->callback = callback;
 | 
						|
    instance->context = context;
 | 
						|
    if(instance->mode == NfcModePoller) {
 | 
						|
        furi_thread_set_callback(instance->worker_thread, nfc_worker_poller);
 | 
						|
    } else {
 | 
						|
        furi_thread_set_callback(instance->worker_thread, nfc_worker_listener);
 | 
						|
    }
 | 
						|
    instance->comm_state = NfcCommStateIdle;
 | 
						|
    furi_thread_start(instance->worker_thread);
 | 
						|
}
 | 
						|
 | 
						|
void nfc_stop(Nfc* instance) {
 | 
						|
    furi_assert(instance);
 | 
						|
    furi_assert(instance->state == NfcStateRunning);
 | 
						|
 | 
						|
    if(instance->mode == NfcModeListener) {
 | 
						|
        furi_hal_nfc_abort();
 | 
						|
    }
 | 
						|
    furi_thread_join(instance->worker_thread);
 | 
						|
 | 
						|
    instance->state = NfcStateIdle;
 | 
						|
}
 | 
						|
 | 
						|
NfcError nfc_listener_tx(Nfc* instance, const BitBuffer* tx_buffer) {
 | 
						|
    furi_assert(instance);
 | 
						|
    furi_assert(tx_buffer);
 | 
						|
 | 
						|
    NfcError ret = NfcErrorNone;
 | 
						|
 | 
						|
    while(furi_hal_nfc_timer_block_tx_is_running()) {
 | 
						|
    }
 | 
						|
 | 
						|
    FuriHalNfcError error =
 | 
						|
        furi_hal_nfc_listener_tx(bit_buffer_get_data(tx_buffer), bit_buffer_get_size(tx_buffer));
 | 
						|
    if(error != FuriHalNfcErrorNone) {
 | 
						|
        FURI_LOG_D(TAG, "Failed in listener TX");
 | 
						|
        ret = nfc_process_hal_error(error);
 | 
						|
    }
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
static NfcError nfc_poller_trx_state_machine(Nfc* instance, uint32_t fwt_fc) {
 | 
						|
    FuriHalNfcEvent event = 0;
 | 
						|
    NfcError error = NfcErrorNone;
 | 
						|
 | 
						|
    while(true) {
 | 
						|
        event = furi_hal_nfc_poller_wait_event(FURI_HAL_NFC_EVENT_WAIT_FOREVER);
 | 
						|
        if(event & FuriHalNfcEventTimerBlockTxExpired) {
 | 
						|
            if(instance->comm_state == NfcCommStateWaitBlockTxTimer) {
 | 
						|
                instance->comm_state = NfcCommStateReadyTx;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if(event & FuriHalNfcEventTxEnd) {
 | 
						|
            if(instance->comm_state == NfcCommStateWaitTxEnd) {
 | 
						|
                if(fwt_fc) {
 | 
						|
                    furi_hal_nfc_timer_fwt_start(fwt_fc);
 | 
						|
                }
 | 
						|
                furi_hal_nfc_timer_block_tx_start_us(instance->fdt_poll_poll_us);
 | 
						|
                instance->comm_state = NfcCommStateWaitRxStart;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if(event & FuriHalNfcEventRxStart) {
 | 
						|
            if(instance->comm_state == NfcCommStateWaitRxStart) {
 | 
						|
                furi_hal_nfc_timer_block_tx_stop();
 | 
						|
                furi_hal_nfc_timer_fwt_stop();
 | 
						|
                instance->comm_state = NfcCommStateWaitRxEnd;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if(event & FuriHalNfcEventRxEnd) {
 | 
						|
            furi_hal_nfc_timer_block_tx_start(instance->fdt_poll_fc);
 | 
						|
            furi_hal_nfc_timer_fwt_stop();
 | 
						|
            instance->comm_state = NfcCommStateWaitBlockTxTimer;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        if(event & FuriHalNfcEventTimerFwtExpired) {
 | 
						|
            if(instance->comm_state == NfcCommStateWaitRxStart) {
 | 
						|
                error = NfcErrorTimeout;
 | 
						|
                FURI_LOG_D(TAG, "FWT Timeout");
 | 
						|
                if(furi_hal_nfc_timer_block_tx_is_running()) {
 | 
						|
                    instance->comm_state = NfcCommStateWaitBlockTxTimer;
 | 
						|
                } else {
 | 
						|
                    instance->comm_state = NfcCommStateReadyTx;
 | 
						|
                }
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return error;
 | 
						|
}
 | 
						|
 | 
						|
NfcError nfc_iso14443a_poller_trx_custom_parity(
 | 
						|
    Nfc* instance,
 | 
						|
    const BitBuffer* tx_buffer,
 | 
						|
    BitBuffer* rx_buffer,
 | 
						|
    uint32_t fwt) {
 | 
						|
    furi_assert(instance);
 | 
						|
    furi_assert(tx_buffer);
 | 
						|
    furi_assert(rx_buffer);
 | 
						|
 | 
						|
    furi_assert(instance->poller_state == NfcPollerStateReady);
 | 
						|
 | 
						|
    NfcError ret = NfcErrorNone;
 | 
						|
    FuriHalNfcError error = FuriHalNfcErrorNone;
 | 
						|
    do {
 | 
						|
        furi_hal_nfc_trx_reset();
 | 
						|
        while(furi_hal_nfc_timer_block_tx_is_running()) {
 | 
						|
            FuriHalNfcEvent event =
 | 
						|
                furi_hal_nfc_poller_wait_event(FURI_HAL_NFC_EVENT_WAIT_FOREVER);
 | 
						|
            if(event & FuriHalNfcEventTimerBlockTxExpired) break;
 | 
						|
        }
 | 
						|
        bit_buffer_write_bytes_with_parity(
 | 
						|
            tx_buffer, instance->tx_buffer, sizeof(instance->tx_buffer), &instance->tx_bits);
 | 
						|
        error =
 | 
						|
            furi_hal_nfc_iso14443a_poller_tx_custom_parity(instance->tx_buffer, instance->tx_bits);
 | 
						|
        if(error != FuriHalNfcErrorNone) {
 | 
						|
            FURI_LOG_D(TAG, "Failed in poller TX");
 | 
						|
            ret = nfc_process_hal_error(error);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        instance->comm_state = NfcCommStateWaitTxEnd;
 | 
						|
        ret = nfc_poller_trx_state_machine(instance, fwt);
 | 
						|
        if(ret != NfcErrorNone) {
 | 
						|
            FURI_LOG_T(TAG, "Failed TRX state machine");
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        error = furi_hal_nfc_poller_rx(
 | 
						|
            instance->rx_buffer, sizeof(instance->rx_buffer), &instance->rx_bits);
 | 
						|
        if(error != FuriHalNfcErrorNone) {
 | 
						|
            FURI_LOG_D(TAG, "Failed in poller RX");
 | 
						|
            ret = nfc_process_hal_error(error);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        if(instance->rx_bits >= 9) {
 | 
						|
            if((instance->rx_bits % 9) != 0) {
 | 
						|
                ret = NfcErrorDataFormat;
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        bit_buffer_copy_bytes_with_parity(rx_buffer, instance->rx_buffer, instance->rx_bits);
 | 
						|
    } while(false);
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
NfcError
 | 
						|
    nfc_poller_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt) {
 | 
						|
    furi_assert(instance);
 | 
						|
    furi_assert(tx_buffer);
 | 
						|
    furi_assert(rx_buffer);
 | 
						|
 | 
						|
    furi_assert(instance->poller_state == NfcPollerStateReady);
 | 
						|
 | 
						|
    NfcError ret = NfcErrorNone;
 | 
						|
    FuriHalNfcError error = FuriHalNfcErrorNone;
 | 
						|
    do {
 | 
						|
        furi_hal_nfc_trx_reset();
 | 
						|
        while(furi_hal_nfc_timer_block_tx_is_running()) {
 | 
						|
            FuriHalNfcEvent event =
 | 
						|
                furi_hal_nfc_poller_wait_event(FURI_HAL_NFC_EVENT_WAIT_FOREVER);
 | 
						|
            if(event & FuriHalNfcEventTimerBlockTxExpired) break;
 | 
						|
        }
 | 
						|
        error =
 | 
						|
            furi_hal_nfc_poller_tx(bit_buffer_get_data(tx_buffer), bit_buffer_get_size(tx_buffer));
 | 
						|
        if(error != FuriHalNfcErrorNone) {
 | 
						|
            FURI_LOG_D(TAG, "Failed in poller TX");
 | 
						|
            ret = nfc_process_hal_error(error);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        instance->comm_state = NfcCommStateWaitTxEnd;
 | 
						|
        ret = nfc_poller_trx_state_machine(instance, fwt);
 | 
						|
        if(ret != NfcErrorNone) {
 | 
						|
            FURI_LOG_T(TAG, "Failed TRX state machine");
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        error = furi_hal_nfc_poller_rx(
 | 
						|
            instance->rx_buffer, sizeof(instance->rx_buffer), &instance->rx_bits);
 | 
						|
        if(error != FuriHalNfcErrorNone) {
 | 
						|
            FURI_LOG_D(TAG, "Failed in poller RX");
 | 
						|
            ret = nfc_process_hal_error(error);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        bit_buffer_copy_bits(rx_buffer, instance->rx_buffer, instance->rx_bits);
 | 
						|
    } while(false);
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
NfcError nfc_iso14443a_listener_set_col_res_data(
 | 
						|
    Nfc* instance,
 | 
						|
    uint8_t* uid,
 | 
						|
    uint8_t uid_len,
 | 
						|
    uint8_t* atqa,
 | 
						|
    uint8_t sak) {
 | 
						|
    furi_assert(instance);
 | 
						|
 | 
						|
    FuriHalNfcError error =
 | 
						|
        furi_hal_nfc_iso14443a_listener_set_col_res_data(uid, uid_len, atqa, sak);
 | 
						|
    instance->comm_state = NfcCommStateIdle;
 | 
						|
    return nfc_process_hal_error(error);
 | 
						|
}
 | 
						|
 | 
						|
NfcError nfc_iso14443a_poller_trx_short_frame(
 | 
						|
    Nfc* instance,
 | 
						|
    NfcIso14443aShortFrame frame,
 | 
						|
    BitBuffer* rx_buffer,
 | 
						|
    uint32_t fwt) {
 | 
						|
    furi_assert(instance);
 | 
						|
    furi_assert(rx_buffer);
 | 
						|
 | 
						|
    FuriHalNfcaShortFrame short_frame = (frame == NfcIso14443aShortFrameAllReqa) ?
 | 
						|
                                            FuriHalNfcaShortFrameAllReq :
 | 
						|
                                            FuriHalNfcaShortFrameSensReq;
 | 
						|
 | 
						|
    furi_assert(instance->poller_state == NfcPollerStateReady);
 | 
						|
 | 
						|
    NfcError ret = NfcErrorNone;
 | 
						|
    FuriHalNfcError error = FuriHalNfcErrorNone;
 | 
						|
    do {
 | 
						|
        furi_hal_nfc_trx_reset();
 | 
						|
        while(furi_hal_nfc_timer_block_tx_is_running()) {
 | 
						|
            FuriHalNfcEvent event =
 | 
						|
                furi_hal_nfc_poller_wait_event(FURI_HAL_NFC_EVENT_WAIT_FOREVER);
 | 
						|
            if(event & FuriHalNfcEventTimerBlockTxExpired) break;
 | 
						|
        }
 | 
						|
        error = furi_hal_nfc_iso14443a_poller_trx_short_frame(short_frame);
 | 
						|
        if(error != FuriHalNfcErrorNone) {
 | 
						|
            FURI_LOG_D(TAG, "Failed in poller TX");
 | 
						|
            ret = nfc_process_hal_error(error);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        instance->comm_state = NfcCommStateWaitTxEnd;
 | 
						|
        ret = nfc_poller_trx_state_machine(instance, fwt);
 | 
						|
        if(ret != NfcErrorNone) {
 | 
						|
            FURI_LOG_T(TAG, "Failed TRX state machine");
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        error = furi_hal_nfc_poller_rx(
 | 
						|
            instance->rx_buffer, sizeof(instance->rx_buffer), &instance->rx_bits);
 | 
						|
        if(error != FuriHalNfcErrorNone) {
 | 
						|
            FURI_LOG_D(TAG, "Failed in poller RX");
 | 
						|
            ret = nfc_process_hal_error(error);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        bit_buffer_copy_bits(rx_buffer, instance->rx_buffer, instance->rx_bits);
 | 
						|
    } while(false);
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
NfcError nfc_iso14443a_poller_trx_sdd_frame(
 | 
						|
    Nfc* instance,
 | 
						|
    const BitBuffer* tx_buffer,
 | 
						|
    BitBuffer* rx_buffer,
 | 
						|
    uint32_t fwt) {
 | 
						|
    furi_assert(instance);
 | 
						|
    furi_assert(tx_buffer);
 | 
						|
    furi_assert(rx_buffer);
 | 
						|
 | 
						|
    furi_assert(instance->poller_state == NfcPollerStateReady);
 | 
						|
 | 
						|
    NfcError ret = NfcErrorNone;
 | 
						|
    FuriHalNfcError error = FuriHalNfcErrorNone;
 | 
						|
    do {
 | 
						|
        furi_hal_nfc_trx_reset();
 | 
						|
        while(furi_hal_nfc_timer_block_tx_is_running()) {
 | 
						|
            FuriHalNfcEvent event =
 | 
						|
                furi_hal_nfc_poller_wait_event(FURI_HAL_NFC_EVENT_WAIT_FOREVER);
 | 
						|
            if(event & FuriHalNfcEventTimerBlockTxExpired) break;
 | 
						|
        }
 | 
						|
        error = furi_hal_nfc_iso14443a_tx_sdd_frame(
 | 
						|
            bit_buffer_get_data(tx_buffer), bit_buffer_get_size(tx_buffer));
 | 
						|
        if(error != FuriHalNfcErrorNone) {
 | 
						|
            FURI_LOG_D(TAG, "Failed in poller TX");
 | 
						|
            ret = nfc_process_hal_error(error);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        instance->comm_state = NfcCommStateWaitTxEnd;
 | 
						|
        ret = nfc_poller_trx_state_machine(instance, fwt);
 | 
						|
        if(ret != NfcErrorNone) {
 | 
						|
            FURI_LOG_T(TAG, "Failed TRX state machine");
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        error = furi_hal_nfc_poller_rx(
 | 
						|
            instance->rx_buffer, sizeof(instance->rx_buffer), &instance->rx_bits);
 | 
						|
        if(error != FuriHalNfcErrorNone) {
 | 
						|
            FURI_LOG_D(TAG, "Failed in poller RX");
 | 
						|
            ret = nfc_process_hal_error(error);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        bit_buffer_copy_bits(rx_buffer, instance->rx_buffer, instance->rx_bits);
 | 
						|
    } while(false);
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
NfcError nfc_iso14443a_listener_tx_custom_parity(Nfc* instance, const BitBuffer* tx_buffer) {
 | 
						|
    furi_assert(instance);
 | 
						|
    furi_assert(tx_buffer);
 | 
						|
 | 
						|
    NfcError ret = NfcErrorNone;
 | 
						|
    FuriHalNfcError error = FuriHalNfcErrorNone;
 | 
						|
 | 
						|
    const uint8_t* tx_data = bit_buffer_get_data(tx_buffer);
 | 
						|
    const uint8_t* tx_parity = bit_buffer_get_parity(tx_buffer);
 | 
						|
    size_t tx_bits = bit_buffer_get_size(tx_buffer);
 | 
						|
 | 
						|
    error = furi_hal_nfc_iso14443a_listener_tx_custom_parity(tx_data, tx_parity, tx_bits);
 | 
						|
    ret = nfc_process_hal_error(error);
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
NfcError nfc_iso15693_listener_tx_sof(Nfc* instance) {
 | 
						|
    furi_assert(instance);
 | 
						|
 | 
						|
    while(furi_hal_nfc_timer_block_tx_is_running()) {
 | 
						|
    }
 | 
						|
 | 
						|
    FuriHalNfcError error = furi_hal_nfc_iso15693_listener_tx_sof();
 | 
						|
    NfcError ret = nfc_process_hal_error(error);
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
NfcError nfc_felica_listener_set_sensf_res_data(
 | 
						|
    Nfc* instance,
 | 
						|
    const uint8_t* idm,
 | 
						|
    const uint8_t idm_len,
 | 
						|
    const uint8_t* pmm,
 | 
						|
    const uint8_t pmm_len) {
 | 
						|
    furi_assert(instance);
 | 
						|
    furi_assert(idm);
 | 
						|
    furi_assert(pmm);
 | 
						|
 | 
						|
    FuriHalNfcError error =
 | 
						|
        furi_hal_nfc_felica_listener_set_sensf_res_data(idm, idm_len, pmm, pmm_len);
 | 
						|
    instance->comm_state = NfcCommStateIdle;
 | 
						|
    return nfc_process_hal_error(error);
 | 
						|
}
 | 
						|
 | 
						|
#endif // APP_UNIT_TESTS
 |