1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     sample_fgonlytask.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 <nn/fs.h>
18 #include <nn/boss.h>
19 #include <nn/boss/boss_FgOnlyTask.h>
20 #include <nn/fs/fs_Parameters.h>
21 #include <nn/ac.h>
22 #include <nn/applet.h>
23 #include <nn/ndm.h>
24 
25 #define RESULT_SUCCESS_ASSERT NN_UTIL_PANIC_IF_FAILED
26 
27 #define NN_BOSS_RESULT_HANDLING(result, target)            \
28     do {                                                   \
29         if(result.IsFailure())                             \
30         {                                                  \
31             NN_LOG("result is err(%08x).(%s)\n", result.GetPrintableBits(), target);        \
32         }                                                  \
33     } while (0)
34 
35 namespace {
InitializeNetwork(void)36     nn::Result InitializeNetwork(void)
37     {
38         nn::Result result;
39         nn::ac::Config config;
40 
41         nn::fs::Initialize();
42         result = nn::ac::Initialize();
43         NN_UTIL_PANIC_IF_FAILED(result);
44 
45         // Create parameters for connection request
46         result = nn::ac::CreateDefaultConfig( &config );
47         if (result.IsFailure())
48         {
49             NN_UTIL_PANIC_IF_FAILED(nn::ac::Finalize());
50             return result;
51         }
52 
53         // Issue connection request
54         result = nn::ac::Connect( config );
55         if (result.IsFailure())
56         {
57             NN_UTIL_PANIC_IF_FAILED(nn::ac::Finalize());
58             return result;
59         }
60 
61         return nn::ResultSuccess();
62     }
63 
FinalizeNetwork(void)64     nn::Result FinalizeNetwork(void)
65     {
66         nn::Result result;
67 
68         // Create parameters for connection request
69         result = nn::ac::Close();
70         NN_UTIL_RETURN_IF_FAILED(result);
71 
72         result = nn::ac::Finalize();
73         NN_UTIL_PANIC_IF_FAILED(result);
74 
75         return nn::ResultSuccess();
76     }
77 
DumpNsdBody(u8 * pBodyBuf,size_t payloadLength)78     void DumpNsdBody(u8* pBodyBuf, size_t payloadLength)
79     {
80     #ifndef NN_SWITCH_DISABLE_DEBUG_PRINT
81         NN_LOG("---NSD Body Dump(Payload-Length=%d)---\n", payloadLength);
82         int hexCheckCount = 0;
83         for(int i = 0; i < payloadLength; ++i)
84         {
85             NN_LOG("%02x ", pBodyBuf[i]);
86             ++hexCheckCount;
87             if(hexCheckCount == 16)
88             {
89                 NN_LOG("\n");
90                 hexCheckCount = 0;
91             }
92         }
93     #else
94         NN_UNUSED_VAR(pBodyBuf);
95         NN_UNUSED_VAR(payloadLength);
96     #endif
97     }
98 }
99 
100 //Expanded save data ID
101 //(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.)
102 const bit32 APP_EXT_STORAGE_ID         = 0x00000011;
103 
104 /* ------------------------------------------------------------------------
105    This sample code uses immediate execution to run the NADL task in sample_nadl_simple.
106    For more details on task settings and other information, see the descriptions given in sample_nadl_simple.
107    ------------------------------------------------------------------------ */
sampleFgOnlyTaskExecute()108 void sampleFgOnlyTaskExecute()
109 {
110     //Register BOSS storage.
111     const size_t NADL_STORAGE_SIZE         = 3*1024*1024;   //The amount of the expanded save data region to use as BOSS storage.
112     {
113         nn::Result result = nn::boss::GetStorageInfo();
114         if(result == nn::boss::ResultStorageNotFound())
115         {
116             NN_LOG("[BOSS Sample]RegisterStorage BOSS Storage.\n");
117             result = nn::boss::RegisterStorage(APP_EXT_STORAGE_ID, NADL_STORAGE_SIZE);
118         }
119         NN_BOSS_RESULT_HANDLING(result, "boss::RegisterStorage");
120     }
121 
122     //Opt-out settings (The following code sets and accesses the local opt-out flag.)
123     /*
124     {
125         //Set the opt-out flag
126         bool optoutValue = true;
127         nn::Result result = nn::boss::SetOptoutFlag(optoutValue);
128         NN_BOSS_RESULT_HANDLING(result, "nn::boss::SetOptoutFlag");
129 
130         // Access the opt-out flag
131         result = nn::boss::GetOptoutFlag(&optoutValue);
132         NN_LOG("[BOSS Sample]Optout value is %d\n", optoutValue);
133         NN_BOSS_RESULT_HANDLING(result, "nn::boss::GetOptoutFlag");
134     }
135     */
136 
137 
138     // Register and run an NADL task using immediate execution
139     {
140         const char8 TASK_TARGET_URL[]         = "https://npdl.cdn.nintendowifi.net/p01/nsa/9x4m4dJwyBBlUc3g/FGONLYT/demofile_notice.dat"; /* Please see man pages for details */
141         //const char8 TASK_TARGET_URL[]       = "https://npdl.cdn.nintendowifi.net/p01/nsa/9x4m4dJwyBBlUc3g/FGONLYT/demofile.dat"; /**< The task's target URL. The Nintendo server BOSS test data (application data; new arrival flag OFF) URL is on the left. */
142         //const char8 TASK_TARGET_URL[]       = "https://npdl.cdn.nintendowifi.net/p01/nsa/9x4m4dJwyBBlUc3g/FGONLYT/demofile_message.dat"; /**< The task's target URL. The Nintendo server BOSS test data (news data; new arrival flag OFF) URL is on the left.*/
143 
144         // Configure the task
145         // You don't need to specify an execution interval or execution count for immediate execution tasks.
146         nn::boss::TaskPolicy dPolicy;
147 
148         nn::boss::NsaDownloadAction dAction;
149         nn::Result result = dAction.Initialize(TASK_TARGET_URL);
150         NN_BOSS_RESULT_HANDLING(result, "NsaDownloadAction::Initialize");
151 
152         //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.
153         //result = dAction.AddHeaderField(pLabel, pValue); // Set a unique HTTP request header, as necessary.
154 
155         // Task for immediate execution
156         // Because the task for immediate execution uses the dedicated task ID "FGONLYT," there is no need to set the task ID with Initialize.
157         //
158         nn::boss::FgOnlyTask dFgOnlyTask;
159 
160         // Register a task for immediate execution.
161         NN_LOG("[BOSS Sample]Regist FG Only Task.\n");
162         result = nn::boss::RegisterImmediateTask(&dFgOnlyTask, &dAction, &dPolicy);
163         NN_BOSS_RESULT_HANDLING(result, "RegisterImmediateTask");
164 
165         // Immediate task execution
166         // FgOnlyTask can only use immediate execution in the foreground.
167         NN_LOG("[BOSS Sample]Start FG Only Task.\n");
168         result = dFgOnlyTask.StartImmediate();
169         NN_BOSS_RESULT_HANDLING(result, "FgOnlyTask::StartImmediate");
170 
171         //Wait for NADL download data
172         //// Get a data download notification event from the BOSS daemon
173         nn::os::Event arriveEvent(false);
174         result = nn::boss::RegisterNewArrivalEvent(&arriveEvent);
175         NN_BOSS_RESULT_HANDLING(result, "boss::RegisterNewArrivalEvent");
176 
177         //// Wait for new data to be downloaded.
178         NN_LOG("[BOSS Sample]Wait NSA data arrive....\n");
179         arriveEvent.Wait();
180         NN_LOG("[BOSS Sample]Recognize NSA data arrive\n");
181 
182         //// 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.)
183         //// When waiting for data download, even if a task is executed, if there is no connection with the server, if the data already exists,
184         //// or if the downloaded data is invalid (decoding process or signature verification fails), the data is discarded and the process cannot return from Wait.
185         //// If you run a task and wait for it to complete, WaitFinish will exit when the task completes even if it had an error.
186         //// Use each method where it suits the purpose.
187         //result = dTask.WaitFinish(); // Wait for the task to complete. (Without a timeout. This will wait indefinitely until processing is complete.)
188         //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.)
189         //// Another way to wait for a task to complete is to poll on the task state using the Task::GetState function.
190         //// After you have detected that the task has completed, you can use the following functions to get information on the completed task.
191         //// Task::GetResult for the execution result
192         //// Task::GetCommErrorCode for the HTTP communication status code run by the task
193         //// Task::GetError for detailed information on task errors
194 
195         //Processing to download data.
196         //// Before you get a list of data IDs, the application's "update indicator flag" is on.
197         {
198             bool arriveFlag = false;
199             NN_UNUSED_VAR(arriveFlag);//Because this variable is exclusively used for output with NN_LOG, configure it to be unusable in Release builds.
200             result = nn::boss::GetNewArrivalFlag(&arriveFlag);
201             NN_BOSS_RESULT_HANDLING(result, "GetNewArrivalFlag");
202             NN_LOG("[BOSS Sample](Before Read Data, NewArrivalFlag is %d.)\n", arriveFlag);
203         }
204 
205         //// Get a serial ID list for the downloaded data. (You can use the first argument to GetNsDataIdList to filter the data that is obtained.)
206         static const u32 MAX_DATA_ID = 32;
207         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.
208         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.
209         serialIdList.Initialize();
210 
211         u32 getNsDataIdListCount = 0;
212         nn::Result getNsDataIdListResult;
213         do
214         {
215             getNsDataIdListResult = nn::boss::GetNsDataIdList(nn::boss::DATA_TYPE_ALL, &serialIdList);
216             //result = nn::boss::GetNsDataIdList(nn::boss::DATA_TYPE_APPDATA|0xffff, &serialIdList); // When you only want to get extra data for the application.
217 
218             if(getNsDataIdListResult == nn::boss::ResultNsDataListUpdated())
219             {
220                 //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.
221                 serialIdList.Initialize();
222                 getNsDataIdListResult = nn::boss::ResultNsDataListSizeShortage();//Update the value of getNsDataIdListResult so that control does not exit the do-while loop.
223                 continue;
224             }
225             else if((getNsDataIdListResult.IsFailure()) && (getNsDataIdListResult != nn::boss::ResultNsDataListSizeShortage()))
226             {
227                 //Any error other than ResultNsDataListUpdated, ResultNsDataListSizeShortage, or ResultSuccess is an unexpected error.
228                 //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).
229                 NN_BOSS_RESULT_HANDLING(result, "boss::GetNsDataIdList");
230             }
231 
232             //Application-specific processing for downloaded data. (This demo dumps the header information and body data for all downloaded data.)
233             ++getNsDataIdListCount;
234             NN_LOG("[BOSS Sample]Dump NSD datas(%d).(data number = %d)\n\n", getNsDataIdListCount, serialIdList.GetSize());
235             for(int i=0; i < serialIdList.GetSize(); ++i)
236             {
237                 NN_LOG("===NSD No.%d(SerialID = %d)===\n", i, serialIdList.GetNsDataId(i));
238                 nn::boss::NsData contentData;
239                 result = contentData.Initialize(serialIdList.GetNsDataId(i));
240                 NN_BOSS_RESULT_HANDLING(result, "NsData::Initialize");
241 
242                 //Check the header
243                 {
244                     nn::fs::TitleId titlleID = 0;
245                     result = contentData.GetHeaderInfo(nn::boss::NSD_TITLEID, &titlleID, sizeof(titlleID));
246                     NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
247                     NN_LOG("TitleID = %llx\n",titlleID);
248 
249                     u32 headerInfo = 0;
250                     result = contentData.GetHeaderInfo(nn::boss::NSD_SERIALID, &headerInfo, sizeof(headerInfo));
251                     NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
252                     NN_LOG("Content SerialID = %d\n",headerInfo);
253 
254                     result = contentData.GetHeaderInfo(nn::boss::NSD_LENGTH, &headerInfo, sizeof(headerInfo));
255                     NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
256                     NN_LOG("Payload Length = %d\n",headerInfo);
257 
258                     result = contentData.GetHeaderInfo(nn::boss::NSD_VERSION, &headerInfo, sizeof(headerInfo));
259                     NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
260                     NN_LOG("Content version = %d\n",headerInfo);
261 
262                     result = contentData.GetHeaderInfo(nn::boss::NSD_FLAGS, &headerInfo, sizeof(headerInfo));
263                     NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
264                     NN_LOG("Content Flags = %d\n",headerInfo);
265 
266                     result = contentData.GetHeaderInfo(nn::boss::NSD_DATATYPE, &headerInfo, sizeof(headerInfo));
267                     RESULT_SUCCESS_ASSERT(result);
268                     NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
269                     NN_LOG("Content DataType = %d\n",headerInfo);
270                 }
271 
272                 //Check the data
273                 {
274                     NN_LOG("---Dump Data---\n");
275                     u8 dDataBuf[4*1024];
276                     memset(dDataBuf, 0, sizeof(dDataBuf));
277                     size_t readSize = 0;
278                     u32 readCount = 0;
279                     do
280                     {
281                         ++readCount;
282                         NN_LOG("(Read %d)\n", readCount);
283                         readSize = contentData.ReadData(reinterpret_cast<u8*>(dDataBuf), sizeof(dDataBuf));
284                         NN_BOSS_RESULT_HANDLING(result, "NsData::ReadData");
285                         DumpNsdBody(dDataBuf, readSize);
286                     }while(readSize != 0);
287                 }
288 
289                 //Get and set data attribute information
290                 {
291                     u32 setInfo = 0x100;
292                     result = contentData.SetAdditionalInfo(setInfo);
293                     NN_BOSS_RESULT_HANDLING(result, "NsData::SetAdditionalInfo");
294 
295                     u32 getInfo;
296                     result = contentData.GetAdditionalInfo(&getInfo);
297                     NN_BOSS_RESULT_HANDLING(result, "NsData::SetAdditionalInfo");
298                     NN_LOG("[BOSS Sample]AdditionalInfo = %d(Set Info = %d)\n", setInfo, setInfo);
299                 }
300 
301                 /*
302                  * You can also use the data's already-read flag.
303                  * 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.
304                  * The flag is off when data is downloaded and stays off as long as the application does not explicitly turn it on.
305                  * Use this when the application manages unprocessed data.
306                  * 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.
307                  */
308                 {
309                     bool nsdReadFlag = true;
310                     result = contentData.GetReadFlag(&nsdReadFlag);
311                     NN_BOSS_RESULT_HANDLING(result, "NsData::GetReadFlag");
312                     NN_LOG("[BOSS Sample]NSD Read Flag = %d\n", nsdReadFlag);
313 
314                     if(nsdReadFlag == false)
315                     {
316                         //Turn the flag on. (The data's already-read flag does not change unless the application sets it.)
317                         result = contentData.SetReadFlag(true);
318                         NN_BOSS_RESULT_HANDLING(result, "NsData::SetNewFrag");
319                     }
320                 }
321 
322                 //Delete data
323                 /*
324                 {
325                     result = contentData.Delete();
326                     NN_BOSS_RESULT_HANDLING(result, "NsData::Delete");
327                 }
328                 */
329             }
330         }while(getNsDataIdListResult == nn::boss::ResultNsDataListSizeShortage());//If this is ResultNsDataListSizeShortage, run GetNsDataIdList again because all of the IDs have still not been obtained.
331 
332         //After you get a list of data IDs, the application's "update indicator flag" is off.
333         {
334             bool arriveFlag = false;
335             result = nn::boss::GetNewArrivalFlag(&arriveFlag);
336             NN_BOSS_RESULT_HANDLING(result, "GetNewArrivalFlag");
337             NN_LOG("[BOSS Sample](After Read Data, NewArrivalFlag is %d.)\n", arriveFlag);
338         }
339 
340         //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).
341         {
342             result = nn::boss::GetNewDataNsDataIdList(nn::boss::DATA_TYPE_ALL, &serialIdList);
343             NN_BOSS_RESULT_HANDLING(result, "GetNewDataNsDataIdList");
344             NN_LOG("[BOSS Sample](After NSD read flag on, New NSD number is = %d)\n", serialIdList.GetSize());
345         }
346     }
347 }
348 
nnMain()349 extern "C" void nnMain()
350 {
351     // Call only the nn::applet::Enable function to also allow execution from the HOME Menu
352     // HOME Menu transitions, POWER Button presses, and sleep are all unsupported
353     nn::applet::Enable();
354 
355     /* =======================================================================
356            Pre-processing
357                  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.
358        ======================================================================== */
359     //Initialize the BOSS library
360     {
361         nn::Result result = nn::boss::Initialize();
362         NN_BOSS_RESULT_HANDLING(result, "boss::Initialize");
363     }
364 
365     //Change settings so that the application runs BOSS in the background when we are not sleeping
366     {
367         // Initialize the NDM library
368         nn::Result result = nn::ndm::Initialize();
369         NN_BOSS_RESULT_HANDLING(result, "ndm::Initialize()");
370 
371         // Resume BOSS
372         result = nn::ndm::Resume(nn::ndm::DN_BOSS);
373         NN_BOSS_RESULT_HANDLING(result, "ndm::Resume()");
374     }
375 
376     //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.)
377     {
378         const char extSaveDataMountName[] = "test:";
379         nn::fs::Initialize();
380         {
381             nn::Result result = nn::fs::MountExtSaveData(extSaveDataMountName, APP_EXT_STORAGE_ID);
382             if(result.IsFailure())
383             {
384                 if(nn::fs::ResultNotFormatted::Includes(result)        ||
385                    nn::fs::ResultBadFormat::Includes(result)           ||
386                    nn::fs::ResultVerificationFailed::Includes(result))
387                 {
388                     nn::fs::DeleteExtSaveData(APP_EXT_STORAGE_ID);
389                 }
390 
391                 if(nn::fs::ResultNotFound::Includes(result)             ||
392                    nn::fs::ResultNotFormatted::Includes(result)         ||
393                    nn::fs::ResultBadFormat::Includes(result)            ||
394                    nn::fs::ResultVerificationFailed::Includes(result))
395                 {
396                     NN_LOG("Create ExtSaveData(ID=%lx)\n", APP_EXT_STORAGE_ID);
397                     //When you create expanded save data, configure the maximum file count so that it also accounts for the number of files downloaded through BOSS.
398                     //Once the maximum number of files already exist in expanded save data, it will no longer be possible to write files downloaded through BOSS.
399 
400                     //In SDK 0.14, icon data of some kind must be specified to fs::CreateExtSaveData.
401                     u8 iconData[] = {0x01};
402                     result = nn::fs::CreateExtSaveData(APP_EXT_STORAGE_ID, iconData, sizeof(iconData), 10, 100);
403                     if(result.IsFailure())
404                     {
405                         NN_LOG_ERROR("CreateExtSaveData failed(%08x)\n", result.GetPrintableBits());
406                         NN_UTIL_PANIC_IF_FAILED(result);
407                     }
408                     result = nn::fs::MountExtSaveData(extSaveDataMountName, APP_EXT_STORAGE_ID);
409                     NN_UTIL_PANIC_IF_FAILED(result);
410                 }
411                 else
412                 {
413                     NN_LOG_ERROR("MountExtSaveData failed(%08x)\n", result.GetPrintableBits());
414                     NN_UTIL_PANIC_IF_FAILED(result);
415                 }
416             }
417         }
418     }
419 
420     NN_LOG("Initializing network.\n");
421 
422     // Connect to the network.
423     // The task is run in the foreground with immediate execution, so you must connect to the network beforehand.
424     {
425         nn::Result result = InitializeNetwork();
426         NN_UTIL_PANIC_IF_FAILED(result);
427     }
428 
429     NN_LOG("BOSS Sample (FgOnlyTask) Start\n");
430 
431     sampleFgOnlyTaskExecute();
432 
433     NN_LOG("BOSS Sample (FgOnlyTask) END\n");
434 
435     /* =======================================================================
436            Clean up
437                  Note: Network termination processing and other processing. If BOSS will still be used later, this does not need to be run.
438        ======================================================================== */
439     NN_LOG("Finalizing network.\n");
440     {
441         nn::Result result = FinalizeNetwork();
442         NN_UTIL_PANIC_IF_FAILED(result);
443     }
444 
445     //Unregister BOSS storage if BOSS features will not be used later.
446     //(Note that once it is unregistered, you will no longer be able to run NADL tasks or read data from BOSS storage.)
447     /*
448     {
449         nn::Result result = nn::boss::UnregisterStorage();
450         NN_UTIL_PANIC_IF_FAILED(result);
451     }
452     */
453 
454     //Finalize the NDM library
455     {
456         nn::Result result = nn::ndm::Finalize();
457         NN_BOSS_RESULT_HANDLING(result, "ndm::Finalize()");
458         //When the program exits, pause/resume settings are also restored
459     }
460 
461     //Shut down the library
462     {
463         nn::Result result = nn::boss::Finalize();
464         NN_UTIL_PANIC_IF_FAILED(result);
465     }
466 
467     NN_LOG("END\n");
468 }
469 
470 
471