1: /*
     2:  *  Guitar-ZyX(tm)::MasterControlProgram - portable guitar F/X controller
     3:  *  Copyright (C) 2009  Douglas McClendon
     4:  *
     5:  *  This program is free software: you can redistribute it and/or modify
     6:  *  it under the terms of the GNU General Public License as published by
     7:  *  the Free Software Foundation, version 3 of the License.
     8:  *
     9:  *  This program is distributed in the hope that it will be useful,
    10:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    11:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12:  *  GNU General Public License for more details.
    13:  *
    14:  *  You should have received a copy of the GNU General Public License
    15:  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16: */
    17: /*
    18: #############################################################################
    19: #############################################################################
    20: ## 
    21: ## gzmcpc::mode__get_update: some source file
    22: ##
    23: #############################################################################
    24: ##
    25: ## Copyright 2008-2009 Douglas McClendon <dmc AT filteredperception DOT org>
    26: ##
    27: #############################################################################
    28: #############################################################################
    29: #
    30: */
    31: 
    32: 
    33: 
    34: 
    35: 
    36: #include <nds.h> 
    37: 
    38: #include <fat.h> 
    39: 
    40: 
    41: #include <stdio.h> 
    42: 
    43: #include <string.h> 
    44: 
    45: #include <sys/socket.h> 
    46: 
    47: #include <unistd.h> 
    48: 
    49: 
    50: 
    51: 
    52: #include "debug.h" 
    53: 
    54: #include "dmc.h" 
    55: 
    56: #include "graphics.h" 
    57: 
    58: #include "mcp.h" 
    59: 
    60: #include "modes.h" 
    61: 
    62: #include "mode__intro__main.h" 
    63: 
    64: #include "mode__get_update.h" 
    65: 
    66: #include "network.h" 
    67: 
    68: #include "cloader/arm9_loader.h" 
    69: 
    70: 
    71: #include "resources/bitmaps/guitar-zyx.splash.main.h" 
    72: 
    73: #include "resources/bitmaps/dlava.h" 
    74: 
    75: 
    76: 
    77: 
    78: 
    79: int overwrite_self_with_update;
    80: 
    81: 
    82: int update_file_size = 42;
    83: int download_bytes = 0;
    84: 
    85: 
    86: 
    87: 
    88: 
    89: void mode__get_update___init(void) {
    90: 
    91:   // to store the retrieved update
    92:   FILE *update_file;
    93: 
    94:   // packet structure for sending commands to the server
    95:   gzmcp_cmd newcmd;
    96: 
    97:   // for send() return values
    98:   int numbytes;
    99:   int rv, i;
   100: 
   101:   // for reading the update file
   102:   int bytes_to_read;
   103:   //  unsigned char read_buf[UPD_RD_BUF_SZ];
   104:   unsigned char *read_buf;
   105: 
   106:   // for magic return value checking
   107:   unsigned char magic_found;
   108:   unsigned char last_byte;
   109:   unsigned char second_to_last_byte;
   110: 
   111:   // for returned signature
   112:   uint32_t update_signature[3];
   113: 
   114: 
   115:   // initialize main screen
   116:   videoSetMode(MODE_5_2D);
   117: 
   118:   // map main screen background fourth (128k) region to vram bank A
   119:   vramSetBankA(VRAM_A_MAIN_BG_0x06060000);
   120:   
   121:   // set the secondary/sub screen for text and a background
   122:   videoSetModeSub(MODE_5_2D);
   123: 
   124:   // map sub screen background (only? 1/4?) to vram bank C
   125:   vramSetBankC(VRAM_C_SUB_BG);
   126: 
   127:   mcp_console_init(&bottom_screen,
   128: 		   MCP_SUB_SCREEN,
   129: 		   0,
   130: 		   1,
   131: 		   1,
   132: 		   BgType_Text4bpp, 
   133: 		   BgSize_T_256x256, 
   134: 		   31, 
   135: 		   0);
   136: 
   137:   // set printf sink
   138:   consoleSelect(&bottom_screen);
   139: 
   140:   // set console background layer to top priority
   141:   bgSetPriority(bottom_screen.bgId, 0);
   142: 
   143:   // note: this must be done _after_ consoleInit (as that resets it)
   144:   //       and _after_ loading our 8bit indexed bitmap reloads it
   145:   // set to black to allow renderer to really control
   146:   BG_PALETTE_SUB[255] = RGB15(0, 0, 0);
   147: 
   148:   bgShow(bottom_screen.bgId);
   149: 
   150:   // default to fully faded to black (31) not the opposite (0)
   151:   //  REG_BLDY = 31;
   152:   // XXX firstpass nofade
   153:   REG_BLDY = 0;
   154:   // but for credits, background starts unfaded
   155:   REG_BLDY_SUB = 0;
   156: 
   157:   // fade the mainscreen background to/from black, layer 3
   158:   REG_BLDCNT = BLEND_FADE_BLACK | BLEND_SRC_BG3;
   159:   // fade the lava background to/from black, layer 3
   160:   REG_BLDCNT_SUB = BLEND_FADE_BLACK | BLEND_SRC_BG3;
   161: 
   162:   // init subscreen layer/background 3 
   163:   // the mapbase offset of 24 here means 24*16k which means utilizing
   164:   // the 4th of the possible main background memory regions that vram
   165:   // bank A can be mapped to.  I.e. above we mapped to the 4th.  Had
   166:   // we mapped to the 1st, we would have used offset 0.  
   167:   // note: vram bank A is 128k, i.e. 8 * 16k.
   168:   // note: *16k is because of bitmap type, else would be *2k
   169:   bg3 = bgInit(3, BgType_Bmp16, BgSize_B16_256x256, 24, 0);
   170:   // its initial priority, lowest (to emphasize lack of other enabled layers)
   171:   // priorities 0..3, 0 highest priority
   172:   bgSetPriority(bg3, 3);
   173: 
   174:   bgHide(bg3);
   175: 
   176:   // load main splash screen into screen/background memory (bgs3)
   177:   // note: if I wanted to do this quickly/perfectly/doublebufferred somehow
   178:   //       I'm not sure if I'd need to tweak the bgInitSub offset or pointer
   179:   //       here or some such.  As it is, the fade to black ensures no tear
   180:   //       as this new image gets loaded into display memory.
   181:   decompress(guitar_zyx_splash_mainBitmap, 
   182: 	     (u16*)bgGetGfxPtr(bg3),  
   183: 	     LZ77Vram);
   184:   
   185:   bgShow(bg3);
   186: 
   187:   // note: using offset=4, because 4 will be 64k offset, where 31 above is 62k
   188:   // (thus above using only 2k? seems plausible with tiles for console text chars
   189:   bgs3 = bgInitSub(3, BgType_Bmp8, BgSize_B8_256x256, 4, 0);
   190:   // its initial priority, lowest (to emphasize lack of other enabled layers)
   191:   // priorities 0..3, 0 highest priority
   192:   bgSetPriority(bgs3, 2);
   193: 
   194:   bgHide(bgs3);
   195: 
   196:   // as per libnds doc on dma
   197:   DC_FlushRange(dlavaBitmap, 256*256);
   198:   dmaCopy(dlavaBitmap, bgGetGfxPtr(bgs3), 256*256);
   199:   DC_FlushRange(dlavaPal, 256*2);
   200:   dmaCopy(dlavaPal, BG_PALETTE_SUB, 256*2);
   201:   
   202:   bgShow(bgs3);
   203: 
   204:   //  BG_PALETTE_SUB[255] = RGB15(0, 0, 0);
   205:   // XXX: firstpass 
   206:   BG_PALETTE_SUB[255] = RGB15(0, 24, 0);
   207: 
   208:   //
   209:   // above is intro__credits with main splash, below is mode init
   210:   //
   211: 
   212:   // clear text screen
   213:   printf("\x1b[2J");
   214: 
   215:   printf("\x1b[11;0H  ============================  ");
   216:   printf("\x1b[13;0H                                ");
   217:   printf("\x1b[13;0H  >> sending update request...  ");
   218:   printf("\x1b[15;0H  ============================  ");
   219:   swiWaitForVBlank();
   220: 
   221:   // send getupdate command
   222:   newcmd.type = GZMCP_CMD_GETUPDATE;
   223:   // TODO: check for existing cached copy, and set these appropriately
   224:   newcmd.data.getupdate.size = 0;
   225:   newcmd.data.getupdate.hash = 0;
   226:   newcmd.data.getupdate.sample_data = 0;
   227:   rv = xmit_cmd(server_socket_fd, newcmd);
   228: 
   229:   if (rv != sizeof(gzmcp_cmd)) {
   230:     printf("\x1b[13;0H                            ");
   231:     printf("\x1b[13;0H  >> dbg:rv was %d / %d",
   232: 	   rv,
   233: 	   sizeof(gzmcp_cmd));
   234:     for (i = 0 ; i < 120 ; i++) {
   235:       swiWaitForVBlank();
   236:     }
   237:   }
   238: 
   239:   //
   240:   // receive update file from server
   241:   //
   242: 
   243:   // discard incoming data until magic is found
   244:   // todo: this could be a generic function with magic and socket_fd as arguments
   245:   // XXX: repitition of this status mechanism is temporary, to be replaced with
   246:   //      a user-abortable nonblocking inmplementation of this mode
   247:   printf("\x1b[11;0H  ============================  ");
   248:   printf("\x1b[13;0H                                ");
   249:   printf("\x1b[13;0H  >> waiting for server ...     ");
   250:   printf("\x1b[15;0H  ============================  ");
   251:   swiWaitForVBlank();
   252:   magic_found = 0;
   253:   last_byte = 0;
   254:   second_to_last_byte = 0;
   255:   while (!magic_found) {
   256:     second_to_last_byte = last_byte;
   257:     // recieve a byte
   258:     numbytes = recv(server_socket_fd,
   259: 		    (void *)&last_byte,
   260: 		    1, 
   261: 		    0);
   262: 
   263:     // check for errors
   264:     if (numbytes < 0) {
   265:       printf("\x1b[13;0H                              ");
   266:       printf("\x1b[13;0H  ~~ rcv mgc err:%d:", numbytes);
   267:       for (i = 0 ; i < 30 ; i++) {
   268: 	swiWaitForVBlank();
   269:       }
   270: 
   271:       perror("recv()");
   272:       //      die("get_update: waiting for return magic");
   273:       die();
   274:     }
   275:     
   276:     printf("\x1b[13;0H                              ");
   277:     printf("\x1b[13;0H  >> got a byte > %d", last_byte);
   278:     swiWaitForVBlank();
   279:     for (i = 0 ; i < 30 ; i++) {
   280:       swiWaitForVBlank();
   281:     }
   282: 
   283:     if ((last_byte == 24) && 
   284: 	(second_to_last_byte == 42)) {
   285:       printf("\x1b[13;0H                              ");
   286:       printf("\x1b[13;0H  >> connected to server");
   287:       swiWaitForVBlank();
   288:       magic_found = 1;
   289:     } 
   290:     
   291:   } // end while (!magic_found)
   292:   
   293:   // read file size, signature, and sample data
   294:   numbytes = recv(server_socket_fd,
   295: 		  (void *)&update_signature,
   296: 		  4 * 3, 
   297: 		  0);
   298:   // check for errors
   299:   if (numbytes < 0) {
   300:     perror("recv()");
   301:     //    die("get_update: waiting for return signature");
   302:     die();
   303:   } else if (numbytes != (4 * 3)) {
   304:     //    die("get_update: return signature incomplete %d/12 bytes received",
   305:     //	numbytes);
   306:     die();
   307:   }
   308:   
   309:   bytes_to_read = update_signature[0];
   310:   
   311:   printf("\x1b[13;0H                              ");
   312:   printf("\x1b[13;0H  >> update is %d KB",
   313: 	 bytes_to_read / 1024);
   314:   swiWaitForVBlank();
   315:   
   316:   for (i = 0 ; i < 10 ; i++) {
   317:     swiWaitForVBlank();
   318:   }
   319: 
   320:   // allocate read buffer
   321:   read_buf = (unsigned char*)malloc(UPD_RD_BUF_SZ);
   322:   if (read_buf == NULL) {
   323:     printf("\x1b[13;0H     ~~~~~~~~~~~~~~~~~~~~~~ ");
   324:     printf("\x1b[13;0H     failed to malloc rdbuf ");
   325:     die();
   326:     return;
   327:   }
   328: 
   329:   // open output file
   330:   update_file = fopen("/gzmcp/gzmcp-update.nds", "w");
   331:   
   332:   if (update_file == NULL) {
   333:     printf("\x1b[13;0H     ~~~~~~~~~~~~~~~~~~~~~~ ");
   334:     printf("\x1b[13;0H     ~ failed to open updst ");
   335:     return;
   336:   }
   337: 
   338:   // read up to UPD_RD_BUF_SZ at a time until done
   339:   bytes_to_read = update_signature[0];
   340:   while (bytes_to_read) {
   341:     numbytes = recv(server_socket_fd,
   342: 		    (void *)read_buf,
   343: 		    UPD_RD_BUF_SZ, 
   344: 		    0);
   345:     // check for errors
   346:     if (numbytes < 0) {
   347:       perror("recv()");
   348:       //      die("get_update: while getting update file data");
   349:       die();
   350:     }
   351:     
   352:     // libfat bug workaround
   353:     fseek(update_file,
   354: 	  0,
   355: 	  SEEK_SET);
   356:     fseek(update_file,
   357: 	  0,
   358: 	  SEEK_END);
   359:     // write data to file
   360:     // XXX major experiment, swapping 1 and numbytes (now undone)
   361:     fwrite(read_buf,
   362: 	   1,
   363: 	   numbytes,
   364: 	   update_file);
   365:     
   366:     // update amount of work left to do
   367:     bytes_to_read -= numbytes;
   368: 
   369:     // quick and dirty status update
   370:     printf("\x1b[13;0H                            ");
   371:     printf("\x1b[13;0H  >> %d KB to go...",
   372: 	   bytes_to_read / 1024);
   373:     swiWaitForVBlank();
   374:     
   375:   }
   376: 
   377:   // free read_buf
   378:   free(read_buf);
   379:   
   380:   // close output file
   381:   fclose(update_file);
   382: 
   383:   // shutdown application-level network state
   384:   netmode_go_offline();
   385: 
   386:   if (overwrite_self_with_update) {
   387:     // if user wanted to, overwrite ourselves with update (after backup)
   388: 
   389:     printf("\x1b[13;0H                            ");
   390:     printf("\x1b[13;0H  >> backing up self...");
   391:     swiWaitForVBlank();
   392: 
   393:     dmc_fs_cp("/gzmcp/gzmcp-client.nds",
   394: 	      "/gzmcp/gzmcp-client.bak");
   395: 
   396:     printf("\x1b[13;0H                            ");
   397:     printf("\x1b[13;0H  >> updating self...");
   398:     swiWaitForVBlank();
   399: 
   400:     dmc_fs_cp("/gzmcp/gzmcp-update.nds",
   401: 	      "/gzmcp/gzmcp-client.nds");
   402: 
   403:     printf("\x1b[13;0H                            ");
   404:     printf("\x1b[13;0H  >> cleaning up...");
   405:     swiWaitForVBlank();
   406: 
   407:     unlink("/gzmcp/gzmcp-update.nds");
   408: 
   409:     printf("\x1b[13;0H                            ");
   410:     printf("\x1b[13;0H  >> rebootstrapping...");
   411:     swiWaitForVBlank();
   412: 
   413:     execz("/gzmcp/gzmcp-client.nds", 0, NULL);
   414:   } else {
   415:     printf("\x1b[13;0H                            ");
   416:     printf("\x1b[13;0H  >> rebootstrapping...");
   417:     swiWaitForVBlank();
   418: 
   419:     execz("/gzmcp/gzmcp-update.nds", 0, NULL);
   420:   }
   421:   // error: code should not reach here
   422: }
   423: 
   424: void mode__get_update___top_renderer(void) {
   425:   
   426:   // 
   427:   // do top background fade
   428:   // 
   429:   if (mode_ms < GET_UPDATE__TOP_BG_FADE_IN_START_MS) {
   430:   } else if (mode_ms < (GET_UPDATE__TOP_BG_FADE_IN_START_MS + 
   431: 			GET_UPDATE__TOP_BG_FADE_IN_DURATION_MS)) {
   432:     // main screen bg fade
   433:     REG_BLDY = 31 - ((mode_ms - GET_UPDATE__TOP_BG_FADE_IN_START_MS) * 31 / 
   434: 		     GET_UPDATE__TOP_BG_FADE_IN_DURATION_MS);
   435: 
   436:   } else if (mode_ms < (GET_UPDATE__TOP_BG_FADE_IN_START_MS + 
   437: 			GET_UPDATE__TOP_BG_FADE_IN_DURATION_MS +
   438: 			GET_UPDATE__TOP_BG_HOLD_DURATION_MS)) {
   439:     REG_BLDY = 0;
   440:   } else if (mode_ms < (GET_UPDATE__TOP_BG_FADE_IN_START_MS + 
   441: 			GET_UPDATE__TOP_BG_FADE_IN_DURATION_MS +
   442: 			GET_UPDATE__TOP_BG_HOLD_DURATION_MS + 
   443: 			GET_UPDATE__TOP_BG_FADE_OUT_DURATION_MS)) {
   444:     REG_BLDY = (mode_ms - 
   445: 		(GET_UPDATE__TOP_BG_FADE_IN_START_MS + 
   446: 		 GET_UPDATE__TOP_BG_FADE_IN_DURATION_MS +
   447: 		 GET_UPDATE__TOP_BG_HOLD_DURATION_MS)) * 
   448:       31 / GET_UPDATE__TOP_BG_FADE_OUT_DURATION_MS;
   449:   }
   450: 
   451: }
   452: 
   453: void mode__get_update___bot_renderer(void) {
   454: 
   455:   unsigned char tfontint = 0;
   456: 
   457: 
   458:   // clear the console text
   459:   consoleClear();
   460: 
   461:   // 
   462:   // do bot background fade
   463:   // 
   464:   if (mode_ms < GET_UPDATE__BOT_BG_FADE_IN_START_MS) {
   465:   } else if (mode_ms < (GET_UPDATE__BOT_BG_FADE_IN_START_MS + 
   466: 			GET_UPDATE__BOT_BG_FADE_IN_DURATION_MS)) {
   467:     // main screen bg fade
   468:     REG_BLDY_SUB = 31 - ((mode_ms - GET_UPDATE__BOT_BG_FADE_IN_START_MS) * 31 / 
   469: 		     GET_UPDATE__BOT_BG_FADE_IN_DURATION_MS);
   470: 
   471:   } else if (mode_ms < (GET_UPDATE__BOT_BG_FADE_IN_START_MS + 
   472: 			GET_UPDATE__BOT_BG_FADE_IN_DURATION_MS +
   473: 			GET_UPDATE__BOT_BG_HOLD_DURATION_MS)) {
   474:     REG_BLDY_SUB = 0;
   475:   } else if (mode_ms < (GET_UPDATE__BOT_BG_FADE_IN_START_MS + 
   476: 			GET_UPDATE__BOT_BG_FADE_IN_DURATION_MS +
   477: 			GET_UPDATE__BOT_BG_HOLD_DURATION_MS + 
   478: 			GET_UPDATE__BOT_BG_FADE_OUT_DURATION_MS)) {
   479:     REG_BLDY_SUB = (mode_ms - 
   480: 		(GET_UPDATE__BOT_BG_FADE_IN_START_MS + 
   481: 		 GET_UPDATE__BOT_BG_FADE_IN_DURATION_MS +
   482: 		 GET_UPDATE__BOT_BG_HOLD_DURATION_MS)) * 
   483:       31 / GET_UPDATE__BOT_BG_FADE_OUT_DURATION_MS;
   484:   }
   485: 
   486: 
   487:   // 
   488:   // do bottom text fade
   489:   // 
   490:   if (mode_ms < GET_UPDATE__BOT_TXT_FADE_IN_START_MS) {
   491:   } else if (mode_ms < (GET_UPDATE__BOT_TXT_FADE_IN_START_MS + 
   492: 			GET_UPDATE__BOT_TXT_FADE_IN_DURATION_MS)) {
   493:     tfontint = (unsigned char)((int)(font_intensity) * 
   494: 			       (mode_ms - GET_UPDATE__BOT_TXT_FADE_IN_START_MS) / 
   495: 			       GET_UPDATE__BOT_TXT_FADE_IN_DURATION_MS);
   496:   } else if (mode_ms < (GET_UPDATE__BOT_TXT_FADE_IN_START_MS + 
   497: 			GET_UPDATE__BOT_TXT_FADE_IN_DURATION_MS +
   498: 			GET_UPDATE__BOT_TXT_HOLD_DURATION_MS)) {
   499:     tfontint = (unsigned char)((int)font_intensity * 1);
   500:   } else if (mode_ms < (GET_UPDATE__BOT_TXT_FADE_IN_START_MS + 
   501: 			GET_UPDATE__BOT_TXT_FADE_IN_DURATION_MS +
   502: 			GET_UPDATE__BOT_TXT_HOLD_DURATION_MS + 
   503: 			GET_UPDATE__BOT_TXT_FADE_OUT_DURATION_MS)) {
   504:     tfontint = ((unsigned char)((int)font_intensity * 1)) -
   505:       (unsigned char)((int)(font_intensity) * 
   506: 		      (mode_ms - (GET_UPDATE__BOT_TXT_FADE_IN_START_MS +
   507: 				  GET_UPDATE__BOT_TXT_FADE_IN_DURATION_MS +
   508: 				  GET_UPDATE__BOT_TXT_HOLD_DURATION_MS)) /
   509: 		      GET_UPDATE__BOT_TXT_FADE_OUT_DURATION_MS);
   510:   }
   511: 
   512:   // set the font color from the calculated intensity (greenish)
   513:   BG_PALETTE_SUB[255] = RGB15(tfontint / 3,
   514: 			      tfontint,
   515: 			      tfontint / 3);
   516: 
   517:   // tell user they can skip the intro
   518:   printf("\x1b[05;0H     ~~~~~~~~~~~~~~~~~~~~~~ ");
   519:   printf("\x1b[06;0H     ~~~~~~~~~~~~~~~~~~~~~~ ");
   520: 
   521:   printf("\x1b[08;0H           Downloading      ");
   522: 
   523:   printf("\x1b[10;0H        Updated Software    ");
   524: 
   525:   printf("\x1b[12;0H     ~~~~~~~~~~~~~~~~~~~~~~ ");
   526:   printf("\x1b[13;0H     ~~~~~~~~~~~~~~~~~~~~~~ ");
   527: 
   528: 
   529: }
   530: 
   531: void mode__get_update___input_handler(void) {
   532:   mode__intro__main___input_handler();
   533: }
   534: 
   535: void mode__get_update___idle(void) {
   536: }
   537: 
   538: void mode__get_update___exit(void) {
   539: 
   540: }
   541: