[FL-1447] NFC application refactoring (#532)
* nfc: add separate nfc_detect * nfc_worker: add callback and context * api-hal-nfc: return busy if rfal worker is running * nfc: introduce nfc_detect, change nfc_worker API, rework main nfc task * nfc_emulate: introduce nfc_emulate module * nfc: introduce nfc_emv module * nfc: introduce nfc_mifare_ul module * nfc: remove unused nfc_views * nfc: separate messages and models * nfc: remove unused nfc message types * nfc: remove message_queue from common api * view_dispatcher: delete internal queue in destructor * api-hal-nfc: fix rfal worker initialization condition Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		| @@ -31,6 +31,10 @@ void view_dispatcher_free(ViewDispatcher* view_dispatcher) { | |||||||
|     ViewDict_clear(view_dispatcher->views); |     ViewDict_clear(view_dispatcher->views); | ||||||
|     // Free ViewPort |     // Free ViewPort | ||||||
|     view_port_free(view_dispatcher->view_port); |     view_port_free(view_dispatcher->view_port); | ||||||
|  |     // Free internal queue | ||||||
|  |     if(view_dispatcher->queue) { | ||||||
|  |         osMessageQueueDelete(view_dispatcher->queue); | ||||||
|  |     } | ||||||
|     // Free dispatcher |     // Free dispatcher | ||||||
|     free(view_dispatcher); |     free(view_dispatcher); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,262 +1,142 @@ | |||||||
| #include "nfc_i.h" | #include "nfc_i.h" | ||||||
| #include "api-hal-nfc.h" | #include "api-hal-nfc.h" | ||||||
|  |  | ||||||
| osMessageQueueId_t message_queue = NULL; |  | ||||||
|  |  | ||||||
| uint32_t nfc_view_stop(void* context) { |  | ||||||
|     furi_assert(message_queue); |  | ||||||
|     NfcMessage message; |  | ||||||
|     message.type = NfcMessageTypeStop; |  | ||||||
|     furi_check(osMessageQueuePut(message_queue, &message, 0, osWaitForever) == osOK); |  | ||||||
|     return NfcViewMenu; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| uint32_t nfc_view_exit(void* context) { | uint32_t nfc_view_exit(void* context) { | ||||||
|     furi_assert(message_queue); |  | ||||||
|     NfcMessage message; |  | ||||||
|     message.type = NfcMessageTypeExit; |  | ||||||
|     furi_check(osMessageQueuePut(message_queue, &message, 0, osWaitForever) == osOK); |  | ||||||
|     return VIEW_NONE; |     return VIEW_NONE; | ||||||
| } | } | ||||||
|  |  | ||||||
| void nfc_menu_callback(void* context, uint32_t index) { | void nfc_menu_callback(void* context, uint32_t index) { | ||||||
|     furi_assert(message_queue); |     furi_assert(context); | ||||||
|  |  | ||||||
|  |     Nfc* nfc = (Nfc*)context; | ||||||
|  |     if(index == NfcSubmenuDetect) { | ||||||
|  |         view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewDetect); | ||||||
|  |     } else if(index == NfcSubmenuEmulate) { | ||||||
|  |         view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewEmulate); | ||||||
|  |     } else if(index == NfcSubmenuEMV) { | ||||||
|  |         view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewEmv); | ||||||
|  |     } else if(index == NfcSubmenuMifareUl) { | ||||||
|  |         view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMifareUl); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_view_dispatcher_callback(uint32_t event, void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |  | ||||||
|  |     Nfc* nfc = (Nfc*)context; | ||||||
|     NfcMessage message; |     NfcMessage message; | ||||||
|     message.type = index; |     osMessageQueueGet(nfc->message_queue, &message, NULL, osWaitForever); | ||||||
|     furi_check(osMessageQueuePut(message_queue, &message, 0, osWaitForever) == osOK); |     if(event == NfcEventDetect) { | ||||||
|  |         nfc_detect_view_dispatcher_callback(nfc->nfc_detect, &message); | ||||||
|  |     } else if(event == NfcEventEmv) { | ||||||
|  |         nfc_emv_view_dispatcher_callback(nfc->nfc_emv, &message); | ||||||
|  |     } else if(event == NfcEventMifareUl) { | ||||||
|  |         nfc_mifare_ul_view_dispatcher_callback(nfc->nfc_mifare_ul, &message); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| Nfc* nfc_alloc() { | Nfc* nfc_alloc() { | ||||||
|     Nfc* nfc = furi_alloc(sizeof(Nfc)); |     Nfc* nfc = furi_alloc(sizeof(Nfc)); | ||||||
|  |  | ||||||
|     message_queue = osMessageQueueNew(8, sizeof(NfcMessage), NULL); |     nfc->message_queue = osMessageQueueNew(8, sizeof(NfcMessage), NULL); | ||||||
|  |     nfc->nfc_common.worker = nfc_worker_alloc(nfc->message_queue); | ||||||
|     nfc->worker = nfc_worker_alloc(message_queue); |     nfc->nfc_common.view_dispatcher = view_dispatcher_alloc(); | ||||||
|  |     view_dispatcher_enable_queue(nfc->nfc_common.view_dispatcher); | ||||||
|  |  | ||||||
|     // Open GUI record |     // Open GUI record | ||||||
|     nfc->gui = furi_record_open("gui"); |     nfc->gui = furi_record_open("gui"); | ||||||
|  |     view_dispatcher_attach_to_gui( | ||||||
|     // View Dispatcher |         nfc->nfc_common.view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); | ||||||
|     nfc->view_dispatcher = view_dispatcher_alloc(); |  | ||||||
|     view_dispatcher_attach_to_gui(nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); |  | ||||||
|  |  | ||||||
|     // Menu |     // Menu | ||||||
|     nfc->submenu = submenu_alloc(); |     nfc->submenu = submenu_alloc(); | ||||||
|     submenu_add_item(nfc->submenu, "Detect", NfcMessageTypeDetect, nfc_menu_callback, nfc); |     submenu_add_item(nfc->submenu, "Detect", NfcSubmenuDetect, nfc_menu_callback, nfc); | ||||||
|     submenu_add_item(nfc->submenu, "Read EMV", NfcMessageTypeReadEMV, nfc_menu_callback, nfc); |     submenu_add_item(nfc->submenu, "Emulate", NfcSubmenuEmulate, nfc_menu_callback, nfc); | ||||||
|  |     submenu_add_item(nfc->submenu, "Read bank card", NfcSubmenuEMV, nfc_menu_callback, nfc); | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         nfc->submenu, "Emulate EMV", NfcMessageTypeEmulateEMV, nfc_menu_callback, nfc); |         nfc->submenu, "Read Mifare Ultralight", NfcSubmenuMifareUl, nfc_menu_callback, nfc); | ||||||
|     submenu_add_item(nfc->submenu, "Emulate", NfcMessageTypeEmulate, nfc_menu_callback, nfc); |  | ||||||
|     submenu_add_item(nfc->submenu, "Field", NfcMessageTypeField, nfc_menu_callback, nfc); |  | ||||||
|     submenu_add_item( |  | ||||||
|         nfc->submenu, "Read MfUltralight", NfcMessageTypeReadMfUltralight, nfc_menu_callback, nfc); |  | ||||||
|  |  | ||||||
|     View* submenu_view = submenu_get_view(nfc->submenu); |     View* submenu_view = submenu_get_view(nfc->submenu); | ||||||
|     view_set_previous_callback(submenu_view, nfc_view_exit); |     view_set_previous_callback(submenu_view, nfc_view_exit); | ||||||
|     view_dispatcher_add_view(nfc->view_dispatcher, NfcViewMenu, submenu_view); |     view_dispatcher_add_view(nfc->nfc_common.view_dispatcher, NfcViewMenu, submenu_view); | ||||||
|  |  | ||||||
|     // Detect |     // Detect | ||||||
|     nfc->view_detect = view_alloc(); |     nfc->nfc_detect = nfc_detect_alloc(&nfc->nfc_common); | ||||||
|     view_set_context(nfc->view_detect, nfc); |     view_dispatcher_add_view( | ||||||
|     view_set_draw_callback(nfc->view_detect, nfc_view_read_draw); |         nfc->nfc_common.view_dispatcher, NfcViewDetect, nfc_detect_get_view(nfc->nfc_detect)); | ||||||
|     view_set_previous_callback(nfc->view_detect, nfc_view_stop); |  | ||||||
|     view_allocate_model(nfc->view_detect, ViewModelTypeLocking, sizeof(NfcViewReadModel)); |  | ||||||
|     view_dispatcher_add_view(nfc->view_dispatcher, NfcViewRead, nfc->view_detect); |  | ||||||
|  |  | ||||||
|     // Read EMV |  | ||||||
|     nfc->view_read_emv = view_alloc(); |  | ||||||
|     view_set_context(nfc->view_read_emv, nfc); |  | ||||||
|     view_set_draw_callback(nfc->view_read_emv, nfc_view_read_emv_draw); |  | ||||||
|     view_set_previous_callback(nfc->view_read_emv, nfc_view_stop); |  | ||||||
|     view_allocate_model(nfc->view_read_emv, ViewModelTypeLocking, sizeof(NfcViewReadModel)); |  | ||||||
|     view_dispatcher_add_view(nfc->view_dispatcher, NfcViewReadEmv, nfc->view_read_emv); |  | ||||||
|  |  | ||||||
|     // Emulate EMV |  | ||||||
|     nfc->view_emulate_emv = view_alloc(); |  | ||||||
|     view_set_context(nfc->view_emulate_emv, nfc); |  | ||||||
|     view_set_draw_callback(nfc->view_emulate_emv, nfc_view_emulate_emv_draw); |  | ||||||
|     view_set_previous_callback(nfc->view_emulate_emv, nfc_view_stop); |  | ||||||
|     view_dispatcher_add_view(nfc->view_dispatcher, NfcViewEmulateEMV, nfc->view_emulate_emv); |  | ||||||
|  |  | ||||||
|     // Emulate |     // Emulate | ||||||
|     nfc->view_emulate = view_alloc(); |     nfc->nfc_emulate = nfc_emulate_alloc(&nfc->nfc_common); | ||||||
|     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_stop); |  | ||||||
|     view_dispatcher_add_view(nfc->view_dispatcher, NfcViewEmulate, nfc->view_emulate); |  | ||||||
|  |  | ||||||
|     // Field |  | ||||||
|     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_stop); |  | ||||||
|     view_dispatcher_add_view(nfc->view_dispatcher, NfcViewField, nfc->view_field); |  | ||||||
|  |  | ||||||
|     // Read Mifare Ultralight |  | ||||||
|     nfc->view_read_mf_ultralight = view_alloc(); |  | ||||||
|     view_set_context(nfc->view_read_mf_ultralight, nfc); |  | ||||||
|     view_set_draw_callback(nfc->view_read_mf_ultralight, nfc_view_read_mf_ultralight_draw); |  | ||||||
|     view_set_previous_callback(nfc->view_read_mf_ultralight, nfc_view_stop); |  | ||||||
|     view_allocate_model( |  | ||||||
|         nfc->view_read_mf_ultralight, ViewModelTypeLocking, sizeof(NfcViewReadModel)); |  | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         nfc->view_dispatcher, NfcViewReadMfUltralight, nfc->view_read_mf_ultralight); |         nfc->nfc_common.view_dispatcher, NfcViewEmulate, nfc_emulate_get_view(nfc->nfc_emulate)); | ||||||
|  |  | ||||||
|     // Error |     // EMV | ||||||
|     nfc->view_error = view_alloc(); |     nfc->nfc_emv = nfc_emv_alloc(&nfc->nfc_common); | ||||||
|     view_set_context(nfc->view_error, nfc); |     view_dispatcher_add_view( | ||||||
|     view_set_draw_callback(nfc->view_error, nfc_view_error_draw); |         nfc->nfc_common.view_dispatcher, NfcViewEmv, nfc_emv_get_view(nfc->nfc_emv)); | ||||||
|     view_set_previous_callback(nfc->view_error, nfc_view_stop); |  | ||||||
|     view_allocate_model(nfc->view_error, ViewModelTypeLockFree, sizeof(NfcViewErrorModel)); |     // Mifare Ultralight | ||||||
|     view_dispatcher_add_view(nfc->view_dispatcher, NfcViewError, nfc->view_error); |     nfc->nfc_mifare_ul = nfc_mifare_ul_alloc(&nfc->nfc_common); | ||||||
|  |     view_dispatcher_add_view( | ||||||
|  |         nfc->nfc_common.view_dispatcher, | ||||||
|  |         NfcViewMifareUl, | ||||||
|  |         nfc_mifare_ul_get_view(nfc->nfc_mifare_ul)); | ||||||
|  |  | ||||||
|  |     // Set View Dispatcher custom event callback | ||||||
|  |     view_dispatcher_set_custom_callback( | ||||||
|  |         nfc->nfc_common.view_dispatcher, nfc_view_dispatcher_callback, nfc); | ||||||
|  |  | ||||||
|     // Switch to menu |     // Switch to menu | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); |     view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMenu); | ||||||
|  |  | ||||||
|     return nfc; |     return nfc; | ||||||
| } | } | ||||||
|  |  | ||||||
| void nfc_free(Nfc* nfc) { | void nfc_free(Nfc* nfc) { | ||||||
|     // Free nfc worker |     furi_assert(nfc); | ||||||
|     nfc_worker_free(nfc->worker); |  | ||||||
|     // Free allocated queue |  | ||||||
|     osMessageQueueDelete(message_queue); |  | ||||||
|     message_queue = NULL; |  | ||||||
|  |  | ||||||
|     // Free allocated views |     // Submenu | ||||||
|     // Menu |     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewMenu); | ||||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewMenu); |  | ||||||
|     submenu_free(nfc->submenu); |     submenu_free(nfc->submenu); | ||||||
|  |  | ||||||
|     // Detect |     // Detect | ||||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewRead); |     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewDetect); | ||||||
|     view_free(nfc->view_detect); |     nfc_detect_free(nfc->nfc_detect); | ||||||
|  |  | ||||||
|     // Read EMV |  | ||||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewReadEmv); |  | ||||||
|     view_free(nfc->view_read_emv); |  | ||||||
|  |  | ||||||
|     // Emulate EMV |  | ||||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewEmulateEMV); |  | ||||||
|     view_free(nfc->view_emulate_emv); |  | ||||||
|  |  | ||||||
|     // Emulate |     // Emulate | ||||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewEmulate); |     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewEmulate); | ||||||
|     view_free(nfc->view_emulate); |     nfc_emulate_free(nfc->nfc_emulate); | ||||||
|  |  | ||||||
|     // Field |     // EMV | ||||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewField); |     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewEmv); | ||||||
|     view_free(nfc->view_field); |     nfc_emv_free(nfc->nfc_emv); | ||||||
|  |  | ||||||
|     // Read Mifare Ultralight |     // Mifare ultralight | ||||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewReadMfUltralight); |     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewMifareUl); | ||||||
|     view_free(nfc->view_read_mf_ultralight); |     nfc_mifare_ul_free(nfc->nfc_mifare_ul); | ||||||
|  |  | ||||||
|     // Error |     // Worker | ||||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewError); |     nfc_worker_stop(nfc->nfc_common.worker); | ||||||
|     view_free(nfc->view_error); |     nfc_worker_free(nfc->nfc_common.worker); | ||||||
|  |  | ||||||
|     // Free View Dispatcher |     // View dispatcher | ||||||
|     view_dispatcher_free(nfc->view_dispatcher); |     view_dispatcher_free(nfc->nfc_common.view_dispatcher); | ||||||
|  |  | ||||||
|     // Close all opened records |     // GUI | ||||||
|     furi_record_close("gui"); |     furi_record_close("gui"); | ||||||
|     nfc->gui = NULL; |     nfc->gui = NULL; | ||||||
|  |  | ||||||
|     // Free nfc object |     // The rest | ||||||
|  |     osMessageQueueDelete(nfc->message_queue); | ||||||
|     free(nfc); |     free(nfc); | ||||||
| } | } | ||||||
|  |  | ||||||
| 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); |  | ||||||
|                 return true; |  | ||||||
|             }); |  | ||||||
|         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); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int32_t nfc_task(void* p) { | int32_t nfc_task(void* p) { | ||||||
|     Nfc* nfc = nfc_alloc(); |     Nfc* nfc = nfc_alloc(); | ||||||
|  |  | ||||||
|     NfcMessage message; |     view_dispatcher_run(nfc->nfc_common.view_dispatcher); | ||||||
|     while(1) { |  | ||||||
|         furi_check(osMessageQueueGet(message_queue, &message, NULL, osWaitForever) == osOK); |  | ||||||
|  |  | ||||||
|         if(message.type == NfcMessageTypeDetect) { |     nfc_free(nfc); | ||||||
|             with_view_model( |  | ||||||
|                 nfc->view_detect, (NfcViewReadModel * model) { |  | ||||||
|                     model->found = false; |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|             nfc_start(nfc, NfcViewRead, NfcWorkerStatePoll); |  | ||||||
|         } else if(message.type == NfcMessageTypeReadEMV) { |  | ||||||
|             with_view_model( |  | ||||||
|                 nfc->view_read_emv, (NfcViewReadModel * model) { |  | ||||||
|                     model->found = false; |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|             nfc_start(nfc, NfcViewReadEmv, NfcWorkerStateReadEMV); |  | ||||||
|         } else if(message.type == NfcMessageTypeEmulateEMV) { |  | ||||||
|             nfc_start(nfc, NfcViewEmulateEMV, NfcWorkerStateEmulateEMV); |  | ||||||
|         } else if(message.type == NfcMessageTypeEmulate) { |  | ||||||
|             nfc_start(nfc, NfcViewEmulate, NfcWorkerStateEmulate); |  | ||||||
|         } else if(message.type == NfcMessageTypeField) { |  | ||||||
|             nfc_start(nfc, NfcViewField, NfcWorkerStateField); |  | ||||||
|         } else if(message.type == NfcMessageTypeReadMfUltralight) { |  | ||||||
|             nfc_start(nfc, NfcViewReadMfUltralight, NfcWorkerStateReadMfUltralight); |  | ||||||
|         } 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; |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|         } else if(message.type == NfcMessageTypeDeviceNotFound) { |  | ||||||
|             with_view_model( |  | ||||||
|                 nfc->view_detect, (NfcViewReadModel * model) { |  | ||||||
|                     model->found = false; |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|         } else if(message.type == NfcMessageTypeEMVFound) { |  | ||||||
|             with_view_model( |  | ||||||
|                 nfc->view_read_emv, (NfcViewReadModel * model) { |  | ||||||
|                     model->found = true; |  | ||||||
|                     model->device = message.device; |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|         } else if(message.type == NfcMessageTypeEMVNotFound) { |  | ||||||
|             with_view_model( |  | ||||||
|                 nfc->view_read_emv, (NfcViewReadModel * model) { |  | ||||||
|                     model->found = false; |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|         } else if(message.type == NfcMessageTypeMfUlFound) { |  | ||||||
|             with_view_model( |  | ||||||
|                 nfc->view_read_mf_ultralight, (NfcViewReadModel * model) { |  | ||||||
|                     model->found = true; |  | ||||||
|                     model->device = message.device; |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|         } else if(message.type == NfcMessageTypeMfUlNotFound) { |  | ||||||
|             with_view_model( |  | ||||||
|                 nfc->view_read_mf_ultralight, (NfcViewReadModel * model) { |  | ||||||
|                     model->found = false; |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|         } else if(message.type == NfcMessageTypeExit) { |  | ||||||
|             nfc_free(nfc); |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										145
									
								
								applications/nfc/nfc_detect.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										145
									
								
								applications/nfc/nfc_detect.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,145 @@ | |||||||
|  | #include "nfc_detect.h" | ||||||
|  |  | ||||||
|  | #include "nfc_i.h" | ||||||
|  | #include "nfc_types.h" | ||||||
|  | #include <furi.h> | ||||||
|  | #include <api-hal.h> | ||||||
|  | #include <input/input.h> | ||||||
|  |  | ||||||
|  | struct NfcDetect { | ||||||
|  |     NfcCommon* nfc_common; | ||||||
|  |     View* view; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     bool found; | ||||||
|  |     NfcDeviceData data; | ||||||
|  | } NfcDetectModel; | ||||||
|  |  | ||||||
|  | void nfc_detect_draw(Canvas* canvas, NfcDetectModel* model) { | ||||||
|  |     char buffer[32]; | ||||||
|  |     canvas_clear(canvas); | ||||||
|  |     canvas_set_font(canvas, FontPrimary); | ||||||
|  |     if(model->found) { | ||||||
|  |         canvas_draw_str(canvas, 0, 12, "Found"); | ||||||
|  |         canvas_draw_str(canvas, 32, 12, nfc_get_dev_type(model->data.device)); | ||||||
|  |         canvas_set_font(canvas, FontSecondary); | ||||||
|  |         if(model->data.protocol != NfcDeviceProtocolUnknown) { | ||||||
|  |             canvas_draw_str(canvas, 0, 22, nfc_get_protocol(model->data.protocol)); | ||||||
|  |         } | ||||||
|  |         // Display UID | ||||||
|  |         for(uint8_t i = 0; i < model->data.uid_len; i++) { | ||||||
|  |             snprintf(buffer + (i * 2), sizeof(buffer) - (i * 2), "%02X", model->data.uid[i]); | ||||||
|  |             buffer[model->data.uid_len * 2] = 0; | ||||||
|  |         } | ||||||
|  |         canvas_draw_str(canvas, 0, 32, "UID: "); | ||||||
|  |         canvas_draw_str(canvas, 22, 32, buffer); | ||||||
|  |         // Display ATQA and SAK | ||||||
|  |         snprintf( | ||||||
|  |             buffer, | ||||||
|  |             sizeof(buffer), | ||||||
|  |             "ATQA: %02X %02X   SAK: %02X", | ||||||
|  |             model->data.atqa[1], | ||||||
|  |             model->data.atqa[0], | ||||||
|  |             model->data.sak); | ||||||
|  |         canvas_draw_str(canvas, 0, 42, buffer); | ||||||
|  |     } else { | ||||||
|  |         canvas_draw_str(canvas, 0, 12, "Searching"); | ||||||
|  |         canvas_set_font(canvas, FontSecondary); | ||||||
|  |         canvas_draw_str(canvas, 2, 22, "Place card to the back"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool nfc_detect_input(InputEvent* event, void* context) { | ||||||
|  |     if(event->key == InputKeyBack) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_detect_worker_callback(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |  | ||||||
|  |     NfcDetect* nfc_detect = (NfcDetect*)context; | ||||||
|  |     view_dispatcher_send_custom_event(nfc_detect->nfc_common->view_dispatcher, NfcEventDetect); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_detect_view_dispatcher_callback(NfcDetect* nfc_detect, NfcMessage* message) { | ||||||
|  |     furi_assert(nfc_detect); | ||||||
|  |     furi_assert(message); | ||||||
|  |  | ||||||
|  |     if(message->found) { | ||||||
|  |         with_view_model( | ||||||
|  |             nfc_detect->view, (NfcDetectModel * model) { | ||||||
|  |                 model->found = true; | ||||||
|  |                 model->data = message->nfc_detect_data; | ||||||
|  |                 return true; | ||||||
|  |             }); | ||||||
|  |     } else { | ||||||
|  |         with_view_model( | ||||||
|  |             nfc_detect->view, (NfcDetectModel * model) { | ||||||
|  |                 model->found = false; | ||||||
|  |                 return true; | ||||||
|  |             }); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_detect_enter(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |  | ||||||
|  |     NfcDetect* nfc_detect = (NfcDetect*)context; | ||||||
|  |     with_view_model( | ||||||
|  |         nfc_detect->view, (NfcDetectModel * model) { | ||||||
|  |             model->found = false; | ||||||
|  |             model->data.protocol = NfcDeviceProtocolUnknown; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  |     nfc_worker_start( | ||||||
|  |         nfc_detect->nfc_common->worker, | ||||||
|  |         NfcWorkerStateDetect, | ||||||
|  |         nfc_detect_worker_callback, | ||||||
|  |         nfc_detect); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_detect_exit(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |  | ||||||
|  |     NfcDetect* nfc_detect = (NfcDetect*)context; | ||||||
|  |     nfc_worker_stop(nfc_detect->nfc_common->worker); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint32_t nfc_detect_back(void* context) { | ||||||
|  |     return NfcViewMenu; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NfcDetect* nfc_detect_alloc(NfcCommon* nfc_common) { | ||||||
|  |     furi_assert(nfc_common); | ||||||
|  |  | ||||||
|  |     NfcDetect* nfc_detect = furi_alloc(sizeof(NfcDetect)); | ||||||
|  |     nfc_detect->nfc_common = nfc_common; | ||||||
|  |  | ||||||
|  |     // View allocation and configuration | ||||||
|  |     nfc_detect->view = view_alloc(); | ||||||
|  |     view_allocate_model(nfc_detect->view, ViewModelTypeLockFree, sizeof(NfcDetectModel)); | ||||||
|  |     view_set_context(nfc_detect->view, nfc_detect); | ||||||
|  |     view_set_draw_callback(nfc_detect->view, (ViewDrawCallback)nfc_detect_draw); | ||||||
|  |     view_set_input_callback(nfc_detect->view, nfc_detect_input); | ||||||
|  |     view_set_enter_callback(nfc_detect->view, nfc_detect_enter); | ||||||
|  |     view_set_exit_callback(nfc_detect->view, nfc_detect_exit); | ||||||
|  |     view_set_previous_callback(nfc_detect->view, nfc_detect_back); | ||||||
|  |  | ||||||
|  |     return nfc_detect; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_detect_free(NfcDetect* nfc_detect) { | ||||||
|  |     furi_assert(nfc_detect); | ||||||
|  |  | ||||||
|  |     view_free(nfc_detect->view); | ||||||
|  |     free(nfc_detect); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | View* nfc_detect_get_view(NfcDetect* nfc_detect) { | ||||||
|  |     furi_assert(nfc_detect); | ||||||
|  |  | ||||||
|  |     return nfc_detect->view; | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								applications/nfc/nfc_detect.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								applications/nfc/nfc_detect.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <gui/view.h> | ||||||
|  | #include "nfc_types.h" | ||||||
|  |  | ||||||
|  | typedef struct NfcDetect NfcDetect; | ||||||
|  |  | ||||||
|  | NfcDetect* nfc_detect_alloc(NfcCommon* nfc_common); | ||||||
|  |  | ||||||
|  | void nfc_detect_free(NfcDetect* nfc_detect); | ||||||
|  |  | ||||||
|  | View* nfc_detect_get_view(NfcDetect* nfc_detect); | ||||||
|  |  | ||||||
|  | void nfc_detect_view_dispatcher_callback(NfcDetect* nfc_detect, NfcMessage* message); | ||||||
							
								
								
									
										79
									
								
								applications/nfc/nfc_emulate.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								applications/nfc/nfc_emulate.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | |||||||
|  | #include "nfc_emulate.h" | ||||||
|  |  | ||||||
|  | #include "nfc_i.h" | ||||||
|  | #include "nfc_types.h" | ||||||
|  | #include <furi.h> | ||||||
|  | #include <api-hal.h> | ||||||
|  | #include <input/input.h> | ||||||
|  |  | ||||||
|  | struct NfcEmulate { | ||||||
|  |     NfcCommon* nfc_common; | ||||||
|  |     View* view; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | void nfc_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: 36 9C E7 B1 0A C1 34"); | ||||||
|  |     canvas_draw_str(canvas, 2, 52, "SAK: 00 ATQA: 00/44"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool nfc_emulate_input(InputEvent* event, void* context) { | ||||||
|  |     if(event->key == InputKeyBack) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_emulate_enter(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |  | ||||||
|  |     NfcEmulate* nfc_emulate = (NfcEmulate*)context; | ||||||
|  |     nfc_worker_start(nfc_emulate->nfc_common->worker, NfcWorkerStateEmulate, NULL, NULL); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_emulate_exit(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |  | ||||||
|  |     NfcEmulate* nfc_emulate = (NfcEmulate*)context; | ||||||
|  |     nfc_worker_stop(nfc_emulate->nfc_common->worker); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint32_t nfc_emulate_back(void* context) { | ||||||
|  |     return NfcViewMenu; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NfcEmulate* nfc_emulate_alloc(NfcCommon* nfc_common) { | ||||||
|  |     furi_assert(nfc_common); | ||||||
|  |  | ||||||
|  |     NfcEmulate* nfc_emulate = furi_alloc(sizeof(NfcEmulate)); | ||||||
|  |     nfc_emulate->nfc_common = nfc_common; | ||||||
|  |  | ||||||
|  |     // View allocation and configuration | ||||||
|  |     nfc_emulate->view = view_alloc(); | ||||||
|  |     view_set_context(nfc_emulate->view, nfc_emulate); | ||||||
|  |     view_set_draw_callback(nfc_emulate->view, (ViewDrawCallback)nfc_emulate_draw); | ||||||
|  |     view_set_input_callback(nfc_emulate->view, nfc_emulate_input); | ||||||
|  |     view_set_enter_callback(nfc_emulate->view, nfc_emulate_enter); | ||||||
|  |     view_set_exit_callback(nfc_emulate->view, nfc_emulate_exit); | ||||||
|  |     view_set_previous_callback(nfc_emulate->view, nfc_emulate_back); | ||||||
|  |  | ||||||
|  |     return nfc_emulate; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_emulate_free(NfcEmulate* nfc_emulate) { | ||||||
|  |     furi_assert(nfc_emulate); | ||||||
|  |  | ||||||
|  |     view_free(nfc_emulate->view); | ||||||
|  |     free(nfc_emulate); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | View* nfc_emulate_get_view(NfcEmulate* nfc_emulate) { | ||||||
|  |     furi_assert(nfc_emulate); | ||||||
|  |  | ||||||
|  |     return nfc_emulate->view; | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								applications/nfc/nfc_emulate.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								applications/nfc/nfc_emulate.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <gui/view.h> | ||||||
|  | #include "nfc_types.h" | ||||||
|  |  | ||||||
|  | typedef struct NfcEmulate NfcEmulate; | ||||||
|  |  | ||||||
|  | NfcEmulate* nfc_emulate_alloc(NfcCommon* nfc_common); | ||||||
|  |  | ||||||
|  | void nfc_emulate_free(NfcEmulate* nfc_emulate); | ||||||
|  |  | ||||||
|  | View* nfc_emulate_get_view(NfcEmulate* nfc_emulate); | ||||||
							
								
								
									
										133
									
								
								applications/nfc/nfc_emv.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										133
									
								
								applications/nfc/nfc_emv.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,133 @@ | |||||||
|  | #include "nfc_emv.h" | ||||||
|  |  | ||||||
|  | #include "nfc_i.h" | ||||||
|  | #include "nfc_types.h" | ||||||
|  | #include <furi.h> | ||||||
|  | #include <api-hal.h> | ||||||
|  | #include <input/input.h> | ||||||
|  |  | ||||||
|  | struct NfcEmv { | ||||||
|  |     NfcCommon* nfc_common; | ||||||
|  |     View* view; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     bool found; | ||||||
|  |     NfcEmvData emv_data; | ||||||
|  | } NfcEmvModel; | ||||||
|  |  | ||||||
|  | void nfc_emv_draw(Canvas* canvas, NfcEmvModel* model) { | ||||||
|  |     char buffer[32]; | ||||||
|  |     canvas_clear(canvas); | ||||||
|  |     canvas_set_font(canvas, FontPrimary); | ||||||
|  |     if(model->found) { | ||||||
|  |         canvas_draw_str(canvas, 0, 12, "Found EMV card"); | ||||||
|  |         canvas_set_font(canvas, FontSecondary); | ||||||
|  |         canvas_draw_str(canvas, 2, 22, "Type:"); | ||||||
|  |         snprintf(buffer, sizeof(buffer), "%s", model->emv_data.name); | ||||||
|  |         canvas_draw_str(canvas, 2, 32, buffer); | ||||||
|  |         snprintf(buffer, sizeof(buffer), "Number:\n"); | ||||||
|  |         canvas_draw_str(canvas, 2, 42, buffer); | ||||||
|  |         uint8_t card_num_len = sizeof(model->emv_data.number); | ||||||
|  |         for(uint8_t i = 0; i < card_num_len; i++) { | ||||||
|  |             snprintf( | ||||||
|  |                 buffer + (i * 2), sizeof(buffer) - (i * 2), "%02X", model->emv_data.number[i]); | ||||||
|  |         } | ||||||
|  |         buffer[card_num_len * 2] = 0; | ||||||
|  |         canvas_draw_str(canvas, 2, 52, buffer); | ||||||
|  |     } else { | ||||||
|  |         canvas_draw_str(canvas, 0, 12, "Searching"); | ||||||
|  |         canvas_set_font(canvas, FontSecondary); | ||||||
|  |         canvas_draw_str(canvas, 2, 22, "Place card to the back"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool nfc_emv_input(InputEvent* event, void* context) { | ||||||
|  |     if(event->key == InputKeyBack) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_emv_worker_callback(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |  | ||||||
|  |     NfcEmv* nfc_emv = (NfcEmv*)context; | ||||||
|  |     view_dispatcher_send_custom_event(nfc_emv->nfc_common->view_dispatcher, NfcEventEmv); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_emv_view_dispatcher_callback(NfcEmv* nfc_emv, NfcMessage* message) { | ||||||
|  |     furi_assert(nfc_emv); | ||||||
|  |     furi_assert(message); | ||||||
|  |  | ||||||
|  |     if(message->found) { | ||||||
|  |         with_view_model( | ||||||
|  |             nfc_emv->view, (NfcEmvModel * model) { | ||||||
|  |                 model->found = true; | ||||||
|  |                 model->emv_data = message->nfc_emv_data; | ||||||
|  |                 return true; | ||||||
|  |             }); | ||||||
|  |     } else { | ||||||
|  |         with_view_model( | ||||||
|  |             nfc_emv->view, (NfcEmvModel * model) { | ||||||
|  |                 model->found = false; | ||||||
|  |                 return true; | ||||||
|  |             }); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_emv_enter(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |  | ||||||
|  |     NfcEmv* nfc_emv = (NfcEmv*)context; | ||||||
|  |     with_view_model( | ||||||
|  |         nfc_emv->view, (NfcEmvModel * model) { | ||||||
|  |             model->found = false; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  |     nfc_worker_start( | ||||||
|  |         nfc_emv->nfc_common->worker, NfcWorkerStateReadEMV, nfc_emv_worker_callback, nfc_emv); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_emv_exit(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |  | ||||||
|  |     NfcEmv* nfc_emv = (NfcEmv*)context; | ||||||
|  |     nfc_worker_stop(nfc_emv->nfc_common->worker); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint32_t nfc_emv_back(void* context) { | ||||||
|  |     return NfcViewMenu; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NfcEmv* nfc_emv_alloc(NfcCommon* nfc_common) { | ||||||
|  |     furi_assert(nfc_common); | ||||||
|  |  | ||||||
|  |     NfcEmv* nfc_emv = furi_alloc(sizeof(NfcEmv)); | ||||||
|  |     nfc_emv->nfc_common = nfc_common; | ||||||
|  |  | ||||||
|  |     // View allocation and configuration | ||||||
|  |     nfc_emv->view = view_alloc(); | ||||||
|  |     view_allocate_model(nfc_emv->view, ViewModelTypeLockFree, sizeof(NfcEmvModel)); | ||||||
|  |     view_set_context(nfc_emv->view, nfc_emv); | ||||||
|  |     view_set_draw_callback(nfc_emv->view, (ViewDrawCallback)nfc_emv_draw); | ||||||
|  |     view_set_input_callback(nfc_emv->view, nfc_emv_input); | ||||||
|  |     view_set_enter_callback(nfc_emv->view, nfc_emv_enter); | ||||||
|  |     view_set_exit_callback(nfc_emv->view, nfc_emv_exit); | ||||||
|  |     view_set_previous_callback(nfc_emv->view, nfc_emv_back); | ||||||
|  |  | ||||||
|  |     return nfc_emv; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_emv_free(NfcEmv* nfc_emv) { | ||||||
|  |     furi_assert(nfc_emv); | ||||||
|  |  | ||||||
|  |     view_free(nfc_emv->view); | ||||||
|  |     free(nfc_emv); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | View* nfc_emv_get_view(NfcEmv* nfc_emv) { | ||||||
|  |     furi_assert(nfc_emv); | ||||||
|  |  | ||||||
|  |     return nfc_emv->view; | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								applications/nfc/nfc_emv.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								applications/nfc/nfc_emv.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <gui/view.h> | ||||||
|  | #include "nfc_types.h" | ||||||
|  |  | ||||||
|  | typedef struct NfcEmv NfcEmv; | ||||||
|  |  | ||||||
|  | NfcEmv* nfc_emv_alloc(NfcCommon* nfc_common); | ||||||
|  |  | ||||||
|  | void nfc_emv_free(NfcEmv* nfc_emv); | ||||||
|  |  | ||||||
|  | View* nfc_emv_get_view(NfcEmv* nfc_emv); | ||||||
|  |  | ||||||
|  | void nfc_emv_view_dispatcher_callback(NfcEmv* nfc_emv, NfcMessage* message); | ||||||
| @@ -2,7 +2,6 @@ | |||||||
|  |  | ||||||
| #include "nfc.h" | #include "nfc.h" | ||||||
| #include "nfc_types.h" | #include "nfc_types.h" | ||||||
| #include "nfc_views.h" |  | ||||||
| #include "nfc_worker.h" | #include "nfc_worker.h" | ||||||
|  |  | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| @@ -10,35 +9,34 @@ | |||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| #include <gui/view.h> | #include <gui/view.h> | ||||||
| #include <gui/view_dispatcher.h> | #include <gui/view_dispatcher.h> | ||||||
| #include <assets_icons.h> |  | ||||||
| #include <cli/cli.h> | #include <cli/cli.h> | ||||||
|  |  | ||||||
| #include <menu/menu.h> |  | ||||||
| #include <menu/menu_item.h> |  | ||||||
| #include <gui/modules/submenu.h> | #include <gui/modules/submenu.h> | ||||||
|  |  | ||||||
|  | #include "nfc_detect.h" | ||||||
|  | #include "nfc_emulate.h" | ||||||
|  | #include "nfc_emv.h" | ||||||
|  | #include "nfc_mifare_ul.h" | ||||||
|  |  | ||||||
| struct Nfc { | struct Nfc { | ||||||
|  |     NfcCommon nfc_common; | ||||||
|     osMessageQueueId_t message_queue; |     osMessageQueueId_t message_queue; | ||||||
|  |  | ||||||
|     NfcWorker* worker; |  | ||||||
|  |  | ||||||
|     Gui* gui; |     Gui* gui; | ||||||
|  |  | ||||||
|     Submenu* submenu; |     Submenu* submenu; | ||||||
|  |     NfcDetect* nfc_detect; | ||||||
|     View* view_detect; |     NfcEmulate* nfc_emulate; | ||||||
|     View* view_read_emv; |     NfcEmv* nfc_emv; | ||||||
|     View* view_emulate_emv; |     NfcMifareUl* nfc_mifare_ul; | ||||||
|     View* view_emulate; |  | ||||||
|     View* view_field; |  | ||||||
|     View* view_read_mf_ultralight; |  | ||||||
|     View* view_cli; |  | ||||||
|     View* view_error; |  | ||||||
|     ViewDispatcher* view_dispatcher; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |     NfcViewMenu, | ||||||
|  |     NfcViewDetect, | ||||||
|  |     NfcViewEmulate, | ||||||
|  |     NfcViewEmv, | ||||||
|  |     NfcViewMifareUl, | ||||||
|  | } NfcView; | ||||||
|  |  | ||||||
| Nfc* nfc_alloc(); | Nfc* nfc_alloc(); | ||||||
|  |  | ||||||
| void nfc_start(Nfc* nfc, NfcView view_id, NfcWorkerState worker_state); | int32_t nfc_task(void* p); | ||||||
|  |  | ||||||
| int32_t nfc_task(void* p); |  | ||||||
|   | |||||||
							
								
								
									
										165
									
								
								applications/nfc/nfc_mifare_ul.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										165
									
								
								applications/nfc/nfc_mifare_ul.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,165 @@ | |||||||
|  | #include "nfc_mifare_ul.h" | ||||||
|  |  | ||||||
|  | #include "nfc_i.h" | ||||||
|  | #include "nfc_types.h" | ||||||
|  | #include <furi.h> | ||||||
|  | #include <api-hal.h> | ||||||
|  | #include <input/input.h> | ||||||
|  |  | ||||||
|  | struct NfcMifareUl { | ||||||
|  |     NfcCommon* nfc_common; | ||||||
|  |     View* view; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     bool found; | ||||||
|  |     NfcMifareUlData nfc_mf_ul_data; | ||||||
|  | } NfcMifareUlModel; | ||||||
|  |  | ||||||
|  | void nfc_mifare_ul_draw(Canvas* canvas, NfcMifareUlModel* model) { | ||||||
|  |     char buffer[32]; | ||||||
|  |     canvas_clear(canvas); | ||||||
|  |     canvas_set_font(canvas, FontPrimary); | ||||||
|  |     if(model->found) { | ||||||
|  |         canvas_draw_str(canvas, 0, 12, "Found Mifare Ultralight"); | ||||||
|  |         canvas_set_font(canvas, FontSecondary); | ||||||
|  |         canvas_draw_str(canvas, 2, 22, "UID:"); | ||||||
|  |         for(uint8_t i = 0; i < model->nfc_mf_ul_data.nfc_data.uid_len; i++) { | ||||||
|  |             snprintf( | ||||||
|  |                 buffer + (i * 2), | ||||||
|  |                 sizeof(buffer) - (i * 2), | ||||||
|  |                 "%02X", | ||||||
|  |                 model->nfc_mf_ul_data.nfc_data.uid[i]); | ||||||
|  |         } | ||||||
|  |         buffer[model->nfc_mf_ul_data.nfc_data.uid_len * 2] = 0; | ||||||
|  |         canvas_draw_str(canvas, 18, 22, buffer); | ||||||
|  |  | ||||||
|  |         uint8_t man_bl_size = sizeof(model->nfc_mf_ul_data.man_block); | ||||||
|  |         canvas_draw_str(canvas, 2, 32, "Manufacturer block:"); | ||||||
|  |         for(uint8_t i = 0; i < man_bl_size / 2; i++) { | ||||||
|  |             snprintf( | ||||||
|  |                 buffer + (i * 2), | ||||||
|  |                 sizeof(buffer) - (i * 2), | ||||||
|  |                 "%02X", | ||||||
|  |                 model->nfc_mf_ul_data.man_block[i]); | ||||||
|  |         } | ||||||
|  |         buffer[man_bl_size] = 0; | ||||||
|  |         canvas_draw_str(canvas, 2, 42, buffer); | ||||||
|  |  | ||||||
|  |         for(uint8_t i = 0; i < man_bl_size / 2; i++) { | ||||||
|  |             snprintf( | ||||||
|  |                 buffer + (i * 2), | ||||||
|  |                 sizeof(buffer) - (i * 2), | ||||||
|  |                 "%02X", | ||||||
|  |                 model->nfc_mf_ul_data.man_block[man_bl_size / 2 + i]); | ||||||
|  |         } | ||||||
|  |         buffer[man_bl_size] = 0; | ||||||
|  |         canvas_draw_str(canvas, 2, 52, buffer); | ||||||
|  |  | ||||||
|  |         canvas_draw_str(canvas, 2, 62, "OTP: "); | ||||||
|  |         for(uint8_t i = 0; i < sizeof(model->nfc_mf_ul_data.otp); i++) { | ||||||
|  |             snprintf( | ||||||
|  |                 buffer + (i * 2), sizeof(buffer) - (i * 2), "%02X", model->nfc_mf_ul_data.otp[i]); | ||||||
|  |         } | ||||||
|  |         buffer[sizeof(model->nfc_mf_ul_data.otp) * 2] = 0; | ||||||
|  |         canvas_draw_str(canvas, 22, 62, buffer); | ||||||
|  |     } else { | ||||||
|  |         canvas_draw_str(canvas, 0, 12, "Searching"); | ||||||
|  |         canvas_set_font(canvas, FontSecondary); | ||||||
|  |         canvas_draw_str(canvas, 2, 22, "Place card to the back"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool nfc_mifare_ul_input(InputEvent* event, void* context) { | ||||||
|  |     if(event->key == InputKeyBack) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_mifare_ul_worker_callback(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |  | ||||||
|  |     NfcMifareUl* nfc_mifare_ul = (NfcMifareUl*)context; | ||||||
|  |     view_dispatcher_send_custom_event( | ||||||
|  |         nfc_mifare_ul->nfc_common->view_dispatcher, NfcEventMifareUl); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_mifare_ul_view_dispatcher_callback(NfcMifareUl* nfc_mifare_ul, NfcMessage* message) { | ||||||
|  |     furi_assert(nfc_mifare_ul); | ||||||
|  |     furi_assert(message); | ||||||
|  |  | ||||||
|  |     if(message->found) { | ||||||
|  |         with_view_model( | ||||||
|  |             nfc_mifare_ul->view, (NfcMifareUlModel * model) { | ||||||
|  |                 model->found = true; | ||||||
|  |                 model->nfc_mf_ul_data = message->nfc_mifare_ul_data; | ||||||
|  |                 return true; | ||||||
|  |             }); | ||||||
|  |     } else { | ||||||
|  |         with_view_model( | ||||||
|  |             nfc_mifare_ul->view, (NfcMifareUlModel * model) { | ||||||
|  |                 model->found = false; | ||||||
|  |                 return true; | ||||||
|  |             }); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_mifare_ul_enter(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |  | ||||||
|  |     NfcMifareUl* nfc_mifare_ul = (NfcMifareUl*)context; | ||||||
|  |     with_view_model( | ||||||
|  |         nfc_mifare_ul->view, (NfcMifareUlModel * m) { | ||||||
|  |             m->found = false; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  |     nfc_worker_start( | ||||||
|  |         nfc_mifare_ul->nfc_common->worker, | ||||||
|  |         NfcWorkerStateReadMfUltralight, | ||||||
|  |         nfc_mifare_ul_worker_callback, | ||||||
|  |         nfc_mifare_ul); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_mifare_ul_exit(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |  | ||||||
|  |     NfcMifareUl* nfc_mifare_ul = (NfcMifareUl*)context; | ||||||
|  |     nfc_worker_stop(nfc_mifare_ul->nfc_common->worker); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint32_t nfc_mifare_ul_back(void* context) { | ||||||
|  |     return NfcViewMenu; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NfcMifareUl* nfc_mifare_ul_alloc(NfcCommon* nfc_common) { | ||||||
|  |     furi_assert(nfc_common); | ||||||
|  |  | ||||||
|  |     NfcMifareUl* nfc_mifare_ul = furi_alloc(sizeof(NfcMifareUl)); | ||||||
|  |     nfc_mifare_ul->nfc_common = nfc_common; | ||||||
|  |  | ||||||
|  |     // View allocation and configuration | ||||||
|  |     nfc_mifare_ul->view = view_alloc(); | ||||||
|  |     view_allocate_model(nfc_mifare_ul->view, ViewModelTypeLockFree, sizeof(NfcMifareUlModel)); | ||||||
|  |     view_set_context(nfc_mifare_ul->view, nfc_mifare_ul); | ||||||
|  |     view_set_draw_callback(nfc_mifare_ul->view, (ViewDrawCallback)nfc_mifare_ul_draw); | ||||||
|  |     view_set_input_callback(nfc_mifare_ul->view, nfc_mifare_ul_input); | ||||||
|  |     view_set_enter_callback(nfc_mifare_ul->view, nfc_mifare_ul_enter); | ||||||
|  |     view_set_exit_callback(nfc_mifare_ul->view, nfc_mifare_ul_exit); | ||||||
|  |     view_set_previous_callback(nfc_mifare_ul->view, nfc_mifare_ul_back); | ||||||
|  |  | ||||||
|  |     return nfc_mifare_ul; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_mifare_ul_free(NfcMifareUl* nfc_mifare_ul) { | ||||||
|  |     furi_assert(nfc_mifare_ul); | ||||||
|  |  | ||||||
|  |     view_free(nfc_mifare_ul->view); | ||||||
|  |     free(nfc_mifare_ul); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | View* nfc_mifare_ul_get_view(NfcMifareUl* nfc_mifare_ul) { | ||||||
|  |     furi_assert(nfc_mifare_ul); | ||||||
|  |  | ||||||
|  |     return nfc_mifare_ul->view; | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								applications/nfc/nfc_mifare_ul.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								applications/nfc/nfc_mifare_ul.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <gui/view.h> | ||||||
|  | #include "nfc_types.h" | ||||||
|  |  | ||||||
|  | typedef struct NfcMifareUl NfcMifareUl; | ||||||
|  |  | ||||||
|  | NfcMifareUl* nfc_mifare_ul_alloc(NfcCommon* nfc_common); | ||||||
|  |  | ||||||
|  | void nfc_mifare_ul_free(NfcMifareUl* nfc_mifare_ul); | ||||||
|  |  | ||||||
|  | View* nfc_mifare_ul_get_view(NfcMifareUl* nfc_mifare_ul); | ||||||
|  |  | ||||||
|  | void nfc_mifare_ul_view_dispatcher_callback(NfcMifareUl* nfc_mifare_ul, NfcMessage* message); | ||||||
| @@ -1,7 +1,71 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <rfal_nfc.h> | #include "st_errno.h" | ||||||
| #include <st_errno.h> | #include "rfal_nfc.h" | ||||||
|  |  | ||||||
|  | #include <gui/view_dispatcher.h> | ||||||
|  | #include "nfc_worker.h" | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     NfcWorker* worker; | ||||||
|  |     ViewDispatcher* view_dispatcher; | ||||||
|  | } NfcCommon; | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |     NfcDeviceNfca, | ||||||
|  |     NfcDeviceNfcb, | ||||||
|  |     NfcDeviceNfcf, | ||||||
|  |     NfcDeviceNfcv, | ||||||
|  | } NfcDeviceType; | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |     NfcDeviceProtocolUnknown, | ||||||
|  |     NfcDeviceProtocolEMV, | ||||||
|  |     NfcDeviceProtocolMfUltralight, | ||||||
|  | } NfcProtocol; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t uid_len; | ||||||
|  |     uint8_t uid[10]; | ||||||
|  |     uint8_t atqa[2]; | ||||||
|  |     uint8_t sak; | ||||||
|  |     NfcDeviceType device; | ||||||
|  |     NfcProtocol protocol; | ||||||
|  | } NfcDeviceData; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     NfcDeviceData nfc_data; | ||||||
|  |     char name[32]; | ||||||
|  |     uint8_t number[8]; | ||||||
|  | } NfcEmvData; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     NfcDeviceData nfc_data; | ||||||
|  |     uint8_t man_block[12]; | ||||||
|  |     uint8_t otp[4]; | ||||||
|  | } NfcMifareUlData; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     bool found; | ||||||
|  |     union { | ||||||
|  |         NfcDeviceData nfc_detect_data; | ||||||
|  |         NfcEmvData nfc_emv_data; | ||||||
|  |         NfcMifareUlData nfc_mifare_ul_data; | ||||||
|  |     }; | ||||||
|  | } NfcMessage; | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |     NfcEventDetect, | ||||||
|  |     NfcEventEmv, | ||||||
|  |     NfcEventMifareUl, | ||||||
|  | } NfcEvent; | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |     NfcSubmenuDetect, | ||||||
|  |     NfcSubmenuEmulate, | ||||||
|  |     NfcSubmenuEMV, | ||||||
|  |     NfcSubmenuMifareUl, | ||||||
|  | } NfcSubmenu; | ||||||
|  |  | ||||||
| static inline const char* nfc_get_dev_type(rfalNfcDevType type) { | static inline const char* nfc_get_dev_type(rfalNfcDevType type) { | ||||||
|     if(type == RFAL_NFC_LISTEN_TYPE_NFCA) { |     if(type == RFAL_NFC_LISTEN_TYPE_NFCA) { | ||||||
| @@ -39,76 +103,12 @@ static inline const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| typedef enum { | static inline const char* nfc_get_protocol(NfcProtocol protocol) { | ||||||
|     NfcDeviceTypeNfca, |     if(protocol == NfcDeviceProtocolEMV) { | ||||||
|     NfcDeviceTypeNfcb, |         return "EMV"; | ||||||
|     NfcDeviceTypeNfcf, |     } else if(protocol == NfcDeviceProtocolMfUltralight) { | ||||||
|     NfcDeviceTypeNfcv, |         return "Mifare UL"; | ||||||
|     NfcDeviceTypeEMV, |     } else { | ||||||
|     NfcDeviceTypeMfUltralight, |         return "Unknown"; | ||||||
| } NfcDeviceType; |     } | ||||||
|  | } | ||||||
| typedef struct { |  | ||||||
|     char name[32]; |  | ||||||
|     uint8_t number[8]; |  | ||||||
| } EMVCard; |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|     uint8_t uid[7]; |  | ||||||
|     uint8_t man_block[12]; |  | ||||||
|     uint8_t otp[4]; |  | ||||||
| } MfUlCard; |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|     NfcDeviceType type; |  | ||||||
|     union { |  | ||||||
|         rfalNfcaListenDevice nfca; |  | ||||||
|         rfalNfcbListenDevice nfcb; |  | ||||||
|         rfalNfcfListenDevice nfcf; |  | ||||||
|         rfalNfcvListenDevice nfcv; |  | ||||||
|         EMVCard emv_card; |  | ||||||
|         MfUlCard mf_ul_card; |  | ||||||
|     }; |  | ||||||
| } NfcDevice; |  | ||||||
|  |  | ||||||
| typedef enum { |  | ||||||
|     // Init states |  | ||||||
|     NfcWorkerStateNone, |  | ||||||
|     NfcWorkerStateBroken, |  | ||||||
|     NfcWorkerStateReady, |  | ||||||
|     // Main worker states |  | ||||||
|     NfcWorkerStatePoll, |  | ||||||
|     NfcWorkerStateReadEMV, |  | ||||||
|     NfcWorkerStateEmulateEMV, |  | ||||||
|     NfcWorkerStateEmulate, |  | ||||||
|     NfcWorkerStateField, |  | ||||||
|     NfcWorkerStateReadMfUltralight, |  | ||||||
|     // Transition |  | ||||||
|     NfcWorkerStateStop, |  | ||||||
| } NfcWorkerState; |  | ||||||
|  |  | ||||||
| typedef enum { |  | ||||||
|     // From Menu |  | ||||||
|     NfcMessageTypeDetect, |  | ||||||
|     NfcMessageTypeReadEMV, |  | ||||||
|     NfcMessageTypeEmulateEMV, |  | ||||||
|     NfcMessageTypeEmulate, |  | ||||||
|     NfcMessageTypeField, |  | ||||||
|     NfcMessageTypeReadMfUltralight, |  | ||||||
|     NfcMessageTypeStop, |  | ||||||
|     NfcMessageTypeExit, |  | ||||||
|     // From Worker |  | ||||||
|     NfcMessageTypeDeviceFound, |  | ||||||
|     NfcMessageTypeDeviceNotFound, |  | ||||||
|     NfcMessageTypeEMVFound, |  | ||||||
|     NfcMessageTypeEMVNotFound, |  | ||||||
|     NfcMessageTypeMfUlFound, |  | ||||||
|     NfcMessageTypeMfUlNotFound, |  | ||||||
| } NfcMessageType; |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|     NfcMessageType type; |  | ||||||
|     union { |  | ||||||
|         NfcDevice device; |  | ||||||
|     }; |  | ||||||
| } NfcMessage; |  | ||||||
|   | |||||||
| @@ -1,235 +0,0 @@ | |||||||
| #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_read_emv_draw(Canvas* canvas, void* model) { |  | ||||||
|     NfcViewReadModel* m = model; |  | ||||||
|     canvas_clear(canvas); |  | ||||||
|     canvas_set_font(canvas, FontPrimary); |  | ||||||
|     char buffer[32]; |  | ||||||
|  |  | ||||||
|     if(m->found) { |  | ||||||
|         canvas_draw_str(canvas, 0, 12, "Found EMV card"); |  | ||||||
|         canvas_set_font(canvas, FontSecondary); |  | ||||||
|         snprintf(buffer, sizeof(buffer), "Type:\n"); |  | ||||||
|         canvas_draw_str(canvas, 2, 22, buffer); |  | ||||||
|         snprintf(buffer, sizeof(buffer), "%s", m->device.emv_card.name); |  | ||||||
|         canvas_draw_str(canvas, 2, 32, buffer); |  | ||||||
|         snprintf(buffer, sizeof(buffer), "Number:\n"); |  | ||||||
|         canvas_draw_str(canvas, 2, 42, buffer); |  | ||||||
|         uint8_t card_num_len = sizeof(m->device.emv_card.number); |  | ||||||
|         for(uint8_t i = 0; i < card_num_len; i++) { |  | ||||||
|             snprintf( |  | ||||||
|                 buffer + (i * 2), sizeof(buffer) - (i * 2), "%02X", m->device.emv_card.number[i]); |  | ||||||
|         } |  | ||||||
|         buffer[card_num_len * 2] = 0; |  | ||||||
|         canvas_draw_str(canvas, 2, 52, buffer); |  | ||||||
|     } 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_emulate_emv_draw(Canvas* canvas, void* model) { |  | ||||||
|     canvas_clear(canvas); |  | ||||||
|     canvas_set_font(canvas, FontPrimary); |  | ||||||
|     canvas_draw_str(canvas, 0, 12, "Emulating EMV"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| 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: 4"); |  | ||||||
|     canvas_draw_str(canvas, 2, 42, "UID: CF72D440"); |  | ||||||
|     canvas_draw_str(canvas, 2, 52, "SAK: 20 ATQA: 00/04"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void nfc_view_read_mf_ultralight_draw(Canvas* canvas, void* model) { |  | ||||||
|     NfcViewReadModel* m = model; |  | ||||||
|     canvas_clear(canvas); |  | ||||||
|     canvas_set_font(canvas, FontPrimary); |  | ||||||
|     char buffer[32]; |  | ||||||
|  |  | ||||||
|     if(m->found) { |  | ||||||
|         canvas_draw_str(canvas, 0, 12, "Found Mifare Ultralight"); |  | ||||||
|         canvas_set_font(canvas, FontSecondary); |  | ||||||
|         canvas_draw_str(canvas, 2, 22, "UID:"); |  | ||||||
|         for(uint8_t i = 0; i < sizeof(m->device.mf_ul_card.uid); i++) { |  | ||||||
|             snprintf( |  | ||||||
|                 buffer + (i * 2), sizeof(buffer) - (i * 2), "%02X", m->device.mf_ul_card.uid[i]); |  | ||||||
|         } |  | ||||||
|         buffer[sizeof(m->device.mf_ul_card.uid) * 2] = 0; |  | ||||||
|         canvas_draw_str(canvas, 18, 22, buffer); |  | ||||||
|  |  | ||||||
|         uint8_t man_bl_size = sizeof(m->device.mf_ul_card.man_block); |  | ||||||
|         canvas_draw_str(canvas, 2, 32, "Manufacturer block:"); |  | ||||||
|         for(uint8_t i = 0; i < man_bl_size / 2; i++) { |  | ||||||
|             snprintf( |  | ||||||
|                 buffer + (i * 2), |  | ||||||
|                 sizeof(buffer) - (i * 2), |  | ||||||
|                 "%02X", |  | ||||||
|                 m->device.mf_ul_card.man_block[i]); |  | ||||||
|         } |  | ||||||
|         buffer[man_bl_size] = 0; |  | ||||||
|         canvas_draw_str(canvas, 2, 42, buffer); |  | ||||||
|  |  | ||||||
|         for(uint8_t i = 0; i < man_bl_size / 2; i++) { |  | ||||||
|             snprintf( |  | ||||||
|                 buffer + (i * 2), |  | ||||||
|                 sizeof(buffer) - (i * 2), |  | ||||||
|                 "%02X", |  | ||||||
|                 m->device.mf_ul_card.man_block[man_bl_size / 2 + i]); |  | ||||||
|         } |  | ||||||
|         buffer[man_bl_size] = 0; |  | ||||||
|         canvas_draw_str(canvas, 2, 52, buffer); |  | ||||||
|  |  | ||||||
|         canvas_draw_str(canvas, 2, 62, "OTP: "); |  | ||||||
|         for(uint8_t i = 0; i < sizeof(m->device.mf_ul_card.otp); i++) { |  | ||||||
|             snprintf( |  | ||||||
|                 buffer + (i * 2), sizeof(buffer) - (i * 2), "%02X", m->device.mf_ul_card.otp[i]); |  | ||||||
|         } |  | ||||||
|         buffer[sizeof(m->device.mf_ul_card.otp) * 2] = 0; |  | ||||||
|         canvas_draw_str(canvas, 22, 62, buffer); |  | ||||||
|     } 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_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"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,43 +0,0 @@ | |||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include <stdint.h> |  | ||||||
| #include <stdbool.h> |  | ||||||
| #include <gui/canvas.h> |  | ||||||
| #include <furi.h> |  | ||||||
|  |  | ||||||
| #include "nfc_types.h" |  | ||||||
|  |  | ||||||
| typedef enum { |  | ||||||
|     NfcViewMenu, |  | ||||||
|     NfcViewRead, |  | ||||||
|     NfcViewReadEmv, |  | ||||||
|     NfcViewEmulateEMV, |  | ||||||
|     NfcViewEmulate, |  | ||||||
|     NfcViewField, |  | ||||||
|     NfcViewReadMfUltralight, |  | ||||||
|     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_read_emv_draw(Canvas* canvas, void* model); |  | ||||||
|  |  | ||||||
| void nfc_view_emulate_emv_draw(Canvas* canvas, void* model); |  | ||||||
| void nfc_view_emulate_draw(Canvas* canvas, void* model); |  | ||||||
| void nfc_view_read_mf_ultralight_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); |  | ||||||
| @@ -5,12 +5,16 @@ | |||||||
|  |  | ||||||
| #define NFC_WORKER_TAG "nfc worker" | #define NFC_WORKER_TAG "nfc worker" | ||||||
|  |  | ||||||
|  | /***************************** NFC Worker API *******************************/ | ||||||
|  |  | ||||||
| NfcWorker* nfc_worker_alloc(osMessageQueueId_t message_queue) { | NfcWorker* nfc_worker_alloc(osMessageQueueId_t message_queue) { | ||||||
|     NfcWorker* nfc_worker = furi_alloc(sizeof(NfcWorker)); |     NfcWorker* nfc_worker = furi_alloc(sizeof(NfcWorker)); | ||||||
|     nfc_worker->message_queue = message_queue; |     nfc_worker->message_queue = message_queue; | ||||||
|     // Worker thread attributes |     // Worker thread attributes | ||||||
|     nfc_worker->thread_attr.name = "nfc_worker"; |     nfc_worker->thread_attr.name = "nfc_worker"; | ||||||
|     nfc_worker->thread_attr.stack_size = 8192; |     nfc_worker->thread_attr.stack_size = 8192; | ||||||
|  |     nfc_worker->callback = NULL; | ||||||
|  |     nfc_worker->context = NULL; | ||||||
|     // Initialize rfal |     // Initialize rfal | ||||||
|     nfc_worker->error = api_hal_nfc_init(); |     nfc_worker->error = api_hal_nfc_init(); | ||||||
|     if(nfc_worker->error == ERR_NONE) { |     if(nfc_worker->error == ERR_NONE) { | ||||||
| @@ -36,9 +40,16 @@ ReturnCode nfc_worker_get_error(NfcWorker* nfc_worker) { | |||||||
|     return nfc_worker->error; |     return nfc_worker->error; | ||||||
| } | } | ||||||
|  |  | ||||||
| void nfc_worker_start(NfcWorker* nfc_worker, NfcWorkerState state) { | void nfc_worker_start( | ||||||
|  |     NfcWorker* nfc_worker, | ||||||
|  |     NfcWorkerState state, | ||||||
|  |     NfcWorkerCallback callback, | ||||||
|  |     void* context) { | ||||||
|     furi_assert(nfc_worker); |     furi_assert(nfc_worker); | ||||||
|     furi_assert(nfc_worker->state == NfcWorkerStateReady); |     furi_assert(nfc_worker->state == NfcWorkerStateReady); | ||||||
|  |  | ||||||
|  |     nfc_worker->callback = callback; | ||||||
|  |     nfc_worker->context = context; | ||||||
|     nfc_worker_change_state(nfc_worker, state); |     nfc_worker_change_state(nfc_worker, state); | ||||||
|     nfc_worker->thread = osThreadNew(nfc_worker_task, nfc_worker, &nfc_worker->thread_attr); |     nfc_worker->thread = osThreadNew(nfc_worker_task, nfc_worker, &nfc_worker->thread_attr); | ||||||
| } | } | ||||||
| @@ -56,24 +67,26 @@ void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state) { | |||||||
|     nfc_worker->state = state; |     nfc_worker->state = state; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /***************************** NFC Worker Thread *******************************/ | ||||||
|  |  | ||||||
| void nfc_worker_task(void* context) { | void nfc_worker_task(void* context) { | ||||||
|     NfcWorker* nfc_worker = context; |     NfcWorker* nfc_worker = context; | ||||||
|  |  | ||||||
|     api_hal_power_insomnia_enter(); |     api_hal_power_insomnia_enter(); | ||||||
|     api_hal_nfc_exit_sleep(); |     api_hal_nfc_exit_sleep(); | ||||||
|  |  | ||||||
|     if(nfc_worker->state == NfcWorkerStatePoll) { |     if(nfc_worker->state == NfcWorkerStateDetect) { | ||||||
|         nfc_worker_poll(nfc_worker); |         nfc_worker_detect(nfc_worker); | ||||||
|  |     } else if(nfc_worker->state == NfcWorkerStateEmulate) { | ||||||
|  |         nfc_worker_emulate(nfc_worker); | ||||||
|     } else if(nfc_worker->state == NfcWorkerStateReadEMV) { |     } else if(nfc_worker->state == NfcWorkerStateReadEMV) { | ||||||
|         nfc_worker_read_emv(nfc_worker); |         nfc_worker_read_emv(nfc_worker); | ||||||
|     } else if(nfc_worker->state == NfcWorkerStateEmulateEMV) { |     } else if(nfc_worker->state == NfcWorkerStateEmulateEMV) { | ||||||
|         nfc_worker_emulate_emv(nfc_worker); |  | ||||||
|     } else if(nfc_worker->state == NfcWorkerStateEmulate) { |  | ||||||
|         nfc_worker_emulate(nfc_worker); |  | ||||||
|     } else if(nfc_worker->state == NfcWorkerStateField) { |  | ||||||
|         nfc_worker_field(nfc_worker); |         nfc_worker_field(nfc_worker); | ||||||
|     } else if(nfc_worker->state == NfcWorkerStateReadMfUltralight) { |     } else if(nfc_worker->state == NfcWorkerStateReadMfUltralight) { | ||||||
|         nfc_worker_read_mf_ultralight(nfc_worker); |         nfc_worker_read_mf_ultralight(nfc_worker); | ||||||
|  |         nfc_worker_emulate_emv(nfc_worker); | ||||||
|  |     } else if(nfc_worker->state == NfcWorkerStateField) { | ||||||
|     } |     } | ||||||
|     api_hal_nfc_deactivate(); |     api_hal_nfc_deactivate(); | ||||||
|     nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); |     nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); | ||||||
| @@ -81,6 +94,55 @@ void nfc_worker_task(void* context) { | |||||||
|     osThreadExit(); |     osThreadExit(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void nfc_worker_detect(NfcWorker* nfc_worker) { | ||||||
|  |     rfalNfcDevice* dev_list; | ||||||
|  |     rfalNfcDevice* dev; | ||||||
|  |     uint8_t dev_cnt; | ||||||
|  |     NfcMessage message; | ||||||
|  |  | ||||||
|  |     while(nfc_worker->state == NfcWorkerStateDetect) { | ||||||
|  |         message.found = false; | ||||||
|  |         if(api_hal_nfc_detect(&dev_list, &dev_cnt, 1000, true)) { | ||||||
|  |             // Process first found device | ||||||
|  |             dev = &dev_list[0]; | ||||||
|  |             message.found = true; | ||||||
|  |             message.nfc_detect_data.uid_len = dev->nfcidLen; | ||||||
|  |             memcpy(message.nfc_detect_data.uid, dev->nfcid, dev->nfcidLen); | ||||||
|  |  | ||||||
|  |             if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCA) { | ||||||
|  |                 message.nfc_detect_data.device = NfcDeviceNfca; | ||||||
|  |                 message.nfc_detect_data.atqa[0] = dev->dev.nfca.sensRes.anticollisionInfo; | ||||||
|  |                 message.nfc_detect_data.atqa[1] = dev->dev.nfca.sensRes.platformInfo; | ||||||
|  |                 message.nfc_detect_data.sak = dev->dev.nfca.selRes.sak; | ||||||
|  |                 // TODO check protocols | ||||||
|  |  | ||||||
|  |             } else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCB) { | ||||||
|  |                 message.nfc_detect_data.device = NfcDeviceNfcb; | ||||||
|  |             } else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCF) { | ||||||
|  |                 message.nfc_detect_data.device = NfcDeviceNfcf; | ||||||
|  |             } else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCV) { | ||||||
|  |                 message.nfc_detect_data.device = NfcDeviceNfcv; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if(nfc_worker->callback) { | ||||||
|  |             nfc_worker->callback(nfc_worker->context); | ||||||
|  |         } | ||||||
|  |         furi_check( | ||||||
|  |             osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK); | ||||||
|  |         osDelay(100); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void nfc_worker_emulate(NfcWorker* nfc_worker) { | ||||||
|  |     while(nfc_worker->state == NfcWorkerStateEmulate) { | ||||||
|  |         if(api_hal_nfc_listen(ApiHalNfcEmulateParamsMifare, 100)) { | ||||||
|  |             FURI_LOG_I(NFC_WORKER_TAG, "Reader detected"); | ||||||
|  |             api_hal_nfc_deactivate(); | ||||||
|  |         } | ||||||
|  |         osDelay(10); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| void nfc_worker_read_emv(NfcWorker* nfc_worker) { | void nfc_worker_read_emv(NfcWorker* nfc_worker) { | ||||||
|     ReturnCode err; |     ReturnCode err; | ||||||
|     rfalNfcDevice* dev_list; |     rfalNfcDevice* dev_list; | ||||||
| @@ -91,9 +153,11 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | |||||||
|     uint8_t* rx_buff; |     uint8_t* rx_buff; | ||||||
|     uint16_t* rx_len; |     uint16_t* rx_len; | ||||||
|  |  | ||||||
|     // Update screen before start searching |     NfcMessage message = {.found = false}; | ||||||
|     NfcMessage message = {.type = NfcMessageTypeEMVNotFound}; |  | ||||||
|     while(nfc_worker->state == NfcWorkerStateReadEMV) { |     while(nfc_worker->state == NfcWorkerStateReadEMV) { | ||||||
|  |         if(nfc_worker->callback) { | ||||||
|  |             nfc_worker->callback(nfc_worker->context); | ||||||
|  |         } | ||||||
|         furi_check( |         furi_check( | ||||||
|             osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK); |             osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK); | ||||||
|         memset(&emv_app, 0, sizeof(emv_app)); |         memset(&emv_app, 0, sizeof(emv_app)); | ||||||
| @@ -105,7 +169,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | |||||||
|                 err = api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); |                 err = api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||||
|                 if(err != ERR_NONE) { |                 if(err != ERR_NONE) { | ||||||
|                     FURI_LOG_E(NFC_WORKER_TAG, "Error during selection PPSE request: %d", err); |                     FURI_LOG_E(NFC_WORKER_TAG, "Error during selection PPSE request: %d", err); | ||||||
|                     message.type = NfcMessageTypeEMVNotFound; |                     message.found = false; | ||||||
|                     api_hal_nfc_deactivate(); |                     api_hal_nfc_deactivate(); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
| @@ -115,7 +179,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | |||||||
|                     FURI_LOG_I(NFC_WORKER_TAG, "Select PPSE responce parced"); |                     FURI_LOG_I(NFC_WORKER_TAG, "Select PPSE responce parced"); | ||||||
|                 } else { |                 } else { | ||||||
|                     FURI_LOG_E(NFC_WORKER_TAG, "Can't find pay application"); |                     FURI_LOG_E(NFC_WORKER_TAG, "Can't find pay application"); | ||||||
|                     message.type = NfcMessageTypeEMVNotFound; |                     message.found = false; | ||||||
|                     api_hal_nfc_deactivate(); |                     api_hal_nfc_deactivate(); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
| @@ -125,7 +189,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | |||||||
|                 if(err != ERR_NONE) { |                 if(err != ERR_NONE) { | ||||||
|                     FURI_LOG_E( |                     FURI_LOG_E( | ||||||
|                         NFC_WORKER_TAG, "Error during application selection request: %d", err); |                         NFC_WORKER_TAG, "Error during application selection request: %d", err); | ||||||
|                     message.type = NfcMessageTypeEMVNotFound; |                     message.found = false; | ||||||
|                     api_hal_nfc_deactivate(); |                     api_hal_nfc_deactivate(); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
| @@ -134,10 +198,10 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | |||||||
|                     "Select application response received. Start parsing response"); |                     "Select application response received. Start parsing response"); | ||||||
|                 if(emv_decode_select_app_response(rx_buff, *rx_len, &emv_app)) { |                 if(emv_decode_select_app_response(rx_buff, *rx_len, &emv_app)) { | ||||||
|                     FURI_LOG_I(NFC_WORKER_TAG, "Card name: %s", emv_app.name); |                     FURI_LOG_I(NFC_WORKER_TAG, "Card name: %s", emv_app.name); | ||||||
|                     memcpy(message.device.emv_card.name, emv_app.name, sizeof(emv_app.name)); |                     memcpy(message.nfc_emv_data.name, emv_app.name, sizeof(emv_app.name)); | ||||||
|                 } else { |                 } else { | ||||||
|                     FURI_LOG_E(NFC_WORKER_TAG, "Can't read card name"); |                     FURI_LOG_E(NFC_WORKER_TAG, "Can't read card name"); | ||||||
|                     message.type = NfcMessageTypeEMVNotFound; |                     message.found = false; | ||||||
|                     api_hal_nfc_deactivate(); |                     api_hal_nfc_deactivate(); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
| @@ -147,15 +211,15 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | |||||||
|                 if(err != ERR_NONE) { |                 if(err != ERR_NONE) { | ||||||
|                     FURI_LOG_E( |                     FURI_LOG_E( | ||||||
|                         NFC_WORKER_TAG, "Error during Get Processing Options command: %d", err); |                         NFC_WORKER_TAG, "Error during Get Processing Options command: %d", err); | ||||||
|                     message.type = NfcMessageTypeEMVNotFound; |                     message.found = false; | ||||||
|                     api_hal_nfc_deactivate(); |                     api_hal_nfc_deactivate(); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if(emv_decode_get_proc_opt(rx_buff, *rx_len, &emv_app)) { |                 if(emv_decode_get_proc_opt(rx_buff, *rx_len, &emv_app)) { | ||||||
|                     FURI_LOG_I(NFC_WORKER_TAG, "Card number parsed"); |                     FURI_LOG_I(NFC_WORKER_TAG, "Card number parsed"); | ||||||
|                     message.type = NfcMessageTypeEMVFound; |                     message.found = true; | ||||||
|                     memcpy( |                     memcpy( | ||||||
|                         message.device.emv_card.number, |                         message.nfc_emv_data.number, | ||||||
|                         emv_app.card_number, |                         emv_app.card_number, | ||||||
|                         sizeof(emv_app.card_number)); |                         sizeof(emv_app.card_number)); | ||||||
|                     api_hal_nfc_deactivate(); |                     api_hal_nfc_deactivate(); | ||||||
| @@ -189,27 +253,27 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | |||||||
|                     } |                     } | ||||||
|                     if(pan_found) { |                     if(pan_found) { | ||||||
|                         FURI_LOG_I(NFC_WORKER_TAG, "Card PAN found"); |                         FURI_LOG_I(NFC_WORKER_TAG, "Card PAN found"); | ||||||
|                         message.type = NfcMessageTypeEMVFound; |                         message.found = true; | ||||||
|                         memcpy( |                         memcpy( | ||||||
|                             message.device.emv_card.number, |                             message.nfc_emv_data.number, | ||||||
|                             emv_app.card_number, |                             emv_app.card_number, | ||||||
|                             sizeof(emv_app.card_number)); |                             sizeof(emv_app.card_number)); | ||||||
|                     } else { |                     } else { | ||||||
|                         FURI_LOG_E(NFC_WORKER_TAG, "Can't read card number"); |                         FURI_LOG_E(NFC_WORKER_TAG, "Can't read card number"); | ||||||
|                         message.type = NfcMessageTypeEMVNotFound; |                         message.found = false; | ||||||
|                     } |                     } | ||||||
|                     api_hal_nfc_deactivate(); |                     api_hal_nfc_deactivate(); | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 // Can't find EMV card |                 // Can't find EMV card | ||||||
|                 FURI_LOG_W(NFC_WORKER_TAG, "Card doesn't support EMV"); |                 FURI_LOG_W(NFC_WORKER_TAG, "Card doesn't support EMV"); | ||||||
|                 message.type = NfcMessageTypeEMVNotFound; |                 message.found = false; | ||||||
|                 api_hal_nfc_deactivate(); |                 api_hal_nfc_deactivate(); | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             // Can't find EMV card |             // Can't find EMV card | ||||||
|             FURI_LOG_W(NFC_WORKER_TAG, "Can't find any cards"); |             FURI_LOG_W(NFC_WORKER_TAG, "Can't find any cards"); | ||||||
|             message.type = NfcMessageTypeEMVNotFound; |             message.found = false; | ||||||
|             api_hal_nfc_deactivate(); |             api_hal_nfc_deactivate(); | ||||||
|         } |         } | ||||||
|         osDelay(20); |         osDelay(20); | ||||||
| @@ -271,44 +335,6 @@ void nfc_worker_emulate_emv(NfcWorker* nfc_worker) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void nfc_worker_poll(NfcWorker* nfc_worker) { |  | ||||||
|     rfalNfcDevice* dev_list; |  | ||||||
|     uint8_t dev_cnt; |  | ||||||
|     // Update screen before start searching |  | ||||||
|     NfcMessage message = {.type = NfcMessageTypeDeviceNotFound}; |  | ||||||
|     furi_check(osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK); |  | ||||||
|  |  | ||||||
|     while(nfc_worker->state == NfcWorkerStatePoll) { |  | ||||||
|         if(api_hal_nfc_detect(&dev_list, &dev_cnt, 1000, true)) { |  | ||||||
|             // Send message with first device found |  | ||||||
|             message.type = NfcMessageTypeDeviceFound; |  | ||||||
|             if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCA) { |  | ||||||
|                 message.device.type = NfcDeviceTypeNfca; |  | ||||||
|                 message.device.nfca = dev_list[0].dev.nfca; |  | ||||||
|             } else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCB) { |  | ||||||
|                 message.device.type = NfcDeviceTypeNfcb; |  | ||||||
|                 message.device.nfcb = dev_list[0].dev.nfcb; |  | ||||||
|             } else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCF) { |  | ||||||
|                 message.device.type = NfcDeviceTypeNfcf; |  | ||||||
|                 message.device.nfcf = dev_list[0].dev.nfcf; |  | ||||||
|             } else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCV) { |  | ||||||
|                 message.device.type = NfcDeviceTypeNfcv; |  | ||||||
|                 message.device.nfcv = dev_list[0].dev.nfcv; |  | ||||||
|             } else { |  | ||||||
|                 // TODO show information about all found devices |  | ||||||
|                 message.type = NfcMessageTypeDeviceNotFound; |  | ||||||
|             } |  | ||||||
|             furi_check( |  | ||||||
|                 osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK); |  | ||||||
|         } else { |  | ||||||
|             message.type = NfcMessageTypeDeviceNotFound; |  | ||||||
|             furi_check( |  | ||||||
|                 osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK); |  | ||||||
|         } |  | ||||||
|         osDelay(5); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { | void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { | ||||||
|     ReturnCode err; |     ReturnCode err; | ||||||
|     rfalNfcDevice* dev_list; |     rfalNfcDevice* dev_list; | ||||||
| @@ -320,8 +346,11 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { | |||||||
|     MfUltralightRead mf_ul_read; |     MfUltralightRead mf_ul_read; | ||||||
|  |  | ||||||
|     // Update screen before start searching |     // Update screen before start searching | ||||||
|     NfcMessage message = {.type = NfcMessageTypeMfUlNotFound}; |     NfcMessage message = {.found = false}; | ||||||
|     while(nfc_worker->state == NfcWorkerStateReadMfUltralight) { |     while(nfc_worker->state == NfcWorkerStateReadMfUltralight) { | ||||||
|  |         if(nfc_worker->callback) { | ||||||
|  |             nfc_worker->callback(nfc_worker->context); | ||||||
|  |         } | ||||||
|         furi_check( |         furi_check( | ||||||
|             osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK); |             osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK); | ||||||
|         api_hal_nfc_deactivate(); |         api_hal_nfc_deactivate(); | ||||||
| @@ -354,7 +383,7 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { | |||||||
|                     api_hal_nfc_deactivate(); |                     api_hal_nfc_deactivate(); | ||||||
|                     if(!api_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) { |                     if(!api_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) { | ||||||
|                         FURI_LOG_E(NFC_WORKER_TAG, "Lost connection. Restarting search"); |                         FURI_LOG_E(NFC_WORKER_TAG, "Lost connection. Restarting search"); | ||||||
|                         message.type = NfcMessageTypeMfUlNotFound; |                         message.found = false; | ||||||
|                         continue; |                         continue; | ||||||
|                     } |                     } | ||||||
|                 } else { |                 } else { | ||||||
| @@ -362,7 +391,7 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { | |||||||
|                         NFC_WORKER_TAG, |                         NFC_WORKER_TAG, | ||||||
|                         "Error getting Mifare Ultralight version. Error code: %d", |                         "Error getting Mifare Ultralight version. Error code: %d", | ||||||
|                         err); |                         err); | ||||||
|                     message.type = NfcMessageTypeMfUlNotFound; |                     message.found = false; | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
| @@ -382,7 +411,7 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { | |||||||
|                         mf_ul_read.pages_readed = mf_ul_read.pages_to_read; |                         mf_ul_read.pages_readed = mf_ul_read.pages_to_read; | ||||||
|                     } else { |                     } else { | ||||||
|                         FURI_LOG_E(NFC_WORKER_TAG, "Fast read failed"); |                         FURI_LOG_E(NFC_WORKER_TAG, "Fast read failed"); | ||||||
|                         message.type = NfcMessageTypeMfUlNotFound; |                         message.found = false; | ||||||
|                         continue; |                         continue; | ||||||
|                     } |                     } | ||||||
|                 } else { |                 } else { | ||||||
| @@ -403,13 +432,19 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { | |||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 // Fill message for nfc application |                 // Fill message for nfc application | ||||||
|                 message.type = NfcMessageTypeMfUlFound; |                 message.found = true; | ||||||
|  |                 message.nfc_mifare_ul_data.nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len; | ||||||
|  |                 message.nfc_mifare_ul_data.nfc_data.atqa[0] = | ||||||
|  |                     dev_list[0].dev.nfca.sensRes.anticollisionInfo; | ||||||
|  |                 message.nfc_mifare_ul_data.nfc_data.atqa[1] = | ||||||
|  |                     dev_list[0].dev.nfca.sensRes.platformInfo; | ||||||
|  |                 message.nfc_mifare_ul_data.nfc_data.sak = dev_list[0].dev.nfca.selRes.sak; | ||||||
|                 memcpy( |                 memcpy( | ||||||
|                     message.device.mf_ul_card.uid, |                     message.nfc_mifare_ul_data.nfc_data.uid, | ||||||
|                     dev_list[0].dev.nfca.nfcId1, |                     dev_list[0].dev.nfca.nfcId1, | ||||||
|                     sizeof(message.device.mf_ul_card.uid)); |                     message.nfc_mifare_ul_data.nfc_data.uid_len); | ||||||
|                 memcpy(message.device.mf_ul_card.man_block, mf_ul_read.dump, 4 * 3); |                 memcpy(message.nfc_mifare_ul_data.man_block, mf_ul_read.dump, 4 * 3); | ||||||
|                 memcpy(message.device.mf_ul_card.otp, &mf_ul_read.dump[4 * 3], 4); |                 memcpy(message.nfc_mifare_ul_data.otp, &mf_ul_read.dump[4 * 3], 4); | ||||||
|                 for(uint8_t i = 0; i < mf_ul_read.pages_readed * 4; i += 4) { |                 for(uint8_t i = 0; i < mf_ul_read.pages_readed * 4; i += 4) { | ||||||
|                     printf("Page %2d: ", i / 4); |                     printf("Page %2d: ", i / 4); | ||||||
|                     for(uint8_t j = 0; j < 4; j++) { |                     for(uint8_t j = 0; j < 4; j++) { | ||||||
| @@ -418,27 +453,17 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { | |||||||
|                     printf("\r\n"); |                     printf("\r\n"); | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 message.type = NfcMessageTypeMfUlNotFound; |                 message.found = false; | ||||||
|                 FURI_LOG_W(NFC_WORKER_TAG, "Tag does not support Mifare Ultralight"); |                 FURI_LOG_W(NFC_WORKER_TAG, "Tag does not support Mifare Ultralight"); | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             message.type = NfcMessageTypeMfUlNotFound; |             message.found = false; | ||||||
|             FURI_LOG_W(NFC_WORKER_TAG, "Can't find any tags"); |             FURI_LOG_W(NFC_WORKER_TAG, "Can't find any tags"); | ||||||
|         } |         } | ||||||
|         osDelay(100); |         osDelay(100); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void nfc_worker_emulate(NfcWorker* nfc_worker) { |  | ||||||
|     while(nfc_worker->state == NfcWorkerStateEmulate) { |  | ||||||
|         if(api_hal_nfc_listen(ApiHalNfcEmulateParamsMifare, 100)) { |  | ||||||
|             FURI_LOG_I(NFC_WORKER_TAG, "Reader detected"); |  | ||||||
|             api_hal_nfc_deactivate(); |  | ||||||
|         } |  | ||||||
|         osDelay(5); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void nfc_worker_field(NfcWorker* nfc_worker) { | void nfc_worker_field(NfcWorker* nfc_worker) { | ||||||
|     api_hal_nfc_field_on(); |     api_hal_nfc_field_on(); | ||||||
|     while(nfc_worker->state == NfcWorkerStateField) { |     while(nfc_worker->state == NfcWorkerStateField) { | ||||||
|   | |||||||
							
								
								
									
										24
									
								
								applications/nfc/nfc_worker.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										24
									
								
								applications/nfc/nfc_worker.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -2,6 +2,24 @@ | |||||||
|  |  | ||||||
| typedef struct NfcWorker NfcWorker; | typedef struct NfcWorker NfcWorker; | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |     // Init states | ||||||
|  |     NfcWorkerStateNone, | ||||||
|  |     NfcWorkerStateBroken, | ||||||
|  |     NfcWorkerStateReady, | ||||||
|  |     // Main worker states | ||||||
|  |     NfcWorkerStateDetect, | ||||||
|  |     NfcWorkerStateEmulate, | ||||||
|  |     NfcWorkerStateReadEMV, | ||||||
|  |     NfcWorkerStateEmulateEMV, | ||||||
|  |     NfcWorkerStateField, | ||||||
|  |     NfcWorkerStateReadMfUltralight, | ||||||
|  |     // Transition | ||||||
|  |     NfcWorkerStateStop, | ||||||
|  | } NfcWorkerState; | ||||||
|  |  | ||||||
|  | typedef void (*NfcWorkerCallback)(void* context); | ||||||
|  |  | ||||||
| NfcWorker* nfc_worker_alloc(osMessageQueueId_t message_queue); | NfcWorker* nfc_worker_alloc(osMessageQueueId_t message_queue); | ||||||
|  |  | ||||||
| NfcWorkerState nfc_worker_get_state(NfcWorker* nfc_worker); | NfcWorkerState nfc_worker_get_state(NfcWorker* nfc_worker); | ||||||
| @@ -10,6 +28,10 @@ ReturnCode nfc_worker_get_error(NfcWorker* nfc_worker); | |||||||
|  |  | ||||||
| void nfc_worker_free(NfcWorker* nfc_worker); | void nfc_worker_free(NfcWorker* nfc_worker); | ||||||
|  |  | ||||||
| void nfc_worker_start(NfcWorker* nfc_worker, NfcWorkerState state); | void nfc_worker_start( | ||||||
|  |     NfcWorker* nfc_worker, | ||||||
|  |     NfcWorkerState state, | ||||||
|  |     NfcWorkerCallback callback, | ||||||
|  |     void* context); | ||||||
|  |  | ||||||
| void nfc_worker_stop(NfcWorker* nfc_worker); | void nfc_worker_stop(NfcWorker* nfc_worker); | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "nfc_types.h" | #include "nfc_i.h" | ||||||
| #include "nfc_worker.h" | #include "nfc_worker.h" | ||||||
|  |  | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| @@ -17,10 +17,13 @@ | |||||||
| #include <st25r3916_irq.h> | #include <st25r3916_irq.h> | ||||||
|  |  | ||||||
| struct NfcWorker { | struct NfcWorker { | ||||||
|     osMessageQueueId_t message_queue; |  | ||||||
|     osThreadAttr_t thread_attr; |     osThreadAttr_t thread_attr; | ||||||
|     osThreadId_t thread; |     osThreadId_t thread; | ||||||
|  |  | ||||||
|  |     osMessageQueueId_t message_queue; | ||||||
|  |     NfcWorkerCallback callback; | ||||||
|  |     void* context; | ||||||
|  |  | ||||||
|     NfcWorkerState state; |     NfcWorkerState state; | ||||||
|     ReturnCode error; |     ReturnCode error; | ||||||
| }; | }; | ||||||
| @@ -33,7 +36,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker); | |||||||
|  |  | ||||||
| void nfc_worker_emulate_emv(NfcWorker* nfc_worker); | void nfc_worker_emulate_emv(NfcWorker* nfc_worker); | ||||||
|  |  | ||||||
| void nfc_worker_poll(NfcWorker* nfc_worker); | void nfc_worker_detect(NfcWorker* nfc_worker); | ||||||
|  |  | ||||||
| void nfc_worker_emulate(NfcWorker* nfc_worker); | void nfc_worker_emulate(NfcWorker* nfc_worker); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -52,10 +52,14 @@ static const rfalNfcDiscoverParam api_hal_nfc_emulate_params_emv = { | |||||||
|  |  | ||||||
| ReturnCode api_hal_nfc_init() { | ReturnCode api_hal_nfc_init() { | ||||||
|     // Check if Nfc worker was started |     // Check if Nfc worker was started | ||||||
|     if(rfalNfcGetState() > RFAL_NFC_STATE_NOTINIT) { |     rfalNfcState state = rfalNfcGetState(); | ||||||
|  |     if(state == RFAL_NFC_STATE_NOTINIT) { | ||||||
|  |         return rfalNfcInitialize(); | ||||||
|  |     } else if(state == RFAL_NFC_STATE_IDLE) { | ||||||
|         return ERR_NONE; |         return ERR_NONE; | ||||||
|  |     } else { | ||||||
|  |         return ERR_BUSY; | ||||||
|     } |     } | ||||||
|     return rfalNfcInitialize(); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| bool api_hal_nfc_is_busy() { | bool api_hal_nfc_is_busy() { | ||||||
|   | |||||||
| @@ -52,10 +52,14 @@ static const rfalNfcDiscoverParam api_hal_nfc_emulate_params_emv = { | |||||||
|  |  | ||||||
| ReturnCode api_hal_nfc_init() { | ReturnCode api_hal_nfc_init() { | ||||||
|     // Check if Nfc worker was started |     // Check if Nfc worker was started | ||||||
|     if(rfalNfcGetState() > RFAL_NFC_STATE_NOTINIT) { |     rfalNfcState state = rfalNfcGetState(); | ||||||
|  |     if(state == RFAL_NFC_STATE_NOTINIT) { | ||||||
|  |         return rfalNfcInitialize(); | ||||||
|  |     } else if(state == RFAL_NFC_STATE_IDLE) { | ||||||
|         return ERR_NONE; |         return ERR_NONE; | ||||||
|  |     } else { | ||||||
|  |         return ERR_BUSY; | ||||||
|     } |     } | ||||||
|     return rfalNfcInitialize(); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| bool api_hal_nfc_is_busy() { | bool api_hal_nfc_is_busy() { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user