1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: sample_datastore.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 <stdio.h>
17 #include <string.h>
18 #include <nn/fs.h>
19 #include <nn/boss.h>
20 #include <nn/fs/fs_Parameters.h>
21 #include <nn/ac.h>
22 #include <nn/applet.h>
23 #include <nn/ndm.h>
24 #include <nn/friends.h>
25
26 #define RESULT_SUCCESS_ASSERT NN_UTIL_PANIC_IF_FAILED
27
28 #define NN_BOSS_RESULT_HANDLING(result, target) \
29 do { \
30 if(result.IsFailure()) \
31 { \
32 NN_LOG("result is err(%08x).(%s)\n", result.GetPrintableBits(), target); \
33 } \
34 } while (0)
35
36 namespace {
InitializeNetwork(void)37 nn::Result InitializeNetwork(void)
38 {
39 nn::Result result;
40 nn::ac::Config config;
41
42 nn::fs::Initialize();
43 result = nn::ac::Initialize();
44 NN_UTIL_PANIC_IF_FAILED(result);
45
46 // Create parameters for connection request
47 result = nn::ac::CreateDefaultConfig( &config );
48 if (result.IsFailure())
49 {
50 NN_UTIL_PANIC_IF_FAILED(nn::ac::Finalize());
51 return result;
52 }
53
54 // Issue connection request
55 result = nn::ac::Connect( config );
56 if (result.IsFailure())
57 {
58 NN_UTIL_PANIC_IF_FAILED(nn::ac::Finalize());
59 return result;
60 }
61
62 return nn::ResultSuccess();
63 }
64
FinalizeNetwork(void)65 nn::Result FinalizeNetwork(void)
66 {
67 nn::Result result;
68
69 // Create parameters for connection request
70 result = nn::ac::Close();
71 NN_UTIL_RETURN_IF_FAILED(result);
72
73 result = nn::ac::Finalize();
74 NN_UTIL_PANIC_IF_FAILED(result);
75
76 return nn::ResultSuccess();
77 }
78
DumpNsdBody(u8 * pBodyBuf,size_t payloadLength)79 void DumpNsdBody(u8* pBodyBuf, size_t payloadLength)
80 {
81 #ifndef NN_SWITCH_DISABLE_DEBUG_PRINT
82 NN_LOG("---NSD Body Dump(Payload-Length=%d)---\n", payloadLength);
83 int hexCheckCount = 0;
84 for(int i = 0; i < payloadLength; ++i)
85 {
86 NN_LOG("%02x ", pBodyBuf[i]);
87 ++hexCheckCount;
88 if(hexCheckCount == 16)
89 {
90 NN_LOG("\n");
91 hexCheckCount = 0;
92 }
93 }
94 #else
95 NN_UNUSED_VAR(pBodyBuf);
96 NN_UNUSED_VAR(payloadLength);
97 #endif
98 }
99
GetMyPrincipalId(nn::friends::PrincipalId * myPrincipalId)100 nn::Result GetMyPrincipalId(nn::friends::PrincipalId *myPrincipalId)
101 {
102 nn::Result result = nn::ResultSuccess();
103
104 // Get PrincipalId
105 *myPrincipalId = nn::friends::GetMyPrincipalId();
106
107 // If PrincipalId does not exist, login and logout of friend server and then try to get again.
108 if (*myPrincipalId == nn::friends::INVALID_PRINCIPAL_ID)
109 {
110 nn::os::Event event(true);
111
112 // Use the friends library to login to the friend server.
113 result = nn::friends::Login(&event);
114 if (result.IsSuccess())
115 {
116 // Wait for login process.
117 event.Wait();
118 if (nn::friends::GetLastResponseResult().IsSuccess())
119 {
120 // Successful login
121 NN_LOG("[BOSS Sample] Login friend server.");
122 }
123 else
124 {
125 NN_LOG("[BOSS Sample] Login friend server failed.");
126 }
127 }
128 else
129 {
130 NN_LOG("[BOSS Sample] Login friend server failed.");
131 }
132
133 // Immediately log out (since only getting PrincipalId)
134 nn::friends::Logout();
135
136 // Re-obtain PrincipalId
137 *myPrincipalId = nn::friends::GetMyPrincipalId();
138 }
139
140 return result;
141 }
142 }
143
144 // Expanded save data ID
145 // Take the file used for uploading when registering the DataStore upload task and copy it to BOSS storage (expanded save data region).
146 const bit32 APP_EXT_STORAGE_ID = 0x00000011;
147
148 const char extSaveDataMountName[] = "test:";
149
150 // Parameters required for accessing the DataStore server.
151 const u32 DATASTORE_GAME_ID = 0x0FE00301; // GameID for accessing the DataStore server (for sample)
152 const wchar_t DATASTORE_ACCESS_KEY[nn::boss::MAX_ACCESS_KEY_LENGTH] = L"871b3169"; // AccessKey for accessing the DataStore server (for sample)
153
154
155 /* ------------------------------------------------------------------------
156 Sample code for BOSS DataStore upload task.
157 ------------------------------------------------------------------------ */
sampleDataStoreUploadTask()158 void sampleDataStoreUploadTask()
159 {
160 // Register BOSS storage.
161 // For the DataStore upload task, the file for uploading is copied to BOSS storage.
162 // The copied file is deleted either when the upload process has completed or when the task is deleted.
163 const size_t NADL_STORAGE_SIZE = 3*1024*1024; // The amount of the expanded save data region to use as BOSS storage.
164 {
165 nn::Result result = nn::boss::GetStorageInfo();
166 if(result == nn::boss::ResultStorageNotFound())
167 {
168 NN_LOG("[BOSS Sample] RegisterStorage BOSS Storage.\n");
169 result = nn::boss::RegisterStorage(APP_EXT_STORAGE_ID, NADL_STORAGE_SIZE);
170 }
171 NN_BOSS_RESULT_HANDLING(result, "boss::RegisterStorage");
172 }
173
174 const char8 DATASTORE_UPLOAD_TASK_ID[] = "DsUpTsk"; /* Please see man pages for details */
175
176 // Account for the fact that there may still be a task with the same ID and delete it.
177 {
178 nn::boss::Task deleteTargetTask;
179 nn::Result result = deleteTargetTask.Initialize(DATASTORE_UPLOAD_TASK_ID);
180 NN_BOSS_RESULT_HANDLING(result, "Task::Initialize");
181
182 deleteTargetTask.Cancel(); //UnregisterTask fails if the task is currently running. To ensure that it is deleted, call UnregisterTask after Cancel.
183 NN_BOSS_RESULT_HANDLING(result, "Task::Cancel");
184
185 result = nn::boss::UnregisterTask(&deleteTargetTask);
186 NN_BOSS_RESULT_HANDLING(result, "boss::UnregisterTask");
187 }
188
189 // Use the friends library to get your own PrincipalId as the destination for the data.
190 nn::friends::PrincipalId myPrincipalId = nn::friends::INVALID_PRINCIPAL_ID;
191 {
192 nn::Result result = nn::friends::Initialize();
193 NN_BOSS_RESULT_HANDLING(result, "friends::Initialize");
194
195 result = GetMyPrincipalId(&myPrincipalId);
196 NN_BOSS_RESULT_HANDLING(result, "GetMyPrincipalId");
197
198 nn::friends::Finalize();
199 }
200
201 // Register and execute the DataStore upload task.
202 {
203
204 const u16 DATASTORE_UPLOAD_TASK_EXECUTE_TIME = 1; /* Please see man pages for details */
205 const u16 DATASTORE_UPLOAD_TASK_EXECUTE_COUNT = 1; /* Please see man pages for details */
206
207 // Register the DataStore upload task.
208 nn::boss::TaskPolicy dPolicy;
209 nn::Result result = dPolicy.Initialize(DATASTORE_UPLOAD_TASK_EXECUTE_TIME, DATASTORE_UPLOAD_TASK_EXECUTE_COUNT);
210 //nn::Result result = dPolicy.InitializeWithSecInterval(DATASTORE_UPLOAD_TASK_EXECUTE_TIME, DATASTORE_UPLOAD_TASK_EXECUTE_COUNT);// You can also specify an execution interval in seconds for testing.
211 NN_BOSS_RESULT_HANDLING(result, "TaskPolicy::Initialize");
212
213 // Open the upload target file.
214 // This demo uploads a file made from the data in memory.
215 u8 uploadData[] = {0x01, 0x02, 0x03, 0x04, 0x05};
216 char uploadTargetFilePath[128];
217 snprintf(uploadTargetFilePath, sizeof(uploadTargetFilePath), "%s/test.bin", extSaveDataMountName);
218
219 // Make a temporary file in the expanded save data region of the data for upload.
220 NN_LOG("[BOSS Sample] Make Upload TempFile(%s).\n", uploadTargetFilePath);
221 nn::fs::TryDeleteFile(uploadTargetFilePath);//Delete old file.
222
223 result = nn::fs::TryCreateFile(uploadTargetFilePath, sizeof(uploadData));
224 NN_BOSS_RESULT_HANDLING(result, "TryCreateFile");
225
226 nn::fs::FileOutputStream uploadTempFile;
227 result = uploadTempFile.TryInitialize(uploadTargetFilePath, false);
228 NN_BOSS_RESULT_HANDLING(result, "FileOutputStream::TryInitialize");
229
230 s32 out;
231 result = uploadTempFile.TryWrite(&out, uploadData, sizeof(uploadData), true);
232 NN_BOSS_RESULT_HANDLING(result, "FileOutputStream::TryWrite");
233 NN_ASSERT(out == sizeof(uploadData));
234 uploadTempFile.Finalize();
235
236 // Set necessary parameters for DataStore upload.
237 const nn::boss::DstKind DATASTORE_UPLOAD_TASK_DST_KIND = nn::boss::DSTKIND_SPECIFIED; // The target for sending of DateStore data (data is sent to specified peer)
238 const u16 DATASTORE_UPLOAD_TASK_DATA_TYPE = 12345; // The DataStore data DataType.
239 const u16 DATASTORE_UPLOAD_TASK_PERIOD = 1; // The expiration period (in days) of the DataStore data.
240 nn::boss::DataStoreUploadAction dAction;
241 result = dAction.Initialize(DATASTORE_GAME_ID,
242 DATASTORE_ACCESS_KEY,
243 DATASTORE_UPLOAD_TASK_DST_KIND,
244 DATASTORE_UPLOAD_TASK_DATA_TYPE,
245 DATASTORE_UPLOAD_TASK_PERIOD);
246 NN_BOSS_RESULT_HANDLING(result, "nn::boss::DataStoreUploadAction::Initialize");
247
248 // Specify own PrincipalID as destination of transmission.
249 result = dAction.AddDstPrincipalId(myPrincipalId);
250 NN_BOSS_RESULT_HANDLING(result, "nn::boss::DataStoreUploadAction::AddDstPrincipalId");
251
252 nn::boss::Task dTask;
253 result = dTask.Initialize(DATASTORE_UPLOAD_TASK_ID);
254 NN_BOSS_RESULT_HANDLING(result, "Task::Initialize");
255
256 // Register the task.
257 NN_LOG("[BOSS Sample] Regist DataStore Upload Task.\n");
258 result = nn::boss::RegisterTask(&dTask, &dPolicy, &dAction, uploadTargetFilePath);
259 if (result == nn::boss::ResultTaskIdAlreadyExist())
260 {
261 NN_LOG("[BOSS Sample] RegisterTask failed. Same name task(%s) already registered.If regist again, need to UnregisterTask before.\n", DATASTORE_UPLOAD_TASK_ID);
262 }
263 NN_BOSS_RESULT_HANDLING(result, "RegisterTask");
264
265 // Execute task
266 NN_LOG("[BOSS Sample] Start DataStore Upload Task.\n");
267 result = dTask.Start();
268 NN_BOSS_RESULT_HANDLING(result, "Task::Start");
269
270 //Use StartImmediate if you want to run a task immediately without waiting for the next task execution time.
271 //However, because StartImmediate runs a task in the foreground, the application must make an infrastructure network connection. (BOSS is not used.)
272 /*
273 [Infrastructure network connection with nn::ac::Connect]
274 result = dTask.StartImmediate();
275 NN_BOSS_RESULT_HANDLING(result, "Task::StartImmediate");
276 (NOTE: Use nn::ac::Close to close the infrastructure network connection after the task finishes processing.)
277 */
278
279 // Polling until completion of execution of DataStore upload task.
280 // If you want to execute immediately, comment out "dPolicy.InitializeWithSecInterval " in the above code.
281 while (1)
282 {
283 nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(5000));
284
285 if (dTask.GetState(true) == nn::boss::TASK_DONE)
286 {
287 NN_LOG("[BOSS Sample] DataStore Upload Task Done.\n");
288 break;
289 }
290 else if (dTask.GetState(true) == nn::boss::TASK_ERROR)
291 {
292 NN_LOG("[BOSS Sample] DataStore Upload Task Error.\n");
293 break;
294 }
295
296 NN_LOG("[BOSS Sample] Polling DataStore Upload Task.\n");
297 }
298 }
299
300 }
301
302 /* ------------------------------------------------------------------------
303 Sample code for BOSS DataStore download task.
304 ------------------------------------------------------------------------ */
sampleDataStoreDownloadTask()305 void sampleDataStoreDownloadTask()
306 {
307 const char8 DATASTORE_DOWNLOAD_TASK_ID[] = "DsDlTsk"; /* Please see man pages for details */
308
309 // Account for the fact that there may still be a task with the same ID and delete it.
310 {
311 nn::boss::Task deleteTargetTask;
312 nn::Result result = deleteTargetTask.Initialize(DATASTORE_DOWNLOAD_TASK_ID);
313 NN_BOSS_RESULT_HANDLING(result, "Task::Initialize");
314
315 deleteTargetTask.Cancel(); //UnregisterTask fails if the task is currently running. To ensure that it is deleted, call UnregisterTask after Cancel.
316 NN_BOSS_RESULT_HANDLING(result, "Task::Cancel");
317
318 result = nn::boss::UnregisterTask(&deleteTargetTask);
319 NN_BOSS_RESULT_HANDLING(result, "boss::UnregisterTask");
320 }
321
322 // Register and execute the DataStore download task.
323 {
324 const u16 DATASTORE_DOWNLOAD_TASK_EXECUTE_TIME = 1; /* Please see man pages for details */
325 const u16 DATASTORE_DOWNLOAD_TASK_EXECUTE_COUNT = 1; /* Please see man pages for details */
326
327 // Register the DataStore download task.
328 nn::boss::TaskPolicy dPolicy;
329 nn::Result result = dPolicy.Initialize(DATASTORE_DOWNLOAD_TASK_EXECUTE_TIME, DATASTORE_DOWNLOAD_TASK_EXECUTE_COUNT);
330 //nn::Result result = dPolicy.InitializeWithSecInterval(DATASTORE_DOWNLOAD_TASK_EXECUTE_TIME, DATASTORE_DOWNLOAD_TASK_EXECUTE_COUNT);// You can also specify an execution interval in seconds for testing.
331 NN_BOSS_RESULT_HANDLING(result, "TaskPolicy::Initialize");
332
333 nn::boss::DataStoreDownloadAction dAction;
334 result = dAction.Initialize(DATASTORE_GAME_ID, DATASTORE_ACCESS_KEY);
335 NN_BOSS_RESULT_HANDLING(result, "DataStoreDownloadAction::Initialize");
336
337 // Set notification to receive at time of DataStore download.
338 const bit32 DATASTORE_DOWNLOAD_NEWS_SERIAL_ID = 100000; // SerialID of NS data received as notification.
339 const wchar_t DATASTORE_DOWNLOAD_NEWS_SUBJECT[] = L"Sample Subject"; // "Subject" part of notification.
340 const wchar_t DATASTORE_DOWNLOAD_NEWS_MESSAGE[] = L"Sample Message"; // "Message" part of notification.
341 const u8 DATASTORE_DOWNLOAD_NEWS_JUMP_PARAM[nn::boss::MAX_NEWS_JUMP_PARAM] = {1}; // General-purpose notification jump parameters.
342 result = dAction.SetNewsPublication(DATASTORE_DOWNLOAD_NEWS_SERIAL_ID,
343 DATASTORE_DOWNLOAD_NEWS_SUBJECT,
344 DATASTORE_DOWNLOAD_NEWS_MESSAGE,
345 DATASTORE_DOWNLOAD_NEWS_JUMP_PARAM);
346 NN_BOSS_RESULT_HANDLING(result, "DataStoreDownloadAction::SetNewsPublication");
347
348 nn::boss::Task dTask;
349 result = dTask.Initialize(DATASTORE_DOWNLOAD_TASK_ID);
350 NN_BOSS_RESULT_HANDLING(result, "Task::Initialize");
351
352 // Register the task.
353 NN_LOG("[BOSS Sample] Regist DataStore Download Task.\n");
354 result = nn::boss::RegisterTask(&dTask, &dPolicy, &dAction);
355 if (result == nn::boss::ResultTaskIdAlreadyExist())
356 {
357 NN_LOG("[BOSS Sample] RegisterTask failed. Same name task(%s) already registered.If regist again, need to UnregisterTask before.\n", DATASTORE_DOWNLOAD_TASK_ID);
358 }
359 NN_BOSS_RESULT_HANDLING(result, "RegisterTask");
360
361 // Execute task
362 NN_LOG("[BOSS Sample] Start DataStore Download Task.\n");
363 result = dTask.Start();
364 NN_BOSS_RESULT_HANDLING(result, "Task::Start");
365
366 // Wait for DataStore download data.
367 // Get a data download notification event from the BOSS daemon.
368 nn::os::Event arriveEvent(false);
369 result = nn::boss::RegisterNewArrivalEvent(&arriveEvent);
370 NN_BOSS_RESULT_HANDLING(result, "Task::RegisterNewArrivalEvent");
371
372 //Use StartImmediate if you want to run a task immediately without waiting for the next task execution time.
373 //However, because StartImmediate runs a task in the foreground, the application must make an infrastructure network connection. (BOSS is not used.)
374 /*
375 [Infrastructure network connection with nn::ac::Connect]
376 result = dTask.StartImmediate();
377 NN_BOSS_RESULT_HANDLING(result, "Task::StartImmediate");
378 (NOTE: Use nn::ac::Close to close the infrastructure network connection after the task finishes processing.)
379 */
380
381 // Wait for new data to be downloaded.
382 NN_LOG("[BOSS Sample] Wait NSA data arrive....\n");
383 arriveEvent.Wait();
384 NN_LOG("[BOSS Sample] Recognize NSA data arrive\n");
385
386 //Processing to download data.
387 //// Before you get a list of data IDs, the application's "update indicator flag" is on.
388 {
389 bool arriveFlag = false;
390 NN_UNUSED_VAR(arriveFlag); //Because this variable is exclusively used for output with NN_LOG, configure it to be unusable in Release builds.
391 result = nn::boss::GetNewArrivalFlag(&arriveFlag);
392 NN_BOSS_RESULT_HANDLING(result, "GetNewArrivalFlag");
393 NN_LOG("[BOSS Sample] (Before Read Data, NewArrivalFlag is %d.)\n", arriveFlag);
394 }
395
396 //// Get a serial ID list for the downloaded data. (You can use the first argument to GetNsDataIdList to filter the data that is obtained.)
397 static const u32 MAX_DATA_ID = 32;
398 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.
399 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.
400 serialIdList.Initialize();
401
402 u32 getNsDataIdListCount = 0;
403 nn::Result getNsDataIdListResult;
404 do
405 {
406 getNsDataIdListResult = nn::boss::GetNsDataIdList(nn::boss::DATA_TYPE_ALL, &serialIdList);
407 //result = nn::boss::GetNsDataIdList(nn::boss::DATA_TYPE_APPDATA|0xffff, &serialIdList); // When you only want to get extra data for the application.
408
409 if(getNsDataIdListResult == nn::boss::ResultNsDataListUpdated())
410 {
411 //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.
412 serialIdList.Initialize();
413 getNsDataIdListResult = nn::boss::ResultNsDataListSizeShortage();//Update the value of getNsDataIdListResult so that control does not exit the do-while loop.
414 continue;
415 }
416 else if((getNsDataIdListResult.IsFailure()) && (getNsDataIdListResult != nn::boss::ResultNsDataListSizeShortage()))
417 {
418 //Any error other than ResultNsDataListUpdated, ResultNsDataListSizeShortage, or ResultSuccess is an unexpected error.
419 //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).
420 NN_BOSS_RESULT_HANDLING(result, "boss::GetNsDataIdList");
421 }
422
423 //Application-specific processing for downloaded data. (This demo dumps the header information and body data for all downloaded data.)
424 ++getNsDataIdListCount;
425 NN_LOG("[BOSS Sample]Dump NSD datas(%d).(data number = %d)\n\n", getNsDataIdListCount, serialIdList.GetSize());
426 for(int i=0; i < serialIdList.GetSize(); ++i)
427 {
428 NN_LOG("===NSD No.%d(SerialID = %d)===\n", i, serialIdList.GetNsDataId(i));
429 nn::boss::NsData contentData;
430 result = contentData.Initialize(serialIdList.GetNsDataId(i));
431 NN_BOSS_RESULT_HANDLING(result, "NsData::Initialize");
432
433 //Check the header
434 {
435 nn::fs::TitleId titlleID = 0;
436 result = contentData.GetHeaderInfo(nn::boss::NSD_TITLEID, &titlleID, sizeof(titlleID));
437 NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
438 NN_LOG("TitleID = %llx\n",titlleID);
439
440 u32 headerInfo = 0;
441 result = contentData.GetHeaderInfo(nn::boss::NSD_SERIALID, &headerInfo, sizeof(headerInfo));
442 NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
443 NN_LOG("Content SerialID = %d\n",headerInfo);
444
445 result = contentData.GetHeaderInfo(nn::boss::NSD_LENGTH, &headerInfo, sizeof(headerInfo));
446 NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
447 NN_LOG("Payload Length = %d\n",headerInfo);
448
449 result = contentData.GetHeaderInfo(nn::boss::NSD_VERSION, &headerInfo, sizeof(headerInfo));
450 NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
451 NN_LOG("Content version = %d\n",headerInfo);
452
453 result = contentData.GetHeaderInfo(nn::boss::NSD_FLAGS, &headerInfo, sizeof(headerInfo));
454 NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
455 NN_LOG("Content Flags = %d\n",headerInfo);
456
457 result = contentData.GetHeaderInfo(nn::boss::NSD_DATATYPE, &headerInfo, sizeof(headerInfo));
458 RESULT_SUCCESS_ASSERT(result);
459 NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
460 NN_LOG("Content DataType = %d\n",headerInfo);
461 }
462
463 //Check the data
464 {
465 NN_LOG("---Dump Data---\n");
466 u8 dDataBuf[4*1024];
467 memset(dDataBuf, 0, sizeof(dDataBuf));
468 size_t readSize = 0;
469 u32 readCount = 0;
470 do
471 {
472 ++readCount;
473 NN_LOG("(Read %d)\n", readCount);
474 readSize = contentData.ReadData(reinterpret_cast<u8*>(dDataBuf), sizeof(dDataBuf));
475 NN_BOSS_RESULT_HANDLING(result, "NsData::ReadData");
476 DumpNsdBody(dDataBuf, readSize);
477 }while(readSize != 0);
478 }
479
480 //Get and set data attribute information
481 {
482 u32 setInfo = 0x100;
483 result = contentData.SetAdditionalInfo(setInfo);
484 NN_BOSS_RESULT_HANDLING(result, "NsData::SetAdditionalInfo");
485
486 u32 getInfo;
487 result = contentData.GetAdditionalInfo(&getInfo);
488 NN_BOSS_RESULT_HANDLING(result, "NsData::SetAdditionalInfo");
489 NN_LOG("[BOSS Sample]AdditionalInfo = %d(Set Info = %d)\n", setInfo, setInfo);
490 }
491
492 /*
493 * You can also use the data's already-read flag.
494 * 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.
495 * The flag is off when data is downloaded and stays off as long as the application does not explicitly turn it on.
496 * Use this when the application manages unprocessed data.
497 * 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.
498 */
499 {
500 bool nsdReadFlag = true;
501 result = contentData.GetReadFlag(&nsdReadFlag);
502 NN_BOSS_RESULT_HANDLING(result, "NsData::GetReadFlag");
503 NN_LOG("[BOSS Sample]NSD Read Flag = %d\n", nsdReadFlag);
504
505 if(nsdReadFlag == false)
506 {
507 //Turn the flag on. (The data's already-read flag does not change unless the application sets it.)
508 result = contentData.SetReadFlag(true);
509 NN_BOSS_RESULT_HANDLING(result, "NsData::SetNewFrag");
510 }
511 }
512
513 //Delete data
514 /*
515 {
516 result = contentData.Delete();
517 NN_BOSS_RESULT_HANDLING(result, "NsData::Delete");
518 }
519 */
520 }
521 }while(getNsDataIdListResult == nn::boss::ResultNsDataListSizeShortage());//If this is ResultNsDataListSizeShortage, run GetNsDataIdList again because all of the IDs have still not been obtained.
522
523 //After you get a list of data IDs, the application's "update indicator flag" is off.
524 {
525 bool arriveFlag = false;
526 result = nn::boss::GetNewArrivalFlag(&arriveFlag);
527 NN_BOSS_RESULT_HANDLING(result, "GetNewArrivalFlag");
528 NN_LOG("[BOSS Sample](After Read Data, NewArrivalFlag is %d.)\n", arriveFlag);
529 }
530
531 //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).
532 {
533 result = nn::boss::GetNewDataNsDataIdList(nn::boss::DATA_TYPE_ALL, &serialIdList);
534 NN_BOSS_RESULT_HANDLING(result, "GetNewDataNsDataIdList");
535 NN_LOG("[BOSS Sample](After NSD read flag on, New NSD number is = %d)\n", serialIdList.GetSize());
536 }
537
538 }
539 }
540
541
nnMain()542 extern "C" void nnMain()
543 {
544 // Call only the nn::applet::Enable function to also allow execution from the HOME Menu
545 // HOME Menu transitions, POWER Button presses, and sleep are all unsupported
546 nn::applet::Enable();
547
548 /* =======================================================================
549 Pre-processing
550 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.
551 ======================================================================== */
552 //Initialize the BOSS library
553 {
554 nn::Result result = nn::boss::Initialize();
555 NN_BOSS_RESULT_HANDLING(result, "boss::Initialize");
556 }
557
558 //Change settings so that the application runs BOSS in the background when we are not sleeping
559 {
560 // Initialize the NDM library
561 nn::Result result = nn::ndm::Initialize();
562 NN_BOSS_RESULT_HANDLING(result, "ndm::Initialize()");
563
564 // Resume BOSS
565 result = nn::ndm::Resume(nn::ndm::DN_BOSS);
566 NN_BOSS_RESULT_HANDLING(result, "ndm::Resume()");
567 }
568
569 // Create the expanded save data
570 // For DataStore upload tasks the data for uploading is saved to BOSS storage in the expanded save data region.
571 // For DataStore download tasks, the downloaded data is saved to BOSS storage in the expanded save data region.
572 // You thus need an expanded save data region in order to use DataStore tasks.
573 {
574 nn::fs::Initialize();
575 {
576 nn::Result result = nn::fs::MountExtSaveData(extSaveDataMountName, APP_EXT_STORAGE_ID);
577 if(result.IsFailure())
578 {
579 if(nn::fs::ResultNotFormatted::Includes(result) ||
580 nn::fs::ResultBadFormat::Includes(result) ||
581 nn::fs::ResultVerificationFailed::Includes(result))
582 {
583 nn::fs::DeleteExtSaveData(APP_EXT_STORAGE_ID);
584 }
585
586 if(nn::fs::ResultNotFound::Includes(result) ||
587 nn::fs::ResultNotFormatted::Includes(result) ||
588 nn::fs::ResultBadFormat::Includes(result) ||
589 nn::fs::ResultVerificationFailed::Includes(result))
590 {
591 NN_LOG("Create ExtSaveData(ID=%lx)\n", APP_EXT_STORAGE_ID);
592 //When you create expanded save data, configure the maximum file count so that it also accounts for the number of files downloaded through BOSS.
593 //Once the maximum number of files already exist in expanded save data, it will no longer be possible to write files downloaded through BOSS.
594
595 //In SDK 0.14, icon data of some kind must be specified to fs::CreateExtSaveData.
596 u8 iconData[] = {0x01};
597 result = nn::fs::CreateExtSaveData(APP_EXT_STORAGE_ID, iconData, sizeof(iconData), 10, 100);
598 if(result.IsFailure())
599 {
600 NN_LOG_ERROR("CreateExtSaveData failed(%08x)\n", result.GetPrintableBits());
601 NN_UTIL_PANIC_IF_FAILED(result);
602 }
603 result = nn::fs::MountExtSaveData(extSaveDataMountName, APP_EXT_STORAGE_ID);
604 NN_UTIL_PANIC_IF_FAILED(result);
605 }
606 else
607 {
608 NN_LOG_ERROR("MountExtSaveData failed(%08x)\n", result.GetPrintableBits());
609 NN_UTIL_PANIC_IF_FAILED(result);
610 }
611 }
612 }
613 }
614
615 NN_LOG("Initializing network.\n");
616
617 // Connect to the network.
618 {
619 nn::Result result = InitializeNetwork();
620 NN_UTIL_PANIC_IF_FAILED(result);
621 }
622
623
624 NN_LOG("BOSS Sample(DataStoreTask) Start\n");
625
626 // Register and execute the DataStore upload task.
627 sampleDataStoreUploadTask();
628
629 // If you do not wait for at least around 20 seconds after uploading to DataStore you cannot download the data.
630 // To play it safe, wait for around 25 seconds.
631 NN_LOG("Wait for 25 sec...\n");
632 nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromSeconds(25));
633
634 // Register and execute the DataStore download task.
635 sampleDataStoreDownloadTask();
636
637 NN_LOG("BOSS Sample(DataStoreTask) END\n");
638
639
640 /* =======================================================================
641 Clean up
642 Note: Network termination processing and other processing. If BOSS will still be used later, this does not need to be run.
643 ======================================================================== */
644 NN_LOG("Finalizing network.\n");
645 {
646 nn::Result result = FinalizeNetwork();
647 NN_UTIL_PANIC_IF_FAILED(result);
648 }
649
650 //Unregister BOSS storage if BOSS features will not be used later.
651 //(Note that once it is unregistered, you will no longer be able to run NADL tasks or read data from BOSS storage.)
652 /*
653 {
654 nn::Result result = nn::boss::UnregisterStorage();
655 NN_UTIL_PANIC_IF_FAILED(result);
656 }
657 */
658
659 //Finalize the NDM library
660 {
661 nn::Result result = nn::ndm::Finalize();
662 NN_BOSS_RESULT_HANDLING(result, "ndm::Finalize()");
663 //When the program exits, pause/resume settings are also restored
664 }
665
666 //Shut down the library
667 {
668 nn::Result result = nn::boss::Finalize();
669 NN_UTIL_PANIC_IF_FAILED(result);
670 }
671
672 NN_LOG("END\n");
673 }
674
675
676