From 69281226506cc8a4cb66866f06cf2464d6cf21fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Mon, 11 Jan 2021 15:42:25 +0300 Subject: [PATCH] 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 --- .github/CODEOWNERS | 1 + applications/dolphin/dolphin.c | 10 +- applications/nfc/dispatcher.c | 57 --- applications/nfc/dispatcher.h | 28 -- applications/nfc/nfc.c | 252 +++++------ applications/nfc/nfc_i.h | 63 ++- applications/nfc/nfc_types.h | 68 +++ applications/nfc/nfc_views.c | 147 +++++++ applications/nfc/nfc_views.h | 36 ++ applications/nfc/nfc_worker.c | 402 +++++++++++++----- applications/nfc/nfc_worker.h | 14 +- applications/nfc/nfc_worker_i.h | 41 ++ firmware/targets/api-hal-include/api-hal-bt.h | 6 +- firmware/targets/f4/Src/main.c | 9 +- firmware/targets/f4/api-hal/api-hal-bt.c | 42 +- firmware/targets/f4/api-hal/api-hal-flash.c | 12 +- firmware/targets/f4/ble-glue/app_ble.c | 5 +- firmware/targets/f4/ble-glue/app_ble.h | 3 +- firmware/targets/f4/ble-glue/app_entry.c | 8 +- firmware/targets/f4/ble-glue/app_entry.h | 1 + lib/ST25RFAL002/platform.c | 42 +- lib/ST25RFAL002/platform.h | 10 +- 22 files changed, 838 insertions(+), 419 deletions(-) delete mode 100644 applications/nfc/dispatcher.c delete mode 100644 applications/nfc/dispatcher.h create mode 100644 applications/nfc/nfc_types.h create mode 100644 applications/nfc/nfc_views.c create mode 100644 applications/nfc/nfc_views.h create mode 100644 applications/nfc/nfc_worker_i.h diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 8474918b..63eb8893 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -59,6 +59,7 @@ applications/menu/** @skotopes # NFC applications/nfc/** @skotopes +lib/ST25RFAL002/** @skotopes # SD Card diff --git a/applications/dolphin/dolphin.c b/applications/dolphin/dolphin.c index 8506c12a..619c5fc2 100644 --- a/applications/dolphin/dolphin.c +++ b/applications/dolphin/dolphin.c @@ -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"); diff --git a/applications/nfc/dispatcher.c b/applications/nfc/dispatcher.c deleted file mode 100644 index 8e2a9c83..00000000 --- a/applications/nfc/dispatcher.c +++ /dev/null @@ -1,57 +0,0 @@ -#include "dispatcher.h" - -#include -#include - -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); -} diff --git a/applications/nfc/dispatcher.h b/applications/nfc/dispatcher.h deleted file mode 100644 index fdbcd3d2..00000000 --- a/applications/nfc/dispatcher.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include -#include - -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); diff --git a/applications/nfc/nfc.c b/applications/nfc/nfc.c index e983f287..854572d7 100644 --- a/applications/nfc/nfc.c +++ b/applications/nfc/nfc.c @@ -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; }); } } } diff --git a/applications/nfc/nfc_i.h b/applications/nfc/nfc_i.h index 455c4b31..d86d62b9 100644 --- a/applications/nfc/nfc_i.h +++ b/applications/nfc/nfc_i.h @@ -1,49 +1,44 @@ #pragma once +#include "nfc.h" +#include "nfc_types.h" +#include "nfc_views.h" +#include "nfc_worker.h" + #include -#include -#include -#include -#include -#include -#include - #include -#include -#include +#include +#include #include #include #include -#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); \ No newline at end of file diff --git a/applications/nfc/nfc_types.h b/applications/nfc/nfc_types.h new file mode 100644 index 00000000..b49c92ec --- /dev/null +++ b/applications/nfc/nfc_types.h @@ -0,0 +1,68 @@ +#pragma once + +#include +#include + +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; diff --git a/applications/nfc/nfc_views.c b/applications/nfc/nfc_views.c new file mode 100644 index 00000000..9832a3bf --- /dev/null +++ b/applications/nfc/nfc_views.c @@ -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"); + } +} diff --git a/applications/nfc/nfc_views.h b/applications/nfc/nfc_views.h new file mode 100644 index 00000000..9f592d9b --- /dev/null +++ b/applications/nfc/nfc_views.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include +#include + +#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); diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c index b6a37736..97e42497 100644 --- a/applications/nfc/nfc_worker.c +++ b/applications/nfc/nfc_worker.c @@ -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(); -} \ No newline at end of file + 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(); +} diff --git a/applications/nfc/nfc_worker.h b/applications/nfc/nfc_worker.h index a767606e..ede84634 100644 --- a/applications/nfc/nfc_worker.h +++ b/applications/nfc/nfc_worker.h @@ -1,3 +1,15 @@ #pragma once -void nfc_worker_task(void* context); \ No newline at end of file +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); diff --git a/applications/nfc/nfc_worker_i.h b/applications/nfc/nfc_worker_i.h new file mode 100644 index 00000000..c118e1d8 --- /dev/null +++ b/applications/nfc/nfc_worker_i.h @@ -0,0 +1,41 @@ +#pragma once + +#include "nfc_types.h" +#include "nfc_worker.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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); diff --git a/firmware/targets/api-hal-include/api-hal-bt.h b/firmware/targets/api-hal-include/api-hal-bt.h index 47d487bf..aebe4b9b 100644 --- a/firmware/targets/api-hal-include/api-hal-bt.h +++ b/firmware/targets/api-hal-include/api-hal-bt.h @@ -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(); diff --git a/firmware/targets/f4/Src/main.c b/firmware/targets/f4/Src/main.c index 9e4ef285..b300041a 100644 --- a/firmware/targets/f4/Src/main.c +++ b/firmware/targets/f4/Src/main.c @@ -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 */ } diff --git a/firmware/targets/f4/api-hal/api-hal-bt.c b/firmware/targets/f4/api-hal/api-hal-bt.c index bb95bcd6..f25c0b70 100644 --- a/firmware/targets/f4/api-hal/api-hal-bt.c +++ b/firmware/targets/f4/api-hal/api-hal-bt.c @@ -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); } diff --git a/firmware/targets/f4/api-hal/api-hal-flash.c b/firmware/targets/f4/api-hal/api-hal-flash.c index 557c81a8..63f583d5 100644 --- a/firmware/targets/f4/api-hal/api-hal-flash.c +++ b/firmware/targets/f4/api-hal/api-hal-flash.c @@ -3,7 +3,9 @@ #include 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; diff --git a/firmware/targets/f4/ble-glue/app_ble.c b/firmware/targets/f4/ble-glue/app_ble.c index adbd795e..45eb2971 100644 --- a/firmware/targets/f4/ble-glue/app_ble.c +++ b/firmware/targets/f4/ble-glue/app_ble.c @@ -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 ) diff --git a/firmware/targets/f4/ble-glue/app_ble.h b/firmware/targets/f4/ble-glue/app_ble.h index f7d43256..a2f25cb4 100644 --- a/firmware/targets/f4/ble-glue/app_ble.h +++ b/firmware/targets/f4/ble-glue/app_ble.h @@ -4,6 +4,7 @@ extern "C" { #endif +#include #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(); diff --git a/firmware/targets/f4/ble-glue/app_entry.c b/firmware/targets/f4/ble-glue/app_entry.c index 7dc7e814..ddf72b8d 100644 --- a/firmware/targets/f4/ble-glue/app_entry.c +++ b/firmware/targets/f4/ble-glue/app_entry.c @@ -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; + } } /************************************************************* diff --git a/firmware/targets/f4/ble-glue/app_entry.h b/firmware/targets/f4/ble-glue/app_entry.h index 2f284783..f1ce6038 100644 --- a/firmware/targets/f4/ble-glue/app_entry.h +++ b/firmware/targets/f4/ble-glue/app_entry.h @@ -7,6 +7,7 @@ extern "C" { typedef enum { BleGlueStatusUninitialized, BleGlueStatusStartup, + BleGlueStatusBroken, BleGlueStatusStarted } BleGlueStatus; diff --git a/lib/ST25RFAL002/platform.c b/lib/ST25RFAL002/platform.c index aa0e235f..00ffb0b6 100644 --- a/lib/ST25RFAL002/platform.c +++ b/lib/ST25RFAL002/platform.c @@ -1,7 +1,34 @@ #include "platform.h" #include #include -#include +#include + +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); } diff --git a/lib/ST25RFAL002/platform.h b/lib/ST25RFAL002/platform.h index 4be2ea66..3918fae9 100644 --- a/lib/ST25RFAL002/platform.h +++ b/lib/ST25RFAL002/platform.h @@ -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 */