1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     sample_nadl_simple.cpp
4 
5   Copyright (C)2009-2012 Nintendo Co., Ltd.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Rev: 46365 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <string.h>
17 #include <nn/fs.h>
18 #include <nn/boss.h>
19 #include <nn/fs/fs_Parameters.h>
20 #include <nn/ac.h>
21 #include <nn/applet.h>
22 #include <nn/ndm.h>
23 
24 #define RESULT_SUCCESS_ASSERT NN_UTIL_PANIC_IF_FAILED
25 
26 #define NN_BOSS_RESULT_HANDLING(result, target)            \
27     do {                                                   \
28         if(result.IsFailure())                             \
29         {                                                  \
30             NN_LOG("Result is err(%08x).(%s)\n", result.GetPrintableBits(), target);        \
31         }                                                  \
32     } while (0)
33 
34 namespace {
InitializeNetwork(void)35     nn::Result InitializeNetwork(void)
36     {
37         nn::Result result;
38         nn::ac::Config config;
39 
40         nn::fs::Initialize();
41         result = nn::ac::Initialize();
42         NN_UTIL_PANIC_IF_FAILED(result);
43 
44         // Create parameters for connection request
45         result = nn::ac::CreateDefaultConfig( &config );
46         if (result.IsFailure())
47         {
48             NN_UTIL_PANIC_IF_FAILED(nn::ac::Finalize());
49             return result;
50         }
51 
52         // Issue connection request
53         result = nn::ac::Connect( config );
54         if (result.IsFailure())
55         {
56             NN_UTIL_PANIC_IF_FAILED(nn::ac::Finalize());
57             return result;
58         }
59 
60         return nn::ResultSuccess();
61     }
62 
FinalizeNetwork(void)63     nn::Result FinalizeNetwork(void)
64     {
65         nn::Result result;
66 
67         // Create parameters for connection request
68         result = nn::ac::Close();
69         NN_UTIL_RETURN_IF_FAILED(result);
70 
71         result = nn::ac::Finalize();
72         NN_UTIL_PANIC_IF_FAILED(result);
73 
74         return nn::ResultSuccess();
75     }
76 
DumpNsdBody(u8 * pBodyBuf,size_t payloadLength)77     void DumpNsdBody(u8* pBodyBuf, size_t payloadLength)
78     {
79     #ifndef NN_SWITCH_DISABLE_DEBUG_PRINT
80         NN_LOG("---NSD Body Dump (Payload-Length=%d)---\n", payloadLength);
81         int hexCheckCount = 0;
82         for(int i = 0; i < payloadLength; ++i)
83         {
84             NN_LOG("%02x ", pBodyBuf[i]);
85             ++hexCheckCount;
86             if(hexCheckCount == 16)
87             {
88                 NN_LOG("\n");
89                 hexCheckCount = 0;
90             }
91         }
92     #else
93         NN_UNUSED_VAR(pBodyBuf);
94         NN_UNUSED_VAR(payloadLength);
95     #endif
96     }
97 }
98 
99 //Expanded save data ID
100 //(Expanded save data is required to use NADL tasks. The expanded save data ID specifies which expanded save data to use and is unique across all applications.)
101 const bit32 APP_EXT_STORAGE_ID         = 0x00000011;
102 
103 /* ------------------------------------------------------------------------
104    Sample code for a BOSS NADL task that downloads Nintendo archive data (in the NSA format) from a Nintendo server.
105    NOTES
106    - NADL tasks download data that is stored in each application's BOSS storage. BOSS storage is created in an application's expanded save data region.
107      The expanded save data region is created on an SD Card. You must therefore insert an SD Card to run this demo.
108    - BOSS tasks do not run unless the user has agreed to the EULA.
109      Note that the user has not agreed to the EULA immediately after a system update. This must be set by the Config tool or some other means.
110    - BOSS tasks run at intervals measured in hours. Although this demo registers a task with the smallest interval of one hour, the task runs for the first time one hour later.
111      If you want to run the task and check behavior immediately, replace the dPolicy.Initialize section in the demo with dPolicy.InitializeWithSecInterval (the commented-out code) immediately below, which uses a test function.
112 
113      This can set the interval in seconds. (Tasks are consequently run for the first time after one second.)
114    - If the NADL task downloads data that already exists in BOSS storage, BOSS deletes the download data.
115      In this case, BOSS does not signal data download notification events waiting in the demo.
116      As a result, when you run this demo continuously it will keep waiting at arriveEvent.Wait(); after it is run for the first time.
117      To check processing that follows arriveEvent.Wait(); after the task is run for the first time, delete the download data in BOSS storage.
118      (The code to delete download data in the demo is marked by the comment "Delete data." It is commented out by default.)
119    ------------------------------------------------------------------------ */
sampleNADLTaskBgExecute()120 void sampleNADLTaskBgExecute()
121 {
122     //Register BOSS storage.
123     //NOTE: An application must register BOSS storage if it downloads data through NADL tasks.
124     //Because BOSS saves the registered information, the application only needs to register storage when it is launched for the first time.
125     //We therefore recommend that if an application uses BOSS, it is designed to register BOSS storage once when it creates new expanded save data (when nn::fs::CreateExtSaveData is run), as in this demo.
126     //
127     //NOTE: An error is returned if you specify an expanded save data ID to which the application does not have access permissions.
128     //NOTE: Applications also register the maximum data size for BOSS storage. BOSS automatically adjusts the total size of data in BOSS storage so that it does not exceed this size.
129     //(Specifically, when the total size exceeds the maximum data size, old data, or data with small serial IDs, is automatically deleted until the total size is no greater than the maximum size.)
130     const size_t NADL_STORAGE_SIZE         = 3*1024*1024;   //The amount of the expanded save data region to use as BOSS storage.
131     {
132         nn::Result result = nn::boss::GetStorageInfo();
133         if(result == nn::boss::ResultStorageNotFound())
134         {
135             NN_LOG("[BOSS Sample] RegisterStorage BOSS Storage.\n");
136             result = nn::boss::RegisterStorage(APP_EXT_STORAGE_ID, NADL_STORAGE_SIZE);
137         }
138         NN_BOSS_RESULT_HANDLING(result, "boss::RegisterStorage");
139     }
140 
141     const char8 DOWNLOAD_TASK_ID[]      = "NadlTsk";
142 
143     //Opt-out settings (The following code sets and accesses the local opt-out flag.)
144     /*
145     {
146         //Set the opt-out flag
147         bool optoutValue = true;
148         nn::Result result = nn::boss::SetOptoutFlag(optoutValue);
149         NN_BOSS_RESULT_HANDLING(result, "nn::boss::SetOptoutFlag");
150 
151         // Access the opt-out flag
152         result = nn::boss::GetOptoutFlag(&optoutValue);
153         NN_LOG("[BOSS Sample]Optout value is %d\n", optoutValue);
154         NN_BOSS_RESULT_HANDLING(result, "nn::boss::GetOptoutFlag");
155     }
156     */
157 
158 
159     //Account for the fact that there may still be a task with the same ID and delete it.
160     /*
161     {
162         nn::boss::Task deleteTargetTask;
163         nn::Result result = deleteTargetTask.Initialize(DOWNLOAD_TASK_ID);
164         NN_BOSS_RESULT_HANDLING(result, "Task::Initialize");
165 
166         deleteTargetTask.Cancel(); // UnregisterTask fails if the task is currently running. To ensure that it is deleted, call UnregisterTask after Cancel.
167         NN_BOSS_RESULT_HANDLING(result, "Task::Cancel");
168 
169         result = nn::boss::UnregisterTask(&deleteTargetTask);
170         NN_BOSS_RESULT_HANDLING(result, "boss::UnregisterTask");
171     }
172     */
173 
174 
175     //Register and run the NADL task
176     {
177         const char8 TASK_TARGET_URL[]         = "https://npdl.cdn.nintendowifi.net/p01/nsa/9x4m4dJwyBBlUc3g/demotask/demofile_notice.dat";
178         //const char8 TASK_TARGET_URL[]       = "https://npdl.cdn.nintendowifi.net/p01/nsa/9x4m4dJwyBBlUc3g/demotask/demofile.dat";
179         //const char8 TASK_TARGET_URL[]       = "https://npdl.cdn.nintendowifi.net/p01/nsa/9x4m4dJwyBBlUc3g/demotask/demofile_message.dat";
180 
181         const u16   NADL_TASK_EXECUTE_TIME  = 1;
182         const u16   NADL_TASK_EXECUTE_COUNT = 1;
183 
184         //Register the NADL task
185         nn::boss::TaskPolicy dPolicy;
186         nn::Result result = dPolicy.Initialize(NADL_TASK_EXECUTE_TIME, NADL_TASK_EXECUTE_COUNT);
187         //nn::Result result = dPolicy.InitializeWithSecInterval(NADL_TASK_EXECUTE_TIME, NADL_TASK_EXECUTE_COUNT); // You can also specify an execution interval in seconds for testing.
188         NN_BOSS_RESULT_HANDLING(result, "TaskPolicy::Initialize");
189 
190         nn::boss::NsaDownloadAction dAction;
191         result = dAction.Initialize(TASK_TARGET_URL);
192         NN_BOSS_RESULT_HANDLING(result, "NsaDownloadAction::Initialize");
193 
194         //result = dAction.SetApInfo( nn::boss::APINFOTYPE_APGROUP|nn::boss::APINFOTYPE_APAREA|nn::boss::APINFOTYPE_AP ); // Configure AP information to be given to HTTP queries, as necessary.
195         //result = dAction.AddHeaderField(pLabel, pValue); // Set a unique HTTP request header, as necessary.
196 
197         nn::boss::Task dTask;
198         result = dTask.Initialize(DOWNLOAD_TASK_ID);
199         NN_BOSS_RESULT_HANDLING(result, "Task::Initialize");
200 
201         //Register the task.
202         //NOTES: RegisterTask returns an error if a task with the same name has already been registered. In this case, enable the code to delete tasks, which is commented out above, and delete the task with the same name.
203         NN_LOG("[BOSS Sample] Register NADL Task.\n");
204         result = nn::boss::RegisterTask(&dTask, &dPolicy, &dAction);
205         if(result == nn::boss::ResultTaskIdAlreadyExist())
206         {
207             NN_LOG("[BOSS Sample] RegisterTask failed. A task with the same name (%s) has already been registered. You need to call UnregisterTask before registering it again.\n", DOWNLOAD_TASK_ID);
208         }
209         NN_BOSS_RESULT_HANDLING(result, "RegisterTask");
210 
211         //Execute task
212         NN_LOG("[BOSS Sample] Start NADL task.\n");
213         result = dTask.Start();
214         NN_BOSS_RESULT_HANDLING(result, "Task::Start");
215 
216         //Wait for NADL download data
217         //// Get a data download notification event from the BOSS daemon
218         nn::os::Event arriveEvent(false);
219         result = nn::boss::RegisterNewArrivalEvent(&arriveEvent);
220         NN_BOSS_RESULT_HANDLING(result, "Task::RegisterNewArrivalEvent");
221 
222         //Use StartImmediate if you want to run a task immediately without waiting for the next task execution time.
223         //However, because StartImmediate runs a task in the foreground, the application must make an infrastructure network connection. (BOSS is not used.)
224         /*
225         [Infrastructure network connection with nn::ac::Connect]
226         result = dTask.StartImmediate();
227         NN_BOSS_RESULT_HANDLING(result, "Task::StartImmediate");
228         (NOTE: Use nn::ac::Close to close the infrastructure network connection after the task finishes processing.)
229         */
230 
231         //// Wait for new data to be downloaded.
232         NN_LOG("[BOSS Sample] Wait for NSA data to arrive....\n");
233         arriveEvent.Wait();
234         NN_LOG("[BOSS Sample] Recognize that NSA data has arrived\n");
235 
236         //// You can also wait for a task to complete rather than for data to be downloaded. (By "waiting for a task to complete," we mean "waiting for the next task to finish executing." This does not refer to running for the full execution count.)
237         //// Even if you run a task and wait for data to be downloaded, the data is deleted and control does not return when you are not connected to the server, when data already exists, and when the downloaded data is invalid (decryption or signature verification failed).
238         ////
239         //// If you run a task and wait for it to complete, WaitFinish will exit when the task completes even if it had an error.
240         //// Use each method where it suits the purpose.
241         //result = dTask.WaitFinish(); // Wait for the task to complete. (Without a timeout. This will wait indefinitely until processing is complete.)
242         //result = dTask.WaitFinish(nn::fnd::TimeSpan::FromSeconds(60)); // Wait for the task to complete. (With a timeout. ResultWaitfinishTimeout returns when processing does not complete within the specified time.)
243         //// Another way to wait for a task to complete is to poll on the task state using the Task::GetState function.
244         //// After you have detected that the task has completed, you can use the following functions to get information on the completed task.
245         //// Task::GetResult for the execution result
246         //// Task::GetCommErrorCode for the HTTP status code run by the task
247         //// Task::GetError for detailed information on task errors
248 
249         //Processing to download data.
250         //// Before you get a list of data IDs, the application's "update indicator flag" is on.
251         {
252             bool arriveFlag = false;
253             NN_UNUSED_VAR(arriveFlag);//Because this variable is exclusively used for output with NN_LOG, configure it to be unusable in Release builds.
254             result = nn::boss::GetNewArrivalFlag(&arriveFlag);
255             NN_BOSS_RESULT_HANDLING(result, "GetNewArrivalFlag");
256             NN_LOG("[BOSS Sample] (Before reading data, NewArrivalFlag is %d.)\n", arriveFlag);
257         }
258 
259         //// Get a serial ID list for the downloaded data. (You can use the first argument to GetNsDataIdList to filter the data that is obtained.)
260         static const u32 MAX_DATA_ID = 32;
261         u32 idBuf[MAX_DATA_ID];//Buffer for storing serial IDs. This is prepared by the application. By providing a large buffer, you can get a large number of serial IDs at one time.
262         nn::boss::NsDataIdList serialIdList(idBuf, MAX_DATA_ID);//The number of serial IDs that can be obtained at one time is the same as the number of elements in the array buffer.
263         serialIdList.Initialize();
264 
265         u32 getNsDataIdListCount = 0;
266         nn::Result getNsDataIdListResult;
267         do
268         {
269             getNsDataIdListResult = nn::boss::GetNsDataIdList(nn::boss::DATA_TYPE_ALL, &serialIdList);
270             //result = nn::boss::GetNsDataIdList(nn::boss::DATA_TYPE_APPDATA|0xffff, &serialIdList); // When you only want to get extra data for the application.
271 
272             if(getNsDataIdListResult == nn::boss::ResultNsDataListUpdated())
273             {
274                 //ResultNsDataListUpdated is returned when NS data is added to or deleted from BOSS storage during the process of getting a list of IDs. Initialize the list and attempt to get a list of serial IDs from the beginning.
275                 serialIdList.Initialize();
276                 getNsDataIdListResult = nn::boss::ResultNsDataListSizeShortage();//Update the value of getNsDataIdListResult so that control does not exit the do-while loop.
277                 continue;
278             }
279             else if((getNsDataIdListResult.IsFailure()) && (getNsDataIdListResult != nn::boss::ResultNsDataListSizeShortage()))
280             {
281                 //Any error other than ResultNsDataListUpdated, ResultNsDataListSizeShortage, or ResultSuccess is an unexpected error.
282                 //ResultNsDataListSizeShortage indicates that a list of IDs was successfully obtained, but all of the IDs could not be stored in the NsDataIdList (the function must be run again). ResultSuccess indicates that a list of IDS was successfully obtained (all IDs were obtained).
283                 NN_BOSS_RESULT_HANDLING(result, "boss::GetNsDataIdList");
284             }
285 
286             //Application-specific processing for downloaded data. (This demo dumps the header information and body data for all downloaded data.)
287             ++getNsDataIdListCount;
288             NN_LOG("[BOSS Sample] Dump NSD data(%d). (data number = %d)\n\n", getNsDataIdListCount, serialIdList.GetSize());
289             for(int i=0; i < serialIdList.GetSize(); ++i)
290             {
291                 NN_LOG("===NSD No.%d (Serial ID = %d)===\n", i, serialIdList.GetNsDataId(i));
292                 nn::boss::NsData contentData;
293                 result = contentData.Initialize(serialIdList.GetNsDataId(i));
294                 NN_BOSS_RESULT_HANDLING(result, "NsData::Initialize");
295 
296                 //Check the header
297                 {
298                     nn::fs::TitleId titlleID = 0;
299                     result = contentData.GetHeaderInfo(nn::boss::NSD_TITLEID, &titlleID, sizeof(titlleID));
300                     NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
301                     NN_LOG("TitleID = %llx\n",titlleID);
302 
303                     u32 headerInfo = 0;
304                     result = contentData.GetHeaderInfo(nn::boss::NSD_SERIALID, &headerInfo, sizeof(headerInfo));
305                     NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
306                     NN_LOG("Content SerialID = %d\n",headerInfo);
307 
308                     result = contentData.GetHeaderInfo(nn::boss::NSD_LENGTH, &headerInfo, sizeof(headerInfo));
309                     NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
310                     NN_LOG("Payload Length = %d\n",headerInfo);
311 
312                     result = contentData.GetHeaderInfo(nn::boss::NSD_VERSION, &headerInfo, sizeof(headerInfo));
313                     NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
314                     NN_LOG("Content version = %d\n",headerInfo);
315 
316                     result = contentData.GetHeaderInfo(nn::boss::NSD_FLAGS, &headerInfo, sizeof(headerInfo));
317                     NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
318                     NN_LOG("Content Flags = %d\n",headerInfo);
319 
320                     result = contentData.GetHeaderInfo(nn::boss::NSD_DATATYPE, &headerInfo, sizeof(headerInfo));
321                     RESULT_SUCCESS_ASSERT(result);
322                     NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
323                     NN_LOG("Content DataType = %d\n",headerInfo);
324                 }
325 
326                 //Check the data
327                 {
328                     NN_LOG("---Dump Data---\n");
329                     u8 dDataBuf[4*1024];
330                     memset(dDataBuf, 0, sizeof(dDataBuf));
331                     size_t readSize = 0;
332                     u32 readCount = 0;
333                     do
334                     {
335                         ++readCount;
336                         NN_LOG("(Read %d)\n", readCount);
337                         readSize = contentData.ReadData(reinterpret_cast<u8*>(dDataBuf), sizeof(dDataBuf));
338                         NN_BOSS_RESULT_HANDLING(result, "NsData::ReadData");
339                         DumpNsdBody(dDataBuf, readSize);
340                     }while(readSize != 0);
341                 }
342 
343                 //Get and set data attribute information
344                 {
345                     u32 setInfo = 0x100;
346                     result = contentData.SetAdditionalInfo(setInfo);
347                     NN_BOSS_RESULT_HANDLING(result, "NsData::SetAdditionalInfo");
348 
349                     u32 getInfo;
350                     result = contentData.GetAdditionalInfo(&getInfo);
351                     NN_BOSS_RESULT_HANDLING(result, "NsData::SetAdditionalInfo");
352                     NN_LOG("[BOSS Sample] AdditionalInfo = %d (Set Info = %d)\n", setInfo, setInfo);
353                 }
354 
355                 /*
356                  * You can also use the data's already-read flag.
357                  * Unlike the application's "update indicator flag" obtained by the RegisterNewArrivalEvent function, the data's already-read flag is used for the application to manage unprocessed data.
358                  * The flag is off when data is downloaded and stays off as long as the application does not explicitly turn it on.
359                  * Use this when the application manages unprocessed data.
360                  * NOTE: The GetNewDataNsDataIdList function returns a list of data for which this flag is off. You can use this for different purposes than GetNsDataIdList, which returns a list of all data regardless of their flags.
361                  */
362                 {
363                     bool nsdReadFlag = true;
364                     result = contentData.GetReadFlag(&nsdReadFlag);
365                     NN_BOSS_RESULT_HANDLING(result, "NsData::GetReadFlag");
366                     NN_LOG("[BOSS Sample] NSD Read Flag = %d\n", nsdReadFlag);
367 
368                     if(nsdReadFlag == false)
369                     {
370                         //Turn the flag on. (The data's already-read flag does not change unless the application sets it.)
371                         result = contentData.SetReadFlag(true);
372                         NN_BOSS_RESULT_HANDLING(result, "NsData::SetNewFrag");
373                     }
374                 }
375 
376                 //Delete data
377                 /*
378                 {
379                     result = contentData.Delete();
380                     NN_BOSS_RESULT_HANDLING(result, "NsData::Delete");
381                 }
382                 */
383             }
384         }while(getNsDataIdListResult == nn::boss::ResultNsDataListSizeShortage());//If this is ResultNsDataListSizeShortage, run GetNsDataIdList again because all of the IDs have still not been obtained.
385 
386         //After you get a list of data IDs, the application's "update indicator flag" is off.
387         {
388             bool arriveFlag = false;
389             result = nn::boss::GetNewArrivalFlag(&arriveFlag);
390             NN_BOSS_RESULT_HANDLING(result, "GetNewArrivalFlag");
391             NN_LOG("[BOSS Sample] (After reading data, NewArrivalFlag is %d.)\n", arriveFlag);
392         }
393 
394         //If you turn on the already-read flag for all data, the GetNewDataNsDataIdList function will get an empty list (because it gets a list of data for which the already-read flag is off).
395         {
396             result = nn::boss::GetNewDataNsDataIdList(nn::boss::DATA_TYPE_ALL, &serialIdList);
397             NN_BOSS_RESULT_HANDLING(result, "GetNewDataNsDataIdList");
398             NN_LOG("[BOSS Sample] (After NSD read flag is on, new NSD number is = %d)\n", serialIdList.GetSize());
399         }
400 
401         /*
402          * When NADL tasks are run periodically, control returns to arriveEvent.Wait (which waits for data to be downloaded) where it waits for the next download.
403          * Once all task processing has finished, the following task is deleted.
404         */
405 
406         //Delete task
407         {
408             nn::boss::Task deleteTargetTask;
409             result = deleteTargetTask.Initialize(DOWNLOAD_TASK_ID);
410             NN_BOSS_RESULT_HANDLING(result, "Task::Initialize");
411 
412             result = nn::boss::UnregisterTask(&deleteTargetTask);
413             NN_BOSS_RESULT_HANDLING(result, "UnregisterTask");
414         }
415     }
416 }
417 
nnMain()418 extern "C" void nnMain()
419 {
420     // Call only nn::applet::Enable to also allow execution from the HOME Menu
421     // HOME Menu transitions, POWER Button presses, and sleep are all unsupported
422     nn::applet::Enable();
423 
424     /* =======================================================================
425            Pre-processing
426                  Note: Network configuration process or other processes. You do not need to implement this if the process has already been run when BOSS is used.
427        ======================================================================== */
428     //Initialize the BOSS library
429     {
430         nn::Result result = nn::boss::Initialize();
431         NN_BOSS_RESULT_HANDLING(result, "boss::Initialize");
432     }
433 
434     //Change settings so that the application runs BOSS in the background when we are not sleeping
435     {
436         // Initialize the NDM library
437         nn::Result result = nn::ndm::Initialize();
438         NN_BOSS_RESULT_HANDLING(result, "ndm::Initialize()");
439 
440         // Resume BOSS
441         result = nn::ndm::Resume(nn::ndm::DN_BOSS);
442         NN_BOSS_RESULT_HANDLING(result, "ndm::Resume()");
443     }
444 
445     //Create expanded save data. (Data downloaded by an NADL task is saved in BOSS storage in the expanded save data region. An expanded save data region is therefore required to use NADL tasks.)
446     {
447         const char extSaveDataMountName[] = "test:";
448         nn::fs::Initialize();
449         {
450             nn::Result result = nn::fs::MountExtSaveData(extSaveDataMountName, APP_EXT_STORAGE_ID);
451             if(result.IsFailure())
452             {
453                 if(nn::fs::ResultNotFormatted::Includes(result)        ||
454                    nn::fs::ResultBadFormat::Includes(result)           ||
455                    nn::fs::ResultVerificationFailed::Includes(result))
456                 {
457                     nn::fs::DeleteExtSaveData(APP_EXT_STORAGE_ID);
458                 }
459 
460                 if(nn::fs::ResultNotFound::Includes(result)             ||
461                    nn::fs::ResultNotFormatted::Includes(result)         ||
462                    nn::fs::ResultBadFormat::Includes(result)            ||
463                    nn::fs::ResultVerificationFailed::Includes(result))
464                 {
465                     NN_LOG("Create ExtSaveData(ID=%lx)\n", APP_EXT_STORAGE_ID);
466                     //When you create expanded save data, configure the maximum file count so that it also accounts for the number of files downloaded through BOSS.
467                     //Once the maximum number of files already exist in expanded save data, it will no longer be possible to write files downloaded through BOSS.
468 
469                     //In SDK 0.14, icon data of some kind must be specified to fs::CreateExtSaveData.
470                     u8 iconData[] = {0x01};
471                     result = nn::fs::CreateExtSaveData(APP_EXT_STORAGE_ID, iconData, sizeof(iconData), 10, 100);
472                     if(result.IsFailure())
473                     {
474                         NN_LOG_ERROR("CreateExtSaveData failed (%08x)\n", result.GetPrintableBits());
475                         NN_UTIL_PANIC_IF_FAILED(result);
476                     }
477                     result = nn::fs::MountExtSaveData(extSaveDataMountName, APP_EXT_STORAGE_ID);
478                     NN_UTIL_PANIC_IF_FAILED(result);
479                 }
480                 else
481                 {
482                     NN_LOG_ERROR("MountExtSaveData failed (%08x)\n", result.GetPrintableBits());
483                     NN_UTIL_PANIC_IF_FAILED(result);
484                 }
485             }
486         }
487     }
488 
489     NN_LOG("Initializing the network.\n");
490 
491     // Connect to the network.
492     //Even if the application does not connect to the network, the CTR system periodically attempts to make an infrastructure network connection (to the WAN) and, if it succeeds, BOSS background processes will start.
493     //This corresponds to BOSS processes during Sleep Mode.
494     //This demo will therefore run even if these processes do not, but it will not start until the periodic infrastructure network connection is made. (After roughly several tens of seconds)
495     //This demo connects to the network because BOSS background processes will immediately start using an infrastructure network connection (to the WAN) once it is made by the application.
496     //
497     {
498         nn::Result result = InitializeNetwork();
499         NN_UTIL_PANIC_IF_FAILED(result);
500     }
501 
502     NN_LOG("BOSS Sample (NadlTaskSimple) Start\n");
503 
504     sampleNADLTaskBgExecute();
505 
506     NN_LOG("BOSS Sample (NadlTaskSimple) End\n");
507 
508     /* =======================================================================
509            Clean up
510                  Note: Network termination processing and other processing. If BOSS will still be used later, this does not need to be run.
511        ======================================================================== */
512     NN_LOG("Finalizing network.\n");
513     {
514         nn::Result result = FinalizeNetwork();
515         NN_UTIL_PANIC_IF_FAILED(result);
516     }
517 
518     //Unregister BOSS storage if BOSS features will not be used later.
519     //(Note that once it is unregistered, you will no longer be able to run NADL tasks or read data from BOSS storage.)
520     /*
521     {
522         nn::Result result = nn::boss::UnregisterStorage();
523         NN_UTIL_PANIC_IF_FAILED(result);
524     }
525     */
526 
527     //Finalize the NDM library
528     {
529         nn::Result result = nn::ndm::Finalize();
530         NN_BOSS_RESULT_HANDLING(result, "ndm::Finalize()");
531         //When the program exits, pause/resume settings are also restored
532     }
533 
534     //Shut down the library
535     {
536         nn::Result result = nn::boss::Finalize();
537         NN_UTIL_PANIC_IF_FAILED(result);
538     }
539 
540     NN_LOG("END\n");
541 }
542 
543 
544