[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); | ||||
|     // Free ViewPort | ||||
|     view_port_free(view_dispatcher->view_port); | ||||
|     // Free internal queue | ||||
|     if(view_dispatcher->queue) { | ||||
|         osMessageQueueDelete(view_dispatcher->queue); | ||||
|     } | ||||
|     // Free dispatcher | ||||
|     free(view_dispatcher); | ||||
| } | ||||
|   | ||||
| @@ -1,262 +1,142 @@ | ||||
| #include "nfc_i.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) { | ||||
|     furi_assert(message_queue); | ||||
|     NfcMessage message; | ||||
|     message.type = NfcMessageTypeExit; | ||||
|     furi_check(osMessageQueuePut(message_queue, &message, 0, osWaitForever) == osOK); | ||||
|     return VIEW_NONE; | ||||
| } | ||||
|  | ||||
| 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; | ||||
|     message.type = index; | ||||
|     furi_check(osMessageQueuePut(message_queue, &message, 0, osWaitForever) == osOK); | ||||
|     osMessageQueueGet(nfc->message_queue, &message, NULL, osWaitForever); | ||||
|     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 = furi_alloc(sizeof(Nfc)); | ||||
|  | ||||
|     message_queue = osMessageQueueNew(8, sizeof(NfcMessage), NULL); | ||||
|  | ||||
|     nfc->worker = nfc_worker_alloc(message_queue); | ||||
|     nfc->message_queue = osMessageQueueNew(8, sizeof(NfcMessage), NULL); | ||||
|     nfc->nfc_common.worker = nfc_worker_alloc(nfc->message_queue); | ||||
|     nfc->nfc_common.view_dispatcher = view_dispatcher_alloc(); | ||||
|     view_dispatcher_enable_queue(nfc->nfc_common.view_dispatcher); | ||||
|  | ||||
|     // Open GUI record | ||||
|     nfc->gui = furi_record_open("gui"); | ||||
|  | ||||
|     // View Dispatcher | ||||
|     nfc->view_dispatcher = view_dispatcher_alloc(); | ||||
|     view_dispatcher_attach_to_gui(nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); | ||||
|     view_dispatcher_attach_to_gui( | ||||
|         nfc->nfc_common.view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); | ||||
|  | ||||
|     // Menu | ||||
|     nfc->submenu = submenu_alloc(); | ||||
|     submenu_add_item(nfc->submenu, "Detect", NfcMessageTypeDetect, nfc_menu_callback, nfc); | ||||
|     submenu_add_item(nfc->submenu, "Read EMV", NfcMessageTypeReadEMV, nfc_menu_callback, nfc); | ||||
|     submenu_add_item(nfc->submenu, "Detect", NfcSubmenuDetect, 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( | ||||
|         nfc->submenu, "Emulate EMV", NfcMessageTypeEmulateEMV, 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); | ||||
|         nfc->submenu, "Read Mifare Ultralight", NfcSubmenuMifareUl, nfc_menu_callback, nfc); | ||||
|  | ||||
|     View* submenu_view = submenu_get_view(nfc->submenu); | ||||
|     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 | ||||
|     nfc->view_detect = view_alloc(); | ||||
|     view_set_context(nfc->view_detect, nfc); | ||||
|     view_set_draw_callback(nfc->view_detect, nfc_view_read_draw); | ||||
|     view_set_previous_callback(nfc->view_detect, nfc_view_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); | ||||
|     nfc->nfc_detect = nfc_detect_alloc(&nfc->nfc_common); | ||||
|     view_dispatcher_add_view( | ||||
|         nfc->nfc_common.view_dispatcher, NfcViewDetect, nfc_detect_get_view(nfc->nfc_detect)); | ||||
|  | ||||
|     // Emulate | ||||
|     nfc->view_emulate = view_alloc(); | ||||
|     view_set_context(nfc->view_emulate, nfc); | ||||
|     view_set_draw_callback(nfc->view_emulate, nfc_view_emulate_draw); | ||||
|     view_set_previous_callback(nfc->view_emulate, nfc_view_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)); | ||||
|     nfc->nfc_emulate = nfc_emulate_alloc(&nfc->nfc_common); | ||||
|     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 | ||||
|     nfc->view_error = view_alloc(); | ||||
|     view_set_context(nfc->view_error, nfc); | ||||
|     view_set_draw_callback(nfc->view_error, nfc_view_error_draw); | ||||
|     view_set_previous_callback(nfc->view_error, nfc_view_stop); | ||||
|     view_allocate_model(nfc->view_error, ViewModelTypeLockFree, sizeof(NfcViewErrorModel)); | ||||
|     view_dispatcher_add_view(nfc->view_dispatcher, NfcViewError, nfc->view_error); | ||||
|     // EMV | ||||
|     nfc->nfc_emv = nfc_emv_alloc(&nfc->nfc_common); | ||||
|     view_dispatcher_add_view( | ||||
|         nfc->nfc_common.view_dispatcher, NfcViewEmv, nfc_emv_get_view(nfc->nfc_emv)); | ||||
|  | ||||
|     // Mifare Ultralight | ||||
|     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 | ||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); | ||||
|     view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMenu); | ||||
|  | ||||
|     return nfc; | ||||
| } | ||||
|  | ||||
| void nfc_free(Nfc* nfc) { | ||||
|     // Free nfc worker | ||||
|     nfc_worker_free(nfc->worker); | ||||
|     // Free allocated queue | ||||
|     osMessageQueueDelete(message_queue); | ||||
|     message_queue = NULL; | ||||
|     furi_assert(nfc); | ||||
|  | ||||
|     // Free allocated views | ||||
|     // Menu | ||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewMenu); | ||||
|     // Submenu | ||||
|     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewMenu); | ||||
|     submenu_free(nfc->submenu); | ||||
|  | ||||
|     // Detect | ||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewRead); | ||||
|     view_free(nfc->view_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); | ||||
|     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewDetect); | ||||
|     nfc_detect_free(nfc->nfc_detect); | ||||
|  | ||||
|     // Emulate | ||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewEmulate); | ||||
|     view_free(nfc->view_emulate); | ||||
|     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewEmulate); | ||||
|     nfc_emulate_free(nfc->nfc_emulate); | ||||
|  | ||||
|     // Field | ||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewField); | ||||
|     view_free(nfc->view_field); | ||||
|     // EMV | ||||
|     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewEmv); | ||||
|     nfc_emv_free(nfc->nfc_emv); | ||||
|  | ||||
|     // Read Mifare Ultralight | ||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewReadMfUltralight); | ||||
|     view_free(nfc->view_read_mf_ultralight); | ||||
|     // Mifare ultralight | ||||
|     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewMifareUl); | ||||
|     nfc_mifare_ul_free(nfc->nfc_mifare_ul); | ||||
|  | ||||
|     // Error | ||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewError); | ||||
|     view_free(nfc->view_error); | ||||
|     // Worker | ||||
|     nfc_worker_stop(nfc->nfc_common.worker); | ||||
|     nfc_worker_free(nfc->nfc_common.worker); | ||||
|  | ||||
|     // Free View Dispatcher | ||||
|     view_dispatcher_free(nfc->view_dispatcher); | ||||
|     // View dispatcher | ||||
|     view_dispatcher_free(nfc->nfc_common.view_dispatcher); | ||||
|  | ||||
|     // Close all opened records | ||||
|     // GUI | ||||
|     furi_record_close("gui"); | ||||
|     nfc->gui = NULL; | ||||
|  | ||||
|     // Free nfc object | ||||
|     // The rest | ||||
|     osMessageQueueDelete(nfc->message_queue); | ||||
|     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) { | ||||
|     Nfc* nfc = nfc_alloc(); | ||||
|  | ||||
|     NfcMessage message; | ||||
|     while(1) { | ||||
|         furi_check(osMessageQueueGet(message_queue, &message, NULL, osWaitForever) == osOK); | ||||
|     view_dispatcher_run(nfc->nfc_common.view_dispatcher); | ||||
|  | ||||
|         if(message.type == NfcMessageTypeDetect) { | ||||
|             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; | ||||
|         } | ||||
|     } | ||||
|     nfc_free(nfc); | ||||
|  | ||||
|     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_types.h" | ||||
| #include "nfc_views.h" | ||||
| #include "nfc_worker.h" | ||||
|  | ||||
| #include <furi.h> | ||||
| @@ -10,35 +9,34 @@ | ||||
| #include <gui/gui.h> | ||||
| #include <gui/view.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| #include <assets_icons.h> | ||||
| #include <cli/cli.h> | ||||
|  | ||||
| #include <menu/menu.h> | ||||
| #include <menu/menu_item.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 { | ||||
|     NfcCommon nfc_common; | ||||
|     osMessageQueueId_t message_queue; | ||||
|  | ||||
|     NfcWorker* worker; | ||||
|  | ||||
|     Gui* gui; | ||||
|  | ||||
|     Submenu* submenu; | ||||
|  | ||||
|     View* view_detect; | ||||
|     View* view_read_emv; | ||||
|     View* view_emulate_emv; | ||||
|     View* view_emulate; | ||||
|     View* view_field; | ||||
|     View* view_read_mf_ultralight; | ||||
|     View* view_cli; | ||||
|     View* view_error; | ||||
|     ViewDispatcher* view_dispatcher; | ||||
|     NfcDetect* nfc_detect; | ||||
|     NfcEmulate* nfc_emulate; | ||||
|     NfcEmv* nfc_emv; | ||||
|     NfcMifareUl* nfc_mifare_ul; | ||||
| }; | ||||
|  | ||||
| typedef enum { | ||||
|     NfcViewMenu, | ||||
|     NfcViewDetect, | ||||
|     NfcViewEmulate, | ||||
|     NfcViewEmv, | ||||
|     NfcViewMifareUl, | ||||
| } NfcView; | ||||
|  | ||||
| Nfc* nfc_alloc(); | ||||
|  | ||||
| void nfc_start(Nfc* nfc, NfcView view_id, NfcWorkerState worker_state); | ||||
|  | ||||
| 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 | ||||
|  | ||||
| #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) { | ||||
|     if(type == RFAL_NFC_LISTEN_TYPE_NFCA) { | ||||
| @@ -39,76 +103,12 @@ static inline const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| typedef enum { | ||||
|     NfcDeviceTypeNfca, | ||||
|     NfcDeviceTypeNfcb, | ||||
|     NfcDeviceTypeNfcf, | ||||
|     NfcDeviceTypeNfcv, | ||||
|     NfcDeviceTypeEMV, | ||||
|     NfcDeviceTypeMfUltralight, | ||||
| } 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; | ||||
| static inline const char* nfc_get_protocol(NfcProtocol protocol) { | ||||
|     if(protocol == NfcDeviceProtocolEMV) { | ||||
|         return "EMV"; | ||||
|     } else if(protocol == NfcDeviceProtocolMfUltralight) { | ||||
|         return "Mifare UL"; | ||||
|     } else { | ||||
|         return "Unknown"; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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" | ||||
|  | ||||
| /***************************** NFC Worker API *******************************/ | ||||
|  | ||||
| NfcWorker* nfc_worker_alloc(osMessageQueueId_t message_queue) { | ||||
|     NfcWorker* nfc_worker = furi_alloc(sizeof(NfcWorker)); | ||||
|     nfc_worker->message_queue = message_queue; | ||||
|     // Worker thread attributes | ||||
|     nfc_worker->thread_attr.name = "nfc_worker"; | ||||
|     nfc_worker->thread_attr.stack_size = 8192; | ||||
|     nfc_worker->callback = NULL; | ||||
|     nfc_worker->context = NULL; | ||||
|     // Initialize rfal | ||||
|     nfc_worker->error = api_hal_nfc_init(); | ||||
|     if(nfc_worker->error == ERR_NONE) { | ||||
| @@ -36,9 +40,16 @@ ReturnCode nfc_worker_get_error(NfcWorker* nfc_worker) { | ||||
|     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->state == NfcWorkerStateReady); | ||||
|  | ||||
|     nfc_worker->callback = callback; | ||||
|     nfc_worker->context = context; | ||||
|     nfc_worker_change_state(nfc_worker, state); | ||||
|     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 Thread *******************************/ | ||||
|  | ||||
| void nfc_worker_task(void* context) { | ||||
|     NfcWorker* nfc_worker = context; | ||||
|  | ||||
|     api_hal_power_insomnia_enter(); | ||||
|     api_hal_nfc_exit_sleep(); | ||||
|  | ||||
|     if(nfc_worker->state == NfcWorkerStatePoll) { | ||||
|         nfc_worker_poll(nfc_worker); | ||||
|     if(nfc_worker->state == NfcWorkerStateDetect) { | ||||
|         nfc_worker_detect(nfc_worker); | ||||
|     } else if(nfc_worker->state == NfcWorkerStateEmulate) { | ||||
|         nfc_worker_emulate(nfc_worker); | ||||
|     } else if(nfc_worker->state == NfcWorkerStateReadEMV) { | ||||
|         nfc_worker_read_emv(nfc_worker); | ||||
|     } 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); | ||||
|     } else if(nfc_worker->state == NfcWorkerStateReadMfUltralight) { | ||||
|         nfc_worker_read_mf_ultralight(nfc_worker); | ||||
|         nfc_worker_emulate_emv(nfc_worker); | ||||
|     } else if(nfc_worker->state == NfcWorkerStateField) { | ||||
|     } | ||||
|     api_hal_nfc_deactivate(); | ||||
|     nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); | ||||
| @@ -81,6 +94,55 @@ void nfc_worker_task(void* context) { | ||||
|     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) { | ||||
|     ReturnCode err; | ||||
|     rfalNfcDevice* dev_list; | ||||
| @@ -91,9 +153,11 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | ||||
|     uint8_t* rx_buff; | ||||
|     uint16_t* rx_len; | ||||
|  | ||||
|     // Update screen before start searching | ||||
|     NfcMessage message = {.type = NfcMessageTypeEMVNotFound}; | ||||
|     NfcMessage message = {.found = false}; | ||||
|     while(nfc_worker->state == NfcWorkerStateReadEMV) { | ||||
|         if(nfc_worker->callback) { | ||||
|             nfc_worker->callback(nfc_worker->context); | ||||
|         } | ||||
|         furi_check( | ||||
|             osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK); | ||||
|         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); | ||||
|                 if(err != ERR_NONE) { | ||||
|                     FURI_LOG_E(NFC_WORKER_TAG, "Error during selection PPSE request: %d", err); | ||||
|                     message.type = NfcMessageTypeEMVNotFound; | ||||
|                     message.found = false; | ||||
|                     api_hal_nfc_deactivate(); | ||||
|                     continue; | ||||
|                 } | ||||
| @@ -115,7 +179,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | ||||
|                     FURI_LOG_I(NFC_WORKER_TAG, "Select PPSE responce parced"); | ||||
|                 } else { | ||||
|                     FURI_LOG_E(NFC_WORKER_TAG, "Can't find pay application"); | ||||
|                     message.type = NfcMessageTypeEMVNotFound; | ||||
|                     message.found = false; | ||||
|                     api_hal_nfc_deactivate(); | ||||
|                     continue; | ||||
|                 } | ||||
| @@ -125,7 +189,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | ||||
|                 if(err != ERR_NONE) { | ||||
|                     FURI_LOG_E( | ||||
|                         NFC_WORKER_TAG, "Error during application selection request: %d", err); | ||||
|                     message.type = NfcMessageTypeEMVNotFound; | ||||
|                     message.found = false; | ||||
|                     api_hal_nfc_deactivate(); | ||||
|                     continue; | ||||
|                 } | ||||
| @@ -134,10 +198,10 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | ||||
|                     "Select application response received. Start parsing response"); | ||||
|                 if(emv_decode_select_app_response(rx_buff, *rx_len, &emv_app)) { | ||||
|                     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 { | ||||
|                     FURI_LOG_E(NFC_WORKER_TAG, "Can't read card name"); | ||||
|                     message.type = NfcMessageTypeEMVNotFound; | ||||
|                     message.found = false; | ||||
|                     api_hal_nfc_deactivate(); | ||||
|                     continue; | ||||
|                 } | ||||
| @@ -147,15 +211,15 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | ||||
|                 if(err != ERR_NONE) { | ||||
|                     FURI_LOG_E( | ||||
|                         NFC_WORKER_TAG, "Error during Get Processing Options command: %d", err); | ||||
|                     message.type = NfcMessageTypeEMVNotFound; | ||||
|                     message.found = false; | ||||
|                     api_hal_nfc_deactivate(); | ||||
|                     continue; | ||||
|                 } | ||||
|                 if(emv_decode_get_proc_opt(rx_buff, *rx_len, &emv_app)) { | ||||
|                     FURI_LOG_I(NFC_WORKER_TAG, "Card number parsed"); | ||||
|                     message.type = NfcMessageTypeEMVFound; | ||||
|                     message.found = true; | ||||
|                     memcpy( | ||||
|                         message.device.emv_card.number, | ||||
|                         message.nfc_emv_data.number, | ||||
|                         emv_app.card_number, | ||||
|                         sizeof(emv_app.card_number)); | ||||
|                     api_hal_nfc_deactivate(); | ||||
| @@ -189,27 +253,27 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | ||||
|                     } | ||||
|                     if(pan_found) { | ||||
|                         FURI_LOG_I(NFC_WORKER_TAG, "Card PAN found"); | ||||
|                         message.type = NfcMessageTypeEMVFound; | ||||
|                         message.found = true; | ||||
|                         memcpy( | ||||
|                             message.device.emv_card.number, | ||||
|                             message.nfc_emv_data.number, | ||||
|                             emv_app.card_number, | ||||
|                             sizeof(emv_app.card_number)); | ||||
|                     } else { | ||||
|                         FURI_LOG_E(NFC_WORKER_TAG, "Can't read card number"); | ||||
|                         message.type = NfcMessageTypeEMVNotFound; | ||||
|                         message.found = false; | ||||
|                     } | ||||
|                     api_hal_nfc_deactivate(); | ||||
|                 } | ||||
|             } else { | ||||
|                 // Can't find EMV card | ||||
|                 FURI_LOG_W(NFC_WORKER_TAG, "Card doesn't support EMV"); | ||||
|                 message.type = NfcMessageTypeEMVNotFound; | ||||
|                 message.found = false; | ||||
|                 api_hal_nfc_deactivate(); | ||||
|             } | ||||
|         } else { | ||||
|             // Can't find EMV card | ||||
|             FURI_LOG_W(NFC_WORKER_TAG, "Can't find any cards"); | ||||
|             message.type = NfcMessageTypeEMVNotFound; | ||||
|             message.found = false; | ||||
|             api_hal_nfc_deactivate(); | ||||
|         } | ||||
|         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) { | ||||
|     ReturnCode err; | ||||
|     rfalNfcDevice* dev_list; | ||||
| @@ -320,8 +346,11 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { | ||||
|     MfUltralightRead mf_ul_read; | ||||
|  | ||||
|     // Update screen before start searching | ||||
|     NfcMessage message = {.type = NfcMessageTypeMfUlNotFound}; | ||||
|     NfcMessage message = {.found = false}; | ||||
|     while(nfc_worker->state == NfcWorkerStateReadMfUltralight) { | ||||
|         if(nfc_worker->callback) { | ||||
|             nfc_worker->callback(nfc_worker->context); | ||||
|         } | ||||
|         furi_check( | ||||
|             osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK); | ||||
|         api_hal_nfc_deactivate(); | ||||
| @@ -354,7 +383,7 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { | ||||
|                     api_hal_nfc_deactivate(); | ||||
|                     if(!api_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) { | ||||
|                         FURI_LOG_E(NFC_WORKER_TAG, "Lost connection. Restarting search"); | ||||
|                         message.type = NfcMessageTypeMfUlNotFound; | ||||
|                         message.found = false; | ||||
|                         continue; | ||||
|                     } | ||||
|                 } else { | ||||
| @@ -362,7 +391,7 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { | ||||
|                         NFC_WORKER_TAG, | ||||
|                         "Error getting Mifare Ultralight version. Error code: %d", | ||||
|                         err); | ||||
|                     message.type = NfcMessageTypeMfUlNotFound; | ||||
|                     message.found = false; | ||||
|                     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; | ||||
|                     } else { | ||||
|                         FURI_LOG_E(NFC_WORKER_TAG, "Fast read failed"); | ||||
|                         message.type = NfcMessageTypeMfUlNotFound; | ||||
|                         message.found = false; | ||||
|                         continue; | ||||
|                     } | ||||
|                 } else { | ||||
| @@ -403,13 +432,19 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { | ||||
|                 } | ||||
|  | ||||
|                 // 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( | ||||
|                     message.device.mf_ul_card.uid, | ||||
|                     message.nfc_mifare_ul_data.nfc_data.uid, | ||||
|                     dev_list[0].dev.nfca.nfcId1, | ||||
|                     sizeof(message.device.mf_ul_card.uid)); | ||||
|                 memcpy(message.device.mf_ul_card.man_block, mf_ul_read.dump, 4 * 3); | ||||
|                 memcpy(message.device.mf_ul_card.otp, &mf_ul_read.dump[4 * 3], 4); | ||||
|                     message.nfc_mifare_ul_data.nfc_data.uid_len); | ||||
|                 memcpy(message.nfc_mifare_ul_data.man_block, mf_ul_read.dump, 4 * 3); | ||||
|                 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) { | ||||
|                     printf("Page %2d: ", i / 4); | ||||
|                     for(uint8_t j = 0; j < 4; j++) { | ||||
| @@ -418,27 +453,17 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { | ||||
|                     printf("\r\n"); | ||||
|                 } | ||||
|             } else { | ||||
|                 message.type = NfcMessageTypeMfUlNotFound; | ||||
|                 message.found = false; | ||||
|                 FURI_LOG_W(NFC_WORKER_TAG, "Tag does not support Mifare Ultralight"); | ||||
|             } | ||||
|         } else { | ||||
|             message.type = NfcMessageTypeMfUlNotFound; | ||||
|             message.found = false; | ||||
|             FURI_LOG_W(NFC_WORKER_TAG, "Can't find any tags"); | ||||
|         } | ||||
|         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) { | ||||
|     api_hal_nfc_field_on(); | ||||
|     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 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); | ||||
|  | ||||
| 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_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); | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "nfc_types.h" | ||||
| #include "nfc_i.h" | ||||
| #include "nfc_worker.h" | ||||
|  | ||||
| #include <furi.h> | ||||
| @@ -17,10 +17,13 @@ | ||||
| #include <st25r3916_irq.h> | ||||
|  | ||||
| struct NfcWorker { | ||||
|     osMessageQueueId_t message_queue; | ||||
|     osThreadAttr_t thread_attr; | ||||
|     osThreadId_t thread; | ||||
|  | ||||
|     osMessageQueueId_t message_queue; | ||||
|     NfcWorkerCallback callback; | ||||
|     void* context; | ||||
|  | ||||
|     NfcWorkerState state; | ||||
|     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_poll(NfcWorker* nfc_worker); | ||||
| void nfc_worker_detect(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() { | ||||
|     // 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; | ||||
|     } else { | ||||
|         return ERR_BUSY; | ||||
|     } | ||||
|     return rfalNfcInitialize(); | ||||
| } | ||||
|  | ||||
| bool api_hal_nfc_is_busy() { | ||||
|   | ||||
| @@ -52,10 +52,14 @@ static const rfalNfcDiscoverParam api_hal_nfc_emulate_params_emv = { | ||||
|  | ||||
| ReturnCode api_hal_nfc_init() { | ||||
|     // 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; | ||||
|     } else { | ||||
|         return ERR_BUSY; | ||||
|     } | ||||
|     return rfalNfcInitialize(); | ||||
| } | ||||
|  | ||||
| bool api_hal_nfc_is_busy() { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user