FL-53: new NFC worker, A/B/F/V poll and display. (#283)
* GUI: view. Flooper-blooper fix compilation error. * GUI: view and viewdispatcher bones * GUI: view implementation, view models, view dispatcher * GUI: view navigation, model refinement. Power: use view, view dispatcher. * HAL Flash: proper page write. Dolphin: views. Power: views * Dolphin: transition idle scree to Views * Dolphin: input events on stats view. Format sources. * HAL: flash erase. Dolphin: permanent state storage. * Dolphin: first start welcome. HAL: flash operation status, errata 2.2.9 crutch. * NFC: rewrite worker * NFC: add support for B,F,V. * NFC: replace rfal irq hanlder with realtime thread, more details about cards. * Bootloader: LSE and RTS shenanigans, LED control, morse code for LSE failure error. * F4: stop in Error_Handler * BLE: handle working FUS, but empty radio stack. * HAL: alive FUS is now sufficient for flash controller access * Dolphin: update model after state load * NFC: detect navigation * RFAL: use osPriorityISR for isr thread * NFC: emulation * Bootloader: rollback incorrectly merged rename * Dolphin: rollback incorrectly merged changes * RFAL: remove volatile from thread attr * RFAL: do not call platform ErrorHandler, error codes is enough * NFC: improved error handling * Format sources * NFC: reset detect view model on start * Format sources * update codeowners * NFC: hide last info if no card detected
This commit is contained in:
parent
34dbb2ea86
commit
6928122650
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@ -59,6 +59,7 @@ applications/menu/** @skotopes
|
||||
# NFC
|
||||
|
||||
applications/nfc/** @skotopes
|
||||
lib/ST25RFAL002/** @skotopes
|
||||
|
||||
# SD Card
|
||||
|
||||
|
@ -92,11 +92,6 @@ Dolphin* dolphin_alloc() {
|
||||
view_set_context(dolphin->idle_view_stats, dolphin);
|
||||
view_allocate_model(
|
||||
dolphin->idle_view_stats, ViewModelTypeLockFree, sizeof(DolphinViewIdleStatsModel));
|
||||
with_view_model(
|
||||
dolphin->idle_view_stats, (DolphinViewIdleStatsModel * model) {
|
||||
model->icounter = dolphin_state_get_icounter(dolphin->state);
|
||||
model->butthurt = dolphin_state_get_butthurt(dolphin->state);
|
||||
});
|
||||
view_set_draw_callback(dolphin->idle_view_stats, dolphin_view_idle_stats_draw);
|
||||
view_set_input_callback(dolphin->idle_view_stats, dolphin_view_idle_stats_input);
|
||||
view_set_previous_callback(dolphin->idle_view_stats, dolphin_view_idle_back);
|
||||
@ -137,6 +132,11 @@ void dolphin_task() {
|
||||
} else {
|
||||
view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewFirstStart);
|
||||
}
|
||||
with_view_model(
|
||||
dolphin->idle_view_stats, (DolphinViewIdleStatsModel * model) {
|
||||
model->icounter = dolphin_state_get_icounter(dolphin->state);
|
||||
model->butthurt = dolphin_state_get_butthurt(dolphin->state);
|
||||
});
|
||||
|
||||
if(!furi_create("dolphin", dolphin)) {
|
||||
printf("[dolphin_task] cannot create the dolphin record\n");
|
||||
|
@ -1,57 +0,0 @@
|
||||
#include "dispatcher.h"
|
||||
|
||||
#include <flipper.h>
|
||||
#include <flipper_v2.h>
|
||||
|
||||
struct Dispatcher {
|
||||
void* message;
|
||||
size_t message_size;
|
||||
osMessageQueueId_t mqueue;
|
||||
osMutexId_t lock_mutex;
|
||||
};
|
||||
|
||||
Dispatcher* dispatcher_alloc(size_t queue_size, size_t message_size) {
|
||||
Dispatcher* dispatcher = furi_alloc(sizeof(Dispatcher));
|
||||
|
||||
dispatcher->message = furi_alloc(message_size);
|
||||
dispatcher->message_size = message_size;
|
||||
|
||||
dispatcher->mqueue = osMessageQueueNew(queue_size, message_size, NULL);
|
||||
furi_check(dispatcher->mqueue);
|
||||
|
||||
dispatcher->lock_mutex = osMutexNew(NULL);
|
||||
furi_check(dispatcher->lock_mutex);
|
||||
dispatcher_lock(dispatcher);
|
||||
|
||||
return dispatcher;
|
||||
}
|
||||
|
||||
void dispatcher_free(Dispatcher* dispatcher) {
|
||||
furi_assert(dispatcher);
|
||||
free(dispatcher);
|
||||
}
|
||||
|
||||
void dispatcher_send(Dispatcher* dispatcher, Message* message) {
|
||||
furi_assert(dispatcher);
|
||||
furi_assert(message);
|
||||
furi_check(osMessageQueuePut(dispatcher->mqueue, message, 0, osWaitForever) == osOK);
|
||||
}
|
||||
|
||||
// TODO: bad side-effect
|
||||
void dispatcher_recieve(Dispatcher* dispatcher, Message* message) {
|
||||
furi_assert(dispatcher);
|
||||
furi_assert(message);
|
||||
dispatcher_unlock(dispatcher);
|
||||
furi_check(osMessageQueueGet(dispatcher->mqueue, message, NULL, osWaitForever) == osOK);
|
||||
dispatcher_lock(dispatcher);
|
||||
}
|
||||
|
||||
void dispatcher_lock(Dispatcher* dispatcher) {
|
||||
furi_assert(dispatcher);
|
||||
furi_check(osMutexAcquire(dispatcher->lock_mutex, osWaitForever) == osOK);
|
||||
}
|
||||
|
||||
void dispatcher_unlock(Dispatcher* dispatcher) {
|
||||
furi_assert(dispatcher);
|
||||
furi_check(osMutexRelease(dispatcher->lock_mutex) == osOK);
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
enum MessageTypeBase {
|
||||
MessageTypeExit = 0x00,
|
||||
MessageTypeMemoryLow = 0x01,
|
||||
MessageTypeBatteryLow = 0x02,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
enum MessageTypeBase type;
|
||||
} Message;
|
||||
|
||||
typedef struct Dispatcher Dispatcher;
|
||||
|
||||
Dispatcher* dispatcher_alloc(size_t queue_size, size_t message_size);
|
||||
|
||||
void dispatcher_free(Dispatcher* dispatcher);
|
||||
|
||||
void dispatcher_send(Dispatcher* dispatcher, Message* message);
|
||||
|
||||
void dispatcher_recieve(Dispatcher* dispatcher, Message* message);
|
||||
|
||||
void dispatcher_lock(Dispatcher* dispatcher);
|
||||
|
||||
void dispatcher_unlock(Dispatcher* dispatcher);
|
@ -1,174 +1,109 @@
|
||||
#include "nfc.h"
|
||||
#include "nfc_i.h"
|
||||
#include "nfc_worker.h"
|
||||
|
||||
void nfc_draw_callback(Canvas* canvas, void* context) {
|
||||
furi_assert(canvas);
|
||||
furi_assert(context);
|
||||
|
||||
Nfc* nfc = context;
|
||||
|
||||
dispatcher_lock(nfc->dispatcher);
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
|
||||
if(nfc->screen == 0) {
|
||||
char status[128 / 8];
|
||||
if(nfc->ret == ERR_WRONG_STATE)
|
||||
canvas_draw_str(canvas, 2, 16, "NFC Wrong State");
|
||||
else if(nfc->ret == ERR_PARAM)
|
||||
canvas_draw_str(canvas, 2, 16, "NFC Wrong Param");
|
||||
else if(nfc->ret == ERR_IO)
|
||||
canvas_draw_str(canvas, 2, 16, "NFC IO Error");
|
||||
else if(nfc->ret == ERR_NONE)
|
||||
canvas_draw_str(canvas, 2, 16, "NFC Device Found");
|
||||
else if(nfc->ret == ERR_TIMEOUT)
|
||||
canvas_draw_str(canvas, 2, 16, "NFC Timeout");
|
||||
else
|
||||
canvas_draw_str(canvas, 2, 16, "NFC error");
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
snprintf(status, sizeof(status), "Found: %d", nfc->devCnt);
|
||||
if(nfc->devCnt > 0) {
|
||||
canvas_draw_str(canvas, 2, 32, status);
|
||||
canvas_draw_str(canvas, 2, 42, nfc->current);
|
||||
|
||||
snprintf(
|
||||
status,
|
||||
sizeof(status),
|
||||
"ATQA:%d SAK:%d",
|
||||
nfc->first_atqa.anticollisionInfo,
|
||||
nfc->first_sak.sak);
|
||||
canvas_draw_str(canvas, 2, 52, status);
|
||||
}
|
||||
} else {
|
||||
canvas_draw_str(canvas, 2, 16, "Not implemented");
|
||||
}
|
||||
|
||||
dispatcher_unlock(nfc->dispatcher);
|
||||
}
|
||||
|
||||
void nfc_input_callback(InputEvent* event, void* context) {
|
||||
furi_assert(event);
|
||||
uint32_t nfc_view_exit(void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
|
||||
if(!event->state || event->input != InputBack) return;
|
||||
|
||||
widget_enabled_set(nfc->widget, false);
|
||||
}
|
||||
|
||||
void nfc_test_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
|
||||
dispatcher_lock(nfc->dispatcher);
|
||||
|
||||
nfc->screen = 0;
|
||||
widget_enabled_set(nfc->widget, true);
|
||||
|
||||
// TODO only for workaround
|
||||
if(nfc->ret != ERR_NONE) {
|
||||
nfc->ret = rfalNfcInitialize();
|
||||
rfalLowPowerModeStart();
|
||||
}
|
||||
|
||||
if(nfc->ret == ERR_NONE && !nfc->worker) {
|
||||
// TODO change to fuirac_start
|
||||
nfc->worker = osThreadNew(nfc_worker_task, nfc, &nfc->worker_attr);
|
||||
}
|
||||
|
||||
dispatcher_unlock(nfc->dispatcher);
|
||||
}
|
||||
|
||||
void nfc_field_on_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
|
||||
// TODO only for workaround
|
||||
if(nfc->ret != ERR_NONE) {
|
||||
nfc->ret = rfalNfcInitialize();
|
||||
rfalLowPowerModeStart();
|
||||
}
|
||||
|
||||
st25r3916OscOn();
|
||||
st25r3916TxRxOn();
|
||||
}
|
||||
|
||||
void nfc_field_off_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
|
||||
// TODO only for workaround
|
||||
if(nfc->ret != ERR_NONE) {
|
||||
nfc->ret = rfalNfcInitialize();
|
||||
rfalLowPowerModeStart();
|
||||
}
|
||||
|
||||
st25r3916TxRxOff();
|
||||
}
|
||||
|
||||
void nfc_read_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
nfc->screen = 1;
|
||||
widget_enabled_set(nfc->widget, true);
|
||||
}
|
||||
|
||||
void nfc_write_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
nfc->screen = 1;
|
||||
widget_enabled_set(nfc->widget, true);
|
||||
}
|
||||
|
||||
void nfc_bridge_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
nfc->screen = 1;
|
||||
widget_enabled_set(nfc->widget, true);
|
||||
NfcMessage message;
|
||||
message.type = NfcMessageTypeStop;
|
||||
furi_check(osMessageQueuePut(nfc->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
return VIEW_NONE;
|
||||
}
|
||||
|
||||
Nfc* nfc_alloc() {
|
||||
Nfc* nfc = furi_alloc(sizeof(Nfc));
|
||||
|
||||
nfc->dispatcher = dispatcher_alloc(32, sizeof(NfcMessage));
|
||||
nfc->message_queue = osMessageQueueNew(8, sizeof(NfcMessage), NULL);
|
||||
nfc->worker = nfc_worker_alloc(nfc->message_queue);
|
||||
|
||||
nfc->icon = assets_icons_get(A_NFC_14);
|
||||
nfc->widget = widget_alloc();
|
||||
widget_draw_callback_set(nfc->widget, nfc_draw_callback, nfc);
|
||||
widget_input_callback_set(nfc->widget, nfc_input_callback, nfc);
|
||||
|
||||
nfc->menu_vm = furi_open("menu");
|
||||
furi_check(nfc->menu_vm);
|
||||
|
||||
nfc->menu = menu_item_alloc_menu("NFC", nfc->icon);
|
||||
menu_item_subitem_add(
|
||||
nfc->menu, menu_item_alloc_function("Test", NULL, nfc_test_callback, nfc));
|
||||
nfc->menu, menu_item_alloc_function("Detect", NULL, nfc_menu_detect_callback, nfc));
|
||||
menu_item_subitem_add(
|
||||
nfc->menu, menu_item_alloc_function("Field On", NULL, nfc_field_on_callback, nfc));
|
||||
nfc->menu, menu_item_alloc_function("Emulate", NULL, nfc_menu_emulate_callback, nfc));
|
||||
menu_item_subitem_add(
|
||||
nfc->menu, menu_item_alloc_function("Field Off", NULL, nfc_field_off_callback, nfc));
|
||||
menu_item_subitem_add(
|
||||
nfc->menu, menu_item_alloc_function("Read", NULL, nfc_read_callback, nfc));
|
||||
menu_item_subitem_add(
|
||||
nfc->menu, menu_item_alloc_function("Write", NULL, nfc_write_callback, nfc));
|
||||
menu_item_subitem_add(
|
||||
nfc->menu, menu_item_alloc_function("Brdige", NULL, nfc_bridge_callback, nfc));
|
||||
nfc->menu, menu_item_alloc_function("Field", NULL, nfc_menu_field_callback, nfc));
|
||||
|
||||
nfc->view_detect = view_alloc();
|
||||
view_set_context(nfc->view_detect, nfc);
|
||||
view_set_draw_callback(nfc->view_detect, nfc_view_read_draw);
|
||||
view_set_previous_callback(nfc->view_detect, nfc_view_exit);
|
||||
view_allocate_model(nfc->view_detect, ViewModelTypeLocking, sizeof(NfcViewReadModel));
|
||||
nfc->view_emulate = view_alloc();
|
||||
view_set_context(nfc->view_emulate, nfc);
|
||||
view_set_draw_callback(nfc->view_emulate, nfc_view_emulate_draw);
|
||||
view_set_previous_callback(nfc->view_emulate, nfc_view_exit);
|
||||
nfc->view_field = view_alloc();
|
||||
view_set_context(nfc->view_field, nfc);
|
||||
view_set_draw_callback(nfc->view_field, nfc_view_field_draw);
|
||||
view_set_previous_callback(nfc->view_field, nfc_view_exit);
|
||||
nfc->view_error = view_alloc();
|
||||
view_set_context(nfc->view_error, nfc);
|
||||
view_set_draw_callback(nfc->view_error, nfc_view_error_draw);
|
||||
view_set_previous_callback(nfc->view_error, nfc_view_exit);
|
||||
view_allocate_model(nfc->view_error, ViewModelTypeLockFree, sizeof(NfcViewErrorModel));
|
||||
nfc->view_dispatcher = view_dispatcher_alloc();
|
||||
view_dispatcher_add_view(nfc->view_dispatcher, NfcViewRead, nfc->view_detect);
|
||||
view_dispatcher_add_view(nfc->view_dispatcher, NfcViewEmulate, nfc->view_emulate);
|
||||
view_dispatcher_add_view(nfc->view_dispatcher, NfcViewField, nfc->view_field);
|
||||
view_dispatcher_add_view(nfc->view_dispatcher, NfcViewError, nfc->view_error);
|
||||
|
||||
nfc->worker_attr.name = "nfc_worker";
|
||||
// nfc->worker_attr.attr_bits = osThreadJoinable;
|
||||
nfc->worker_attr.stack_size = 4096;
|
||||
return nfc;
|
||||
}
|
||||
|
||||
void nfc_menu_detect_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
NfcMessage message;
|
||||
message.type = NfcMessageTypeDetect;
|
||||
furi_check(osMessageQueuePut(nfc->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
}
|
||||
|
||||
void nfc_menu_emulate_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
NfcMessage message;
|
||||
message.type = NfcMessageTypeEmulate;
|
||||
furi_check(osMessageQueuePut(nfc->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
}
|
||||
|
||||
void nfc_menu_field_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
NfcMessage message;
|
||||
message.type = NfcMessageTypeField;
|
||||
furi_check(osMessageQueuePut(nfc->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
}
|
||||
|
||||
void nfc_menu_field_off_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
NfcMessage message;
|
||||
message.type = NfcMessageTypeField;
|
||||
furi_check(osMessageQueuePut(nfc->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
}
|
||||
|
||||
void nfc_start(Nfc* nfc, NfcView view_id, NfcWorkerState worker_state) {
|
||||
NfcWorkerState state = nfc_worker_get_state(nfc->worker);
|
||||
if(state == NfcWorkerStateBroken) {
|
||||
with_view_model(
|
||||
nfc->view_error,
|
||||
(NfcViewErrorModel * model) { model->error = nfc_worker_get_error(nfc->worker); });
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewError);
|
||||
} else if(state == NfcWorkerStateReady) {
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, view_id);
|
||||
nfc_worker_start(nfc->worker, worker_state);
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_task(void* p) {
|
||||
Nfc* nfc = nfc_alloc();
|
||||
|
||||
Gui* gui = furi_open("gui");
|
||||
widget_enabled_set(nfc->widget, false);
|
||||
gui_add_widget(gui, nfc->widget, GuiLayerFullscreen);
|
||||
view_dispatcher_attach_to_gui(nfc->view_dispatcher, gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
with_value_mutex(
|
||||
nfc->menu_vm, (Menu * menu) { menu_item_add(menu, nfc->menu); });
|
||||
@ -178,17 +113,30 @@ void nfc_task(void* p) {
|
||||
furiac_exit(NULL);
|
||||
}
|
||||
|
||||
// TODO only for workaround
|
||||
nfc->ret = ERR_WRONG_STATE;
|
||||
|
||||
furiac_ready();
|
||||
|
||||
NfcMessage message;
|
||||
while(1) {
|
||||
dispatcher_recieve(nfc->dispatcher, (Message*)&message);
|
||||
|
||||
if(message.base.type == MessageTypeExit) {
|
||||
break;
|
||||
furi_check(osMessageQueueGet(nfc->message_queue, &message, NULL, osWaitForever) == osOK);
|
||||
if(message.type == NfcMessageTypeDetect) {
|
||||
with_view_model(
|
||||
nfc->view_detect, (NfcViewReadModel * model) { model->found = false; });
|
||||
nfc_start(nfc, NfcViewRead, NfcWorkerStatePoll);
|
||||
} else if(message.type == NfcMessageTypeEmulate) {
|
||||
nfc_start(nfc, NfcViewEmulate, NfcWorkerStateEmulate);
|
||||
} else if(message.type == NfcMessageTypeField) {
|
||||
nfc_start(nfc, NfcViewField, NfcWorkerStateField);
|
||||
} else if(message.type == NfcMessageTypeStop) {
|
||||
nfc_worker_stop(nfc->worker);
|
||||
} else if(message.type == NfcMessageTypeDeviceFound) {
|
||||
with_view_model(
|
||||
nfc->view_detect, (NfcViewReadModel * model) {
|
||||
model->found = true;
|
||||
model->device = message.device;
|
||||
});
|
||||
} else if(message.type == NfcMessageTypeDeviceNotFound) {
|
||||
with_view_model(
|
||||
nfc->view_detect, (NfcViewReadModel * model) { model->found = false; });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,49 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include "nfc.h"
|
||||
#include "nfc_types.h"
|
||||
#include "nfc_views.h"
|
||||
#include "nfc_worker.h"
|
||||
|
||||
#include <flipper_v2.h>
|
||||
|
||||
#include <rfal_analogConfig.h>
|
||||
#include <rfal_rf.h>
|
||||
#include <rfal_nfc.h>
|
||||
#include <rfal_nfca.h>
|
||||
#include <st25r3916.h>
|
||||
#include <st25r3916_irq.h>
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <gui/widget.h>
|
||||
#include <gui/canvas.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <assets_icons.h>
|
||||
|
||||
#include <menu/menu.h>
|
||||
#include <menu/menu_item.h>
|
||||
|
||||
#include "dispatcher.h"
|
||||
|
||||
typedef enum {
|
||||
MessageTypeBase,
|
||||
} NfcMessageType;
|
||||
|
||||
typedef struct {
|
||||
Message base;
|
||||
void* data;
|
||||
} NfcMessage;
|
||||
|
||||
struct Nfc {
|
||||
Dispatcher* dispatcher;
|
||||
Icon* icon;
|
||||
Widget* widget;
|
||||
osMessageQueueId_t message_queue;
|
||||
|
||||
NfcWorker* worker;
|
||||
|
||||
ValueMutex* menu_vm;
|
||||
MenuItem* menu;
|
||||
rfalNfcDiscoverParam* disParams;
|
||||
Icon* icon;
|
||||
|
||||
osThreadAttr_t worker_attr;
|
||||
osThreadId_t worker;
|
||||
|
||||
uint8_t screen;
|
||||
uint8_t ret;
|
||||
uint8_t devCnt;
|
||||
rfalNfcaSensRes first_atqa;
|
||||
rfalNfcaSelRes first_sak;
|
||||
|
||||
char* current;
|
||||
View* view_detect;
|
||||
View* view_emulate;
|
||||
View* view_field;
|
||||
View* view_error;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
};
|
||||
|
||||
Nfc* nfc_alloc();
|
||||
|
||||
void nfc_menu_detect_callback(void* context);
|
||||
|
||||
void nfc_menu_emulate_callback(void* context);
|
||||
|
||||
void nfc_menu_field_callback(void* context);
|
||||
|
||||
void nfc_start(Nfc* nfc, NfcView view_id, NfcWorkerState worker_state);
|
||||
|
||||
void nfc_task(void* p);
|
68
applications/nfc/nfc_types.h
Normal file
68
applications/nfc/nfc_types.h
Normal file
@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include <rfal_nfc.h>
|
||||
#include <st_errno.h>
|
||||
|
||||
static inline const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type) {
|
||||
if(type == RFAL_NFCA_T1T) {
|
||||
return "T1T";
|
||||
} else if(type == RFAL_NFCA_T2T) {
|
||||
return "T2T";
|
||||
} else if(type == RFAL_NFCA_T4T) {
|
||||
return "T4T";
|
||||
} else if(type == RFAL_NFCA_NFCDEP) {
|
||||
return "NFCDEP";
|
||||
} else if(type == RFAL_NFCA_T4T_NFCDEP) {
|
||||
return "T4T_NFCDEP";
|
||||
} else {
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
NfcDeviceTypeNfca,
|
||||
NfcDeviceTypeNfcb,
|
||||
NfcDeviceTypeNfcf,
|
||||
NfcDeviceTypeNfcv,
|
||||
NfcDeviceTypeNfcMifare
|
||||
} NfcDeviceType;
|
||||
|
||||
typedef struct {
|
||||
NfcDeviceType type;
|
||||
union {
|
||||
rfalNfcaListenDevice nfca;
|
||||
rfalNfcbListenDevice nfcb;
|
||||
rfalNfcfListenDevice nfcf;
|
||||
rfalNfcvListenDevice nfcv;
|
||||
};
|
||||
} NfcDevice;
|
||||
|
||||
typedef enum {
|
||||
// Init states
|
||||
NfcWorkerStateNone,
|
||||
NfcWorkerStateBroken,
|
||||
NfcWorkerStateReady,
|
||||
// Main worker states
|
||||
NfcWorkerStatePoll,
|
||||
NfcWorkerStateEmulate,
|
||||
NfcWorkerStateField,
|
||||
// Transition
|
||||
NfcWorkerStateStop,
|
||||
} NfcWorkerState;
|
||||
|
||||
typedef enum {
|
||||
NfcMessageTypeDetect,
|
||||
NfcMessageTypeEmulate,
|
||||
NfcMessageTypeField,
|
||||
NfcMessageTypeStop,
|
||||
// From Worker
|
||||
NfcMessageTypeDeviceFound,
|
||||
NfcMessageTypeDeviceNotFound,
|
||||
} NfcMessageType;
|
||||
|
||||
typedef struct {
|
||||
NfcMessageType type;
|
||||
union {
|
||||
NfcDevice device;
|
||||
};
|
||||
} NfcMessage;
|
147
applications/nfc/nfc_views.c
Normal file
147
applications/nfc/nfc_views.c
Normal file
@ -0,0 +1,147 @@
|
||||
#include "nfc_views.h"
|
||||
|
||||
void nfc_view_read_draw(Canvas* canvas, void* model) {
|
||||
NfcViewReadModel* m = model;
|
||||
canvas_clear(canvas);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
if(m->found) {
|
||||
if(m->device.type == NfcDeviceTypeNfca) {
|
||||
nfc_view_read_nfca_draw(canvas, m);
|
||||
} else if(m->device.type == NfcDeviceTypeNfcb) {
|
||||
nfc_view_read_nfcb_draw(canvas, m);
|
||||
} else if(m->device.type == NfcDeviceTypeNfcv) {
|
||||
nfc_view_read_nfcv_draw(canvas, m);
|
||||
} else if(m->device.type == NfcDeviceTypeNfcf) {
|
||||
nfc_view_read_nfcf_draw(canvas, m);
|
||||
}
|
||||
} else {
|
||||
canvas_draw_str(canvas, 0, 12, "Searching");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 2, 22, "Place card to the back");
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_view_read_nfca_draw(Canvas* canvas, NfcViewReadModel* model) {
|
||||
char buffer[32];
|
||||
canvas_draw_str(canvas, 0, 12, "Found NFC-A");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
snprintf(buffer, sizeof(buffer), "Type: %s", nfc_get_nfca_type(model->device.nfca.type));
|
||||
canvas_draw_str(canvas, 2, 22, buffer);
|
||||
snprintf(buffer, sizeof(buffer), "UID length: %d", model->device.nfca.nfcId1Len);
|
||||
canvas_draw_str(canvas, 2, 32, buffer);
|
||||
|
||||
canvas_draw_str(canvas, 2, 42, "UID:");
|
||||
for(uint8_t i = 0; i < model->device.nfca.nfcId1Len; i++) {
|
||||
snprintf(buffer + (i * 2), sizeof(buffer) - (i * 2), "%02X", model->device.nfca.nfcId1[i]);
|
||||
}
|
||||
buffer[model->device.nfca.nfcId1Len * 2] = 0;
|
||||
canvas_draw_str(canvas, 18, 42, buffer);
|
||||
|
||||
snprintf(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"SAK: %02X ATQA: %02X/%02X",
|
||||
model->device.nfca.selRes.sak,
|
||||
model->device.nfca.sensRes.anticollisionInfo,
|
||||
model->device.nfca.sensRes.platformInfo);
|
||||
canvas_draw_str(canvas, 2, 52, buffer);
|
||||
}
|
||||
|
||||
void nfc_view_read_nfcb_draw(Canvas* canvas, NfcViewReadModel* model) {
|
||||
char buffer[32];
|
||||
canvas_draw_str(canvas, 0, 12, "Found NFC-B");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "UID length: %d", RFAL_NFCB_NFCID0_LEN);
|
||||
canvas_draw_str(canvas, 2, 32, buffer);
|
||||
|
||||
canvas_draw_str(canvas, 2, 42, "UID:");
|
||||
for(uint8_t i = 0; i < RFAL_NFCB_NFCID0_LEN; i++) {
|
||||
snprintf(
|
||||
buffer + (i * 2),
|
||||
sizeof(buffer) - (i * 2),
|
||||
"%02X",
|
||||
model->device.nfcb.sensbRes.nfcid0[i]);
|
||||
}
|
||||
buffer[RFAL_NFCB_NFCID0_LEN * 2] = 0;
|
||||
canvas_draw_str(canvas, 18, 42, buffer);
|
||||
}
|
||||
|
||||
void nfc_view_read_nfcf_draw(Canvas* canvas, NfcViewReadModel* model) {
|
||||
char buffer[32];
|
||||
canvas_draw_str(canvas, 0, 12, "Found NFC-F");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "UID length: %d", RFAL_NFCF_NFCID2_LEN);
|
||||
canvas_draw_str(canvas, 2, 32, buffer);
|
||||
|
||||
canvas_draw_str(canvas, 2, 42, "UID:");
|
||||
for(uint8_t i = 0; i < RFAL_NFCF_NFCID2_LEN; i++) {
|
||||
snprintf(
|
||||
buffer + (i * 2),
|
||||
sizeof(buffer) - (i * 2),
|
||||
"%02X",
|
||||
model->device.nfcf.sensfRes.NFCID2[i]);
|
||||
}
|
||||
buffer[RFAL_NFCF_NFCID2_LEN * 2] = 0;
|
||||
canvas_draw_str(canvas, 18, 42, buffer);
|
||||
}
|
||||
|
||||
void nfc_view_read_nfcv_draw(Canvas* canvas, NfcViewReadModel* model) {
|
||||
char buffer[32];
|
||||
canvas_draw_str(canvas, 0, 12, "Found NFC-V");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "UID length: %d", RFAL_NFCV_UID_LEN);
|
||||
canvas_draw_str(canvas, 2, 32, buffer);
|
||||
|
||||
canvas_draw_str(canvas, 2, 42, "UID:");
|
||||
for(uint8_t i = 0; i < RFAL_NFCV_UID_LEN; i++) {
|
||||
snprintf(
|
||||
buffer + (i * 2), sizeof(buffer) - (i * 2), "%02X", model->device.nfcv.InvRes.UID[i]);
|
||||
}
|
||||
buffer[RFAL_NFCV_UID_LEN * 2] = 0;
|
||||
canvas_draw_str(canvas, 18, 42, buffer);
|
||||
}
|
||||
|
||||
void nfc_view_emulate_draw(Canvas* canvas, void* model) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 0, 12, "Emulating NFC-A");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 2, 22, "Type: T2T");
|
||||
canvas_draw_str(canvas, 2, 32, "UID length: 7");
|
||||
canvas_draw_str(canvas, 2, 42, "UID: 00010203040506");
|
||||
canvas_draw_str(canvas, 2, 52, "SAK: 00 ATQA: 44/00");
|
||||
}
|
||||
|
||||
void nfc_view_field_draw(Canvas* canvas, void* model) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 0, 12, "Field ON");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 2, 22, "TX/RX is disabled");
|
||||
}
|
||||
|
||||
void nfc_view_error_draw(Canvas* canvas, void* model) {
|
||||
NfcViewErrorModel* m = model;
|
||||
char buffer[32];
|
||||
|
||||
canvas_clear(canvas);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
snprintf(buffer, sizeof(buffer), "Error: %d", m->error);
|
||||
canvas_draw_str(canvas, 0, 12, buffer);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
if(m->error == ERR_WRONG_STATE) {
|
||||
canvas_draw_str(canvas, 2, 22, "Wrong State");
|
||||
} else if(m->error == ERR_PARAM) {
|
||||
canvas_draw_str(canvas, 2, 22, "Wrong Param");
|
||||
} else if(m->error == ERR_HW_MISMATCH) {
|
||||
canvas_draw_str(canvas, 2, 22, "HW mismatch");
|
||||
} else if(m->error == ERR_IO) {
|
||||
canvas_draw_str(canvas, 2, 22, "IO Error");
|
||||
} else {
|
||||
canvas_draw_str(canvas, 2, 22, "Details in st_errno.h");
|
||||
}
|
||||
}
|
36
applications/nfc/nfc_views.h
Normal file
36
applications/nfc/nfc_views.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <gui/canvas.h>
|
||||
#include <flipper_v2.h>
|
||||
|
||||
#include "nfc_types.h"
|
||||
|
||||
typedef enum {
|
||||
NfcViewRead,
|
||||
NfcViewEmulate,
|
||||
NfcViewField,
|
||||
NfcViewError,
|
||||
} NfcView;
|
||||
|
||||
typedef struct {
|
||||
bool found;
|
||||
NfcDevice device;
|
||||
} NfcViewReadModel;
|
||||
|
||||
void nfc_view_read_draw(Canvas* canvas, void* model);
|
||||
void nfc_view_read_nfca_draw(Canvas* canvas, NfcViewReadModel* model);
|
||||
void nfc_view_read_nfcb_draw(Canvas* canvas, NfcViewReadModel* model);
|
||||
void nfc_view_read_nfcf_draw(Canvas* canvas, NfcViewReadModel* model);
|
||||
void nfc_view_read_nfcv_draw(Canvas* canvas, NfcViewReadModel* model);
|
||||
|
||||
void nfc_view_emulate_draw(Canvas* canvas, void* model);
|
||||
|
||||
void nfc_view_field_draw(Canvas* canvas, void* model);
|
||||
|
||||
typedef struct {
|
||||
ReturnCode error;
|
||||
} NfcViewErrorModel;
|
||||
|
||||
void nfc_view_error_draw(Canvas* canvas, void* model);
|
@ -1,108 +1,320 @@
|
||||
#include "nfc_worker.h"
|
||||
#include "nfc.h"
|
||||
#include "nfc_i.h"
|
||||
#include "nfc_worker_i.h"
|
||||
|
||||
#define EXAMPLE_NFCA_DEVICES 5
|
||||
|
||||
// TODO replace with pubsub
|
||||
static bool isr_enabled = false;
|
||||
|
||||
void nfc_isr() {
|
||||
if(isr_enabled) {
|
||||
st25r3916Isr();
|
||||
NfcWorker* nfc_worker_alloc(osMessageQueueId_t message_queue) {
|
||||
NfcWorker* nfc_worker = furi_alloc(sizeof(NfcWorker));
|
||||
nfc_worker->message_queue = message_queue;
|
||||
// Worker thread attributes
|
||||
nfc_worker->thread_attr.name = "nfc_worker";
|
||||
nfc_worker->thread_attr.stack_size = 2048;
|
||||
// Initialize rfal
|
||||
rfalAnalogConfigInitialize();
|
||||
nfc_worker->error = rfalNfcInitialize();
|
||||
if(nfc_worker->error == ERR_NONE) {
|
||||
rfalLowPowerModeStart();
|
||||
nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
|
||||
} else {
|
||||
nfc_worker_change_state(nfc_worker, NfcWorkerStateBroken);
|
||||
}
|
||||
|
||||
return nfc_worker;
|
||||
}
|
||||
|
||||
NfcWorkerState nfc_worker_get_state(NfcWorker* nfc_worker) {
|
||||
return nfc_worker->state;
|
||||
}
|
||||
|
||||
ReturnCode nfc_worker_get_error(NfcWorker* nfc_worker) {
|
||||
return nfc_worker->error;
|
||||
}
|
||||
|
||||
void nfc_worker_free(NfcWorker* nfc_worker) {
|
||||
furi_assert(nfc_worker);
|
||||
}
|
||||
|
||||
void nfc_worker_start(NfcWorker* nfc_worker, NfcWorkerState state) {
|
||||
furi_assert(nfc_worker);
|
||||
furi_assert(nfc_worker->state == NfcWorkerStateReady);
|
||||
nfc_worker_change_state(nfc_worker, state);
|
||||
nfc_worker->thread = osThreadNew(nfc_worker_task, nfc_worker, &nfc_worker->thread_attr);
|
||||
}
|
||||
|
||||
void nfc_worker_stop(NfcWorker* nfc_worker) {
|
||||
furi_assert(nfc_worker);
|
||||
if(nfc_worker->state == NfcWorkerStateBroken) {
|
||||
return;
|
||||
}
|
||||
|
||||
nfc_worker_change_state(nfc_worker, NfcWorkerStateStop);
|
||||
}
|
||||
|
||||
void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state) {
|
||||
nfc_worker->state = state;
|
||||
}
|
||||
|
||||
void nfc_worker_task(void* context) {
|
||||
Nfc* nfc = context;
|
||||
ReturnCode err;
|
||||
rfalNfcaSensRes sensRes;
|
||||
rfalNfcaSelRes selRes;
|
||||
rfalNfcaListenDevice nfcaDevList[EXAMPLE_NFCA_DEVICES];
|
||||
uint8_t devCnt;
|
||||
uint8_t devIt;
|
||||
NfcWorker* nfc_worker = context;
|
||||
|
||||
rfalLowPowerModeStop();
|
||||
if(nfc_worker->state == NfcWorkerStatePoll) {
|
||||
nfc_worker_poll(nfc_worker);
|
||||
} else if(nfc_worker->state == NfcWorkerStateEmulate) {
|
||||
nfc_worker_emulate(nfc_worker);
|
||||
} else if(nfc_worker->state == NfcWorkerStateField) {
|
||||
nfc_worker_field(nfc_worker);
|
||||
}
|
||||
rfalLowPowerModeStart();
|
||||
|
||||
isr_enabled = true;
|
||||
nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
|
||||
|
||||
while(widget_is_enabled(nfc->widget)) {
|
||||
osThreadExit();
|
||||
}
|
||||
|
||||
void nfc_worker_poll(NfcWorker* nfc_worker) {
|
||||
while(nfc_worker->state == NfcWorkerStatePoll) {
|
||||
bool is_found = false;
|
||||
is_found |= nfc_worker_nfca_poll(nfc_worker);
|
||||
is_found |= nfc_worker_nfcb_poll(nfc_worker);
|
||||
is_found |= nfc_worker_nfcf_poll(nfc_worker);
|
||||
is_found |= nfc_worker_nfcv_poll(nfc_worker);
|
||||
rfalFieldOff();
|
||||
platformDelay(500);
|
||||
nfc->current = "Not detected";
|
||||
nfc->devCnt = 0;
|
||||
|
||||
rfalNfcaPollerInitialize();
|
||||
rfalFieldOnAndStartGT();
|
||||
nfc->ret = err = rfalNfcaPollerTechnologyDetection(RFAL_COMPLIANCE_MODE_NFC, &sensRes);
|
||||
if(err == ERR_NONE) {
|
||||
err = rfalNfcaPollerFullCollisionResolution(
|
||||
RFAL_COMPLIANCE_MODE_NFC, EXAMPLE_NFCA_DEVICES, nfcaDevList, &devCnt);
|
||||
nfc->devCnt = devCnt;
|
||||
if((err == ERR_NONE) && (devCnt > 0)) {
|
||||
platformLog("NFC-A device(s) found %d\r\n", devCnt);
|
||||
devIt = 0;
|
||||
if(nfcaDevList[devIt].isSleep) {
|
||||
err = rfalNfcaPollerCheckPresence(
|
||||
RFAL_14443A_SHORTFRAME_CMD_WUPA, &sensRes); /* Wake up all cards */
|
||||
if(err != ERR_NONE) {
|
||||
continue;
|
||||
}
|
||||
err = rfalNfcaPollerSelect(
|
||||
nfcaDevList[devIt].nfcId1,
|
||||
nfcaDevList[devIt].nfcId1Len,
|
||||
&selRes); /* Select specific device */
|
||||
if(err != ERR_NONE) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
nfc->first_atqa = nfcaDevList[devIt].sensRes;
|
||||
nfc->first_sak = nfcaDevList[devIt].selRes;
|
||||
|
||||
switch(nfcaDevList[devIt].type) {
|
||||
case RFAL_NFCA_T1T:
|
||||
/* No further activation needed for a T1T (RID already performed)*/
|
||||
platformLog(
|
||||
"NFC-A T1T device found \r\n"); /* NFC-A T1T device found, NFCID/UID is contained in: t1tRidRes.uid */
|
||||
nfc->current = "NFC-A T1T";
|
||||
/* Following communications shall be performed using:
|
||||
* - Non blocking: rfalStartTransceive() + rfalGetTransceiveState()
|
||||
* - Blocking: rfalTransceiveBlockingTx() + rfalTransceiveBlockingRx() or rfalTransceiveBlockingTxRx() */
|
||||
break;
|
||||
case RFAL_NFCA_T2T:
|
||||
/* No specific activation needed for a T2T */
|
||||
platformLog(
|
||||
"NFC-A T2T device found \r\n"); /* NFC-A T2T device found, NFCID/UID is contained in: nfcaDev.nfcid */
|
||||
nfc->current = "NFC-A T2T";
|
||||
/* Following communications shall be performed using:
|
||||
* - Non blocking: rfalStartTransceive() + rfalGetTransceiveState()
|
||||
* - Blocking: rfalTransceiveBlockingTx() + rfalTransceiveBlockingRx() or rfalTransceiveBlockingTxRx() */
|
||||
break;
|
||||
case RFAL_NFCA_T4T:
|
||||
platformLog(
|
||||
"NFC-A T4T (ISO-DEP) device found \r\n"); /* NFC-A T4T device found, NFCID/UID is contained in: nfcaDev.nfcid */
|
||||
nfc->current = "NFC-A T4T";
|
||||
/* Activation should continue using rfalIsoDepPollAHandleActivation(), see exampleRfalPoller.c */
|
||||
break;
|
||||
case RFAL_NFCA_T4T_NFCDEP: /* Device supports T4T and NFC-DEP */
|
||||
case RFAL_NFCA_NFCDEP: /* Device supports NFC-DEP */
|
||||
platformLog(
|
||||
"NFC-A P2P (NFC-DEP) device found \r\n"); /* NFC-A P2P device found, NFCID/UID is contained in: nfcaDev.nfcid */
|
||||
nfc->current = "NFC-A P2P";
|
||||
/* Activation should continue using rfalNfcDepInitiatorHandleActivation(), see exampleRfalPoller.c */
|
||||
break;
|
||||
}
|
||||
rfalNfcaPollerSleep(); /* Put device to sleep / HLTA (useless as the field will be turned off anyhow) */
|
||||
}
|
||||
if(!is_found) {
|
||||
NfcMessage message;
|
||||
message.type = NfcMessageTypeDeviceNotFound;
|
||||
furi_check(
|
||||
osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
}
|
||||
widget_update(nfc->widget);
|
||||
platformDelay(333);
|
||||
}
|
||||
}
|
||||
|
||||
bool nfc_worker_nfca_poll(NfcWorker* nfc_worker) {
|
||||
ReturnCode ret;
|
||||
rfalNfcaSensRes sense_res;
|
||||
|
||||
rfalNfcaPollerInitialize();
|
||||
rfalFieldOnAndStartGT();
|
||||
ret = rfalNfcaPollerTechnologyDetection(RFAL_COMPLIANCE_MODE_NFC, &sense_res);
|
||||
if(ret != ERR_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
isr_enabled = false;
|
||||
rfalFieldOff();
|
||||
rfalLowPowerModeStart();
|
||||
nfc->ret = ERR_NONE;
|
||||
nfc->worker = NULL;
|
||||
osThreadExit();
|
||||
}
|
||||
uint8_t dev_cnt;
|
||||
rfalNfcaListenDevice device;
|
||||
ret = rfalNfcaPollerFullCollisionResolution(RFAL_COMPLIANCE_MODE_NFC, 1, &device, &dev_cnt);
|
||||
if(ret != ERR_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(dev_cnt) {
|
||||
rfalNfcaPollerSleep();
|
||||
NfcMessage message;
|
||||
message.type = NfcMessageTypeDeviceFound;
|
||||
message.device.type = NfcDeviceTypeNfca;
|
||||
message.device.nfca = device;
|
||||
furi_check(
|
||||
osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nfc_worker_nfcb_poll(NfcWorker* nfc_worker) {
|
||||
ReturnCode ret;
|
||||
|
||||
rfalNfcbPollerInitialize();
|
||||
rfalFieldOnAndStartGT();
|
||||
|
||||
rfalNfcbSensbRes sensb_res;
|
||||
uint8_t sensb_res_len;
|
||||
ret = rfalNfcbPollerTechnologyDetection(RFAL_COMPLIANCE_MODE_NFC, &sensb_res, &sensb_res_len);
|
||||
if(ret != ERR_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t dev_cnt;
|
||||
rfalNfcbListenDevice device;
|
||||
ret = rfalNfcbPollerCollisionResolution(RFAL_COMPLIANCE_MODE_NFC, 1, &device, &dev_cnt);
|
||||
if(ret != ERR_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(dev_cnt) {
|
||||
rfalNfcbPollerSleep(device.sensbRes.nfcid0);
|
||||
NfcMessage message;
|
||||
message.type = NfcMessageTypeDeviceFound;
|
||||
message.device.type = NfcDeviceTypeNfcb;
|
||||
message.device.nfcb = device;
|
||||
furi_check(
|
||||
osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nfc_worker_nfcf_poll(NfcWorker* nfc_worker) {
|
||||
ReturnCode ret;
|
||||
|
||||
rfalNfcfPollerInitialize(RFAL_BR_212);
|
||||
rfalFieldOnAndStartGT();
|
||||
|
||||
ret = rfalNfcfPollerCheckPresence();
|
||||
if(ret != ERR_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t dev_cnt;
|
||||
rfalNfcfListenDevice device;
|
||||
ret = rfalNfcfPollerCollisionResolution(RFAL_COMPLIANCE_MODE_NFC, 1, &device, &dev_cnt);
|
||||
if(ret != ERR_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(dev_cnt) {
|
||||
NfcMessage message;
|
||||
message.type = NfcMessageTypeDeviceFound;
|
||||
message.device.type = NfcDeviceTypeNfcf;
|
||||
message.device.nfcf = device;
|
||||
furi_check(
|
||||
osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nfc_worker_nfcv_poll(NfcWorker* nfc_worker) {
|
||||
ReturnCode ret;
|
||||
rfalNfcvInventoryRes invRes;
|
||||
|
||||
rfalNfcvPollerInitialize();
|
||||
rfalFieldOnAndStartGT();
|
||||
|
||||
ret = rfalNfcvPollerCheckPresence(&invRes);
|
||||
if(ret != ERR_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t dev_cnt;
|
||||
rfalNfcvListenDevice device;
|
||||
ret = rfalNfcvPollerCollisionResolution(RFAL_COMPLIANCE_MODE_NFC, 1, &device, &dev_cnt);
|
||||
if(ret != ERR_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(dev_cnt) {
|
||||
rfalNfcvPollerSleep(RFAL_NFCV_REQ_FLAG_DEFAULT, device.InvRes.UID);
|
||||
NfcMessage message;
|
||||
message.type = NfcMessageTypeDeviceFound;
|
||||
message.device.type = NfcDeviceTypeNfcv;
|
||||
message.device.nfcv = device;
|
||||
furi_check(
|
||||
osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void nfc_worker_state_callback(rfalNfcState st) {
|
||||
(void)st;
|
||||
}
|
||||
|
||||
ReturnCode nfc_worker_trx(
|
||||
uint8_t* txBuf,
|
||||
uint16_t txBufSize,
|
||||
uint8_t** rxData,
|
||||
uint16_t** rcvLen,
|
||||
uint32_t fwt) {
|
||||
ReturnCode err;
|
||||
|
||||
err = rfalNfcDataExchangeStart(txBuf, txBufSize, rxData, rcvLen, fwt);
|
||||
if(err == ERR_NONE) {
|
||||
do {
|
||||
rfalNfcWorker();
|
||||
err = rfalNfcDataExchangeGetStatus();
|
||||
} while(err == ERR_BUSY);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void nfc_worker_exchange(NfcWorker* nfc_worker, rfalNfcDevice* nfc_device) {
|
||||
ReturnCode err;
|
||||
uint8_t* rxData;
|
||||
uint16_t* rcvLen;
|
||||
uint8_t txBuf[100];
|
||||
uint16_t txLen;
|
||||
|
||||
do {
|
||||
rfalNfcWorker();
|
||||
switch(rfalNfcGetState()) {
|
||||
case RFAL_NFC_STATE_ACTIVATED:
|
||||
err = nfc_worker_trx(NULL, 0, &rxData, &rcvLen, 0);
|
||||
break;
|
||||
case RFAL_NFC_STATE_DATAEXCHANGE:
|
||||
case RFAL_NFC_STATE_DATAEXCHANGE_DONE:
|
||||
// Not supported
|
||||
txBuf[0] = ((char)0x68);
|
||||
txBuf[1] = ((char)0x00);
|
||||
txLen = 2;
|
||||
err = nfc_worker_trx(txBuf, txLen, &rxData, &rcvLen, RFAL_FWT_NONE);
|
||||
break;
|
||||
case RFAL_NFC_STATE_START_DISCOVERY:
|
||||
return;
|
||||
case RFAL_NFC_STATE_LISTEN_SLEEP:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while((err == ERR_NONE) || (err == ERR_SLEEP_REQ));
|
||||
}
|
||||
|
||||
void nfc_worker_emulate(NfcWorker* nfc_worker) {
|
||||
rfalNfcDiscoverParam params;
|
||||
params.compMode = RFAL_COMPLIANCE_MODE_NFC;
|
||||
params.techs2Find = RFAL_NFC_LISTEN_TECH_A;
|
||||
params.totalDuration = 1000U;
|
||||
params.devLimit = 1;
|
||||
params.wakeupEnabled = false;
|
||||
params.wakeupConfigDefault = true;
|
||||
params.nfcfBR = RFAL_BR_212;
|
||||
params.ap2pBR = RFAL_BR_424;
|
||||
params.maxBR = RFAL_BR_KEEP;
|
||||
params.GBLen = RFAL_NFCDEP_GB_MAX_LEN;
|
||||
params.notifyCb = nfc_worker_state_callback;
|
||||
|
||||
params.lmConfigPA.nfcidLen = RFAL_LM_NFCID_LEN_07;
|
||||
params.lmConfigPA.nfcid[0] = 0x00;
|
||||
params.lmConfigPA.nfcid[1] = 0x01;
|
||||
params.lmConfigPA.nfcid[2] = 0x02;
|
||||
params.lmConfigPA.nfcid[3] = 0x03;
|
||||
params.lmConfigPA.nfcid[4] = 0x04;
|
||||
params.lmConfigPA.nfcid[5] = 0x05;
|
||||
params.lmConfigPA.nfcid[6] = 0x06;
|
||||
params.lmConfigPA.SENS_RES[0] = 0x44;
|
||||
params.lmConfigPA.SENS_RES[1] = 0x00;
|
||||
params.lmConfigPA.SEL_RES = 0x00;
|
||||
|
||||
ReturnCode ret;
|
||||
ret = rfalNfcDiscover(¶ms);
|
||||
if(ret != ERR_NONE) {
|
||||
asm("bkpt 1");
|
||||
return;
|
||||
}
|
||||
|
||||
rfalNfcDevice* nfc_device;
|
||||
while(nfc_worker->state == NfcWorkerStateEmulate) {
|
||||
rfalNfcWorker();
|
||||
if(rfalNfcIsDevActivated(rfalNfcGetState())) {
|
||||
rfalNfcGetActiveDevice(&nfc_device);
|
||||
nfc_worker_exchange(nfc_worker, nfc_device);
|
||||
}
|
||||
osDelay(10);
|
||||
}
|
||||
|
||||
rfalNfcDeactivate(false);
|
||||
}
|
||||
|
||||
void nfc_worker_field(NfcWorker* nfc_worker) {
|
||||
st25r3916TxRxOn();
|
||||
while(nfc_worker->state == NfcWorkerStateField) {
|
||||
osDelay(50);
|
||||
}
|
||||
st25r3916TxRxOff();
|
||||
}
|
||||
|
@ -1,3 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
void nfc_worker_task(void* context);
|
||||
typedef struct NfcWorker NfcWorker;
|
||||
|
||||
NfcWorker* nfc_worker_alloc(osMessageQueueId_t message_queue);
|
||||
|
||||
NfcWorkerState nfc_worker_get_state(NfcWorker* nfc_worker);
|
||||
|
||||
ReturnCode nfc_worker_get_error(NfcWorker* nfc_worker);
|
||||
|
||||
void nfc_worker_free(NfcWorker* nfc_worker);
|
||||
|
||||
void nfc_worker_start(NfcWorker* nfc_worker, NfcWorkerState state);
|
||||
|
||||
void nfc_worker_stop(NfcWorker* nfc_worker);
|
||||
|
41
applications/nfc/nfc_worker_i.h
Normal file
41
applications/nfc/nfc_worker_i.h
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include "nfc_types.h"
|
||||
#include "nfc_worker.h"
|
||||
|
||||
#include <flipper_v2.h>
|
||||
#include <cmsis_os2.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <rfal_analogConfig.h>
|
||||
#include <rfal_rf.h>
|
||||
#include <rfal_nfc.h>
|
||||
#include <rfal_nfca.h>
|
||||
#include <rfal_nfcb.h>
|
||||
#include <rfal_nfcf.h>
|
||||
#include <rfal_nfcv.h>
|
||||
#include <st25r3916.h>
|
||||
#include <st25r3916_irq.h>
|
||||
|
||||
struct NfcWorker {
|
||||
osMessageQueueId_t message_queue;
|
||||
osThreadAttr_t thread_attr;
|
||||
osThreadId_t thread;
|
||||
|
||||
NfcWorkerState state;
|
||||
ReturnCode error;
|
||||
};
|
||||
|
||||
void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state);
|
||||
|
||||
void nfc_worker_task(void* context);
|
||||
|
||||
void nfc_worker_poll(NfcWorker* nfc_worker);
|
||||
bool nfc_worker_nfca_poll(NfcWorker* nfc_worker);
|
||||
bool nfc_worker_nfcb_poll(NfcWorker* nfc_worker);
|
||||
bool nfc_worker_nfcf_poll(NfcWorker* nfc_worker);
|
||||
bool nfc_worker_nfcv_poll(NfcWorker* nfc_worker);
|
||||
|
||||
void nfc_worker_emulate(NfcWorker* nfc_worker);
|
||||
|
||||
void nfc_worker_field(NfcWorker* nfc_worker);
|
@ -16,8 +16,10 @@ void api_hal_bt_dump_state(string_t buffer);
|
||||
/* Get BT/BLE system component state */
|
||||
bool api_hal_bt_is_alive();
|
||||
|
||||
/* Lock shared access to flash controller */
|
||||
void api_hal_bt_lock_flash();
|
||||
/* Lock shared access to flash controller
|
||||
* @return true if lock was successful, false if not
|
||||
*/
|
||||
bool api_hal_bt_lock_flash();
|
||||
|
||||
/* Unlock shared access to flash controller */
|
||||
void api_hal_bt_unlock_flash();
|
||||
|
@ -223,13 +223,6 @@ void SystemClock_Config(void)
|
||||
Error_Handler();
|
||||
}
|
||||
/* USER CODE BEGIN Smps */
|
||||
|
||||
if (!LL_RCC_LSE_IsReady()) {
|
||||
LL_RCC_ForceBackupDomainReset();
|
||||
LL_RCC_ReleaseBackupDomainReset();
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
/* USER CODE END Smps */
|
||||
/** Enables the Clock Security System
|
||||
*/
|
||||
@ -272,7 +265,7 @@ void Error_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN Error_Handler_Debug */
|
||||
/* User can add his own implementation to report the HAL error return state */
|
||||
|
||||
asm("bkpt 1");
|
||||
/* USER CODE END Error_Handler_Debug */
|
||||
}
|
||||
|
||||
|
@ -39,34 +39,40 @@ bool api_hal_bt_is_alive() {
|
||||
}
|
||||
|
||||
bool api_hal_bt_wait_transition() {
|
||||
if (APPE_Status() == BleGlueStatusUninitialized) {
|
||||
return false;
|
||||
}
|
||||
while (APPE_Status() != BleGlueStatusStarted) {
|
||||
osDelay(1);
|
||||
uint8_t counter = 0;
|
||||
while (APPE_Status() == BleGlueStatusStartup) {
|
||||
osDelay(10);
|
||||
counter++;
|
||||
if (counter > 1000) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void api_hal_bt_lock_flash() {
|
||||
bool api_hal_bt_lock_flash() {
|
||||
if (!api_hal_bt_wait_transition()) {
|
||||
return false;
|
||||
}
|
||||
if (APPE_Status() == BleGlueStatusUninitialized) {
|
||||
HAL_FLASH_Unlock();
|
||||
return;
|
||||
} else {
|
||||
while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) {
|
||||
osDelay(1);
|
||||
}
|
||||
SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON);
|
||||
HAL_FLASH_Unlock();
|
||||
while(LL_FLASH_IsOperationSuspended()) {};
|
||||
}
|
||||
while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) {
|
||||
osDelay(1);
|
||||
}
|
||||
SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON);
|
||||
HAL_FLASH_Unlock();
|
||||
while(LL_FLASH_IsOperationSuspended()) {};
|
||||
return true;
|
||||
}
|
||||
|
||||
void api_hal_bt_unlock_flash() {
|
||||
if (!api_hal_bt_wait_transition()) {
|
||||
if (APPE_Status() == BleGlueStatusUninitialized) {
|
||||
HAL_FLASH_Lock();
|
||||
return;
|
||||
} else {
|
||||
SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF);
|
||||
HAL_FLASH_Lock();
|
||||
HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID);
|
||||
}
|
||||
SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF);
|
||||
HAL_FLASH_Lock();
|
||||
HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID);
|
||||
}
|
||||
|
@ -3,7 +3,9 @@
|
||||
#include <stm32wbxx.h>
|
||||
|
||||
bool api_hal_flash_erase(uint8_t page, uint8_t count) {
|
||||
api_hal_bt_lock_flash();
|
||||
if (!api_hal_bt_lock_flash()) {
|
||||
return false;
|
||||
}
|
||||
FLASH_EraseInitTypeDef erase;
|
||||
erase.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
erase.Page = page;
|
||||
@ -15,14 +17,18 @@ bool api_hal_flash_erase(uint8_t page, uint8_t count) {
|
||||
}
|
||||
|
||||
bool api_hal_flash_write_dword(size_t address, uint64_t data) {
|
||||
api_hal_bt_lock_flash();
|
||||
if (!api_hal_bt_lock_flash()) {
|
||||
return false;
|
||||
}
|
||||
HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, data);
|
||||
api_hal_bt_unlock_flash();
|
||||
return status == HAL_OK;
|
||||
}
|
||||
|
||||
bool api_hal_flash_write_row(size_t address, size_t source_address) {
|
||||
api_hal_bt_lock_flash();
|
||||
if (!api_hal_bt_lock_flash()) {
|
||||
return false;
|
||||
}
|
||||
HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FAST, address, source_address);
|
||||
api_hal_bt_unlock_flash();
|
||||
return status == HAL_OK;
|
||||
|
@ -129,7 +129,7 @@ static void AdvUpdateProcess(void *argument);
|
||||
static void Adv_Update( void );
|
||||
|
||||
|
||||
void APP_BLE_Init() {
|
||||
bool APP_BLE_Init() {
|
||||
SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = {
|
||||
{{0,0,0}}, /**< Header unused */
|
||||
{0, /** pBleBufferAddress not used */
|
||||
@ -158,7 +158,7 @@ void APP_BLE_Init() {
|
||||
HciUserEvtProcessId = osThreadNew(HciUserEvtProcess, NULL, &HciUserEvtProcess_attr);
|
||||
// Starts the BLE Stack on CPU2
|
||||
if (SHCI_C2_BLE_Init( &ble_init_cmd_packet ) != SHCI_Success) {
|
||||
Error_Handler();
|
||||
return false;
|
||||
}
|
||||
// Initialization of HCI & GATT & GAP layer
|
||||
Ble_Hci_Gap_Gatt_Init();
|
||||
@ -191,6 +191,7 @@ void APP_BLE_Init() {
|
||||
AdvIntervalMax = CFG_FAST_CONN_ADV_INTERVAL_MAX;
|
||||
|
||||
Adv_Request(APP_BLE_FAST_ADV);
|
||||
return true;
|
||||
}
|
||||
|
||||
SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt )
|
||||
|
@ -4,6 +4,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "hci_tl.h"
|
||||
|
||||
typedef enum {
|
||||
@ -16,7 +17,7 @@ typedef enum {
|
||||
APP_BLE_CONNECTED_CLIENT
|
||||
} APP_BLE_ConnStatus_t;
|
||||
|
||||
void APP_BLE_Init();
|
||||
bool APP_BLE_Init();
|
||||
|
||||
APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status();
|
||||
|
||||
|
@ -136,8 +136,12 @@ static void APPE_SysUserEvtRx( void * pPayload ) {
|
||||
UNUSED(pPayload);
|
||||
/* Traces channel initialization */
|
||||
// APPD_EnableCPU2( );
|
||||
ble_glue_status = BleGlueStatusStarted;
|
||||
APP_BLE_Init( );
|
||||
|
||||
if (APP_BLE_Init()) {
|
||||
ble_glue_status = BleGlueStatusStarted;
|
||||
} else {
|
||||
ble_glue_status = BleGlueStatusBroken;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
|
@ -7,6 +7,7 @@ extern "C" {
|
||||
typedef enum {
|
||||
BleGlueStatusUninitialized,
|
||||
BleGlueStatusStartup,
|
||||
BleGlueStatusBroken,
|
||||
BleGlueStatusStarted
|
||||
} BleGlueStatus;
|
||||
|
||||
|
@ -1,7 +1,34 @@
|
||||
#include "platform.h"
|
||||
#include <assert.h>
|
||||
#include <main.h>
|
||||
#include <spi.h>
|
||||
#include <api-hal-spi.h>
|
||||
|
||||
static osThreadAttr_t platform_irq_thread_attr;
|
||||
static volatile osThreadId_t platform_irq_thread_id = NULL;
|
||||
static volatile PlatformIrqCallback platform_irq_callback = NULL;
|
||||
|
||||
void nfc_isr() {
|
||||
if(platform_irq_callback && platformGpioIsHigh( ST25R_INT_PORT, ST25R_INT_PIN )) {
|
||||
osThreadFlagsSet(platform_irq_thread_id, 0x1);
|
||||
}
|
||||
}
|
||||
|
||||
void platformIrqWorker() {
|
||||
while(1) {
|
||||
uint32_t flags = osThreadFlagsWait(0x1, osFlagsWaitAny, osWaitForever);
|
||||
if (flags & 0x1) {
|
||||
platform_irq_callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void platformSetIrqCallback(PlatformIrqCallback callback) {
|
||||
platform_irq_callback = callback;
|
||||
platform_irq_thread_attr.name = "rfal_irq_worker";
|
||||
platform_irq_thread_attr.stack_size = 512;
|
||||
platform_irq_thread_attr.priority = osPriorityISR;
|
||||
platform_irq_thread_id = osThreadNew(platformIrqWorker, NULL, &platform_irq_thread_attr);
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef platformSpiTxRx(const uint8_t *txBuf, uint8_t *rxBuf, uint16_t len) {
|
||||
HAL_StatusTypeDef ret;
|
||||
@ -14,18 +41,17 @@ HAL_StatusTypeDef platformSpiTxRx(const uint8_t *txBuf, uint8_t *rxBuf, uint16_t
|
||||
}
|
||||
|
||||
if(ret != HAL_OK) {
|
||||
exit(250);
|
||||
asm("bkpt 1");
|
||||
exit(255);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void platformProtectST25RComm()
|
||||
{
|
||||
void platformProtectST25RComm() {
|
||||
api_hal_spi_lock(&SPI_R);
|
||||
NFC_SPI_Reconfigure();
|
||||
}
|
||||
|
||||
void platformUnprotectST25RComm()
|
||||
{
|
||||
|
||||
void platformUnprotectST25RComm() {
|
||||
api_hal_spi_unlock(&SPI_R);
|
||||
}
|
||||
|
@ -11,6 +11,9 @@
|
||||
#include "spi.h"
|
||||
#include "main.h"
|
||||
|
||||
typedef void (*PlatformIrqCallback)();
|
||||
void platformSetIrqCallback(PlatformIrqCallback cb);
|
||||
|
||||
HAL_StatusTypeDef platformSpiTxRx(const uint8_t *txBuf, uint8_t *rxBuf, uint16_t len);
|
||||
void platformProtectST25RComm();
|
||||
void platformUnprotectST25RComm();
|
||||
@ -21,8 +24,8 @@ void platformUnprotectST25RComm();
|
||||
#define ST25R_INT_PIN NFC_IRQ_Pin
|
||||
#define ST25R_INT_PORT NFC_IRQ_GPIO_Port
|
||||
|
||||
#define PLATFORM_LED_RX_PIN LED_GREEN_Pin
|
||||
#define PLATFORM_LED_RX_PORT LED_GREEN_GPIO_Port
|
||||
#define PLATFORM_LED_RX_PIN LED_RED_Pin
|
||||
#define PLATFORM_LED_RX_PORT LED_RED_GPIO_Port
|
||||
#define PLATFORM_LED_FIELD_PIN LED_BLUE_Pin
|
||||
#define PLATFORM_LED_FIELD_PORT LED_BLUE_GPIO_Port
|
||||
|
||||
@ -52,6 +55,7 @@ void platformUnprotectST25RComm();
|
||||
#define RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN 512U /*!< ISO-DEP APDU max length. */
|
||||
#define RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN 512U /*!< NFC-DEP PDU max length. */
|
||||
|
||||
#define platformIrqST25RSetCallback( cb ) platformSetIrqCallback(cb)
|
||||
|
||||
#define platformProtectST25RIrqStatus() platformProtectST25RComm() /*!< Protect unique access to IRQ status var - IRQ disable on single thread environment (MCU) ; Mutex lock on a multi thread environment */
|
||||
#define platformUnprotectST25RIrqStatus() platformUnprotectST25RComm() /*!< Unprotect the IRQ status var - IRQ enable on a single thread environment (MCU) ; Mutex unlock on a multi thread environment */
|
||||
@ -72,7 +76,7 @@ void platformUnprotectST25RComm();
|
||||
#define platformGetSysTick() osKernelGetTickCount() /*!< Get System Tick (1 tick = 1 ms) */
|
||||
|
||||
#define platformAssert( exp ) assert_param( exp ) /*!< Asserts whether the given expression is true*/
|
||||
#define platformErrorHandle() Error_Handler() /*!< Global error handle\trap */
|
||||
// #define platformErrorHandle() Error_Handler() /*!< Global error handle\trap */
|
||||
|
||||
#define platformSpiSelect() platformGpioClear( ST25R_SS_PORT, ST25R_SS_PIN ) /*!< SPI SS\CS: Chip|Slave Select */
|
||||
#define platformSpiDeselect() platformGpioSet( ST25R_SS_PORT, ST25R_SS_PIN ) /*!< SPI SS\CS: Chip|Slave Deselect */
|
||||
|
Loading…
Reference in New Issue
Block a user