6. Using the NFP Library

Note the following cautions when implementing an application that uses the NFP library.

  • The NFP library does not support multithreaded processes. Do not call NFP library functions simultaneously from multiple threads.
  • A successful function call generally returns nn::ResultSuccess, but uses the IsSuccess function or the IsFailure function to determine whether execution succeeded.
  • Return values belonging to nn::nfp::ResultInvalidUsage are implementation errors (nn::nfp::ResultInvalidArgument, nn::nfp::ResultInvalidPointer, and nn::nfp::ResultBufferIsSmall). Fix your implementation during development so that these errors are not returned.
  • Many of the API functions provided by the NFP library have processing times in the range from a few dozen milliseconds to several hundred milliseconds. In particular, initializing the library can take upwards of five seconds and writing to an NFP tag can take around one second. For this reason, we recommend calling the functions in the NFP library from a separate thread rather than from the main loop.
  • After a tag is detected, if communication is lost because, for example, the tag is moved too far away from the reader, a loss-of-tag notification is sent to the application. At this point, the NFP library transitions to the RW_DEACTIVE state, and the mounted tag is unmounted.
    If you call an NFP library function in this state, most functions will return nn::nfp::ResultInvalidOperation. Be sure to have your application handle the tag loss notification and verify that the detected tag is still accessible before calling any NFP library functions.
  • If the system enters Sleep Mode or wireless-disabled mode during the execution of an NFP library function, most functions will return nn::nfp::ResultSleep or nn::nfp::ResultWifiOff. When these values are returned, the NFP library reverts to the INIT state, tag detection stops, and the mounted tag is unmounted. This state is the same as the one that is entered when the nn::nfp::Unmount and nn::nfp::StopDetection functions are called.
    Even if the system wakes from Sleep Mode or transitions back to wireless-enabled mode, the NFP library does not automatically return to its previous state. The application must resume tag detection by calling nn::nfp::StartDetection again.
  • Before transitioning to the HOME Menu or Sleep Mode, if the nn::nfp::Flush function has not yet been called when writing to the application-specific region, you can delay the transition to the HOME Menu or Sleep Mode until the write operation has been completed by calling nn::nfp::Flush. An alternative approach is to display the HOME Menu Disabled icon and prevent transitioning to the HOME Menu while writing to the NFP tag.
  • Before transitioning to the HOME Menu or an applet, call nn::nfp::Finalize to put the NFP library into the NONE state. If this operation is omitted, the touch panel and NFC-related features will be unavailable to the HOME Menu or applet.

 

The NFP library includes functions that access backup data and NFP tags. Calling these functions excessively can shorten the life of the hardware and NFP tag.

Implement your application so that it does not call the following functions too often, unless the user intentionally repeats an operation that requires them.

Table 6-1. Functions That Access Backup Data or NFP Tags
Function Read From Backup Data Write to Backup Data Write to NFP Tag
nn::nfp::Initialize Always When there is no save data for backups None
nn::nfp::Mount Always When mounting a tag for the first time, or when mounting a tag that was overwritten by another device None
nn::nfp::Restore Always None Always
nn::nfp::Flush None Always Always
nn::nfp::CreateApplicationArea None Always Always

6.1. Initialization

Call the nn::nfp::Initialize function to initialize the NFP library. Nintendo strongly recommends calling this function outside of the main thread because it usually takes around one second to execute, and as much as five seconds when run for the first time. Nintendo also recommends calling this function after the application is ready to update the screen instead of during startup.

Almost all of the functions in the NFP library return nn::nfp::ResultInvalidOperation if called before the library is initialized. If you call nn::nfp::Initialize when the library is already initialized, it returns nn::nfp::ResultInvalidOperation, but you can handle this result as a success in this case.

If initialization of the NFP library fails, sometimes nn::nfp::ResultNeedRetry is returned. When this occurs, call nn::nfp::Initialize again. You can increase the chance of success if you wait around one second before calling.

Table 6-2. Possible Return Values From nn::nfp::Initialize
Return Value Description
nn::ResultSuccess Initialization successful.
nn::nfp::ResultInvalidOperation Already initialized.
nn::nfp::ResultNeedRetry Try again.

6.1.1. Setting Events to Receive Tag Detection Notifications

Before starting tag detection, you must set events so the application can receive tag detection notifications from the NFP library.

The NFP library sends tag detection notifications to the application at the following times.

  • A tag was detected within the range of communication of the NFC module (tag detection notification).
  • The detected tag left the range of communication (tag loss notification).
  • The nn::nfp::StopDetection, nn::nfp::Disconnect or nn::nfp::Finalize function was called when a tag had been detected (tag loss notification).

Use the nn::nfp::SetActivateEvent function to set the event for tag detection notifications and the nn::nfp::SetDeactivateEvent function for tag loss notifications.

Each of these functions takes a pointer to an instance of the nn::os::Event class as an argument. The NFP library manages the events, so the application does not need to initialize or finalize the instances that are passed.

These functions must be called before starting tag detection (while the state is INIT).

Table 6-3. Possible Return Values From nn::nfp::SetActivateEvent and nn::nfp::SetDeactivateEvent
Return Value Description
nn::ResultSuccess The event was successfully set.
nn::nfp::ResultInvalidPointer The pointer passed as an argument is invalid.
nn::nfp::ResultInvalidOperation The library is not in an appropriate state for calling this function.

6.1.1.1. Handling Tag Detection Notifications

When the NFP library detects a tag, the application is notified by putting the event object set with nn::nfp::SetActivateEvent into a signaled state.

When a tag is detected, the following processes become available.

 

6.1.1.2. Handling Tag Loss Notifications

When the NFP library loses a tag because the tag leaves the range of communication, the application is notified by putting the event object set with nn::nfp::SetDeactivateEvent into a signaled state. The NFP library transitions to the RW_DEACTIVE state as soon as the notification is received. To continue tag detection, you must call the nn::nfp::StartDetection function again.

You can determine the cause of the tag loss based on the tag connection status that can be retrieved using nn::nfp::GetConnectionStatus. The tag connection status is defined with the nn::nfp::ConnectionStatus structure. A pointer to the structure must be passed to nn::nfp::GetConnectionStatus.

If nn::nfp::GetConnectionStatus succeeds, the connection status of the current tag will be stored in the structure that was passed as an argument. The detailed connection status (reason for disconnect) is defined by the nn::nfp::DeactivateReason enumerator and stored in the deactivateReason member of the structure.

Table 6-4. Detailed Connection Status (Reason for Disconnect)
Definition Connection Status Description
BEFORE_ACTIVATION Not found A tag has not been detected yet.
TAG_IS_ACTIVE Connected The tag can be accessed.
DETECT_ERROR Connection failure Not recognized as a valid tag. The tag data may be corrupted.
CONNECTION_LOST Disconnected Could not maintain the connection because the tag left the range of communication or the signal is too weak.
UNKNOWN_DEACTIVATE_REASON Disconnected The connection was lost for a reason not recognized by the library.
Table 6-5. Possible Return Values From nn::nfp::GetConnectionStatus
Return Value Description
nn::ResultSuccess The connection status was successfully retrieved.
nn::nfp::ResultInvalidPointer The pointer passed as an argument is invalid.
nn::nfp::ResultInvalidOperation The library is not in an appropriate state for calling this function.

6.2. Starting Tag Detection

Call the nn::nfp::StartDetection function to start tag detection.

While tag detection is running, the NFP library periodically checks whether any tags have been detected and whether it can communicate with any detected tags. There is a time lag of several hundred milliseconds between the occurrence of the event that causes the tag detection state to change, and when the application is notified of the tag detection or tag loss. Do not implement your application in a way that requires careful timing when applying and removing tags. This assumes that the tag is placed in the center of the lower screen on the New Nintendo 3DS system. Specifically, the tag can be accurately recognized within ±10 mm in the horizontal and vertical directions from the center of the LCD screen, and within 5 mm of the surface. This range also applies to the New Nintendo 3DS XL. Avoid gameplay and user interface designs that encourage the user to place a tag away from the center of the LCD screen.

Also note that the electromagnetic waves used for tag detection on the New Nintendo 3DS system cause the input from the touch panel to become unstable. Use of the touch panel for input during detection is restricted on the New Nintendo 3DS due to the potential for unintended operations in an application. Specifically, the status member of nn::hid::CTR::TouchPanelStatus is always 0 (pen up) from the time the nn::nfp::StartDetection function is called until the nn::nfp::StopDetection or nn::nfp::Finalize function is called to stop tag detection.

There is no such restriction on the original Nintendo 3DS systems because a peripheral device is used for tag detection. However, if your application uses the touch panel on the Nintendo 3DS during tag detection, make sure that the application can also be controlled on the New Nintendo 3DS by providing a different UI or other method.

Table 6-6. Possible Return Values From nn::nfp::StartDetection
Return Value Description
nn::ResultSuccess Tag detection has started.
nn::nfp::ResultInvalidOperation The library is not in an appropriate state for calling this function.
nn::nfp::ResultSleep The process failed because the system is entering Sleep Mode.
nn::nfp::ResultWifiOff The process failed because the system is in wireless-disabled mode.

6.3. Getting Tag Information

Call the nn::nfp::GetTagInfo function to get tag information. Tag information is defined with the nn::nfp::TagInfo structure. A pointer to the structure must be passed to nn::nfp::GetTagInfo.

After a tag is detected, if it leaves the range of communication or is swapped with a different tag before nn::nfp::GetTagInfo is called, the nn::nfp::GetTagInfo function will return nn::nfp::ResultTagNotFound. When this value is returned, the NFP library transitions to the RW_DEACTIVE state as soon as the notification is received. To continue tag detection, you must call the nn::nfp::StartDetection function again.

Table 6-7. Possible Return Values From nn::nfp::GetTagInfo
Return Value Description
nn::ResultSuccess The tag information was successfully retrieved.
nn::nfp::ResultInvalidPointer The pointer passed as an argument is invalid.
nn::nfp::ResultInvalidOperation The library is not in an appropriate state for calling this function.
nn::nfp::ResultTagNotFound The tag could not be found. This result is caused by the tag leaving the range of communication or being swapped with a different tag.
nn::nfp::ResultSleep The process failed because the system is entering Sleep Mode.
nn::nfp::ResultWifiOff The process failed because the system is in wireless-disabled mode.
Note:

The NFP library can only get the tag UID from the tag information. We recommend using nn::nfp::GetTagInfo to get the tag information in advance for applications that access the application-specific region of the NFP tag.

Because the tag information only contains information that can be retrieved from any tag type that is accessible to the NFP library, there is no way to determine whether the detected tag is an NFP tag.

6.4. Mounting a Tag

To access the information in an NFP tag, you must first call nn::nfp::Mount or nn::nfp::MountRom to mount the detected tag.

Neither function will mount a tag that is not an NFP tag, but the nn::nfp::MountRom function can mount a tag even if it has corrupted data, although there are limitations on the information that can be accessed.

You can use the return value to determine whether a tag is an NFP tag, as described below.

Table 6-8. Tag Statuses and Function Return Values
Tag Status nn::nfp::Mount nn::nfp::MountRom
Not an NFP tag nn::nfp::ResultNotSupported
NFP tag with unknown format version nn::nfp::ResultInvalidFormatVersion
NFP tag with normal data nn::nfp::ResultSuccess

NFP tag with corrupted data

(No backup data for the tag)

nn::nfp::ResultNeedFormat nn::nfp::ResultSuccess

NFP tag with corrupted data

(Backup data for the tag is available)

nn::nfp::ResultNeedRestore nn::nfp::ResultSuccess

If the detected tag is not an NFP tag, a value of nn::nfp::ResultNotSupported is returned.

If the detected tag is an NFP tag but cannot be mounted because the format version is unknown, a value of nn::nfp::ReultInvalidFormatVersion is returned.

If the detected tag is an NFP tag and is successfully mounted, a value of nn::nfp::ResultSuccess is returned.

If the detected tag is an NFP tag and the data is corrupted, a value of nn::nfp::ResultNeedRestore or nn::nfp::ResultNeedFormat is returned. If the first value is returned, you can restore the tag data in the application by calling nn::nfp::Restore. If the second value is returned, you cannot restore the tag data within the application, so the NFP tag must be reset in amiibo Settings.

When nn::nfp::ResultTagNotFound is returned, the NFP library transitions to the RW_DEACTIVE state as soon as the notification is received. To continue tag detection, you must call the nn::nfp::StartDetection function again.

When nn::nfp::ResultNeedRetry is returned, the mounting process might succeed if nn::nfp::Mount is called again.

Note:

Mounting a tag can take longer than a second.

If you want to try again, we recommend a retry interval of around 100 milliseconds.

Table 6-9. Possible Return Values From nn::nfp::Mount
Return Value Description
nn::ResultSuccess The tag was successfully mounted.
nn::nfp::ResultInvalidOperation The library is not in an appropriate state for calling this function.
nn::nfp::ResultSleep The process failed because the system is entering Sleep Mode.
nn::nfp::ResultWifiOff The process failed because the system is in wireless-disabled mode.
nn::nfp::ResultNotSupported The tag is not an NFP tag.
nn::nfp::ResultNeedRestore The tag data is corrupted. Call nn::nfp::Restore to restore the tag data.
nn::nfp::ResultNeedFormat The tag data is corrupted and must be reset in amiibo Settings.
nn::nfp::ResultTagNotFound The tag could not be found. This result is caused by the tag leaving the range of communication or being swapped with a different tag.
nn::nfp::ResultNeedRetry An error occurred during mounting. The process might succeed if tried again.
nn::nfp::ResultInvalidFormatVersion The tag version is not supported. Inform the user that the tag is not supported.
Table 6-10. Possible Return Values From nn::nfp::MountRom
Return Value Description
nn::ResultSuccess The tag was successfully mounted.
nn::nfp::ResultInvalidOperation The library is not in an appropriate state for calling this function.
nn::nfp::ResultSleep The process failed because the system is entering Sleep Mode.
nn::nfp::ResultWifiOff The process failed because the system is in wireless-disabled mode.
nn::nfp::ResultNotSupported The tag is not an NFP tag.
nn::nfp::ResultTagNotFound The tag could not be found. This result is caused by the tag leaving the range of communication or being swapped with a different tag.
nn::nfp::ResultInvalidFormatVersion The tag version is not supported. Inform the user that the tag is not supported.

6.4.1. Restoring Tags

When the nn::nfp::Mount function returns nn::nfp::ResultNeedRestore, you can restore the NFP tag from the application by calling the nn::nfp::Restore function.

If a value of nn::nfp::ResultNeedRetry is returned, the tag restoration process might succeed if nn::nfp::Restore is called again.

Note:

Restoring a tag can take longer than a second.

If you want to try again, we recommend a retry interval of around 100 milliseconds.

The tag is restored using the data that was backed up by the NFP library when mounting the tag or immediately before writing to the tag. Consequently, the restored data is the data that the application is attempting to write, and not the data that was in the tag before the write process failed.

Table 6-11. Possible Return Values From nn::nfp::Restore
Return Value Description
nn::ResultSuccess The tag was successfully restored.
nn::nfp::ResultInvalidOperation The library is not in an appropriate state for calling this function.
nn::nfp::ResultSleep The process failed because the system is entering Sleep Mode.
nn::nfp::ResultWifiOff The process failed because the system is in wireless-disabled mode.
nn::nfp::ResultNotSupported The tag is not an NFP tag.
nn::nfp::ResultNeedRetry An error occurred during the write process. The function must be called again.
nn::nfp::ResultNotBroken Restoration is unnecessary because the tag is not corrupted.
nn::nfp::ResultOperationFailed An error occurred during writing. The tag data might not have been restored correctly.
nn::nfp::ResultTagNotFound The tag could not be found. This result is caused by the tag leaving the range of communication or being swapped with a different tag.
nn::nfp::ResultBackupError Failed to access the backup data. This NFP tag cannot be restored.

6.5. Starting amiibo Settings

The following steps are required when starting amiibo Settings.

  1. Configure the information required to start amiibo Settings.
  2. Finalize the NFP library.
  3. Start amiibo Settings.

Start by configuring the nn::nfp::Parameter structure with the information required to start amiibo Settings.

Call nn::nfp::InitializeParameter to initialize the structure and then configure the input member (nn::nfp::Input structure) with the information required when starting amiibo Settings from an application.

When amiibo Settings detects the tag, it must determine whether it is the same tag specified by the application. Be sure to specify the tag information previously retrieved using nn::nfp::GetTagInfo in the tagInfo member.

Configure the other members (mode, isRegistered, registerInfo, and commonInfo) with the following values based on the use case.

Table 6-12. Values to Use When Starting amiibo Settings by Use Case
Use Case mode isRegistered registerInfo commonInfo
The nn::nfp::Mount function returned nn::nfp::ResultNeedRestore. AMIIBO_SETTINGS_RESTORE false NULL NULL
The nn::nfp::GetNfpRegisterInfo function returned nn::nfp::ResultNeedRegister. AMIIBO_SETTINGS_NICKNAME_OWNER false NULL Information retrieved using nn::nfp::GetNfpCommonInfo
The nn::nfp::GetNfpRegisterInfo function returned nn::nfp::ResultSuccess, but the nickname was an empty string. AMIIBO_SETTINGS_NICKNAME_OWNER true Information retrieved using nn::nfp::GetNfpRegisterInfo Information retrieved using nn::nfp::GetNfpCommonInfo
The nn::nfp::OpenApplicationArea function returned nn::nfp::ResultAccessIdMisMatch, so you want to delete the application-specific region. AMIIBO_SETTINGS_ERASE_GAMEDATA true Information retrieved using nn::nfp::GetNfpRegisterInfo Information retrieved using nn::nfp::GetNfpCommonInfo

The mode member takes an enumerator of the nn::nfp::AmiiboSettingsMode enumeration and specifies the mode to use when starting amiibo Settings.

Table 6-13. amiibo Settings Startup Modes
Definition Description
AMIIBO_SETTINGS_RESTORE Restores a tag.
AMIIBO_SETTINGS_NICKNAME_OWNER Registers the owner and sets a nickname.
AMIIBO_SETTINGS_ERASE_GAMEDATA Erases the application-specific region.

Call the nn::nfp::StartAmiiboSettings function to start amiibo Settings. Before calling this function, you must finalize the NFP library by calling nn::nfp::Finalize. Consequently, the NFP library must be reinitialized before use after returning from amiibo Settings.

If the nn::nfp::StartAmiiboSettings returns false, the startup of amiibo Settings failed. This result could be caused by the following factors.

  • The NFP library was not finalized (by calling nn::nfp::Finalize).
  • The amiibo Settings applet is not installed (nn::nfp::IsAmiiboSettingsAvailable returns false).
  • The parameter settings are incorrect.
  • The applet failed to start.

The Parameter.output.result object stores whether any changes were made to the NFP tag in amiibo Settings. A value of nn::nfp::AMIIBO_SETTINGS_RESULT_SUCCESS in this member indicates that changes were made to the NFP tag in amiibo Settings, while any other value indicates that no changes were made because the operation was canceled by the user or other reason.

Similar to other library applets, when control returns from nn::nfp::StartAmiiboSettings, use the nn::applet::IsExpectedToProcessPowerButton and nn::applet::IsExpectedToCloseApplication functions to check whether the application has been requested to close because the POWER Button was pressed while the applet was running.

6.6. Accessing the NFP Tag

When a tag is successfully mounted, you can access the following information in the NFP tag.

  • Shared region
  • Application-specific region
Warning:

The application cannot access the application-specific region unless it has the same access ID as the application that created the region.

If the tag was mounted with nn::nfp::MountRom, the application can only access part of the shared region.

6.6.1. Accessing the Shared Region

Before using the information in the mounted NFP tag, use nn::nfp::GetNfpCommonInfo or nn::nfp::GetNfpRomInfo to get the information in the shared region to determine whether the NFP tag is compatible with the application.

Warning:

If the tag was mounted with nn::nfp::MountRom, the nn::nfp::GetNfpCommonInfo function returns nn::nfp::ResultInvalidOperation.

The shared region information retrieved by nn::nfp::GetNfpCommonInfo is defined with the nn::nfp::CommonInfo structure. A pointer to this structure must be passed to the function.

The shared region information retrieved by nn::nfp::GetNfpRomInfo is defined with the nn::nfp::RomInfo structure. A pointer to this structure must be passed to the function.

Only use the character ID (characterId) to determine compatibility of the NFP tag. You must prepare a list of compatible character IDs in your application.

Warning:

Using any information other than the character ID in an application is currently prohibited.

Table 6-14. Possible Return Values From nn::nfp::GetNfpCommonInfo

Return Value Description
nn::ResultSuccess The information was successfully retrieved.
nn::nfp::ResultInvalidPointer The pointer passed as an argument is invalid.
nn::nfp::ResultInvalidOperation The library is not in an appropriate state for calling this function.
nn::nfp::ResultSleep The process failed because the system is entering Sleep Mode.
nn::nfp::ResultWifiOff The process failed because the system is in wireless-disabled mode.
Table 6-15. Possible Return Values From nn::nfp::GetNfpRomInfo

Return Value Description
nn::ResultSuccess The information was successfully retrieved.
nn::nfp::ResultInvalidPointer The pointer passed as an argument is invalid.
nn::nfp::ResultInvalidOperation The library is not in an appropriate state for calling this function.
nn::nfp::ResultSleep The process failed because the system is entering Sleep Mode.
nn::nfp::ResultWifiOff The process failed because the system is in wireless-disabled mode.

The shared region includes registration information that is retrieved using the nn::nfp::GetNfpRegisterInfo function in addition to the information that is retrieved using nn::nfp:GetNfpCommonInfo and nn::nfp::GetNfpRomInfo.

Warning:

If the tag was mounted with nn::nfp::MountRom, the nn::nfp::GetNfpRegisterInfo function returns nn::nfp::ResultInvalidOperation.

Registration information is defined with the nn::nfp::RegisterInfo structure. A pointer to the structure must be passed to nn::nfp::GetNfpRegisterInfo.

If a value of nn::nfp::ResultNeedRegister is returned, an owner has not yet been registered for the NFP tag in amiibo Settings. Start amiibo Settings if your application requires registration information.

Note:

For more information, see 6.5. Starting amiibo Settings.

The registration information includes data about the Mii that is registered as the owner (miiData), the nickname of the amiibo (nickName), and the font region required to display the nickname (fontRegion).

To use the Mii data inside your application, you must include the Face Library. For more information about how to display Mii characters in your application, see the Face Library documentation.

Nicknames are stored using UTF-16 BE, so convert the endianness and encoding as required. The terminating character is NULL (0x0000). When displaying a nickname in your application, handle the display of unsupported characters in a way that does not corrupt the display or prevent the application from proceeding. For example, you can use the system font specified in the font region or display substitute characters for characters that are not included in the application font.

If an owner is registered, Mii data is definitely available, but in some cases a nickname might not be set (it might be an empty string). If your application requires a nickname, start amiibo Settings using the same procedure described for nn::nfp::ResultNeedRegister.

Note:

Applications that display the nickname must take care in the handling of amiibo nicknames and Mii nicknames. In particular, avoid displaying the nickname in a manner that implies it is the name of the owner Mii. Also be sure to display a substitute string such as "(owner name)'s amiibo," "(amiibo character name)," or just "amiiibo" if the nickname is not set.

Warning:

Using country information (country) in an application is currently prohibited.

Table 6-16. Possible Return Values From nn::nfp::GetNfpRegisterInfo
Return Value Description
nn::ResultSuccess The information was successfully retrieved.
nn::nfp::ResultInvalidPointer The pointer passed as an argument is invalid.
nn::nfp::ResultInvalidOperation The library is not in an appropriate state for calling this function.
nn::nfp::ResultSleep The process failed because the system is entering Sleep Mode.
nn::nfp::ResultWifiOff The process failed because the system is in wireless-disabled mode.
nn::nfp::ResultNeedRegister The owner has not been registered in amiibo Settings.

6.6.2. Accessing the Application-Specific Region

Access privileges for the application-specific region are controlled by the access ID. Before opening access to the application-specific region, you must first call nn::nfp::OpenApplicationArea and check whether the application has access privileges.

If a value of nn::nfp::ResultAccessIdMisMatch is returned, the application does not have access privileges because the application-specific area was created by a different access ID. In this case, both reading and writing are restricted. There is no way to delete the application-specific region from an application. If you want to use this region for your application, you must use amiibo Settings to delete it.

A return value of nn::nfp::ResultNeedCreate means the mounted NFP tag does not have an application-specific region. Your application must create one.

Table 6-17. Possible Return Values From nn::nfp::OpenApplicationArea
Return Value Description
nn::ResultSuccess The process was successful. The application-specific region can be accessed.
nn::nfp::ResultInvalidOperation The library is not in an appropriate state for calling this function.
nn::nfp::ResultSleep The process failed because the system is entering Sleep Mode.
nn::nfp::ResultWifiOff The process failed because the system is in wireless-disabled mode.
nn::nfp::ResultAccessIdMisMatch The application-specific area cannot be accessed because it was created by a different access ID.
nn::nfp::ResultNeedCreate The application-specific region has not been created.

6.6.2.1. Creating the Application-Specific Region

The application-specific region is created by calling the nn::nfp::CreateApplicationArea function.

Use the nn::nfp::InitializeCreateInfo function to initialize the nn::nfp::ApplicationAreaCreateInfo structure that is passed to this function before setting the member variables.

If the data written to the application-specific region will also be read by Cafe, we recommend standardizing the byte order because the Cafe and CTR/SNAKE architectures have different endianness.

Note:

Creating the application-specific region can take longer than a second.

If you want to try the operation again, we recommend a retry interval of around 100 milliseconds.

Because the function performs the same operations as nn::nfp::Flush, you do not need to call nn::nfp::Flush after calling nn::nfp::CreateApplication.

Table 6-18. Possible Return Values From nn::nfp::CreateApplicationArea
Return Value Description
nn::ResultSuccess The process was successful. The application-specific region has been created.
nn::nfp::ResultInvalidArgument The process failed due to a problem in the argument that was specified. This result is an implementation error that must be fixed in the development phase.
nn::nfp::ResultInvalidPointer The process failed due to a problem in the argument that was specified. This result is an implementation error that must be fixed in the development phase.
nn::nfp::ResultInvalidOperation The library is not in an appropriate state for calling this function.
nn::nfp::ResultSleep The process failed because the system is entering Sleep Mode.
nn::nfp::ResultWifiOff The process failed because the system is in wireless-disabled mode.
nn::nfp::ResultNotSupported The tag is not supported. The tag may have been switched with a different tag.
nn::nfp::ResultAlreadyCreated The application-specific region has already been created.
nn::nfp::ResultTagNotFound The tag could not be found. This result is caused by the tag leaving the range of communication or being swapped with a different tag.
nn::nfp::ResultNeedRetry An error occurred during writing. The process might succeed if tried again.
nn::nfp::ResultOperationFailed An error occurred during writing. The tag content may be corrupted.

The following sample code retries the operation up to three times.

Code 6-1. Creating the Application-Specific Region
#define MY_ACCESS_ID 0x12345678
#define MY_APPLICATION_AREA_SIZE 128
nn::Result result;
bit8 writeData[MY_APPLICATION_AREA_SIZE];

// First, initialize the settings information.
nn::nfp::ApplicationAreaCreateInfo createInfo;
result = nn::nfp::InitializeCreateInfo(&createInfo);
if (result.IsFailure())
{
    // Error.
    return;
}

// Prepare the initialization data.
{
    memset(writeData, NULL, sizeof(writeData));
    // Write the data with big-endian byte order. 
    writeData[0] = 'I';
    writeData[1] = 'N';
    writeData[2] = 'I';
    writeData[3] = 'T';
    writeData[4] = 0x00;
    writeData[5] = 0x00;
    writeData[6] = 0x00;
    writeData[7] = 0x01;
}
// Set the data required for initialization.
createInfo.accessId = MY_ACCESS_ID;
createInfo.pInitialData = writeData;
createInfo.initialDataSize = sizeof(writeData);

// Create the application-specific region.
int retryCount = 0;
while (true)
{
    result = nn::nfp::CreateApplicationArea(createInfo);
    if (result.IsSuccess()) break;
    if (result.IsFailure())
    {
        if (nn::nfp::ResultNeedRetry::Includes(result))
        {
            // Retry up to 3 times.
            retryCount++;
            if (retryCount < 3)
            {
                // Wait 0.1 seconds before retrying.
                nn::os::Thread::Sleep(100);
                continue;
            }
            // Process failed. Handle by starting over from tag detection or a similar measure.
        }
        else if (nn::nfp::ResultAlreadyCreated::Includes(result))
        {
            // The application-specific region has already been created.
            // Make sure the data is valid. The process succeeded if no problems are found.
        }
        else if (nn::nfp::ResultNotSupported::Includes(result))
        {
            // The tag might have been switched.
        }
        else if (nn::nfp::ResultOperationFailed::Includes(result))
        {
            // The tag might be corrupted.
        }
        else if (nn::nfp::ResultTagNotFound::Includes(result))
        {
            // The tag might have been removed from the reader.
        }
        else if (nn::nfp::ResultInvalidOperation::Includes(result))
        {
            // Entered a state where the function cannot be called.
        }
        else if (nn::nfp::ResultWifiOff::Includes(result))
        {
            // Failed because the system is in wireless-disabled mode.
        }
        else if (nn::nfp::ResultSleep::Includes(result))
        {
            // Failed because the system is in Sleep Mode.
        }
        else
        {
            // Other error.
        }
        return;
    }
}
// nn::nfp::Flush does not need to be called. 

6.6.2.2. Reading the Application-Specific Region

To read the data that is written to the application-specific region, call the nn::nfp::ReadApplicationArea function.

This lets you read the specified number of bytes from the beginning of the application-specific region. The maximum size of the data that can be read from the application-specific region can be retrieved from the applicationAreaSize member of the CommonInfo structure that can be retrieved using the nn::nfp::GetCommonInfo function.

Table 6-19. Possible Return Values From nn::nfp::ReadApplicationArea
Return Value Description
nn::ResultSuccess The process was successful.
nn::nfp::ResultInvalidOperation The library is not in an appropriate state for calling this function.
nn::nfp::ResultInvalidPointer The process failed due to a problem in the argument that was specified. This result is an implementation error that must be fixed in the development phase.
nn::nfp::ResultInvalidArgument The process failed due to a problem in the argument that was specified. This result is an implementation error that must be fixed in the development phase.

6.6.2.3. Writing to the Application-Specific Region

The application-specific region is written to by calling the nn::nfp::WriteApplicationArea function, followed by the nn::nfp::Flush function.

The UID of the target NFP tag is required when calling nn::nfp::WriteApplicationArea. Take the value of the tagId member of the TagInfo structure that was retrieved using nn::nfp::GetTagInfo beforehand and pass it as an argument. We recommend encoding the data to be written to the application-specific region using the same big-endian encoding as the information written to the tag by the NFP library.

The data is not actually written to the application-specific region when nn::nfp::WriteApplicationArea finishes executing. It is stored in a cache in the NFP library. The data is actually written to the application-specific region of the NFP tag when the nn::nfp::Flush function is called.

Note:

Writing to the application-specific region of the NFP tag can take longer than a second.

If you want to try the operation again, we recommend a retry interval of around 100 milliseconds.

Table 6-20. Possible Return Values From nn::nfp::WriteApplicationArea
Return Value Description
nn::ResultSuccess The process was successful.
nn::nfp::ResultInvalidArgument The process failed due to a problem in the argument that was specified. This result is an implementation error that must be fixed in the development phase.
nn::nfp::ResultInvalidPointer The process failed due to a problem in the argument that was specified. This result is an implementation error that must be fixed in the development phase.
nn::nfp::ResultInvalidOperation The library is not in an appropriate state for calling this function.
nn::nfp::ResultSleep The process failed because the system is entering Sleep Mode.
nn::nfp::ResultWifiOff The process failed because the system is in wireless-disabled mode.
nn::nfp::ResultUidMisMatch The tag UID does not match the specified UID.
Table 6-21. Possible Return Values From nn::nfp::Flush
Return Value Description
nn::ResultSuccess The process was successful.
nn::nfp::ResultInvalidOperation The library is not in an appropriate state for calling this function.
nn::nfp::ResultSleep The process failed because the system is entering Sleep Mode.
nn::nfp::ResultWifiOff The process failed because the system is in wireless-disabled mode.
nn::nfp::ResultNotSupported The tag is not supported. The tag may have been switched with a different tag.
nn::nfp::ResultTagNotFound The tag could not be found. This result is caused by the tag leaving the range of communication or being swapped with a different tag.
nn::nfp::ResultNeedRetry An error occurred during writing. The process might succeed if tried again.
nn::nfp::ResultOperationFailed An error occurred during writing. The tag content may be corrupted.

6.7. Unmounting a Tag

Tags are unmounted by calling the nn::nfp::Unmount function.

Table 6-22. Possible Return Values From nn::nfp::Unmount
Return Value Description
nn::ResultSuccess The process was successful.
nn::nfp::ResultInvalidOperation The library is not in an appropriate state for calling this function.
nn::nfp::ResultSleep The process failed because the system is entering Sleep Mode.
nn::nfp::ResultWifiOff The process failed because the system is in wireless-disabled mode.

6.8. Stopping Tag Detection

Call the nn::nfp::StopDetection function to stop tag detection.

If this function is called while a tag is mounted, the NFP library unmounts the tag.

If the tag is in a detected state when nn::nfp::StopDetection is called, the application receives a tag loss notification.

Table 6-23. Possible Return Values From nn::nfp::StopDetection
Return Value Description
nn::ResultSuccess The process was successful.
nn::nfp::ResultInvalidOperation The library is not in an appropriate state for calling this function.
nn::nfp::ResultSleep The process failed because the system is entering Sleep Mode.
nn::nfp::ResultWifiOff The process failed because the system is in wireless-disabled mode.

6.9. Finalization

Call the nn::nfp::Finalize function to finalize the NFP library. This function unmounts the tag, stops tag detection, and, if a tag had been detected, issues a tag loss notification.

Table 6-24. Possible Return Values From nn::nfp::Finalize
Return Value Description
nn::ResultSuccess The process was successful.
nn::nfp::ResultInvalidOperation The library has already been finalized.

6.10. Using in 3DS Applications

To use the NFP library in a 3DS application, you must implement code to support various 3DS features such as the HOME Button, Sleep Mode, and the POWER Button.

In addition, the NFC reader that is being prepared for CTR uses the infrared port on the CTR system. This necessitates the handling of notifications from the reader and when the reader is connected and disconnected.

6.10.1. Handling the HOME Button

When a HOME Button press is detected, call nn::nfp::Finalize to put the NFP library into the NONE state before transitioning to the HOME Menu. If this operation is omitted, the touch panel and NFC-related features will be unavailable to the HOME Menu or any applets started from the HOME Menu.

You can display the HOME Menu Disabled icon and not transition to the HOME Menu if it is necessary to protect the integrity of the tag data because, for example, the application is in the middle of writing data to the application-specific region.
Note: Data writing usually finishes in around one to two seconds.

Code 6-2. Handling the HOME Button
// Check if transitioning to the HOME Menu.
if (nn::applet::IsExpectedToProcessHomeButton())
{
    // Do not transition to the HOME Menu if writing to the NFP tag.
    if (_isNfpTagWritingInProgress())
    {
        // Display the Home Menu Disabled icon.
        _displyHomeNixSign();
        nn::applet::ClearHomeButtonState();
    }
    else
    {
        // Stop access to the NFP tag.
        // Call nn::nfp::StopDetection to enter the INIT state before transitioning to the HOME Menu.
        _stopNfpTagAccess();
        // Processes to run before transitioning to the HOME Menu.
        _prepareHomeMenu();
        // Transition to the HOME Menu.
        nn::applet::ProcessHomeButtonAndWait();
        if (nn::applet::IsExpectedToCloseApplication())
        {
            // Close the application.
            _finalizeNfpTagAccess();
            _closeApplication();
        }
        // Processes after returning from the HOME Menu.
        _returnFromHomeMenu();
        // Start tag detection here if resuming immediately. (Call nn::nfp::StartDetection.)
        if (_needRestartNfpTagAccess()) _startNfpTagAccess();
    }
} 

6.10.2. Handling Sleep Mode Requests

The NFP library automatically changes the state to INIT when the system transitions to Sleep Mode. However, we recommend having the application handle the transition if it is necessary to protect the integrity of the NFP tag data because, for example, the application is in the middle of writing to the application-specific region.

Code 6-3. Handling Sleep Mode Requests
// Handling Sleep Mode Requests
// Assumes the sleep query callback function will wait for the reply.
if (nn::applet::IsExpectedToReplySleepQuery())
{
    // Check whether the NFP tag is being written to.
    if (_isNfpTagWritingInProgress())
    {
        // Do not enter Sleep Mode if the NFP tag is being written to.
    } else {
        // Processes to run before Sleep Mode.
        _prepareSleep();
        // Allow transition to Sleep Mode.
        nn::applet::ReplySleepQuery(nn::applet::REPLY_ACCEPT);
        // Wait for the event to be signaled by the wakeup callback, etc.
        _waitAwakeEvent();
        // Processes for returning from Sleep Mode.
        _returnFromSleep();
        // Start tag detection here if resuming immediately. (Call nn::nfp::StartDetection.)
        if (_needRestartNfpTagAccess()) _startNfpTagAccess();
    }
} 

6.10.3. Handling the POWER Button

When the POWER Button is pressed, the application must quickly display the POWER Menu. However, the application can wait for the writing process to complete before displaying the POWER Menu if it is necessary to protect the integrity of the NFP tag data because, for example, the application is in the middle of writing data to the application-specific region. Data writing usually finishes in around one to two seconds.

Because the touch panel cannot be used on SNAKE during tag detection, the application must call nn::nfp::StopDetection, nn::nfp::Disconnect, or nn::nfp::Finalize before displaying the POWER Menu.

Code 6-4. Handling the POWER Button
// Handling the POWER Button
if (nn::applet::IsExpectedToProcessPowerButton())
{
    // Check whether the NFP tag is being written to.
    if (_isNfpTagWritingInProgress())
    {
        // Do not handle the POWER Button until finished writing to the NFP tag.
    }
    else
    {
        // Stop access to the NFP tag.
        _stopNfpTagAccess();
        // Processes to run before transitioning to the POWER Menu.
        _preparePowerButtonMenu();
        // Display the POWER Menu.
        nn::applet::ProcessPowerButtonAndWait();
        if (nn::applet::IsExpectedCloseApplication())
        {
            // Application finalization process.
            _finalizeNfpTagAccess();
            _closeApplication();
        }
        else
        {
            // Return from the POWER Menu.
            _returnFromPowerButtonMenu();
        }
    }
} 

6.10.4. Implementation Requirements for CTR

If your application uses the NFC reader/writer for CTR, you must explicitly connect to the device from the application. Your application also must handle the connected and disconnected states of the device, in addition to the tag detection and loss notifications.

The following four functions are related to using the NFC reader/writer

  • nn::nfp::Connect
  • nn::nfp::GetTargetConnectionStatus
  • nn::nfp::GetConnectResult
  • nn::nfp::Disconnect

The nn::nfp::Connect function requests that the NFP library establish a connection to the reader. This function is asynchronous. The nn::nfp::GetTargetConnectionStatus function returns a value of nn::nfp::TARGET_CONNECTED if the connection succeeded, or nn::nfp::TARGET_DISCONNECTED if the connection failed.

If the nn::nfp::GetTargetConnectionStatus function is called on SNAKE hardware, it always returns nn::nfp::TARGET_CONNECTED.

If the NFC reader/write and CTR are correctly oriented, the connection process takes several hundred milliseconds to complete.

However, the connection can take a full second to complete if the system attempts to connect immediately after the NFC reader/writer is turned on due to an internal initialization process.

If the NFC reader/writer and CTR system are not correctly oriented, the system attempts to connect for one second until it times out, after which the state becomes nn::nfp::TARGET_DISCONNECTED.

On SNAKE hardware, this function does nothing and returns nn::ResultSuccess immediately.

If the connection fails, the nn::nfp::GetConnectResult function is called to get the cause of the failure.  Call this function after the nn::nfp::GetTargetConnectionStatus function returns nn::nfp::TARGET_DISCONNECTED.

On SNAKE hardware, the function ends immediately and returns nn::ResultSuccess in both the parameter and the return value.

The nn::nfp::Disconnect function is called by the application when you explicitly want to disconnect from the reader. This process takes between 10 and 100 milliseconds to complete.

If tag detection is currently in progress (nn::nfp::StartDetection was called), the nn::nfp::StopDetection function is called internally to stop tag detection. The entire process takes around 100 milliseconds to complete.

This function returns nn::nfp::ResultInvalidOperation if called when the NFC reader/writer is already disconnected. We recommend handling notifications from the library to keep track of the connection status.

When called on SNAKE hardware, this function only stops tag detection (nn::nfp::StopDetection) and returns success (nn::ResultSuccess).

Note:

There is a one second timeout when the nn::nfp::Connect function is called while the system cannot communicate with the NFC reader/writer. The time required for the system to determine that a connection has been lost is also one second.
Consequently, if the CTR is pointed away from the NFC reader/writer while the user is playing, the disconnect is detected in a relatively short amount of time.
If you do not want the user to be aware of the disconnection, you can implement the application to keep track of the connection state and automatically call nn::nfp::Connect if the state is nn::nfp::TARGET_DISCONNECTED.

Note:

The remaining battery life of the NFC reader/writer is only checked once, immediately after it is connected to the CTR using the nn::nfp::Connect function. It is not checked again until the device is disconnected.
Consequently, if the NFC reader/writer continuously detects and writes tags for several minutes without updating the connection state, it might suddenly turn off without the red remaining battery life warning LED turning on.

If your application continuously detects and writes tags, we recommend calling the nn::nfp::Disconnect and nn::nfp::Connect functions on a regular basis (for example, once per minute).

For certain battery types, the LED might light up blue when the power is turned back on after the device loses power as described above. This is by design.
If you continue to use FANGATE without changing the batteries, the LED will turn red before the device loses power again.  

The following sample code shows how to start and stop tag detection.

Code 6-5. Starting and Stopping Tag Detection
bool _willTerminate = false;
bool _connected = false;
nn::Result _lastResult = nn::ResultSuccess();
nn::os::Event _eventActivate;
nn::os::Event _eventDeactivate;
nn::nfp::TargetConnectionStatus _targetConnectionStatus;

// Start tag detection.
nn::Result _startDetection()
{
    // CTR-specific code.
    if (!nn::os::IsRunOnSnake())
    {
        // Connect to external NFC device.
        if (!_connected)
        {
            _lastResult = nn::nfp::Connect(&_eventConnect, &_eventDisconnect);
            if (_lastResult.IsSuccess())
            {
                // Wait for connection process to complete.
                while (1)
                {
                    nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(500));
                    nn::nfp::GetTargetConnectionStatus(&_targetConnectionStatus);
                    if (_targetConnectionStatus == nn::nfp::TARGET_CONNECTED)
                    {
                        // Connection successful.
                        _connected = true;
                        break;
                    }
                    else if (_targetConnectionStatus == nn::nfp::TARGET_DISCONNECTED)
                    {
                        // Connection failed or timed out.
                        _connected = false;
                        nn::nfp::GetConnectResult(&_lastResult);
                        return _lastResult;
                    }
                }
            }
            else
            {
                if (nn::nfp::ResultInvalidOperation::Includes(_lastResult))
                {
                    // Abnormal state.
                }
                else
                {
                    // Stop on a panic for any other error.
                    NN_PANIC_WITH_RESULT(_lastResult);
                }
                return _lastResult;
            }
        }
    }

    // Start detection.
    _lastResult = nn::nfp::StartDetection();
    if (_lastResult.IsSuccess())
    {
        // Process succeeded.
        // Prompt the user to touch the tag to the touchpoint.
    }
    else if (nn::nfp::ResultWifiOff::Includes(_lastResult))
    {
        // Wireless-disabled mode.
    }
    else if (nn::nfp::ResultSleep::Includes(_lastResult))
    {
        // Sleep Mode.
    }
    else if (nn::nfp::ResultInvalidOperation::Includes(_lastResult))
    {
        // Abnormal state.
    }
    else
    {
        // Stop on a panic for any other error.
        NN_PANIC_WITH_RESULT(_lastResult);
    }
    return _lastResult;
}

// Stop tag detection.
nn::Result _stopDetection(bool forceDisconnect = false)
{
    // Stop detection.
    _lastResult = nn::nfp::StopDetection();
    if (_lastResult.IsSuccess())
    {
        // Success.
    }
    else if (nn::nfp::ResultWifiOff::Includes(_lastResult))
    {
        // Wireless-disabled mode.
    }
    else if (nn::nfp::ResultSleep::Includes(_lastResult))
    {
        // Sleep Mode.
    }
    else if (nn::nfp::ResultInvalidOperation::Includes(_lastResult))
    {
        // Abnormal state.
    }
    else
    {
        // Stop on a panic for any other error.
        NN_PANIC_WITH_RESULT(_lastResult);
    }

    // CTR-specific code.
    if (!nn::os::IsRunOnSnake())
    {
        // Disconnect external NFC device.
        if (forceDisconnect && _connected)
        {
            _connected = false;
            _lastResult = nn::nfp::Disconnect();
            if (_lastResult.IsSuccess())
            {
                // Success.
            }
            else if (nn::nfp::ResultInvalidOperation::Includes(_lastResult))
            {
                // Abnormal state.
            }
            else
            {
                // Stop on a panic for any other error.
                NN_PANIC_WITH_RESULT(_lastResult);
            }
        }
    }    
    return _lastResult;
}

// Thread function that waits for notifications from the NFP library.
void _procTagDetection()
{
    const int waitMilliSeconds = 500;
    nn::os::WaitObject* events[2] = {
        &_eventActivate, &_eventDeactivate };
    while (!_willTerminate)
    {
        const int eventIndex = nn::os::WaitObject::WaitAny(
            events, 2, nn::fnd::TimeSpan::FromMilliSeconds(waitMilliSeconds));
        if (eventIndex == 0)
        {
            _activate();
        }
        else if (eventIndex == 1)
        {
            _deactivate();
        }
        else
        {
            nn::nfp::TargetConnectionStatus currentTargetConnectionStatus;
            nn::nfp::GetTargetConnectionStatus(&currentTargetConnectionStatus);
            if( _targetConnectionStatus != currentTargetConnectionStatus )
            {
                if (currentTargetConnectionStatus == nn::nfp::TARGET_CONNECTED)
                {
                    _connected = true;
                }
                else if (currentTargetConnectionStatus == nn::nfp::TARGET_DISCONNECTED)
                {
                    _connected = false;
                }
                _targetConnectionStatus = currentTargetConnectionStatus;
            }
        }
    }
} 

CONFIDENTIAL