FL-53: new NFC worker, A/B/F/V poll and display. (#283)
* GUI: view. Flooper-blooper fix compilation error. * GUI: view and viewdispatcher bones * GUI: view implementation, view models, view dispatcher * GUI: view navigation, model refinement. Power: use view, view dispatcher. * HAL Flash: proper page write. Dolphin: views. Power: views * Dolphin: transition idle scree to Views * Dolphin: input events on stats view. Format sources. * HAL: flash erase. Dolphin: permanent state storage. * Dolphin: first start welcome. HAL: flash operation status, errata 2.2.9 crutch. * NFC: rewrite worker * NFC: add support for B,F,V. * NFC: replace rfal irq hanlder with realtime thread, more details about cards. * Bootloader: LSE and RTS shenanigans, LED control, morse code for LSE failure error. * F4: stop in Error_Handler * BLE: handle working FUS, but empty radio stack. * HAL: alive FUS is now sufficient for flash controller access * Dolphin: update model after state load * NFC: detect navigation * RFAL: use osPriorityISR for isr thread * NFC: emulation * Bootloader: rollback incorrectly merged rename * Dolphin: rollback incorrectly merged changes * RFAL: remove volatile from thread attr * RFAL: do not call platform ErrorHandler, error codes is enough * NFC: improved error handling * Format sources * NFC: reset detect view model on start * Format sources * update codeowners * NFC: hide last info if no card detected
This commit is contained in:
		
							parent
							
								
									34dbb2ea86
								
							
						
					
					
						commit
						6928122650
					
				
							
								
								
									
										1
									
								
								.github/CODEOWNERS
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/CODEOWNERS
									
									
									
									
										vendored
									
									
								
							| @ -59,6 +59,7 @@ applications/menu/** @skotopes | |||||||
| # NFC | # NFC | ||||||
| 
 | 
 | ||||||
| applications/nfc/** @skotopes | applications/nfc/** @skotopes | ||||||
|  | lib/ST25RFAL002/** @skotopes | ||||||
| 
 | 
 | ||||||
| # SD Card | # SD Card | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -92,11 +92,6 @@ Dolphin* dolphin_alloc() { | |||||||
|     view_set_context(dolphin->idle_view_stats, dolphin); |     view_set_context(dolphin->idle_view_stats, dolphin); | ||||||
|     view_allocate_model( |     view_allocate_model( | ||||||
|         dolphin->idle_view_stats, ViewModelTypeLockFree, sizeof(DolphinViewIdleStatsModel)); |         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_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_input_callback(dolphin->idle_view_stats, dolphin_view_idle_stats_input); | ||||||
|     view_set_previous_callback(dolphin->idle_view_stats, dolphin_view_idle_back); |     view_set_previous_callback(dolphin->idle_view_stats, dolphin_view_idle_back); | ||||||
| @ -137,6 +132,11 @@ void dolphin_task() { | |||||||
|     } else { |     } else { | ||||||
|         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewFirstStart); |         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)) { |     if(!furi_create("dolphin", dolphin)) { | ||||||
|         printf("[dolphin_task] cannot create the dolphin record\n"); |         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_i.h" | ||||||
| #include "nfc_worker.h" |  | ||||||
| 
 | 
 | ||||||
| void nfc_draw_callback(Canvas* canvas, void* context) { | uint32_t nfc_view_exit(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); |  | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
| 
 |     NfcMessage message; | ||||||
|     if(!event->state || event->input != InputBack) return; |     message.type = NfcMessageTypeStop; | ||||||
| 
 |     furi_check(osMessageQueuePut(nfc->message_queue, &message, 0, osWaitForever) == osOK); | ||||||
|     widget_enabled_set(nfc->widget, false); |     return VIEW_NONE; | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 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); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Nfc* nfc_alloc() { | Nfc* nfc_alloc() { | ||||||
|     Nfc* nfc = furi_alloc(sizeof(Nfc)); |     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->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"); |     nfc->menu_vm = furi_open("menu"); | ||||||
|     furi_check(nfc->menu_vm); |     furi_check(nfc->menu_vm); | ||||||
| 
 | 
 | ||||||
|     nfc->menu = menu_item_alloc_menu("NFC", nfc->icon); |     nfc->menu = menu_item_alloc_menu("NFC", nfc->icon); | ||||||
|     menu_item_subitem_add( |     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( |     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( |     menu_item_subitem_add( | ||||||
|         nfc->menu, menu_item_alloc_function("Field Off", NULL, nfc_field_off_callback, nfc)); |         nfc->menu, menu_item_alloc_function("Field", NULL, nfc_menu_field_callback, nfc)); | ||||||
|     menu_item_subitem_add( | 
 | ||||||
|         nfc->menu, menu_item_alloc_function("Read", NULL, nfc_read_callback, nfc)); |     nfc->view_detect = view_alloc(); | ||||||
|     menu_item_subitem_add( |     view_set_context(nfc->view_detect, nfc); | ||||||
|         nfc->menu, menu_item_alloc_function("Write", NULL, nfc_write_callback, nfc)); |     view_set_draw_callback(nfc->view_detect, nfc_view_read_draw); | ||||||
|     menu_item_subitem_add( |     view_set_previous_callback(nfc->view_detect, nfc_view_exit); | ||||||
|         nfc->menu, menu_item_alloc_function("Brdige", NULL, nfc_bridge_callback, nfc)); |     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; |     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) { | void nfc_task(void* p) { | ||||||
|     Nfc* nfc = nfc_alloc(); |     Nfc* nfc = nfc_alloc(); | ||||||
| 
 | 
 | ||||||
|     Gui* gui = furi_open("gui"); |     Gui* gui = furi_open("gui"); | ||||||
|     widget_enabled_set(nfc->widget, false); |     view_dispatcher_attach_to_gui(nfc->view_dispatcher, gui, ViewDispatcherTypeFullscreen); | ||||||
|     gui_add_widget(gui, nfc->widget, GuiLayerFullscreen); |  | ||||||
| 
 | 
 | ||||||
|     with_value_mutex( |     with_value_mutex( | ||||||
|         nfc->menu_vm, (Menu * menu) { menu_item_add(menu, nfc->menu); }); |         nfc->menu_vm, (Menu * menu) { menu_item_add(menu, nfc->menu); }); | ||||||
| @ -178,17 +113,30 @@ void nfc_task(void* p) { | |||||||
|         furiac_exit(NULL); |         furiac_exit(NULL); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // TODO only for workaround
 |  | ||||||
|     nfc->ret = ERR_WRONG_STATE; |  | ||||||
| 
 |  | ||||||
|     furiac_ready(); |     furiac_ready(); | ||||||
| 
 | 
 | ||||||
|     NfcMessage message; |     NfcMessage message; | ||||||
|     while(1) { |     while(1) { | ||||||
|         dispatcher_recieve(nfc->dispatcher, (Message*)&message); |         furi_check(osMessageQueueGet(nfc->message_queue, &message, NULL, osWaitForever) == osOK); | ||||||
| 
 |         if(message.type == NfcMessageTypeDetect) { | ||||||
|         if(message.base.type == MessageTypeExit) { |             with_view_model( | ||||||
|             break; |                 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 | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include "nfc.h" | ||||||
|  | #include "nfc_types.h" | ||||||
|  | #include "nfc_views.h" | ||||||
|  | #include "nfc_worker.h" | ||||||
|  | 
 | ||||||
| #include <flipper_v2.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/gui.h> | ||||||
| #include <gui/widget.h> | #include <gui/view.h> | ||||||
| #include <gui/canvas.h> | #include <gui/view_dispatcher.h> | ||||||
| #include <assets_icons.h> | #include <assets_icons.h> | ||||||
| 
 | 
 | ||||||
| #include <menu/menu.h> | #include <menu/menu.h> | ||||||
| #include <menu/menu_item.h> | #include <menu/menu_item.h> | ||||||
| 
 | 
 | ||||||
| #include "dispatcher.h" |  | ||||||
| 
 |  | ||||||
| typedef enum { |  | ||||||
|     MessageTypeBase, |  | ||||||
| } NfcMessageType; |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
|     Message base; |  | ||||||
|     void* data; |  | ||||||
| } NfcMessage; |  | ||||||
| 
 |  | ||||||
| struct Nfc { | struct Nfc { | ||||||
|     Dispatcher* dispatcher; |     osMessageQueueId_t message_queue; | ||||||
|     Icon* icon; | 
 | ||||||
|     Widget* widget; |     NfcWorker* worker; | ||||||
|  | 
 | ||||||
|     ValueMutex* menu_vm; |     ValueMutex* menu_vm; | ||||||
|     MenuItem* menu; |     MenuItem* menu; | ||||||
|     rfalNfcDiscoverParam* disParams; |     Icon* icon; | ||||||
| 
 | 
 | ||||||
|     osThreadAttr_t worker_attr; |     View* view_detect; | ||||||
|     osThreadId_t worker; |     View* view_emulate; | ||||||
| 
 |     View* view_field; | ||||||
|     uint8_t screen; |     View* view_error; | ||||||
|     uint8_t ret; |     ViewDispatcher* view_dispatcher; | ||||||
|     uint8_t devCnt; |  | ||||||
|     rfalNfcaSensRes first_atqa; |  | ||||||
|     rfalNfcaSelRes first_sak; |  | ||||||
| 
 |  | ||||||
|     char* current; |  | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | 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_worker_i.h" | ||||||
| #include "nfc.h" |  | ||||||
| #include "nfc_i.h" |  | ||||||
| 
 | 
 | ||||||
| #define EXAMPLE_NFCA_DEVICES 5 | NfcWorker* nfc_worker_alloc(osMessageQueueId_t message_queue) { | ||||||
| 
 |     NfcWorker* nfc_worker = furi_alloc(sizeof(NfcWorker)); | ||||||
| // TODO replace with pubsub
 |     nfc_worker->message_queue = message_queue; | ||||||
| static bool isr_enabled = false; |     // Worker thread attributes
 | ||||||
| 
 |     nfc_worker->thread_attr.name = "nfc_worker"; | ||||||
| void nfc_isr() { |     nfc_worker->thread_attr.stack_size = 2048; | ||||||
|     if(isr_enabled) { |     // Initialize rfal
 | ||||||
|         st25r3916Isr(); |     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) { | void nfc_worker_task(void* context) { | ||||||
|     Nfc* nfc = context; |     NfcWorker* nfc_worker = context; | ||||||
|     ReturnCode err; |  | ||||||
|     rfalNfcaSensRes sensRes; |  | ||||||
|     rfalNfcaSelRes selRes; |  | ||||||
|     rfalNfcaListenDevice nfcaDevList[EXAMPLE_NFCA_DEVICES]; |  | ||||||
|     uint8_t devCnt; |  | ||||||
|     uint8_t devIt; |  | ||||||
| 
 | 
 | ||||||
|     rfalLowPowerModeStop(); |     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(); |         rfalFieldOff(); | ||||||
|         platformDelay(500); |         if(!is_found) { | ||||||
|         nfc->current = "Not detected"; |             NfcMessage message; | ||||||
|         nfc->devCnt = 0; |             message.type = NfcMessageTypeDeviceNotFound; | ||||||
|  |             furi_check( | ||||||
|  |                 osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK); | ||||||
|  |         } | ||||||
|  |         platformDelay(333); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool nfc_worker_nfca_poll(NfcWorker* nfc_worker) { | ||||||
|  |     ReturnCode ret; | ||||||
|  |     rfalNfcaSensRes sense_res; | ||||||
| 
 | 
 | ||||||
|     rfalNfcaPollerInitialize(); |     rfalNfcaPollerInitialize(); | ||||||
|     rfalFieldOnAndStartGT(); |     rfalFieldOnAndStartGT(); | ||||||
|         nfc->ret = err = rfalNfcaPollerTechnologyDetection(RFAL_COMPLIANCE_MODE_NFC, &sensRes); |     ret = rfalNfcaPollerTechnologyDetection(RFAL_COMPLIANCE_MODE_NFC, &sense_res); | ||||||
|  |     if(ret != ERR_NONE) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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) { |     if(err == ERR_NONE) { | ||||||
|             err = rfalNfcaPollerFullCollisionResolution( |         do { | ||||||
|                 RFAL_COMPLIANCE_MODE_NFC, EXAMPLE_NFCA_DEVICES, nfcaDevList, &devCnt); |             rfalNfcWorker(); | ||||||
|             nfc->devCnt = devCnt; |             err = rfalNfcDataExchangeGetStatus(); | ||||||
|             if((err == ERR_NONE) && (devCnt > 0)) { |         } while(err == ERR_BUSY); | ||||||
|                 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; |  | ||||||
|     } |     } | ||||||
|  |     return err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|                 nfc->first_atqa = nfcaDevList[devIt].sensRes; | void nfc_worker_exchange(NfcWorker* nfc_worker, rfalNfcDevice* nfc_device) { | ||||||
|                 nfc->first_sak = nfcaDevList[devIt].selRes; |     ReturnCode err; | ||||||
|  |     uint8_t* rxData; | ||||||
|  |     uint16_t* rcvLen; | ||||||
|  |     uint8_t txBuf[100]; | ||||||
|  |     uint16_t txLen; | ||||||
| 
 | 
 | ||||||
|                 switch(nfcaDevList[devIt].type) { |     do { | ||||||
|                 case RFAL_NFCA_T1T: |         rfalNfcWorker(); | ||||||
|                     /* No further activation needed for a T1T (RID already performed)*/ |         switch(rfalNfcGetState()) { | ||||||
|                     platformLog( |         case RFAL_NFC_STATE_ACTIVATED: | ||||||
|                         "NFC-A T1T device found \r\n"); /* NFC-A T1T device found, NFCID/UID is contained in: t1tRidRes.uid */ |             err = nfc_worker_trx(NULL, 0, &rxData, &rcvLen, 0); | ||||||
|                     nfc->current = "NFC-A T1T"; |  | ||||||
|                     /* Following communications shall be performed using:
 |  | ||||||
|                          *   - Non blocking: rfalStartTransceive() + rfalGetTransceiveState() |  | ||||||
|                          *   -     Blocking: rfalTransceiveBlockingTx() + rfalTransceiveBlockingRx() or rfalTransceiveBlockingTxRx()    */ |  | ||||||
|             break; |             break; | ||||||
|                 case RFAL_NFCA_T2T: |         case RFAL_NFC_STATE_DATAEXCHANGE: | ||||||
|                     /* No specific activation needed for a T2T */ |         case RFAL_NFC_STATE_DATAEXCHANGE_DONE: | ||||||
|                     platformLog( |             // Not supported
 | ||||||
|                         "NFC-A T2T device found \r\n"); /* NFC-A T2T device found, NFCID/UID is contained in: nfcaDev.nfcid */ |             txBuf[0] = ((char)0x68); | ||||||
|                     nfc->current = "NFC-A T2T"; |             txBuf[1] = ((char)0x00); | ||||||
|                     /* Following communications shall be performed using:
 |             txLen = 2; | ||||||
|                          *   - Non blocking: rfalStartTransceive() + rfalGetTransceiveState() |             err = nfc_worker_trx(txBuf, txLen, &rxData, &rcvLen, RFAL_FWT_NONE); | ||||||
|                          *   -     Blocking: rfalTransceiveBlockingTx() + rfalTransceiveBlockingRx() or rfalTransceiveBlockingTxRx()    */ |  | ||||||
|             break; |             break; | ||||||
|                 case RFAL_NFCA_T4T: |         case RFAL_NFC_STATE_START_DISCOVERY: | ||||||
|                     platformLog( |             return; | ||||||
|                         "NFC-A T4T (ISO-DEP) device found \r\n"); /* NFC-A T4T device found, NFCID/UID is contained in: nfcaDev.nfcid */ |         case RFAL_NFC_STATE_LISTEN_SLEEP: | ||||||
|                     nfc->current = "NFC-A T4T"; |         default: | ||||||
|                     /* 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; |             break; | ||||||
|         } |         } | ||||||
|                 rfalNfcaPollerSleep(); /* Put device to sleep / HLTA (useless as the field will be turned off anyhow) */ |     } while((err == ERR_NONE) || (err == ERR_SLEEP_REQ)); | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         widget_update(nfc->widget); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|     isr_enabled = false; | void nfc_worker_emulate(NfcWorker* nfc_worker) { | ||||||
|     rfalFieldOff(); |     rfalNfcDiscoverParam params; | ||||||
|     rfalLowPowerModeStart(); |     params.compMode = RFAL_COMPLIANCE_MODE_NFC; | ||||||
|     nfc->ret = ERR_NONE; |     params.techs2Find = RFAL_NFC_LISTEN_TECH_A; | ||||||
|     nfc->worker = NULL; |     params.totalDuration = 1000U; | ||||||
|     osThreadExit(); |     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 | #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 */ | /* Get BT/BLE system component state */ | ||||||
| bool api_hal_bt_is_alive(); | bool api_hal_bt_is_alive(); | ||||||
| 
 | 
 | ||||||
| /* Lock shared access to flash controller */ | /* Lock shared access to flash controller
 | ||||||
| void api_hal_bt_lock_flash(); |  * @return true if lock was successful, false if not | ||||||
|  |  */ | ||||||
|  | bool api_hal_bt_lock_flash(); | ||||||
| 
 | 
 | ||||||
| /* Unlock shared access to flash controller */ | /* Unlock shared access to flash controller */ | ||||||
| void api_hal_bt_unlock_flash(); | void api_hal_bt_unlock_flash(); | ||||||
|  | |||||||
| @ -223,13 +223,6 @@ void SystemClock_Config(void) | |||||||
|     Error_Handler(); |     Error_Handler(); | ||||||
|   } |   } | ||||||
|   /* USER CODE BEGIN Smps */ |   /* USER CODE BEGIN Smps */ | ||||||
| 
 |  | ||||||
|   if (!LL_RCC_LSE_IsReady()) { |  | ||||||
|     LL_RCC_ForceBackupDomainReset(); |  | ||||||
|     LL_RCC_ReleaseBackupDomainReset(); |  | ||||||
|     NVIC_SystemReset(); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /* USER CODE END Smps */ |   /* USER CODE END Smps */ | ||||||
|   /** Enables the Clock Security System
 |   /** Enables the Clock Security System
 | ||||||
|   */ |   */ | ||||||
| @ -272,7 +265,7 @@ void Error_Handler(void) | |||||||
| { | { | ||||||
|   /* USER CODE BEGIN Error_Handler_Debug */ |   /* USER CODE BEGIN Error_Handler_Debug */ | ||||||
|   /* User can add his own implementation to report the HAL error return state */ |   /* User can add his own implementation to report the HAL error return state */ | ||||||
| 
 |   asm("bkpt 1"); | ||||||
|   /* USER CODE END Error_Handler_Debug */ |   /* USER CODE END Error_Handler_Debug */ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -39,20 +39,24 @@ bool api_hal_bt_is_alive() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool api_hal_bt_wait_transition() { | bool api_hal_bt_wait_transition() { | ||||||
|     if (APPE_Status() == BleGlueStatusUninitialized) { |     uint8_t counter = 0; | ||||||
|  |     while (APPE_Status() == BleGlueStatusStartup) { | ||||||
|  |         osDelay(10); | ||||||
|  |         counter++; | ||||||
|  |         if (counter > 1000) { | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|     while (APPE_Status() != BleGlueStatusStarted) { |  | ||||||
|         osDelay(1); |  | ||||||
|     } |     } | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void api_hal_bt_lock_flash() { | bool api_hal_bt_lock_flash() { | ||||||
|     if (!api_hal_bt_wait_transition()) { |     if (!api_hal_bt_wait_transition()) { | ||||||
|         HAL_FLASH_Unlock(); |         return false; | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
|  |     if (APPE_Status() == BleGlueStatusUninitialized) { | ||||||
|  |         HAL_FLASH_Unlock(); | ||||||
|  |     } else { | ||||||
|         while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) { |         while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) { | ||||||
|             osDelay(1); |             osDelay(1); | ||||||
|         } |         } | ||||||
| @ -60,13 +64,15 @@ void api_hal_bt_lock_flash() { | |||||||
|         HAL_FLASH_Unlock(); |         HAL_FLASH_Unlock(); | ||||||
|         while(LL_FLASH_IsOperationSuspended()) {}; |         while(LL_FLASH_IsOperationSuspended()) {}; | ||||||
|     } |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| void api_hal_bt_unlock_flash() { | void api_hal_bt_unlock_flash() { | ||||||
|     if (!api_hal_bt_wait_transition()) { |     if (APPE_Status() == BleGlueStatusUninitialized) { | ||||||
|         HAL_FLASH_Lock(); |         HAL_FLASH_Lock(); | ||||||
|         return; |     } else { | ||||||
|     } |  | ||||||
|         SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); |         SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); | ||||||
|         HAL_FLASH_Lock(); |         HAL_FLASH_Lock(); | ||||||
|         HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID); |         HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID); | ||||||
|     } |     } | ||||||
|  | } | ||||||
|  | |||||||
| @ -3,7 +3,9 @@ | |||||||
| #include <stm32wbxx.h> | #include <stm32wbxx.h> | ||||||
| 
 | 
 | ||||||
| bool api_hal_flash_erase(uint8_t page, uint8_t count) { | 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; |     FLASH_EraseInitTypeDef erase; | ||||||
|     erase.TypeErase = FLASH_TYPEERASE_PAGES; |     erase.TypeErase = FLASH_TYPEERASE_PAGES; | ||||||
|     erase.Page = page; |     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) { | 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); |     HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, data); | ||||||
|     api_hal_bt_unlock_flash(); |     api_hal_bt_unlock_flash(); | ||||||
|     return status == HAL_OK; |     return status == HAL_OK; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool api_hal_flash_write_row(size_t address, size_t source_address) { | 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); |     HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FAST, address, source_address); | ||||||
|     api_hal_bt_unlock_flash(); |     api_hal_bt_unlock_flash(); | ||||||
|     return status == HAL_OK; |     return status == HAL_OK; | ||||||
|  | |||||||
| @ -129,7 +129,7 @@ static void AdvUpdateProcess(void *argument); | |||||||
| static void Adv_Update( void ); | static void Adv_Update( void ); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| void APP_BLE_Init() { | bool APP_BLE_Init() { | ||||||
|   SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = { |   SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = { | ||||||
|     {{0,0,0}},                  /**< Header unused */ |     {{0,0,0}},                  /**< Header unused */ | ||||||
|     {0,                         /** pBleBufferAddress not used */ |     {0,                         /** pBleBufferAddress not used */ | ||||||
| @ -158,7 +158,7 @@ void APP_BLE_Init() { | |||||||
|   HciUserEvtProcessId = osThreadNew(HciUserEvtProcess, NULL, &HciUserEvtProcess_attr); |   HciUserEvtProcessId = osThreadNew(HciUserEvtProcess, NULL, &HciUserEvtProcess_attr); | ||||||
|   // Starts the BLE Stack on CPU2
 |   // Starts the BLE Stack on CPU2
 | ||||||
|   if (SHCI_C2_BLE_Init( &ble_init_cmd_packet ) != SHCI_Success) { |   if (SHCI_C2_BLE_Init( &ble_init_cmd_packet ) != SHCI_Success) { | ||||||
|     Error_Handler(); |     return false; | ||||||
|   } |   } | ||||||
|   // Initialization of HCI & GATT & GAP layer
 |   // Initialization of HCI & GATT & GAP layer
 | ||||||
|   Ble_Hci_Gap_Gatt_Init(); |   Ble_Hci_Gap_Gatt_Init(); | ||||||
| @ -191,6 +191,7 @@ void APP_BLE_Init() { | |||||||
|   AdvIntervalMax = CFG_FAST_CONN_ADV_INTERVAL_MAX; |   AdvIntervalMax = CFG_FAST_CONN_ADV_INTERVAL_MAX; | ||||||
| 
 | 
 | ||||||
|   Adv_Request(APP_BLE_FAST_ADV); |   Adv_Request(APP_BLE_FAST_ADV); | ||||||
|  |   return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt ) | SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt ) | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ | |||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #include <stdbool.h> | ||||||
| #include "hci_tl.h" | #include "hci_tl.h" | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
| @ -16,7 +17,7 @@ typedef enum { | |||||||
|     APP_BLE_CONNECTED_CLIENT |     APP_BLE_CONNECTED_CLIENT | ||||||
| } APP_BLE_ConnStatus_t; | } APP_BLE_ConnStatus_t; | ||||||
| 
 | 
 | ||||||
| void APP_BLE_Init(); | bool APP_BLE_Init(); | ||||||
| 
 | 
 | ||||||
| APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status(); | APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -136,8 +136,12 @@ static void APPE_SysUserEvtRx( void * pPayload ) { | |||||||
|   UNUSED(pPayload); |   UNUSED(pPayload); | ||||||
|   /* Traces channel initialization */ |   /* Traces channel initialization */ | ||||||
|   // APPD_EnableCPU2( );
 |   // APPD_EnableCPU2( );
 | ||||||
|  |    | ||||||
|  |   if (APP_BLE_Init()) { | ||||||
|     ble_glue_status = BleGlueStatusStarted; |     ble_glue_status = BleGlueStatusStarted; | ||||||
|   APP_BLE_Init( ); |   } else { | ||||||
|  |     ble_glue_status = BleGlueStatusBroken; | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*************************************************************
 | /*************************************************************
 | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ extern "C" { | |||||||
| typedef enum { | typedef enum { | ||||||
|     BleGlueStatusUninitialized, |     BleGlueStatusUninitialized, | ||||||
|     BleGlueStatusStartup, |     BleGlueStatusStartup, | ||||||
|  |     BleGlueStatusBroken, | ||||||
|     BleGlueStatusStarted |     BleGlueStatusStarted | ||||||
| } BleGlueStatus; | } BleGlueStatus; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,7 +1,34 @@ | |||||||
| #include "platform.h" | #include "platform.h" | ||||||
| #include <assert.h> | #include <assert.h> | ||||||
| #include <main.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 platformSpiTxRx(const uint8_t *txBuf, uint8_t *rxBuf, uint16_t len) { | ||||||
|     HAL_StatusTypeDef ret; |     HAL_StatusTypeDef ret; | ||||||
| @ -14,18 +41,17 @@ HAL_StatusTypeDef platformSpiTxRx(const uint8_t *txBuf, uint8_t *rxBuf, uint16_t | |||||||
|     } |     } | ||||||
|      |      | ||||||
|     if(ret != HAL_OK) { |     if(ret != HAL_OK) { | ||||||
|         exit(250); |         asm("bkpt 1"); | ||||||
|  |         exit(255); | ||||||
|     } |     } | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | void platformProtectST25RComm() { | ||||||
| void platformProtectST25RComm() |     api_hal_spi_lock(&SPI_R); | ||||||
| { |  | ||||||
|     NFC_SPI_Reconfigure(); |     NFC_SPI_Reconfigure(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void platformUnprotectST25RComm() | void platformUnprotectST25RComm() { | ||||||
| { |     api_hal_spi_unlock(&SPI_R); | ||||||
|      |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -11,6 +11,9 @@ | |||||||
| #include "spi.h" | #include "spi.h" | ||||||
| #include "main.h" | #include "main.h" | ||||||
| 
 | 
 | ||||||
|  | typedef void (*PlatformIrqCallback)(); | ||||||
|  | void platformSetIrqCallback(PlatformIrqCallback cb); | ||||||
|  | 
 | ||||||
| HAL_StatusTypeDef platformSpiTxRx(const uint8_t *txBuf, uint8_t *rxBuf, uint16_t len); | HAL_StatusTypeDef platformSpiTxRx(const uint8_t *txBuf, uint8_t *rxBuf, uint16_t len); | ||||||
| void platformProtectST25RComm(); | void platformProtectST25RComm(); | ||||||
| void platformUnprotectST25RComm(); | void platformUnprotectST25RComm(); | ||||||
| @ -21,8 +24,8 @@ void platformUnprotectST25RComm(); | |||||||
| #define ST25R_INT_PIN NFC_IRQ_Pin | #define ST25R_INT_PIN NFC_IRQ_Pin | ||||||
| #define ST25R_INT_PORT NFC_IRQ_GPIO_Port | #define ST25R_INT_PORT NFC_IRQ_GPIO_Port | ||||||
| 
 | 
 | ||||||
| #define PLATFORM_LED_RX_PIN LED_GREEN_Pin | #define PLATFORM_LED_RX_PIN LED_RED_Pin | ||||||
| #define PLATFORM_LED_RX_PORT LED_GREEN_GPIO_Port | #define PLATFORM_LED_RX_PORT LED_RED_GPIO_Port | ||||||
| #define PLATFORM_LED_FIELD_PIN LED_BLUE_Pin | #define PLATFORM_LED_FIELD_PIN LED_BLUE_Pin | ||||||
| #define PLATFORM_LED_FIELD_PORT LED_BLUE_GPIO_Port | #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_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 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 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         */ | #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 platformGetSysTick()                          osKernelGetTickCount()                                    /*!< Get System Tick (1 tick = 1 ms)             */ | ||||||
| 
 | 
 | ||||||
| #define platformAssert( exp )                         assert_param( exp )                                      /*!< Asserts whether the given expression is true*/ | #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 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              */ | #define platformSpiDeselect()                         platformGpioSet( ST25R_SS_PORT, ST25R_SS_PIN )           /*!< SPI SS\CS: Chip|Slave Deselect              */ | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 あく
						あく