1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - WBT - demos - wbt-1
3   File:     main.c
4 
5   Copyright 2006-2008 Nintendo. 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   $Date:: 2008-12-16#$
14   $Rev: 9665 $
15   $Author: kitase_hirotake $
16  *---------------------------------------------------------------------------*/
17 
18 /*---------------------------------------------------------------------------*
19     A simple functional sample of wireless communication using the WM library.
20     It automatically connects to the wbt-demo in the area.
21 
22     HOWTO:
23         1. Press the A Button to start communications as a parent.
24            As soon as a nearby child that has the same wbt-1 demo is found, it automatically begins.
25             Communication with up to 15 children is possible at the same time.
26         2. Press the B Button to start communications as a child.
27            As soon as a nearby parent that has the same wbt-1 demo is found, it automatically begins.
28 
29         3. If the START button is pressed during a busy screen while a connection is being established, or during a communication screen after a connection is established, the connection is reset, and the display returns to the initial screen.
30 
31  *---------------------------------------------------------------------------*/
32 
33 #ifdef SDK_TWL
34 #include <twl.h>
35 #else
36 #include <nitro.h>
37 #endif
38 
39 #include <nitro/wm.h>
40 #include <nitro/wbt.h>
41 
42 #include    "font.h"
43 #include    "text.h"
44 #include    "wh.h"
45 #include    "bt.h"
46 
47 
48 #define MIYA_PRINT 1
49 
50 
51 /*---------------------------------------------------------------------------*
52     Constant Definitions
53  *---------------------------------------------------------------------------*/
54 #define     KEY_REPEAT_START    25     // Number of frames until key repeat starts
55 #define     KEY_REPEAT_SPAN     10     // Number of frames between key repeats
56 
57 // Game information
58 /* Constants related to MP communications */
59 #define     DEFAULT_GGID            0x003fff30
60 
61 /*---------------------------------------------------------------------------*
62     Structure Definitions
63  *---------------------------------------------------------------------------*/
64 // Key input data
65 typedef struct KeyInfo
66 {
67     u16     cnt;                       // Unprocessed input value
68     u16     trg;                       // Push trigger input
69     u16     up;                        // Release trigger input
70     u16     rep;                       // Press and hold repeat input
71 
72 }
73 KeyInfo;
74 
75 
76 /*---------------------------------------------------------------------------*
77     Internal Function Definitions
78  *---------------------------------------------------------------------------*/
79 static void ModeSelect(void);          // Parent/child select screen
80 static void ModeStartParent(void);     // State with a finished calculation of the channel with a low usage rate
81 static void ModeError(void);           // Error display screen
82 static void ModeWorking(void);         // Busy screen
83 static void ModeParent(void);          // Parent communications screen
84 static void ModeChild(void);           // Child communications screen
85 static void VBlankIntr(void);          // V-Blank interrupt handler
86 
87 // Functions called when receiving data
88 static void ParentReceiveCallback(u16 aid, u16 *data, u16 length);
89 static void ChildReceiveCallback(u16 aid, u16 *data, u16 length);
90 
91 // Function called when data is sent
92 void    ParentSendCallback(void);
93 void    ChildSendCallback(void);
94 
95 // Block transfer status notification function
96 static void BlockTransferCallback(void *arg);
97 static void SendCallback(BOOL result);
98 
99 // General purpose subroutines
100 static void KeyRead(KeyInfo * pKey);
101 static void ClearString(int vram_num);
102 static void PrintString(s16 x, s16 y, u8 palette, char *text, ...);
103 static void InitializeAllocateSystem(void);
104 
105 
106 /*---------------------------------------------------------------------------*
107     Internal Variable Definitions
108  *---------------------------------------------------------------------------*/
109 static KeyInfo gKey;                   // Key input
110 static s32 gFrame;                     // Frame counter
111 
112 // Send/receive buffer for display
113 static u8 gSendBuf[256] ATTRIBUTE_ALIGN(32);
114 static BOOL gRecvFlag[1 + WM_NUM_MAX_CHILD];
115 
116 static int send_counter[16];
117 static int recv_counter[16];
118 
119 static BOOL gFirstSendAtChild = TRUE;
120 
121 #define PRINTF mprintf
122 
123 #define VRAM_SIZE 2*32*32
124 static u8 g_screen[NUM_OF_SCREEN][VRAM_SIZE] ATTRIBUTE_ALIGN(32);
125 
126 
127 static TEXT_CTRL textctrl[NUM_OF_SCREEN];
128 TEXT_CTRL *tc[NUM_OF_SCREEN];
129 
130 static int vram_num[2];
131 static int screen_toggle = 0;
132 
133 static u32 v_blank_intr_counter = 0;
134 #define TEXT_HEAPBUF_SIZE 0x8000
135 static u8 text_heap_buffer[TEXT_HEAPBUF_SIZE];
136 
137 static BOOL wbt_available = FALSE;
138 static u16 connected_bitmap = 0;
139 
140 
141 /*---------------------------------------------------------------------------*
142   Name:         InitWireless
143 
144   Description:  Initializes and re-initializes wireless processing.
145 
146   Arguments:    None.
147 
148   Returns:      None.
149  *---------------------------------------------------------------------------*/
InitWireless(void)150 static void InitWireless(void)
151 {
152     //********************************
153     // Initialize wireless
154     connected_bitmap = 0;
155 
156     if (!WH_Initialize())
157     {
158         OS_Panic("WH_Initialize failed.");
159     }
160     WH_SetSessionUpdateCallback(BlockTransferCallback);
161 
162     //********************************
163     if (wbt_available)
164     {
165         bt_stop();
166         WBT_End();
167         wbt_available = FALSE;
168     }
169 }
170 
171 /*---------------------------------------------------------------------------*
172   Name:         NitroMain / TwlMain
173 
174   Description:  Initialization and main loop.
175 
176   Arguments:    None.
177 
178   Returns:      None.
179  *---------------------------------------------------------------------------*/
180 #ifdef SDK_TWL
TwlMain(void)181 void TwlMain(void)
182 #else
183 void NitroMain(void)
184 #endif
185 {
186     int     i;
187 
188     // Various types of initialization
189     OS_Init();
190     OS_InitTick();
191 
192     // Memory allocation
193     (void)init_text_buf_sys((void *)&(text_heap_buffer[0]),
194                             (void *)&(text_heap_buffer[TEXT_HEAPBUF_SIZE]));
195 
196     for (i = 0; i < NUM_OF_SCREEN; i++)
197     {
198         tc[i] = &(textctrl[i]);
199         init_text(tc[i], (u16 *)&(g_screen[i]), 4 /* Pal no. */ );
200     }
201 
202     FX_Init();
203     GX_Init();
204     GX_DispOff();
205     GXS_DispOff();
206 
207     // Initializes display settings
208 
209     GX_SetBankForLCDC(GX_VRAM_LCDC_ALL);
210     MI_CpuClearFast((void *)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE);
211     (void)GX_DisableBankForLCDC();
212     MI_CpuFillFast((void *)HW_OAM, 192, HW_OAM_SIZE);
213     MI_CpuClearFast((void *)HW_PLTT, HW_PLTT_SIZE);
214     MI_CpuFillFast((void *)HW_DB_OAM, 192, HW_DB_OAM_SIZE);
215     MI_CpuClearFast((void *)HW_DB_PLTT, HW_DB_PLTT_SIZE);
216 
217 
218     /* BG0 display configuration */
219     GX_SetBankForBG(GX_VRAM_BG_128_A);
220     G2_SetBG0Control(GX_BG_SCRSIZE_TEXT_256x256, GX_BG_COLORMODE_16, GX_BG_SCRBASE_0xf000,      // SCR base block 31
221                      GX_BG_CHARBASE_0x00000,    // CHR base block 0
222                      GX_BG_EXTPLTT_01);
223     G2_SetBG0Priority(0);
224     G2_BG0Mosaic(FALSE);
225     // 2D display settings
226     GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BG0_AS_2D);
227     GX_LoadBG0Char(d_CharData, 0, sizeof(d_CharData));
228     GX_LoadBGPltt(d_PaletteData, 0, sizeof(d_PaletteData));
229 
230     // OBJ display settings
231     GX_SetBankForOBJ(GX_VRAM_OBJ_128_B);
232     GX_SetOBJVRamModeChar(GX_OBJVRAMMODE_CHAR_2D);
233 
234     GX_SetVisiblePlane(GX_PLANEMASK_BG0 | GX_PLANEMASK_OBJ);
235 
236     /* Sub BG0 display configuration */
237     GX_SetBankForSubBG(GX_VRAM_SUB_BG_48_HI);
238     G2S_SetBG0Control(GX_BG_SCRSIZE_TEXT_256x256, GX_BG_COLORMODE_16, GX_BG_SCRBASE_0xb800,     // SCR base block 23
239                       GX_BG_CHARBASE_0x00000,   // CHR base block 0
240                       GX_BG_EXTPLTT_01);
241     G2S_SetBG0Priority(0);
242     G2S_BG0Mosaic(FALSE);
243     GXS_SetGraphicsMode(GX_BGMODE_0);
244     GXS_LoadBG0Char(d_CharData, 0, sizeof(d_CharData));
245     GXS_LoadBGPltt(d_PaletteData, 0, sizeof(d_PaletteData));
246 
247     GX_SetBankForSubOBJ(GX_VRAM_SUB_OBJ_128_D);
248     GXS_SetOBJVRamModeChar(GX_OBJVRAMMODE_CHAR_2D);
249 
250     GXS_SetVisiblePlane(GX_PLANEMASK_BG0 | GX_PLANEMASK_OBJ);
251 
252     G2_SetBG0Offset(0, 0);
253     G2S_SetBG0Offset(0, 0);
254 
255 
256     InitializeAllocateSystem();
257 
258     // LCD display start
259     GX_DispOn();
260     GXS_DispOn();
261 
262     // For V-Blank
263     (void)OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
264     (void)OS_EnableIrqMask(OS_IE_V_BLANK);
265     (void)OS_EnableIrq();
266     (void)OS_EnableInterrupts();
267     (void)GX_VBlankIntr(TRUE);
268 
269 
270     // Debug string output
271     PRINTF("ARM9: WBT-1 demo started.\n");
272     vram_num[0] = 1;
273     vram_num[1] = 0;
274 
275     // Initialize wireless (use the WH library)
276     InitWireless();
277     WH_SetGgid(DEFAULT_GGID);
278 
279     // Main loop
280 
281     for (gFrame = 0; TRUE; gFrame++)
282     {
283         text_buf_to_vram(tc[vram_num[0]]);
284         text_buf_to_vram(tc[vram_num[1]]);
285 
286         if (gKey.trg & PAD_BUTTON_SELECT)
287         {
288             screen_toggle ^= 1;
289         }
290         if (gKey.trg & PAD_BUTTON_L)
291         {
292             vram_num[screen_toggle]--;
293             if (vram_num[screen_toggle] < 0)
294             {
295                 vram_num[screen_toggle] = (NUM_OF_SCREEN - 1);
296             }
297         }
298         else if (gKey.trg & PAD_BUTTON_R)
299         {
300             vram_num[screen_toggle]++;
301             if (vram_num[screen_toggle] > (NUM_OF_SCREEN - 1))
302             {
303                 vram_num[screen_toggle] = 0;
304             }
305         }
306 
307         // Get key input data
308         KeyRead(&gKey);
309 
310         // Distributes processes based on communication status
311         switch (WH_GetSystemState())
312         {
313         case WH_SYSSTATE_IDLE:
314             ModeSelect();
315             break;
316         case WH_SYSSTATE_MEASURECHANNEL:
317             ModeStartParent();
318             break;
319         case WH_SYSSTATE_ERROR:
320         case WH_SYSSTATE_CONNECT_FAIL:
321             WH_Reset();
322             break;
323         case WH_SYSSTATE_FATAL:
324             ModeError();
325             break;
326         case WH_SYSSTATE_SCANNING:
327         case WH_SYSSTATE_BUSY:
328             ModeWorking();
329             break;
330         case WH_SYSSTATE_CONNECTED:
331             // Branch again based on whether this is a parent or child device
332             switch (WH_GetConnectMode())
333             {
334             case WH_CONNECTMODE_MP_PARENT:
335                 ModeParent();
336                 break;
337             case WH_CONNECTMODE_MP_CHILD:
338                 ModeChild();
339                 break;
340             }
341             break;
342         }
343 
344         // Waiting for the V-Blank
345         OS_WaitVBlankIntr();
346     }
347 }
348 
349 /*---------------------------------------------------------------------------*
350   Name:         ModeSelect
351 
352   Description:  Process in parent/child selection screen.
353 
354   Arguments:    None.
355 
356   Returns:      None.
357  *---------------------------------------------------------------------------*/
ModeSelect(void)358 static void ModeSelect(void)
359 {
360     // Clear counters
361     MI_CpuClear(send_counter, sizeof(send_counter));
362     MI_CpuClear(recv_counter, sizeof(recv_counter));
363 
364     gFirstSendAtChild = TRUE;
365 
366     if (wbt_available)
367     {
368         bt_stop();
369         WBT_End();
370         wbt_available = FALSE;
371     }
372 
373 
374     PrintString(3, 10, 0xf, "Push A to connect as PARENT");
375     PrintString(3, 12, 0xf, "Push B to connect as CHILD");
376 
377     if (gKey.trg & PAD_BUTTON_A)
378     {
379         //********************************
380         WBT_InitParent(BT_PARENT_PACKET_SIZE, BT_CHILD_PACKET_SIZE, bt_callback);
381         WH_SetReceiver(ParentReceiveCallback);
382         bt_register_blocks();
383         (void)WH_StartMeasureChannel();
384         wbt_available = TRUE;
385         //********************************
386     }
387     else if (gKey.trg & PAD_BUTTON_B)
388     {
389         static const u8 ANY_PARENT[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
390         //********************************
391         WBT_InitChild(bt_callback);
392         WH_SetReceiver(ChildReceiveCallback);
393         (void)WH_ChildConnectAuto(WH_CONNECTMODE_MP_CHILD, ANY_PARENT, 0);
394         wbt_available = TRUE;
395         //********************************
396         vram_num[1] = 2;
397     }
398 }
399 
400 /*---------------------------------------------------------------------------*
401   Name:         ModeStartParent
402 
403   Description:  This process is run when the channel with a low usage rate is done being calculated.
404 
405   Arguments:    None.
406 
407   Returns:      None.
408  *---------------------------------------------------------------------------*/
ModeStartParent(void)409 static void ModeStartParent(void)
410 {
411     (void)WH_ParentConnect(WH_CONNECTMODE_MP_PARENT, 0x0000, WH_GetMeasureChannel());
412 }
413 
414 /*---------------------------------------------------------------------------*
415   Name:         ModeError
416 
417   Description:  Processing in error display screen.
418 
419   Arguments:    None.
420 
421   Returns:      None.
422  *---------------------------------------------------------------------------*/
ModeError(void)423 static void ModeError(void)
424 {
425     PrintString(5, 10, 0x1, "======= ERROR! =======");
426     PrintString(5, 13, 0xf, " Fatal error occured.");
427     PrintString(5, 14, 0xf, "Please reboot program.");
428 }
429 
430 /*---------------------------------------------------------------------------*
431   Name:         ModeWorking
432 
433   Description:  Processing in busy screen.
434 
435   Arguments:    None.
436 
437   Returns:      None.
438  *---------------------------------------------------------------------------*/
ModeWorking(void)439 static void ModeWorking(void)
440 {
441     PrintString(9, 11, 0xf, "Now working...");
442 
443     if (gKey.trg & PAD_BUTTON_START)
444     {
445         //********************************
446         WH_Finalize();
447         //********************************
448     }
449 }
450 
451 /*---------------------------------------------------------------------------*
452   Name:         ModeParent
453 
454   Description:  Processing in parent communications screen.
455 
456   Arguments:    None.
457 
458   Returns:      None.
459  *---------------------------------------------------------------------------*/
ModeParent(void)460 static void ModeParent(void)
461 {
462     PrintString(8, 1, 0x2, "Parent mode");
463     PrintString(4, 3, 0x4, "Send:     %08X", send_counter[0]);
464 
465     PrintString(4, 5, 0x4, "Receive:");
466     {
467         s32     i;
468 
469         for (i = 1; i < (WM_NUM_MAX_CHILD + 1); i++)
470         {
471             if (gRecvFlag[i])
472             {
473                 PrintString(5, (s16)(6 + i), 0x4, "Child%02d: %08X", i, recv_counter[i]);
474             }
475             else
476             {
477                 PrintString(5, (s16)(6 + i), 0x7, "No child");
478             }
479         }
480     }
481 
482     if (gKey.trg & PAD_BUTTON_START)
483     {
484         //********************************
485         WH_Finalize();
486         //********************************
487     }
488 }
489 
490 /*---------------------------------------------------------------------------*
491   Name:         ModeChild
492 
493   Description:  Processing in child communications screen.
494 
495   Arguments:    None.
496 
497   Returns:      None.
498  *---------------------------------------------------------------------------*/
ModeChild(void)499 static void ModeChild(void)
500 {
501     PrintString(8, 1, 0x2, "Child mode");
502     PrintString(4, 3, 0x4, "Send:     %08X", send_counter[0]);
503     PrintString(4, 5, 0x4, "Receive:");
504     PrintString(5, 7, 0x4, "Parent:  %08X", recv_counter[0]);
505 
506     if (gFirstSendAtChild)
507     {
508         // First data transmission
509         ChildSendCallback();
510         gFirstSendAtChild = FALSE;
511     }
512 
513     if (gKey.trg & PAD_BUTTON_START)
514     {
515         //********************************
516         WH_Finalize();
517         //********************************
518     }
519     else if (gKey.trg & PAD_BUTTON_Y)
520     {
521         bt_start();
522     }
523     else if (gKey.trg & PAD_BUTTON_X)
524     {
525         bt_stop();
526     }
527 }
528 
529 /*---------------------------------------------------------------------------*
530   Name:         VBlankIntr
531 
532   Description:  V-Blank interrupt vector.
533 
534   Arguments:    None.
535 
536   Returns:      None.
537  *---------------------------------------------------------------------------*/
VBlankIntr(void)538 static void VBlankIntr(void)
539 {
540     vu16   *ptr;
541     int     i;
542 
543     DC_FlushRange((void *)&(g_screen[vram_num[0]]), VRAM_SIZE);
544     /* I/O register is accessed using DMA operation, so cache wait is not needed */
545     // DC_WaitWriteBufferEmpty();
546     GX_LoadBG0Scr(&(g_screen[vram_num[0]]), 0, VRAM_SIZE);
547 
548     DC_FlushRange((void *)&(g_screen[vram_num[1]]), VRAM_SIZE);
549     /* I/O register is accessed using DMA operation, so cache wait is not needed */
550     // DC_WaitWriteBufferEmpty();
551     GXS_LoadBG0Scr(&(g_screen[vram_num[1]]), 0, VRAM_SIZE);
552 
553     if (screen_toggle)
554         ptr = (u16 *)G2S_GetBG0ScrPtr();
555     else
556         ptr = (u16 *)G2_GetBG0ScrPtr();
557 
558     for (i = 0; i < 32; i++)
559     {
560         *ptr = (u16)((2 << 12) | (0x00ff & '='));
561         ptr++;
562     }
563 
564 
565     v_blank_intr_counter++;
566     OS_SetIrqCheckFlag(OS_IE_V_BLANK);
567 }
568 
569 /*---------------------------------------------------------------------------*
570   Name:         ParentReceiveCallback
571 
572   Description:  Function that is called when a parent receives data from a child.
573 
574   Arguments:    aid: AID of send origin child
575                 data: Pointer to received data (NULL is disconnection notification)
576                 length: Size of received data
577 
578   Returns:      None.
579  *---------------------------------------------------------------------------*/
ParentReceiveCallback(u16 aid,u16 * data,u16 length)580 static void ParentReceiveCallback(u16 aid, u16 *data, u16 length)
581 {
582 	recv_counter[aid]++;
583     if (data != NULL)
584     {
585         gRecvFlag[aid] = TRUE;
586         // Copy source is aligned to 2 bytes (not 4 bytes)
587 //        recv_counter[aid]++;
588         WBT_MpParentRecvHook((u8 *)data, length, aid);
589     }
590     else
591     {
592         gRecvFlag[aid] = FALSE;
593     }
594 }
595 
596 
597 /*---------------------------------------------------------------------------*
598   Name:         ChildReceiveCallback
599 
600   Description:  Function that is called when a child receives data from a parent.
601 
602   Arguments:    aid: AID of sending source parent (always 0)
603                 data: Pointer to received data (NULL is disconnection notification)
604                 length: Size of received data
605 
606   Returns:      None.
607  *---------------------------------------------------------------------------*/
ChildReceiveCallback(u16 aid,u16 * data,u16 length)608 static void ChildReceiveCallback(u16 aid, u16 *data, u16 length)
609 {
610     (void)aid;
611     recv_counter[0]++;
612     if (data != NULL)
613     {
614         gRecvFlag[0] = TRUE;
615         // Copy source is aligned to 2 bytes (not 4 bytes)
616         WBT_MpChildRecvHook((u8 *)data, length);
617     }
618     else
619     {
620         gRecvFlag[0] = FALSE;
621     }
622 }
623 
624 /*---------------------------------------------------------------------------*
625   Name:         BlockTransferCallback
626 
627   Description:  Block transfer status notification function
628 
629   Arguments:    arg: Callback pointer for the notification source WM function
630 
631   Returns:      None.
632  *---------------------------------------------------------------------------*/
BlockTransferCallback(void * arg)633 static void BlockTransferCallback(void *arg)
634 {
635     int connectMode = WH_GetConnectMode();
636 
637     switch (((WMCallback*)arg)->apiid)
638     {
639     case WM_APIID_START_MP:
640         {                              /* Begin MP state */
641            WMStartMPCallback *cb = (WMStartMPCallback *)arg;
642             switch (cb->state)
643             {
644             case WM_STATECODE_MP_START:
645                 if (connectMode == WH_CONNECTMODE_MP_PARENT)
646                 {
647                     ParentSendCallback();
648                 }
649                 else if (connectMode == WH_CONNECTMODE_MP_CHILD)
650                 {
651                     WBT_SetOwnAid(WH_GetCurrentAid());
652                     mfprintf(tc[2], "aid = %d\n", WH_GetCurrentAid());
653                     bt_start();
654                     ChildSendCallback();
655                 }
656                 break;
657             }
658         }
659         break;
660     case WM_APIID_SET_MP_DATA:
661         {                              /* Complete single MP communication */
662             if (connectMode == WH_CONNECTMODE_MP_PARENT)
663             {
664                 if (connected_bitmap != 0)
665                 {
666                     ParentSendCallback();
667                 }
668             }
669             else if (connectMode == WH_CONNECTMODE_MP_CHILD)
670             {
671                 ChildSendCallback();
672             }
673         }
674         break;
675     case WM_APIID_START_PARENT:
676         {                              /* Connect to a new child */
677             WMStartParentCallback *cb = (WMStartParentCallback *)arg;
678             if (connectMode == WH_CONNECTMODE_MP_PARENT)
679             {
680                 switch (cb->state)
681                 {
682                 case WM_STATECODE_CONNECTED:
683                     if (connected_bitmap == 0)
684                     {
685                         ParentSendCallback();
686                     }
687                     connected_bitmap |= (1 << cb->aid);
688                     break;
689                 case WM_STATECODE_DISCONNECTED:
690                     connected_bitmap &= ~(1 << cb->aid);
691                     break;
692                 }
693             }
694         }
695         break;
696     }
697 }
698 
699 
700 /*---------------------------------------------------------------------------*
701   Name:         ParentSendCallback
702 
703   Description:  Function that is called when a parent sends data to a child.
704 
705   Arguments:    None.
706 
707   Returns:      None.
708  *---------------------------------------------------------------------------*/
ParentSendCallback(void)709 void ParentSendCallback(void)
710 {
711     const u16 size = (u16)WBT_MpParentSendHook(gSendBuf, WC_PARENT_DATA_SIZE_MAX);
712     send_counter[0]++;
713     (void)WH_SendData(gSendBuf, size, NULL);
714 }
715 
716 
717 /*---------------------------------------------------------------------------*
718   Name:         ChildSendCallback
719 
720   Description:  Function that is called when a child receives data from a parent.
721 
722   Arguments:    None.
723 
724   Returns:      None.
725  *---------------------------------------------------------------------------*/
ChildSendCallback(void)726 void ChildSendCallback(void)
727 {
728     const u16 size = (u16)WBT_MpChildSendHook(gSendBuf, WC_CHILD_DATA_SIZE_MAX);
729     send_counter[0]++;
730     (void)WH_SendData(gSendBuf, size, NULL);
731 }
732 
733 /*---------------------------------------------------------------------------*
734   Name:         KeyRead
735 
736   Description:  Edits key input data.
737                 Detects press trigger, release trigger, and press-and-hold repeat.
738 
739   Arguments:    pKey: Structure that holds key input data to be edited.
740 
741   Returns:      None.
742  *---------------------------------------------------------------------------*/
KeyRead(KeyInfo * pKey)743 static void KeyRead(KeyInfo * pKey)
744 {
745     static u16 repeat_count[12];
746     int     i;
747     u16     r;
748 
749     r = PAD_Read();
750     pKey->trg = 0x0000;
751     pKey->up = 0x0000;
752     pKey->rep = 0x0000;
753 
754     for (i = 0; i < 12; i++)
755     {
756         if (r & (0x0001 << i))
757         {
758             if (!(pKey->cnt & (0x0001 << i)))
759             {
760                 pKey->trg |= (0x0001 << i);     // Press trigger
761                 repeat_count[i] = 1;
762             }
763             else
764             {
765                 if (repeat_count[i] > KEY_REPEAT_START)
766                 {
767                     pKey->rep |= (0x0001 << i); // Press-and-hold repeat
768                     repeat_count[i] = KEY_REPEAT_START - KEY_REPEAT_SPAN;
769                 }
770                 else
771                 {
772                     repeat_count[i]++;
773                 }
774             }
775         }
776         else
777         {
778             if (pKey->cnt & (0x0001 << i))
779             {
780                 pKey->up |= (0x0001 << i);      // Release trigger
781             }
782         }
783     }
784     pKey->cnt = r;                     // Unprocessed key input
785 }
786 
787 /*---------------------------------------------------------------------------*
788   Name:         ClearString
789 
790   Description:  Clears the virtual screen.
791 
792   Arguments:    None.
793 
794   Returns:      None.
795  *---------------------------------------------------------------------------*/
ClearString(int vram_num)796 static void ClearString(int vram_num)
797 {
798     MI_DmaClear32(0, (void *)&(g_screen[vram_num]), VRAM_SIZE);
799 }
800 
801 
802 /*---------------------------------------------------------------------------*
803   Name:         PrintString
804 
805   Description:  Positions the text string on the virtual screen. The string can be up to 32 chars.
806 
807   Arguments:    x: X-coordinate where character string starts (x 8 dots)
808                 y: Y-coordinate where character string starts (x 8 dots)
809                 palette: Specify text color by palette number
810                 text: Text string to position. Null-terminated.
811                 ...: Virtual argument
812 
813   Returns:      None.
814  *---------------------------------------------------------------------------*/
PrintString(s16 x,s16 y,u8 palette,char * text,...)815 static void PrintString(s16 x, s16 y, u8 palette, char *text, ...)
816 {
817     va_list vlist;
818     char    temp[32 + 2];
819     s32     i;
820 
821     va_start(vlist, text);
822     (void)OS_VSNPrintf(temp, 32, text, vlist);
823     va_end(vlist);
824     *(u16 *)(&temp[31]) = 0x0000;
825     for (i = 0;; i++)
826     {
827         if (temp[i] == 0x00)
828         {
829             break;
830         }
831         tc[1]->screen[(y * 32) + x + i] = (u16)((palette << 12) | temp[i]);
832     }
833 }
834 
835 
836 /*---------------------------------------------------------------------------*
837   Name:         InitializeAllocateSystem
838 
839   Description:  Initializes the memory allocation system within the main memory arena.
840 
841   Arguments:    None.
842 
843   Returns:      None.
844  *---------------------------------------------------------------------------*/
InitializeAllocateSystem(void)845 static void InitializeAllocateSystem(void)
846 {
847     void   *tempLo;
848     OSHeapHandle hh;
849 
850     mprintf(" arena lo = %08x\n", OS_GetMainArenaLo());
851     mprintf(" arena hi = %08x\n", OS_GetMainArenaHi());
852 
853     // Based on the premise that OS_Init has been already called
854     tempLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
855     OS_SetArenaLo(OS_ARENA_MAIN, tempLo);
856     hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
857     if (hh < 0)
858     {
859         OS_Panic("ARM9: Fail to create heap...\n");
860     }
861     hh = OS_SetCurrentHeap(OS_ARENA_MAIN, hh);
862 }
863 
864 
865 /*---------------------------------------------------------------------------*
866   End of file
867  *---------------------------------------------------------------------------*/
868