/*---------------------------------------------------------------------------* Project: WiiConnect24 File: Download.c Copyright 2007 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Log: Download.c,v $ Revision 1.6 2008/08/27 02:51:42 adachi_hiroaki Revised comments. Revision 1.5 2008/07/30 02:09:41 adachi_hiroaki Added support for NANDCheck. Revision 1.4 2008/03/10 00:30:46 adachi_hiroaki Removed notes. Revision 1.3 2008/03/10 00:15:42 adachi_hiroaki Added a note about the overhead of VF archives. Revision 1.2 2007/11/30 08:49:07 adachi_hiroaki Changed the priority that is set. Revision 1.1 2007/06/07 06:06:39 adachi_hiroaki Added a demo of the download feature. *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include /*---------------------------------------------------------------------------* Macros *---------------------------------------------------------------------------*/ #define VERIFY_NWC24ERR(err, expected) ASSERTMSG( err == expected, "unexpected error code: %d", err ) #define URL "http://nintendo/file.bin" #define DRIVE "C" #define SIZE_VF (500*1024) /* Force simulation of the initial run (it is best to initialize the task list with nwc24init.elf) */ #define SIMULATE_FIRSTRUN /* Do not use a signature */ #define NOSIGN /* Use the public key prepared by the application */ //#define USE_MYPUBLICKEY BOOL DownloadTaskMain( void ); /*---------------------------------------------------------------------------* Static Data *---------------------------------------------------------------------------*/ /* The application's public key is specified here. It is easiest to use makeo */ static u8 publicKey[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /*---------------------------------------------------------------------------* Forward references to local functions *---------------------------------------------------------------------------*/ static void SetProperty( NWC24DlTask* task ); static NWC24Err UpdateTask( NWC24DlTask* task ); static BOOL CheckVf( NWC24DlTask* task, NWC24Err* nwc24Err, VFErr* vfErr ); static u32 GetFsBlock(s32 sizeByte); int main() { OSReport("*******************************************************\n"); OSReport(" WiiConnect24 download sample\n"); OSReport("*******************************************************\n"); VFInit(); if (DownloadTaskMain()) { OSReport("==== Waiting... ====\n"); OSSleepSeconds(60*5); (void) DownloadTaskMain(); } else { OSReport("NG\n"); } OSHalt("Finished.\n"); return 0; } BOOL DownloadTaskMain( void ) { static u32 libWorkMem[NWC24_WORK_MEM_SIZE/sizeof(u32)] ATTRIBUTE_ALIGN(32); NWC24Err err = NWC24_OK; NWC24Err err2 = NWC24_OK; VFErr vfErr = VF_ERR_SUCCESS; NWC24DlTask dlTask; /* Ease the restrictions on the parameters for the sake of debugging (Incorporating this into products is prohibited) */ NWC24EnableDlLaxParameterChecking(TRUE); /* Reduce the scheduler interval to make the downloads happen earlier (Incorporating this into products is prohibited) */ (void) NWC24SetScheduleSpan(10, 1); err = NWC24OpenLib(&libWorkMem); if (err < NWC24_OK) { return FALSE; } /* Update the task */ err = UpdateTask(&dlTask); if (err < NWC24_OK) { goto close; } /* Display the task's content to the console */ (void) NWC24DumpDlTask(&dlTask); /* Check that the content was downloaded */ if (CheckVf(&dlTask, &err, &vfErr)) { OSReport("a new content was found.\n"); } close: err2 = NWC24CloseLib(); return err == NWC24_OK; } static NWC24Err UpdateTask( NWC24DlTask* task ) { NWC24Err err; u16 myId = 0; /* Get the tasks that have already been registered. Register again if it failed Note: This function cannot be used when a single application registers two or more tasks The application must save each task ID and get the tasks using NWC24GetDlTask() */ #ifndef SIMULATE_FIRSTRUN err = NWC24GetDlTaskMine( task ); #else err = NWC24_ERR_NOT_FOUND; #endif if (err == NWC24_ERR_NOT_FOUND) { /* The task was deleted, either because it had not been registered or had expired, and must be recreated */ /* Create a new binary data receiving-type task */ err = NWC24InitDlTask(task, NWC24_DLTYPE_OCTETSTREAM); if (err < NWC24_OK) { return err; } /* If the task was newly created, configure the required items */ SetProperty( task ); } else if (err < NWC24_OK) { return err; } /* Specify the number of remaining downloads Each time a download is done, the number is decreased by one; when it reaches zero, the task is removed For this reason, it is necessary to restore the value each time the application is run in order to prevent the task from being removed */ err = NWC24SetDlCount( task, 50 ); if (err < NWC24_OK) { return err; } /* Register the task data in the task list */ err = NWC24AddDlTask(task); if (err < NWC24_OK) { return err; } return NWC24_OK; } static void SetProperty( NWC24DlTask* task ) { NWC24Err err; u32 flags = 0; /* Specify the URL */ err = NWC24SetDlUrl( task, URL ); VERIFY_NWC24ERR( err, NWC24_OK ); /* Specify the priority. Tasks will be run with priority given to those with lower values The values should be set following the guidelines */ err = NWC24SetDlPriority( task, 192 ); VERIFY_NWC24ERR( err, NWC24_OK ); /* Specify the execution interval of the download task Note that task execution will not necessarily be performed in this interval */ err = NWC24SetDlInterval( task, 1 ); VERIFY_NWC24ERR( err, NWC24_OK ); /* Specify the filename when storing in VF */ err = NWC24SetDlFilename(task, "file.dat"); VERIFY_NWC24ERR( err, NWC24_OK ); #ifdef USE_MYPUBLICKEY flags |= NWC24_DL_FLAG_USE_MYPUBLICKEY; #endif /* Specify to download unsigned content without any further processing If parameter checking has been disabled for tasks, this cannot be used for http:// URLs */ #ifdef NOSIGN flags |= NWC24_DL_FLAG_RAW_CONTENT; #endif err = NWC24SetDlFlags(task, flags); VERIFY_NWC24ERR( err, NWC24_OK ); } static u32 GetFsBlock(s32 sizeByte) { ASSERT(sizeByte > 0); if ((sizeByte % NAND_FSBLOCK_SIZE) == 0) { return (u32)(sizeByte / NAND_FSBLOCK_SIZE); } else { return (u32)(sizeByte / NAND_FSBLOCK_SIZE + 1); } } static BOOL CheckVf( NWC24DlTask* task, NWC24Err* nwc24Err, VFErr* vfErr ) { VFFile* vfFile = NULL; BOOL create = TRUE; BOOL result = FALSE; char bufVfName[NAND_MAX_PATH]; char bufVfContentName[VF_PATH_BUF_SIZE]; /* Load the content that was obtained using the VF library */ /* Get the VFF filename */ *nwc24Err = NWC24GetDlVfName(task, bufVfName, sizeof(bufVfName)); VERIFY_NWC24ERR( *nwc24Err, NWC24_OK ); /* Get the filename of the content that was saved within VFF */ *nwc24Err = NWC24GetDlFilename(task, bufVfContentName, sizeof(bufVfContentName)); VERIFY_NWC24ERR( *nwc24Err, NWC24_OK ); OSReport("VF archive = %s\n", bufVfName); /* Mount */ *vfErr = VFMountDriveNANDFlash( DRIVE, bufVfName ); if (*vfErr == VF_ERR_SUCCESS) { vfFile = VFOpenFile(bufVfContentName, "r", 0); if ( vfFile ) { /* Load the content that was downloaded here */ { s32 length = 0; length = VFGetFileSizeByFd( vfFile ); OSReport("filename = %s, size = %d\n", bufVfContentName, length); /* To determine if received content is new, it is necessary to embed the sequence number, creation date, and other information in said content and then compare this information with what was previously received */ } (void)VFCloseFile( vfFile ); /* If subsequent files are not required, delete them */ *vfErr = VFDeleteFile(bufVfContentName); result = TRUE; create = FALSE; } else { result = FALSE; /* Find out the reason that the file failed to open */ *vfErr = VFGetLastError(); if (*vfErr == VF_ERR_ENOENT) { /* The file simply does not exist. Recreating VFF is not necessary */ create = FALSE; } else { /* There is a chance that the VFF file is corrupted. Recreate it just in case */ create = TRUE; } } (void)VFUnmountDrive( DRIVE ); } else { result = FALSE; create = TRUE; } /* If the VFF file needs to be recreated, do so together with files under the home directory */ if (create) { s32 checkResult = 0; u32 answer = 0; /* Prepare by deleting all files below the home directory */ (void)NANDDelete(bufVfName); (void)NWC24ClearDlKeys(); /* Before creating the files, do a check with NANDCheck() If you will use NWC24SetDlKeys(), the key file must also be checked (The key file uses 1 FS block and consumes 1 inode) */ checkResult = NANDCheck(GetFsBlock(SIZE_VF) + 1, 2, &answer); if (checkResult != NAND_RESULT_OK || answer != 0) { /* Follow the NANDCheck processing sequence */ return FALSE; } /* Prepare a 500 KB VF archive as the destination for storing the download file The FAT region is included in the 500 KB, so the actual downloadable size is approximately 490 KB */ *nwc24Err = NWC24CreateDlVf(task, SIZE_VF); if (*nwc24Err < NWC24_OK) { /* If creation failed, handle it in the same way as you would if save data creation failed */ return FALSE; } *nwc24Err = NWC24SetDlKeys(publicKey, NULL); if (*nwc24Err < NWC24_OK) { /* If configuration failed, handle it in the same way as you would if save data creation failed */ return FALSE; } } return result; } #if 0 static void CheckErrors( NWC24DlTask* task ) { NWC24Err err; int globalErr = 0, count = 0; /* Get the error that occurred when the task was running */ err = NWC24GetDlError( task, &globalErr, &count ); VERIFY_NWC24ERR( err, NWC24_OK ); if (count > 0 && globalErr != 0) { /* Handle errors */ OSReport("error %d\n", globalErr); /* Clear error information stored in the task */ (void) NWC24ClearDlError( task ); } } #endif /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/