// Include the most common headers from the C standard library #include #include #include #include // Include the main libnx system header, for Switch development #include // See also libnx nfc.h. static PadState pad; // Indefinitely wait for an event to be signaled // Break when + is pressed, or if the application should quit (in this case, return value will be non-zero) Result eventWaitLoop(Event *event) { Result rc = 1; while (appletMainLoop()) { rc = eventWait(event, 0); padUpdate(&pad); if (R_SUCCEEDED(rc) || (padGetButtonsDown(&pad) & HidNpadButton_Plus)) break; consoleUpdate(NULL); } return rc; } // Print raw data as hexadecimal numbers. void print_hex(void *buf, size_t size) { for (size_t i=0; i NfpDeviceState_TagFound) { printf("Bad nfp device state: %u\n", device_state); consoleUpdate(NULL); rc = -1; } } if (R_FAILED(rc)) goto fail_1; // Start the detection of tags. rc = nfpStartDetection(&handle); if (R_SUCCEEDED(rc)) { printf("Scanning for a tag...\n"); consoleUpdate(NULL); } // Wait until a tag is detected. // You could also wait until nfpGetDeviceState returns NfpDeviceState_TagFound. if (R_SUCCEEDED(rc)) { rc = eventWaitLoop(&activate_event); if (R_SUCCEEDED(rc)) { printf("A tag was detected, please do not remove it from the NFC spot.\n"); consoleUpdate(NULL); } } // If a tag was successfully detected, load it into memory. if (R_SUCCEEDED(rc)) rc = nfpMount(&handle, NfpDeviceType_Amiibo, NfpMountTarget_All); // Retrieve the model info data, which contains the amiibo id. if (R_SUCCEEDED(rc)) { NfpModelInfo model_info = {0}; rc = nfpGetModelInfo(&handle, &model_info); if (R_SUCCEEDED(rc)) { printf("Amiibo ID: "); print_hex(model_info.amiibo_id, 8); } } // Retrieve the common info data, which contains the application area size. u32 app_area_size = 0; if (R_SUCCEEDED(rc)) { NfpCommonInfo common_info = {0}; rc = nfpGetCommonInfo(&handle, &common_info); if (R_SUCCEEDED(rc)) app_area_size = common_info.application_area_size; } if (R_SUCCEEDED(rc)) { rc = nfpOpenApplicationArea(&handle, app_id); if (rc == 0x10073) // 2115-0128 printf("This tag contains no application data.\n"); if (rc == 0x13073) // 2115-0152 printf("This tag contains application data associated with an ID other than 0x%x.\n", app_id); } u8 app_area[0xd8] = {0}; // Maximum size of the application area. if (app_area_size > sizeof(app_area)) app_area_size = sizeof(app_area); if (R_SUCCEEDED(rc)) { rc = nfpGetApplicationArea(&handle, app_area, app_area_size); if (R_SUCCEEDED(rc)) { printf("App area:\n"); print_hex(app_area, app_area_size); } } // Wait until the tag is removed. // You could also wait until nfpGetDeviceState returns NfpDeviceState_TagRemoved. if (R_SUCCEEDED(rc)) { printf("You can now remove the tag.\n"); consoleUpdate(NULL); eventWaitLoop(&deactivate_event); } // Unmount the tag. nfpUnmount(&handle); // Stop the detection of tags. nfpStopDetection(&handle); // Cleanup. fail_1: eventClose(&deactivate_event); fail_0: eventClose(&activate_event); return rc; } // Main program entrypoint int main(int argc, char* argv[]) { Result rc = 0; // Hardcoded for Super Smash Bros. Ultimate. // See also: https://switchbrew.org/wiki/NFC_services#Application_IDs u32 app_id = 0x34f80200; // This example uses a text console, as a simple way to output text to the screen. // If you want to write a software-rendered graphics application, // take a look at the graphics/simplegfx example, which uses the libnx Framebuffer API instead. // If on the other hand you want to write an OpenGL based application, // take a look at the graphics/opengl set of examples, which uses EGL instead. consoleInit(NULL); // Configure our supported input layout: a single player with standard controller styles padConfigureInput(1, HidNpadStyleSet_NpadStandard); // Initialize the default gamepad (which reads handheld mode inputs as well as the first connected controller) padInitializeDefault(&pad); printf("NFC example program.\n"); printf("Scan an amiibo tag to display information about it.\n\n"); consoleUpdate(NULL); // Initialize the nfp:* service. rc = nfpInitialize(NfpServiceType_User); // Check if NFC is enabled. If not, wait until it is. // Note that various official games don't use nfc*(). if (R_SUCCEEDED(rc)) rc = nfcInitialize(NfcServiceType_User); if (R_SUCCEEDED(rc)) { bool nfc_enabled = false; rc = nfcIsNfcEnabled(&nfc_enabled); if (R_SUCCEEDED(rc) && !nfc_enabled) { // Get the availability change event. This is signaled when a change in NFC availability happens. See libnx nfc.h for the required sysver. Event availability_change_event = {0}; rc = nfpAttachAvailabilityChangeEvent(&availability_change_event); // Wait for a change in availability. if (R_SUCCEEDED(rc)) { printf("NFC is disabled. Please turn off plane mode via the quick settings to continue.\n"); consoleUpdate(NULL); rc = eventWaitLoop(&availability_change_event); } eventClose(&availability_change_event); } nfcExit(); } if (R_FAILED(rc)) goto fail_main; printf("Press A to process an amiibo.\n"); printf("Press + at any time to exit.\n"); printf("Waiting for user input...\n\n"); consoleUpdate(NULL); // Main loop while (appletMainLoop()) { // Scan the gamepad. This should be done once for each frame padUpdate(&pad); // padGetButtonsDown returns the set of buttons that have been // newly pressed in this frame compared to the previous one if (padGetButtonsDown(&pad) & HidNpadButton_A) { rc = process_amiibo(app_id); // If an error happened, print it. if (R_FAILED(rc)) printf("Error: 0x%x.\n", rc); printf("Waiting for user input...\n\n"); } // If + was pressed to exit an eventWaitLoop(), we also catch it here. if (padGetButtonsDown(&pad) & HidNpadButton_Plus) break; // break in order to return to hbmenu // Update the console, sending a new frame to the display consoleUpdate(NULL); } fail_main: nfpExit(); // Deinitialize and clean up resources used by the console (important!) consoleExit(NULL); return 0; }