1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: sample_nsalist.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:$
14 *---------------------------------------------------------------------------*/
15
16 #include <string.h>
17 #include <sstream>
18
19 #include <nn/fs.h>
20 #include <nn/boss.h>
21 #include <nn/boss/boss_NsaList.h>
22 #include <nn/fs/fs_Parameters.h>
23 #include <nn/ac.h>
24 #include <nn/applet.h>
25 #include <nn/ndm.h>
26
27 #define RESULT_SUCCESS_ASSERT NN_UTIL_PANIC_IF_FAILED
28
29 #define NN_BOSS_RESULT_HANDLING(result, target) \
30 do { \
31 if(result.IsFailure()) \
32 { \
33 NN_LOG("result is err(%08x).(%s)\n", result.GetPrintableBits(), target); \
34 } \
35 } while (0)
36
37 namespace {
InitializeNetwork(void)38 nn::Result InitializeNetwork(void)
39 {
40 nn::Result result;
41 nn::ac::Config config;
42
43 nn::fs::Initialize();
44 result = nn::ac::Initialize();
45 NN_UTIL_PANIC_IF_FAILED(result);
46
47 // Create parameters for connection request
48 result = nn::ac::CreateDefaultConfig( &config );
49 if (result.IsFailure())
50 {
51 NN_UTIL_PANIC_IF_FAILED(nn::ac::Finalize());
52 return result;
53 }
54
55 // Issue connection request
56 result = nn::ac::Connect( config );
57 if (result.IsFailure())
58 {
59 NN_UTIL_PANIC_IF_FAILED(nn::ac::Finalize());
60 return result;
61 }
62
63 return nn::ResultSuccess();
64 }
65
FinalizeNetwork(void)66 nn::Result FinalizeNetwork(void)
67 {
68 nn::Result result;
69
70 // Create parameters for connection request
71 result = nn::ac::Close();
72 NN_UTIL_RETURN_IF_FAILED(result);
73
74 result = nn::ac::Finalize();
75 NN_UTIL_PANIC_IF_FAILED(result);
76
77 return nn::ResultSuccess();
78 }
79
DumpNsdBody(u8 * pBodyBuf,size_t payloadLength)80 void DumpNsdBody(u8* pBodyBuf, size_t payloadLength)
81 {
82 #ifndef NN_SWITCH_DISABLE_DEBUG_PRINT
83 NN_LOG("---NSD Body Dump(Payload-Length=%d)---\n", payloadLength);
84 int hexCheckCount = 0;
85 for(int i = 0; i < payloadLength; ++i)
86 {
87 NN_LOG("%02x ", pBodyBuf[i]);
88 ++hexCheckCount;
89 if(hexCheckCount == 16)
90 {
91 NN_LOG("\n");
92 hexCheckCount = 0;
93 }
94 }
95 #else
96 NN_UNUSED_VAR(pBodyBuf);
97 NN_UNUSED_VAR(payloadLength);
98 #endif
99 }
100 }
101
102 // Expanded save data ID
103 // 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.
104 // The expanded save data region is also used to store downloaded NSA lists.
105 const bit32 APP_EXT_STORAGE_ID = 0x00000011;
106
107
108 // Task ID
109 // Both a BOSS code and a task ID must be specified when you get an NSA list.
110 const char8 DOWNLOAD_TASK_ID[] = "flist"; /* Please see man pages for details */
111 const char BOSS_CODE[] = "9x4m4dJwyBBlUc3g"; /* BOSS code */
112
113 /* ------------------------------------------------------------------------
114 This sample code gets a task's NSA list from the server, and then uses an NADL task to download the files in that list.
115 For more details, see sample_nadl_simple, which uses the same process of downloading files through an NADL task.
116 ------------------------------------------------------------------------ */
sampleNSAListExecute()117 void sampleNSAListExecute()
118 {
119 // Create an instance of nn::boss::NsaList
120 nn::boss::NsaList nsaList("test:/filelist.txt");
121
122 // Download the NSA list
123 {
124 // Specify a BOSS code and a task ID to download the NSA list.
125 nn::Result result = nsaList.Download(BOSS_CODE, DOWNLOAD_TASK_ID);
126 if (result.IsFailure())
127 {
128 NN_LOG_ERROR("nn::boss::NsaList::Download failed(0x%08x)\n", result.GetPrintableBits());
129 NN_UTIL_PANIC_IF_FAILED(result);
130 }
131 }
132
133 // Check for errors related to downloading an NSA list
134 {
135 if (nsaList.GetResult() != nn::boss::TASK_SUCCESS)
136 {
137 NN_LOG_ERROR("nn::boss::NsaList::Download failed\n");
138 NN_LOG_ERROR("nn::boss::NsaList::GetResult(%d)\n", nsaList.GetResult());
139 }
140 }
141
142 // Get the NSA list's Digest value
143 /*
144 {
145 const u32 DIGEST_BUF_SIZE = 40+1;
146 u8 digestBuf[DIGEST_BUF_SIZE] = {0};
147 nn::Result result = nsaList.GetDigest(digestBuf, DIGEST_BUF_SIZE);
148 if(result.IsFailure())
149 {
150 // Error
151 NN_LOG_ERROR("nn::boss::NsaList::GetDigest failed(0x%08x)\n", result.GetPrintableBits());
152 NN_UTIL_PANIC_IF_FAILED(result);
153 }
154 NN_LOG("NSA List Digest : %s\n", (char *)digestBuf);
155 }
156 */
157
158 // Determine whether the NSA list is valid
159 const u32 WORK_BUF_SIZE = 256;
160 u8 workBuf[WORK_BUF_SIZE];
161 {
162 memset(workBuf, 0, WORK_BUF_SIZE);
163 if (!nsaList.CheckValidity((void *)workBuf, WORK_BUF_SIZE))
164 {
165 // Error
166 NN_LOG_ERROR("nn::boss::NsaList::CheckValidity failed\n");
167 }
168 }
169
170 // Parse the downloaded NSA list
171 u32 numNsaList = 0;
172 const u32 NSA_LIST_LENGTH = 10;
173 nn::boss::NsaList::NsaInformation nsaListInfo[NSA_LIST_LENGTH];
174 {
175 memset(workBuf, 0, WORK_BUF_SIZE);
176 s32 parseResult = nsaList.Parse(&numNsaList, nsaListInfo, NSA_LIST_LENGTH, (void *)workBuf, WORK_BUF_SIZE);
177 if (parseResult < 0)
178 {
179 // Error
180 NN_LOG_ERROR("nn::boss::NsaList::Parse failed(%d)\n", parseResult);
181 }
182 }
183
184 // Display the content of the downloaded NSA list
185 for (int i = 0; i < numNsaList; i++)
186 {
187 NN_LOG("----- NSA List %d -----\n", i+1);
188 NN_LOG(" FileName : %s\n", nsaListInfo[i].fileName);
189 NN_LOG(" FileSize : %d\n", nsaListInfo[i].fileSize);
190 NN_LOG(" UpdateEpochTime : %d\n", nsaListInfo[i].updateEpochTime);
191 NN_LOG(" Attribute1 : %s\n", nsaListInfo[i].attribute1);
192 NN_LOG(" Attribute2 : %s\n", nsaListInfo[i].attribute2);
193 NN_LOG(" Attribute2 : %s\n", nsaListInfo[i].attribute3);
194 NN_LOG(" Caption : %s\n", nsaListInfo[i].caption);
195 NN_LOG("----------------------\n");
196 }
197
198
199 ////////////////////////////////////////////////////////////////////////////
200 //
201 // Download the (NSA) file in the obtained NSA list
202 // This uses the same basic processing as sample_nadl_simple.
203 //
204 ////////////////////////////////////////////////////////////////////////////
205
206 //Register BOSS storage.
207 const size_t NADL_STORAGE_SIZE = 3*1024*1024; //The amount of the expanded save data region to use as BOSS storage.
208 {
209 nn::Result result = nn::boss::GetStorageInfo();
210 if(result == nn::boss::ResultStorageNotFound())
211 {
212 NN_LOG("[BOSS Sample]RegisterStorage BOSS Storage.\n");
213 result = nn::boss::RegisterStorage(APP_EXT_STORAGE_ID, NADL_STORAGE_SIZE);
214 }
215 NN_BOSS_RESULT_HANDLING(result, "boss::RegisterStorage");
216 }
217
218 //Opt-out settings (The following code sets and accesses the local opt-out flag.)
219 /*
220 {
221 //Set the opt-out flag
222 bool optoutValue = true;
223 nn::Result result = nn::boss::SetOptoutFlag(optoutValue);
224 NN_BOSS_RESULT_HANDLING(result, "nn::boss::SetOptoutFlag");
225
226 // Access the opt-out flag
227 result = nn::boss::GetOptoutFlag(&optoutValue);
228 NN_LOG("[BOSS Sample]Optout value is %d\n", optoutValue);
229 NN_BOSS_RESULT_HANDLING(result, "nn::boss::GetOptoutFlag");
230 }
231 */
232
233
234 // Register and run the NADL task
235 // This downloads the files in the NSA list using an immediate execution task.
236 {
237 const char8 TASK_TARGET_URL[] = "https://npdl.cdn.nintendowifi.net/p01/nsa/9x4m4dJwyBBlUc3g/flist/file1"; /* Please see man pages for details */
238 //const char8 TASK_TARGET_URL[] = "https://npdl.cdn.nintendowifi.net/p01/nsa/9x4m4dJwyBBlUc3g/flist/file2"; /**< The task's target URL. This downloads file2 from the files in the NSA list. */
239 //const char8 TASK_TARGET_URL[] = "https://npdl.cdn.nintendowifi.net/p01/nsa/9x4m4dJwyBBlUc3g/flist/file3"; /**< The task's target URL. This downloads file3 from the files in the NSA list. */
240
241 // Register the NADL task
242 // You don't need to specify an execution interval or execution count for immediate execution tasks.
243 nn::boss::TaskPolicy dPolicy;
244
245 nn::boss::NsaDownloadAction dAction;
246 nn::Result result = dAction.Initialize(TASK_TARGET_URL);
247 NN_BOSS_RESULT_HANDLING(result, "NsaDownloadAction::Initialize");
248
249 //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.
250 //result = dAction.AddHeaderField(pLabel, pValue); // Set a unique HTTP request header, as necessary.
251
252 // Task for immediate execution
253 // Because the task for immediate execution uses the dedicated task ID "FGONLYT," there is no need to set the task ID with Initialize.
254 //
255 nn::boss::FgOnlyTask dFgOnlyTask;
256
257 // Register a task for immediate execution.
258 NN_LOG("[BOSS Sample]Regist FG Only Task.\n");
259 result = nn::boss::RegisterImmediateTask(&dFgOnlyTask, &dAction, &dPolicy);
260 NN_BOSS_RESULT_HANDLING(result, "RegisterImmediateTask");
261
262 //Wait for NADL download data
263 //// Get a data download notification event from the BOSS daemon
264 nn::os::Event arriveEvent(false);
265 result = nn::boss::RegisterNewArrivalEvent(&arriveEvent);
266 NN_BOSS_RESULT_HANDLING(result, "Task::RegisterNewArrivalEvent");
267
268 // Immediate task execution
269 // FgOnlyTask can only use immediate execution in the foreground.
270 NN_LOG("[BOSS Sample]Start FG Only Task.\n");
271 result = dFgOnlyTask.StartImmediate();
272 NN_BOSS_RESULT_HANDLING(result, "FgOnlyTask::StartImmediate");
273
274 //// Wait for new data to be downloaded.
275 NN_LOG("[BOSS Sample]Wait NSA data arrive....\n");
276 arriveEvent.Wait();
277 NN_LOG("[BOSS Sample]Recognize NSA data arrive\n");
278
279 //// 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.)
280 //// When waiting for data download, even if a task is executed, if there is no connection with the server, if the data already exists,
281 //// or if the downloaded data is invalid (decoding process or signature verification fails), the data is discarded and the process cannot return from Wait.
282 //// If you run a task and wait for it to complete, WaitFinish will exit when the task completes even if it had an error.
283 //// Use each method where it suits the purpose.
284 //result = dTask.WaitFinish(); // Wait for the task to complete. (Without a timeout. This will wait indefinitely until processing is complete.)
285 //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.)
286 //// Another way to wait for a task to complete is to poll on the task state using the Task::GetState function.
287 //// After you have detected that the task has completed, you can use the following functions to get information on the completed task.
288 //// Task::GetResult for the execution result
289 //// Task::GetCommErrorCode for the HTTP communication status code run by the task
290 //// Task::GetError for detailed information on task errors
291
292
293 /* ------------------------------------------------------------------------
294 * When a file in the NSA list is downloaded, often that data is processed by the application immediately, but if there are multiple instances of NS data existing in BOSS storage already, there is no way for the application to determine which data was just downloaded.
295 *
296 *
297 * For that reason, process the NS data in BOSS storage before getting the file and clear out BOSS storage.
298 *
299 * The following code assumes that the BOSS storage is empty.
300 *
301 * To download a file from the NSA list while leaving the existing NS data in BOSS storage, set the data version and private data type when registering the NSA list file (data) so that it can be distinguished from other NS data when getting NS data.
302 *
303 *
304 *
305 ------------------------------------------------------------------------ */
306
307
308 //Processing to download data.
309 //// Before you get a list of data IDs, the application's "update indicator flag" is on.
310 {
311 bool arriveFlag = false;
312 NN_UNUSED_VAR(arriveFlag);//Because this variable is exclusively used for output with NN_LOG, configure it to be unusable in Release builds.
313 result = nn::boss::GetNewArrivalFlag(&arriveFlag);
314 NN_BOSS_RESULT_HANDLING(result, "GetNewArrivalFlag");
315 NN_LOG("[BOSS Sample](Before Read Data, NewArrivalFlag is %d.)\n", arriveFlag);
316 }
317
318 //// Get a serial ID list for the downloaded data. (You can use the first argument to GetNsDataIdList to filter the data that is obtained.)
319 u32 idBuf; // Buffer for storing serial IDs. This is prepared by the application.
320 nn::boss::NsDataIdList serialIdList(&idBuf, 1); // Download a file in the NSA list and get a single instance of NS data.
321 serialIdList.Initialize();
322
323
324 while (1)
325 {
326 result = nn::boss::GetNsDataIdList(nn::boss::DATA_TYPE_APPDATA|0xffff, &serialIdList); //If you only want to get extra data for the application.
327 if (result == nn::boss::ResultNsDataListUpdated())
328 {
329 // If ResultNsDataListUpdated is returned, this indicates that 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.
330 serialIdList.Initialize();
331 continue;
332 }
333
334 break;
335 }
336
337 if ((result.IsFailure()) && (result != nn::boss::ResultNsDataListSizeShortage()))
338 {
339 //Any error other than ResultNsDataListUpdated, ResultNsDataListSizeShortage, or ResultSuccess is an unexpected error.
340 //ResultNsDataListSizeShortage() indicates that a list of IDs was obtained successfully, but the IDs could not all be stored in an NsDataIdList (the operation must be repeated). ResultSuccess() indicates that a list of IDs was obtained successfully (all of the IDs were obtained).
341 NN_BOSS_RESULT_HANDLING(result, "boss::GetNsDataIdList");
342 }
343
344 //Application-specific processing for downloaded data. (This demo dumps the header information and body data for all downloaded data.)
345 NN_LOG("[BOSS Sample]Dump NSD data.\n\n");
346 NN_LOG("===NSD (SerialID = %d)===\n", serialIdList.GetNsDataId(0));
347
348 nn::boss::NsData contentData;
349 result = contentData.Initialize(serialIdList.GetNsDataId(0));
350 NN_BOSS_RESULT_HANDLING(result, "NsData::Initialize");
351
352 //Check the header
353 {
354 nn::fs::TitleId titlleID = 0;
355 result = contentData.GetHeaderInfo(nn::boss::NSD_TITLEID, &titlleID, sizeof(titlleID));
356 NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
357 NN_LOG("TitleID = %llx\n",titlleID);
358
359 u32 headerInfo = 0;
360 result = contentData.GetHeaderInfo(nn::boss::NSD_SERIALID, &headerInfo, sizeof(headerInfo));
361 NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
362 NN_LOG("Content SerialID = %d\n",headerInfo);
363
364 result = contentData.GetHeaderInfo(nn::boss::NSD_LENGTH, &headerInfo, sizeof(headerInfo));
365 NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
366 NN_LOG("Payload Length = %d\n",headerInfo);
367
368 result = contentData.GetHeaderInfo(nn::boss::NSD_VERSION, &headerInfo, sizeof(headerInfo));
369 NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
370 NN_LOG("Content version = %d\n",headerInfo);
371
372 result = contentData.GetHeaderInfo(nn::boss::NSD_FLAGS, &headerInfo, sizeof(headerInfo));
373 NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
374 NN_LOG("Content Flags = %d\n",headerInfo);
375
376 result = contentData.GetHeaderInfo(nn::boss::NSD_DATATYPE, &headerInfo, sizeof(headerInfo));
377 RESULT_SUCCESS_ASSERT(result);
378 NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
379 NN_LOG("Content DataType = %d\n",headerInfo);
380 }
381
382 //Check the data
383 {
384 NN_LOG("---Dump Data---\n");
385 u8 dDataBuf[4*1024];
386 memset(dDataBuf, 0, sizeof(dDataBuf));
387 size_t readSize = 0;
388 u32 readCount = 0;
389 do
390 {
391 ++readCount;
392 NN_LOG("(Read %d)\n", readCount);
393 readSize = contentData.ReadData(reinterpret_cast<u8*>(dDataBuf), sizeof(dDataBuf));
394 NN_BOSS_RESULT_HANDLING(result, "NsData::ReadData");
395 DumpNsdBody(dDataBuf, readSize);
396 }while(readSize != 0);
397 }
398
399 //Get and set data attribute information
400 {
401 u32 setInfo = 0x100;
402 result = contentData.SetAdditionalInfo(setInfo);
403 NN_BOSS_RESULT_HANDLING(result, "NsData::SetAdditionalInfo");
404
405 u32 getInfo;
406 result = contentData.GetAdditionalInfo(&getInfo);
407 NN_BOSS_RESULT_HANDLING(result, "NsData::SetAdditionalInfo");
408 NN_LOG("[BOSS Sample]AdditionalInfo = %d(Set Info = %d)\n", setInfo, setInfo);
409 }
410
411 /*
412 * You can also use the data's already-read flag.
413 * 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.
414 * The flag is off when data is downloaded and stays off as long as the application does not explicitly turn it on.
415 * Use this when the application manages unprocessed data.
416 * 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.
417 */
418 {
419 bool nsdReadFlag = true;
420 result = contentData.GetReadFlag(&nsdReadFlag);
421 NN_BOSS_RESULT_HANDLING(result, "NsData::GetReadFlag");
422 NN_LOG("[BOSS Sample]NSD Read Flag = %d\n", nsdReadFlag);
423
424 if(nsdReadFlag == false)
425 {
426 //Turn the flag on. (The data's already-read flag does not change unless the application sets it.)
427 result = contentData.SetReadFlag(true);
428 NN_BOSS_RESULT_HANDLING(result, "NsData::SetNewFrag");
429 }
430 }
431
432 //Delete data
433 /*
434 {
435 result = contentData.Delete();
436 NN_BOSS_RESULT_HANDLING(result, "NsData::Delete");
437 }
438 */
439
440
441 //After you get a list of data IDs, the application's "update indicator flag" is off.
442 {
443 bool arriveFlag = false;
444 result = nn::boss::GetNewArrivalFlag(&arriveFlag);
445 NN_BOSS_RESULT_HANDLING(result, "GetNewArrivalFlag");
446 NN_LOG("[BOSS Sample](After Read Data, NewArrivalFlag is %d.)\n", arriveFlag);
447 }
448
449 //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).
450 {
451 result = nn::boss::GetNewDataNsDataIdList(nn::boss::DATA_TYPE_ALL, &serialIdList);
452 NN_BOSS_RESULT_HANDLING(result, "GetNewDataNsDataIdList");
453 NN_LOG("[BOSS Sample](After NSD read flag on, New NSD number is = %d)\n", serialIdList.GetSize());
454 }
455
456 }
457
458 }
459
nnMain()460 extern "C" void nnMain()
461 {
462 // Call only the nn::applet::Enable function to also allow execution from the HOME Menu
463 // HOME Menu transitions, POWER Button presses, and sleep are all unsupported
464 nn::applet::Enable();
465
466 /* =======================================================================
467 Pre-processing
468 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.
469 ======================================================================== */
470 //Initialize the BOSS library
471 {
472 nn::Result result = nn::boss::Initialize();
473 NN_BOSS_RESULT_HANDLING(result, "boss::Initialize");
474 }
475
476 //Change settings so that the application runs BOSS in the background when we are not sleeping
477 {
478 // Initialize the NDM library
479 nn::Result result = nn::ndm::Initialize();
480 NN_BOSS_RESULT_HANDLING(result, "ndm::Initialize()");
481
482 // Resume BOSS
483 result = nn::ndm::Resume(nn::ndm::DN_BOSS);
484 NN_BOSS_RESULT_HANDLING(result, "ndm::Resume()");
485 }
486
487 // Create the expanded save data
488 // Save the downloaded NSA list in the expanded save data region.
489 {
490 const char extSaveDataMountName[] = "test:";
491 nn::fs::Initialize();
492 {
493 nn::Result result = nn::fs::MountExtSaveData(extSaveDataMountName, APP_EXT_STORAGE_ID);
494 if(result.IsFailure())
495 {
496 if(nn::fs::ResultNotFormatted::Includes(result) ||
497 nn::fs::ResultBadFormat::Includes(result) ||
498 nn::fs::ResultVerificationFailed::Includes(result))
499 {
500 nn::fs::DeleteExtSaveData(APP_EXT_STORAGE_ID);
501 }
502
503 if(nn::fs::ResultNotFound::Includes(result) ||
504 nn::fs::ResultNotFormatted::Includes(result) ||
505 nn::fs::ResultBadFormat::Includes(result) ||
506 nn::fs::ResultVerificationFailed::Includes(result))
507 {
508 NN_LOG("Create ExtSaveData(ID=%lx)\n", APP_EXT_STORAGE_ID);
509
510 //In SDK 0.14, icon data of some kind must be specified to fs::CreateExtSaveData.
511 u8 iconData[] = {0x01};
512 result = nn::fs::CreateExtSaveData(APP_EXT_STORAGE_ID, iconData, sizeof(iconData), 10, 100);
513 if(result.IsFailure())
514 {
515 NN_LOG_ERROR("CreateExtSaveData failed(%08x)\n", result.GetPrintableBits());
516 NN_UTIL_PANIC_IF_FAILED(result);
517 }
518 result = nn::fs::MountExtSaveData(extSaveDataMountName, APP_EXT_STORAGE_ID);
519 NN_UTIL_PANIC_IF_FAILED(result);
520 }
521 else
522 {
523 NN_LOG_ERROR("MountExtSaveData failed(%08x)\n", result.GetPrintableBits());
524 NN_UTIL_PANIC_IF_FAILED(result);
525 }
526 }
527 }
528 }
529
530 NN_LOG("Initializing network.\n");
531
532 // Connect to the network.
533 // The NSA list is downloaded in the foreground, so you must connect to the network beforehand.
534 {
535 nn::Result result = InitializeNetwork();
536 NN_UTIL_PANIC_IF_FAILED(result);
537 }
538
539 NN_LOG("BOSS Sample (NSA List Simple) Start\n");
540
541 // Get the NSA list and download the files in the list
542 sampleNSAListExecute();
543
544 NN_LOG("BOSS Sample (NSA List Simple) END\n");
545
546 /* =======================================================================
547 Clean up
548 Note: Network termination processing and other processing. If BOSS will still be used later, this does not need to be run.
549 ======================================================================== */
550 NN_LOG("Finalizing network.\n");
551 {
552 nn::Result result = FinalizeNetwork();
553 NN_UTIL_PANIC_IF_FAILED(result);
554 }
555
556 //Unregister BOSS storage if BOSS features will not be used later.
557 //(Note that once it is unregistered, you will no longer be able to run NADL tasks or read data from BOSS storage.)
558 /*
559 {
560 nn::Result result = nn::boss::UnregisterStorage();
561 NN_UTIL_PANIC_IF_FAILED(result);
562 }
563 */
564
565 //Finalize the NDM library
566 {
567 nn::Result result = nn::ndm::Finalize();
568 NN_BOSS_RESULT_HANDLING(result, "ndm::Finalize()");
569 //When the program exits, pause/resume settings are also restored
570 }
571
572 //Shut down the library
573 {
574 nn::Result result = nn::boss::Finalize();
575 NN_UTIL_PANIC_IF_FAILED(result);
576 }
577
578 NN_LOG("END\n");
579 }
580
581
582