about summary refs log tree commit diff stats
path: root/source/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/main.c')
-rw-r--r--source/main.c514
1 files changed, 362 insertions, 152 deletions
diff --git a/source/main.c b/source/main.c index ad34eff..8a9e672 100644 --- a/source/main.c +++ b/source/main.c
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (c) 2017 slipstream/RoL 2 * Copyright (C) 2017 hatkirby
3 * Copyright (C) 2017 slipstream/RoL
3 * Copyright (C) 2016 FIX94 4 * Copyright (C) 2016 FIX94
4 * 5 *
5 * This software may be modified and distributed under the terms 6 * This software may be modified and distributed under the terms
@@ -7,13 +8,12 @@
7 */ 8 */
8#include <gccore.h> 9#include <gccore.h>
9#include <stdio.h> 10#include <stdio.h>
10#include <malloc.h> 11#include <stdlib.h>
11#include <unistd.h> 12#include <unistd.h>
12#include <string.h> 13#include <string.h>
13#include <stdlib.h> 14#include <malloc.h>
14#include <sys/types.h> 15#include "link.h"
15#include <sys/stat.h> 16#include "encoding.h"
16#include <fcntl.h>
17 17
18//from my tests 50us seems to be the lowest 18//from my tests 50us seems to be the lowest
19//safe si transfer delay in between calls 19//safe si transfer delay in between calls
@@ -24,10 +24,11 @@ extern u32 gba_mb_gba_size;
24 24
25void printmain() 25void printmain()
26{ 26{
27 printf("\x1b[2J"); 27 printf("\x1b[2J");
28 printf("\x1b[37m"); 28 printf("\x1b[37m");
29 printf("Pokemon Gen 3 GBA Multiboot PoC by slipstream/RoL\n"); 29 printf("Pokemon Gen III Data Extractor by hatkirby\n");
30 printf("Based on GBA Link Cable Dumper by FIX94\n\n"); 30 printf("Based on gba-gen3multiboot by slipstream/RoL\n");
31 printf("Based on GBA Link Cable Dumper v1.6 by FIX94\n");
31} 32}
32 33
33u8 *resbuf,*cmdbuf; 34u8 *resbuf,*cmdbuf;
@@ -35,285 +36,494 @@ u8 *resbuf,*cmdbuf;
35volatile u32 transval = 0; 36volatile u32 transval = 0;
36void transcb(s32 chan, u32 ret) 37void transcb(s32 chan, u32 ret)
37{ 38{
38 transval = 1; 39 transval = 1;
39} 40}
40 41
41volatile u32 resval = 0; 42volatile u32 resval = 0;
42void acb(s32 res, u32 val) 43void acb(s32 res, u32 val)
43{ 44{
44 resval = val; 45 resval = val;
45} 46}
46 47
47unsigned int docrc(u32 crc,u32 val) { 48unsigned int docrc(u32 crc,u32 val)
49{
48 u32 result; 50 u32 result;
49 51
50 result = val ^ crc; 52 result = val ^ crc;
51 for (int i = 0; i < 0x20; i++) { 53 for (int i = 0; i < 0x20; i++)
52 if (result & 1) { 54 {
55 if (result & 1)
56 {
53 result >>= 1; 57 result >>= 1;
54 result ^= 0xA1C1; 58 result ^= 0xA1C1;
55 } else result >>= 1; 59 } else {
60 result >>= 1;
61 }
56 } 62 }
63
57 return result; 64 return result;
58} 65}
59 66
60void endproc() 67void doreset()
61{ 68{
62 printf("Start pressed, exit\n"); 69 cmdbuf[0] = 0xFF; //reset
63 VIDEO_WaitVSync(); 70 transval = 0;
64 VIDEO_WaitVSync(); 71 SI_Transfer(1, cmdbuf, 1, resbuf, 3, transcb, SI_TRANS_DELAY);
65 exit(0); 72
73 while (transval == 0);
66} 74}
67 75
68void doreset() 76void getstatus()
69{ 77{
70 cmdbuf[0] = 0xFF; //reset 78 cmdbuf[0] = 0; //status
71 transval = 0; 79 transval = 0;
72 SI_Transfer(1,cmdbuf,1,resbuf,3,transcb,SI_TRANS_DELAY); 80 SI_Transfer(1, cmdbuf, 1, resbuf, 3, transcb, SI_TRANS_DELAY);
73 while(transval == 0) ; 81
82 while (transval == 0);
74} 83}
75 84
76void getstatus() 85void endproc()
77{ 86{
78 cmdbuf[0] = 0; //status 87 doreset();
79 transval = 0; 88 printf("Start pressed, exit\n");
80 SI_Transfer(1,cmdbuf,1,resbuf,3,transcb,SI_TRANS_DELAY); 89 VIDEO_WaitVSync();
81 while(transval == 0) ; 90 VIDEO_WaitVSync();
91 exit(0);
82} 92}
83 93
84u32 recv() 94u32 recv()
85{ 95{
86 memset(resbuf,0,32); 96 memset(resbuf,0,32);
87 cmdbuf[0]=0x14; //read 97 cmdbuf[0]=0x14; //read
88 transval = 0; 98 transval = 0;
89 SI_Transfer(1,cmdbuf,1,resbuf,5,transcb,SI_TRANS_DELAY); 99 SI_Transfer(1, cmdbuf, 1, resbuf, 5, transcb, SI_TRANS_DELAY);
90 while(transval == 0) ; 100
91 return *(vu32*)resbuf; 101 while (transval == 0);
102 printf("%08lx\n", *(vu32*)resbuf);
103 return *(vu32*)resbuf;
92} 104}
93 105
94void send(u32 msg) 106void send(u32 msg)
95{ 107{
96 cmdbuf[0]=0x15;cmdbuf[1]=(msg>>0)&0xFF;cmdbuf[2]=(msg>>8)&0xFF; 108 cmdbuf[0] = 0x15;
97 cmdbuf[3]=(msg>>16)&0xFF;cmdbuf[4]=(msg>>24)&0xFF; 109 cmdbuf[1] = (msg >> 0) & 0xFF;
98 transval = 0; 110 cmdbuf[2] = (msg >> 8) & 0xFF;
99 resbuf[0] = 0; 111 cmdbuf[3] = (msg >> 16) & 0xFF;
100 SI_Transfer(1,cmdbuf,5,resbuf,1,transcb,SI_TRANS_DELAY); 112 cmdbuf[4] = (msg >> 24) & 0xFF;
101 while(transval == 0) ; 113
114 transval = 0;
115 resbuf[0] = 0;
116 SI_Transfer(1, cmdbuf, 5, resbuf, 1, transcb, SI_TRANS_DELAY);
117
118 while (transval == 0);
102} 119}
103 120
104void warnError(char *msg) 121void warnError(char *msg)
105{ 122{
106 puts(msg); 123 puts(msg);
107 VIDEO_WaitVSync(); 124 VIDEO_WaitVSync();
108 VIDEO_WaitVSync(); 125 VIDEO_WaitVSync();
109 sleep(2); 126 sleep(2);
110} 127}
128
111void fatalError(char *msg) 129void fatalError(char *msg)
112{ 130{
113 puts(msg); 131 puts(msg);
114 VIDEO_WaitVSync(); 132 VIDEO_WaitVSync();
115 VIDEO_WaitVSync(); 133 VIDEO_WaitVSync();
116 sleep(5); 134 sleep(5);
117 exit(0); 135 exit(0);
118} 136}
119 137
120u32 genKeyA() { 138u32 genKeyA()
139{
121 u32 retries = 0; 140 u32 retries = 0;
122 while (true) { 141
142 for (;;)
143 {
123 u32 key = 0; 144 u32 key = 0;
124 if (retries > 32) { 145
146 if (retries > 32)
147 {
125 key = 0xDD654321; 148 key = 0xDD654321;
126 } else { 149 } else {
127 key = (rand() & 0x00ffffff) | 0xDD000000; 150 key = (rand() & 0x00ffffff) | 0xDD000000;
128 } 151 }
152
129 u32 unk = (key % 2 != 0); 153 u32 unk = (key % 2 != 0);
130 u32 v12 = key; 154 u32 v12 = key;
131 for (u32 v13 = 1; v13 < 32; v13++) { 155 for (u32 v13 = 1; v13 < 32; v13++)
156 {
132 v12 >>= 1; 157 v12 >>= 1;
133 unk += (v12 % 2 != 0); 158 unk += (v12 % 2 != 0);
134 } 159 }
135 if ((unk >= 10 && unk <= 24)) { 160
136 if (retries > 4) printf("KeyA retries = %d",retries); 161 if ((unk >= 10 && unk <= 24))
137 printf("KeyA = 0x%08x\n",key); 162 {
163 if (retries > 4)
164 {
165 printf("KeyA retries = %ld", retries);
166 }
167
168 printf("KeyA = 0x%08lx\n", key);
169
138 return key; 170 return key;
139 } 171 }
172
140 retries++; 173 retries++;
141 } 174 }
142} 175}
143 176
144u32 checkKeyB(u32 KeyBRaw) { 177u32 checkKeyB(u32 KeyBRaw)
145 if ((KeyBRaw & 0xFF) != 0xEE) { 178{
146 printf("Invalid KeyB - lowest 8 bits should be 0xEE, actually 0x%02x\n",((u8)(KeyBRaw))); 179 if ((KeyBRaw & 0xFF) != 0xEE)
180 {
181 printf("Invalid KeyB - lowest 8 bits should be 0xEE, actually 0x%02x\n",
182 ((u8)(KeyBRaw)));
183
147 return 0; 184 return 0;
148 } 185 }
186
149 u32 KeyB = KeyBRaw & 0xffffff00; 187 u32 KeyB = KeyBRaw & 0xffffff00;
150 u32 val = KeyB; 188 u32 val = KeyB;
151 u32 unk = (val < 0); 189 u32 unk = (val < 0);
152 for (u32 i = 1; i < 24; i++) { 190 for (u32 i = 1; i < 24; i++)
191 {
153 val <<= 1; 192 val <<= 1;
154 unk += (val < 0); 193 unk += (val < 0);
155 } 194 }
156 if (unk > 14) { 195
157 printf("Invalid KeyB - high 24 bits bad: 0x%08x\n",KeyB); 196 if (unk > 14)
197 {
198 printf("Invalid KeyB - high 24 bits bad: 0x%08lx\n", KeyB);
199
158 return 0; 200 return 0;
159 } 201 }
160 printf("Valid KeyB: 0x%08x\n",KeyB); 202
203 printf("Valid KeyB: 0x%08lx\n", KeyB);
204
161 return KeyB; 205 return KeyB;
162} 206}
163 207
164u32 deriveKeyC(u32 keyCderive, u32 kcrc) { 208u32 deriveKeyC(u32 keyCderive, u32 kcrc)
209{
165 u32 keyc = 0; 210 u32 keyc = 0;
166 u32 keyCi = 0; 211 u32 keyCi = 0;
167 do { 212
213 do
214 {
168 u32 v5 = 0x1000000 * keyCi - 1; 215 u32 v5 = 0x1000000 * keyCi - 1;
169 u32 keyCattempt = docrc(kcrc,v5); 216 u32 keyCattempt = docrc(kcrc,v5);
170 //printf("i = %d; keyCderive = %08x; keyCattempt = %08x\n",keyCi,keyCderive,keyCattempt); 217
171 if (keyCderive == keyCattempt) { 218 if (keyCderive == keyCattempt)
219 {
172 keyc = v5; 220 keyc = v5;
173 printf("Found keyC: %08x\n",keyc); 221
222 printf("Found keyC: %08lx\n",keyc);
223
174 return keyc; 224 return keyc;
175 } 225 }
226
176 keyCi++; 227 keyCi++;
177 } while (keyCi < 256); 228 } while (keyCi < 256);
229
178 return keyc; 230 return keyc;
179} 231}
180 232
181int main(int argc, char *argv[]) 233u32 getMsg()
182{ 234{
183 void *xfb = NULL; 235 u32 val = 0;
184 GXRModeObj *rmode = NULL; 236 while (val == 0)
185 VIDEO_Init();
186 rmode = VIDEO_GetPreferredMode(NULL);
187 xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
188 VIDEO_Configure(rmode);
189 VIDEO_SetNextFramebuffer(xfb);
190 VIDEO_SetBlack(FALSE);
191 VIDEO_Flush();
192 VIDEO_WaitVSync();
193 if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();
194 int x = 24, y = 32, w, h;
195 w = rmode->fbWidth - (32);
196 h = rmode->xfbHeight - (48);
197 CON_InitEx(rmode, x, y, w, h);
198 VIDEO_ClearFrameBuffer(rmode, xfb, COLOR_BLACK);
199 PAD_Init();
200 cmdbuf = memalign(32,32);
201 resbuf = memalign(32,32);
202 int i;
203 while(1)
204 { 237 {
205 printmain(); 238 val = __builtin_bswap32(recv());
206 printf("Waiting for a GBA in port 2...\n"); 239 sleep(1);
207 resval = 0; 240 }
241
242 send(0);
243 while (recv()!=0) {sleep(1);};
244 send(0);
245
246 return val;
247}
248
249int main(int argc, char *argv[])
250{
251 void *xfb = NULL;
252 GXRModeObj *rmode = NULL;
253 VIDEO_Init();
254 rmode = VIDEO_GetPreferredMode(NULL);
255 xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
256 VIDEO_Configure(rmode);
257 VIDEO_SetNextFramebuffer(xfb);
258 VIDEO_SetBlack(FALSE);
259 VIDEO_Flush();
260 VIDEO_WaitVSync();
261 if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();
262 int x = 24, y = 32, w, h;
263 w = rmode->fbWidth - (32);
264 h = rmode->xfbHeight - (48);
265 CON_InitEx(rmode, x, y, w, h);
266 VIDEO_ClearFrameBuffer(rmode, xfb, COLOR_BLACK);
267 PAD_Init();
268 cmdbuf = memalign(32,32);
269 resbuf = memalign(32,32);
208 270
209 SI_GetTypeAsync(1,acb); 271 for (;;)
210 while(1) 272 {
273 printmain();
274
275 printf("Press A to begin, press Start to quit.\n");
276 if (waitForButtons(PAD_BUTTON_A | PAD_BUTTON_START) & PAD_BUTTON_START)
211 { 277 {
212 if(resval) 278 endproc();
213 {
214 if(resval == 0x80 || resval & 8)
215 {
216 resval = 0;
217 SI_GetTypeAsync(1,acb);
218 }
219 else if(resval)
220 break;
221 }
222 PAD_ScanPads();
223 VIDEO_WaitVSync();
224 if(PAD_ButtonsDown(0) & PAD_BUTTON_START)
225 endproc();
226 } 279 }
227 if (resval & SI_GBA) 280
228 { 281 printf("Waiting for a GBA in port 2...\n");
229 printf("GBA Found! Waiting on BIOS\n"); 282 resval = 0;
283
284 SI_GetTypeAsync(1,acb);
285 while(1)
286 {
287 if (resval)
288 {
289 if (resval == 0x80 || resval & 8)
290 {
291 resval = 0;
292 SI_GetTypeAsync(1,acb);
293 } else if (resval)
294 {
295 break;
296 }
297 }
298
299 PAD_ScanPads();
300 VIDEO_WaitVSync();
301 if (PAD_ButtonsHeld(0) & PAD_BUTTON_START)
302 {
303 getstatus();
304 endproc();
305 }
306 }
307
308 if (resval & SI_GBA)
309 {
310 printf("GBA Found! Waiting on BIOS\n");
311
230 resbuf[2]=0; 312 resbuf[2]=0;
231 u32 oldresult = 0; 313
232 u32 newresult = 0;
233 // wait for the BIOS to hand over to the game 314 // wait for the BIOS to hand over to the game
234 do { 315 do
316 {
235 doreset(); 317 doreset();
236 } while (!(resbuf[1] > 4)); 318 } while (!(resbuf[1] > 4));
319
237 printf("BIOS handed over to game, waiting on game\n"); 320 printf("BIOS handed over to game, waiting on game\n");
321
238 do 322 do
239 { 323 {
240 doreset(); 324 doreset();
241 } while((resbuf[0] != 0) || !(resbuf[2]&0x10)); 325 } while ((resbuf[0] != 0) || !(resbuf[2] & 0x10));
326
242 // receive the game-code from GBA side. 327 // receive the game-code from GBA side.
243 u32 gamecode = recv(); 328 u32 gamecode = recv();
329
244 printf("Ready, sending multiboot ROM\n"); 330 printf("Ready, sending multiboot ROM\n");
331
245 unsigned int sendsize = ((gba_mb_gba_size+7)&~7); 332 unsigned int sendsize = ((gba_mb_gba_size+7)&~7);
333
246 // generate KeyA 334 // generate KeyA
247 unsigned int ourkey = genKeyA(); 335 unsigned int ourkey = genKeyA();
336
248 //printf("Our Key: %08x\n", ourkey); 337 //printf("Our Key: %08x\n", ourkey);
249 printf("Sending game code that we got: 0x%08x\n",__builtin_bswap32(gamecode)); 338 printf("Sending game code that we got: 0x%08lx\n",
339 __builtin_bswap32(gamecode));
340
250 // send the game code back, then KeyA. 341 // send the game code back, then KeyA.
251 send(__builtin_bswap32(gamecode)); 342 send(__builtin_bswap32(gamecode));
252 send(ourkey); 343 send(ourkey);
253 // get KeyB from GBA, check it to make sure its valid, then xor with KeyA to derive the initial CRC value and the sessionkey. 344
345 // get KeyB from GBA, check it to make sure its valid, then xor with KeyA
346 // to derive the initial CRC value and the sessionkey.
254 u32 sessionkeyraw = 0; 347 u32 sessionkeyraw = 0;
255 do { 348 do
349 {
256 sessionkeyraw = recv(); 350 sessionkeyraw = recv();
257 } while (sessionkeyraw == gamecode); 351 } while (sessionkeyraw == gamecode);
352
258 sessionkeyraw = checkKeyB(__builtin_bswap32(sessionkeyraw)); 353 sessionkeyraw = checkKeyB(__builtin_bswap32(sessionkeyraw));
354 if (sessionkeyraw == 0)
355 {
356 warnError("Cannot continue.\n");
357
358 continue;
359 }
360
259 u32 sessionkey = sessionkeyraw ^ ourkey; 361 u32 sessionkey = sessionkeyraw ^ ourkey;
260 u32 kcrc = sessionkey; 362 u32 kcrc = sessionkey;
261 printf("start kCRC=%08x\n",kcrc); 363 printf("start kCRC=%08lx\n",kcrc);
364
262 sessionkey = (sessionkey*0x6177614b)+1; 365 sessionkey = (sessionkey*0x6177614b)+1;
366
263 // send hacked up send-size in uint32s 367 // send hacked up send-size in uint32s
264 u32 hackedupsize = (sendsize >> 3) - 1; 368 u32 hackedupsize = (sendsize >> 3) - 1;
265 printf("Sending hacked up size 0x%08x\n",hackedupsize); 369
370 printf("Sending hacked up size 0x%08lx\n",hackedupsize);
266 send(hackedupsize); 371 send(hackedupsize);
372
267 //unsigned int fcrc = 0x00bb; 373 //unsigned int fcrc = 0x00bb;
268 // send over multiboot binary header, in the clear until the end of the nintendo logo. 374 // send over multiboot binary header, in the clear until the end of the
269 // GBA checks this, if nintendo logo does not match the one in currently inserted cart's ROM, it will not accept any more data. 375 // nintendo logo. GBA checks this, if nintendo logo does not match the
270 for(i = 0; i < 0xA0; i+=4) { 376 // one in currently inserted cart's ROM, it will not accept any more data.
377 for (int i = 0; i < 0xA0; i+=4)
378 {
271 vu32 rom_dword = *(vu32*)(gba_mb_gba+i); 379 vu32 rom_dword = *(vu32*)(gba_mb_gba+i);
272 send(__builtin_bswap32(rom_dword)); 380 send(__builtin_bswap32(rom_dword));
273 } 381 }
382
274 printf("\n"); 383 printf("\n");
275 printf("Header done! Sending ROM...\n"); 384 printf("Header done! Sending ROM...\n");
276 // Add each uint32 of the multiboot image to the checksum, encrypt the uint32 with the session key, increment the session key, send the encrypted uint32. 385
277 for(i = 0xA0; i < sendsize; i+=4) 386 // Add each uint32 of the multiboot image to the checksum, encrypt the
387 // uint32 with the session key, increment the session key, send the
388 // encrypted uint32.
389 for (int i = 0xA0; i < sendsize; i+=4)
278 { 390 {
279 u32 dec = ( 391 u32 dec = (
280 ((gba_mb_gba[i+3]) << 24) & 0xff000000 | 392 (((gba_mb_gba[i+3]) << 24) & 0xff000000) |
281 ((gba_mb_gba[i+2]) << 16) & 0x00ff0000 | 393 (((gba_mb_gba[i+2]) << 16) & 0x00ff0000) |
282 ((gba_mb_gba[i+1]) << 8) & 0x0000ff00 | 394 (((gba_mb_gba[i+1]) << 8) & 0x0000ff00) |
283 ((gba_mb_gba[i]) << 0) & 0x000000ff 395 (((gba_mb_gba[i]) << 0) & 0x000000ff)
284 ); 396 );
397
285 u32 enc = (dec - kcrc) ^ sessionkey; 398 u32 enc = (dec - kcrc) ^ sessionkey;
286 kcrc=docrc(kcrc,dec); 399 kcrc = docrc(kcrc,dec);
287 sessionkey = (sessionkey*0x6177614B)+1; 400 sessionkey = (sessionkey * 0x6177614B) + 1;
288 //enc^=((~(i+(0x20<<20)))+1); 401 //enc^=((~(i+(0x20<<20)))+1);
289 //enc^=0x6f646573;//0x20796220; 402 //enc^=0x6f646573;//0x20796220;
403
290 send(enc); 404 send(enc);
291 } 405 }
406
292 //fcrc |= (sendsize<<16); 407 //fcrc |= (sendsize<<16);
293 printf("ROM done! CRC: %08x\n", kcrc); 408 printf("ROM done! CRC: %08lx\n", kcrc);
294 //get crc back (unused) 409 //get crc back (unused)
410
295 // Get KeyC derivation material from GBA (eventually) 411 // Get KeyC derivation material from GBA (eventually)
296 u32 keyCderive = 0; 412 u32 keyCderive = 0;
297 do { 413 do
414 {
298 keyCderive = recv(); 415 keyCderive = recv();
299 } while (keyCderive <= 0xfeffffff); 416 } while (keyCderive <= 0xfeffffff);
417
300 keyCderive = __builtin_bswap32(keyCderive); 418 keyCderive = __builtin_bswap32(keyCderive);
301 keyCderive >>= 8; 419 keyCderive >>= 8;
302 printf("KeyC derivation material: %08x\n",keyCderive); 420
303 421 printf("KeyC derivation material: %08lx\n",keyCderive);
304 // (try to) find the KeyC, using the checksum of the multiboot image, and the derivation material that GBA sent to us 422
305 423 // (try to) find the KeyC, using the checksum of the multiboot image, and
424 // the derivation material that GBA sent to us
306 u32 keyc = deriveKeyC(keyCderive,kcrc); 425 u32 keyc = deriveKeyC(keyCderive,kcrc);
307 if (keyc == 0) printf("Could not find keyC - kcrc=0x%08x\n",kcrc); 426 if (keyc == 0)
308 427 {
309 // derive the boot key from the found KeyC, and send to GBA. if this is not correct, GBA will not jump to the multiboot image it was sent. 428 printf("Could not find keyC - kcrc=0x%08lx\n",kcrc);
429 warnError("Cannot continue.\n");
430
431 continue;
432 }
433
434 // derive the boot key from the found KeyC, and send to GBA. if this is
435 // not correct, GBA will not jump to the multiboot image it was sent.
310 u32 bootkey = docrc(0xBB,keyc) | 0xbb000000; 436 u32 bootkey = docrc(0xBB,keyc) | 0xbb000000;
311 printf("BootKey = 0x%08x\n",bootkey); 437 printf("BootKey = 0x%08lx\n",bootkey);
438
312 send(bootkey); 439 send(bootkey);
313 440 sleep(2);
314 printf("Done! Press any key to start sending again.\n"); 441
315 do { PAD_ScanPads(); } while (!PAD_ButtonsDown(0)); 442 printf("Waiting for GBA...\n");
316 } 443 while (recv() != 0) {sleep(1);};
317 } 444 send(0);
318 return 0; 445
446 VIDEO_WaitVSync();
447
448 // Get game
449 // -1 - unsupported game
450 // 1 - Ruby
451 // 2 - Sapphire
452 // 3 - FireRed
453 // 4 - LeafGreen
454 // 5 - Emerald
455 u32 gameId = getMsg();
456 if (gameId == -1)
457 {
458 warnError("ERROR: Unsupported GBA game inserted!\n");
459
460 continue;
461 }
462
463 printf("\nPokemon ");
464 switch (gameId)
465 {
466 case 1: printf("Ruby"); break;
467 case 2: printf("Sapphire"); break;
468 case 3: printf("FireRed"); break;
469 case 4: printf("LeafGreen"); break;
470 case 5: printf("Emerald"); break;
471 }
472
473 printf("\n");
474 VIDEO_WaitVSync();
475
476 u32 isValid = getMsg();
477 if (isValid == -1)
478 {
479 warnError("ERROR: Unsupported game version inserted!\n");
480
481 continue;
482 }
483
484 // Get trainer name
485 u8 trainerName[8];
486
487 u32 tnd = getMsg();
488 trainerName[0] = (tnd & 0xFF000000) >> 24;
489 trainerName[1] = (tnd & 0x00FF0000) >> 16;
490 trainerName[2] = (tnd & 0x0000FF00) >> 8;
491 trainerName[3] = (tnd & 0x000000FF);
492
493 tnd = getMsg();
494 trainerName[4] = (tnd & 0xFF000000) >> 24;
495 trainerName[5] = (tnd & 0x00FF0000) >> 16;
496 trainerName[6] = (tnd & 0x0000FF00) >> 8;
497 trainerName[7] = (tnd & 0x000000FF);
498
499 // Get trainer ID
500 u32 trainerId = getMsg();
501
502 printf("Trainer: ");
503
504 for (int i = 0; i < 8; i++)
505 {
506 if (trainerName[i] == 0xFF)
507 {
508 break;
509 } else {
510 printf("%c", debugGen3Decode(trainerName[i]));
511 }
512 }
513
514 printf(" (%ld)\n", trainerId);
515
516 // Wait for confirmation.
517 printf("Press A to import the data from this game.\n");
518 printf("Press B to cancel.\n");
519 VIDEO_WaitVSync();
520
521 if (waitForButtons(PAD_BUTTON_A | PAD_BUTTON_B) & PAD_BUTTON_B)
522 {
523 continue;
524 }
525 }
526 }
527
528 return 0;
319} 529}