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:
		
							
								
								
									
										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              */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user