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: