1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - WBT - demos - wbt-1
3   File:     main.c
4 
5   Copyright 2006-2009 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:: 2009-06-04#$
14   $Rev: 10698 $
15   $Author: okubata_ryoma $
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     connected_bitmap = 0;
367     if (wbt_available)
368     {
369         bt_stop();
370         WBT_End();
371         wbt_available = FALSE;
372     }
373 
374 
375     PrintString(3, 10, 0xf, "Push A to connect as PARENT");
376     PrintString(3, 12, 0xf, "Push B to connect as CHILD");
377 
378     if (gKey.trg & PAD_BUTTON_A)
379     {
380         //********************************
381         WBT_InitParent(BT_PARENT_PACKET_SIZE, BT_CHILD_PACKET_SIZE, bt_callback);
382         WH_SetReceiver(ParentReceiveCallback);
383         bt_register_blocks();
384         (void)WH_StartMeasureChannel();
385         wbt_available = TRUE;
386         //********************************
387     }
388     else if (gKey.trg & PAD_BUTTON_B)
389     {
390         static const u8 ANY_PARENT[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
391         //********************************
392         WBT_InitChild(bt_callback);
393         WH_SetReceiver(ChildReceiveCallback);
394         (void)WH_ChildConnectAuto(WH_CONNECTMODE_MP_CHILD, ANY_PARENT, 0);
395         wbt_available = TRUE;
396         //********************************
397         vram_num[1] = 2;
398     }
399 }
400 
401 /*---------------------------------------------------------------------------*
402   Name:         ModeStartParent
403 
404   Description:  This process is run when the channel with a low usage rate is done being calculated.
405 
406   Arguments:    None.
407 
408   Returns:      None.
409  *---------------------------------------------------------------------------*/
ModeStartParent(void)410 static void ModeStartParent(void)
411 {
412     (void)WH_ParentConnect(WH_CONNECTMODE_MP_PARENT, 0x0000, WH_GetMeasureChannel());
413 }
414 
415 /*---------------------------------------------------------------------------*
416   Name:         ModeError
417 
418   Description:  Processing in error display screen.
419 
420   Arguments:    None.
421 
422   Returns:      None.
423  *---------------------------------------------------------------------------*/
ModeError(void)424 static void ModeError(void)
425 {
426     PrintString(5, 10, 0x1, "======= ERROR! =======");
427     PrintString(5, 13, 0xf, " Fatal error occured.");
428     PrintString(5, 14, 0xf, "Please reboot program.");
429 }
430 
431 /*---------------------------------------------------------------------------*
432   Name:         ModeWorking
433 
434   Description:  Processing in busy screen.
435 
436   Arguments:    None.
437 
438   Returns:      None.
439  *---------------------------------------------------------------------------*/
ModeWorking(void)440 static void ModeWorking(void)
441 {
442     PrintString(9, 11, 0xf, "Now working...");
443 
444     if (gKey.trg & PAD_BUTTON_START)
445     {
446         //********************************
447         WH_Finalize();
448         //********************************
449     }
450 }
451 
452 /*---------------------------------------------------------------------------*
453   Name:         ModeParent
454 
455   Description:  Processing in parent communications screen.
456 
457   Arguments:    None.
458 
459   Returns:      None.
460  *---------------------------------------------------------------------------*/
ModeParent(void)461 static void ModeParent(void)
462 {
463     PrintString(8, 1, 0x2, "Parent mode");
464     PrintString(4, 3, 0x4, "Send:     %08X", send_counter[0]);
465 
466     PrintString(4, 5, 0x4, "Receive:");
467     {
468         s32     i;
469 
470         for (i = 1; i < (WM_NUM_MAX_CHILD + 1); i++)
471         {
472             if (gRecvFlag[i])
473             {
474                 PrintString(5, (s16)(6 + i), 0x4, "Child%02d: %08X", i, recv_counter[i]);
475             }
476             else
477             {
478                 PrintString(5, (s16)(6 + i), 0x7, "No child");
479             }
480         }
481     }
482 
483     if (gKey.trg & PAD_BUTTON_START)
484     {
485         //********************************
486         WH_Finalize();
487         //********************************
488     }
489 }
490 
491 /*---------------------------------------------------------------------------*
492   Name:         ModeChild
493 
494   Description:  Processing in child communications screen.
495 
496   Arguments:    None.
497 
498   Returns:      None.
499  *---------------------------------------------------------------------------*/
ModeChild(void)500 static void ModeChild(void)
501 {
502     PrintString(8, 1, 0x2, "Child mode");
503     PrintString(4, 3, 0x4, "Send:     %08X", send_counter[0]);
504     PrintString(4, 5, 0x4, "Receive:");
505     PrintString(5, 7, 0x4, "Parent:  %08X", recv_counter[0]);
506 
507     if (gFirstSendAtChild)
508     {
509         // First data transmission
510         ChildSendCallback();
511         gFirstSendAtChild = FALSE;
512     }
513 
514     if (gKey.trg & PAD_BUTTON_START)
515     {
516         //********************************
517         WH_Finalize();
518         //********************************
519     }
520     else if (gKey.trg & PAD_BUTTON_Y)
521     {
522         bt_start();
523     }
524     else if (gKey.trg & PAD_BUTTON_X)
525     {
526         bt_stop();
527     }
528 }
529 
530 /*---------------------------------------------------------------------------*
531   Name:         VBlankIntr
532 
533   Description:  V-Blank interrupt vector.
534 
535   Arguments:    None.
536 
537   Returns:      None.
538  *---------------------------------------------------------------------------*/
VBlankIntr(void)539 static void VBlankIntr(void)
540 {
541     vu16   *ptr;
542     int     i;
543 
544     DC_FlushRange((void *)&(g_screen[vram_num[0]]), VRAM_SIZE);
545     /* I/O register is accessed using DMA operation, so cache wait is not needed */
546     // DC_WaitWriteBufferEmpty();
547     GX_LoadBG0Scr(&(g_screen[vram_num[0]]), 0, VRAM_SIZE);
548 
549     DC_FlushRange((void *)&(g_screen[vram_num[1]]), VRAM_SIZE);
550     /* I/O register is accessed using DMA operation, so cache wait is not needed */
551     // DC_WaitWriteBufferEmpty();
552     GXS_LoadBG0Scr(&(g_screen[vram_num[1]]), 0, VRAM_SIZE);
553 
554     if (screen_toggle)
555         ptr = (u16 *)G2S_GetBG0ScrPtr();
556     else
557         ptr = (u16 *)G2_GetBG0ScrPtr();
558 
559     for (i = 0; i < 32; i++)
560     {
561         *ptr = (u16)((2 << 12) | (0x00ff & '='));
562         ptr++;
563     }
564 
565 
566     v_blank_intr_counter++;
567     OS_SetIrqCheckFlag(OS_IE_V_BLANK);
568 }
569 
570 /*---------------------------------------------------------------------------*
571   Name:         ParentReceiveCallback
572 
573   Description:  Function that is called when a parent receives data from a child.
574 
575   Arguments:    aid: AID of send origin child
576                 data: Pointer to received data (NULL is disconnection notification)
577                 length: Size of received data
578 
579   Returns:      None.
580  *---------------------------------------------------------------------------*/
ParentReceiveCallback(u16 aid,u16 * data,u16 length)581 static void ParentReceiveCallback(u16 aid, u16 *data, u16 length)
582 {
583 	recv_counter[aid]++;
584     if (data != NULL)
585     {
586         gRecvFlag[aid] = TRUE;
587         // Copy source is aligned to 2 bytes (not 4 bytes)
588 //        recv_counter[aid]++;
589         WBT_MpParentRecvHook((u8 *)data, length, aid);
590     }
591     else
592     {
593         gRecvFlag[aid] = FALSE;
594     }
595 }
596 
597 
598 /*---------------------------------------------------------------------------*
599   Name:         ChildReceiveCallback
600 
601   Description:  Function that is called when a child receives data from a parent.
602 
603   Arguments:    aid: AID of sending source parent (always 0)
604                 data: Pointer to received data (NULL is disconnection notification)
605                 length: Size of received data
606 
607   Returns:      None.
608  *---------------------------------------------------------------------------*/
ChildReceiveCallback(u16 aid,u16 * data,u16 length)609 static void ChildReceiveCallback(u16 aid, u16 *data, u16 length)
610 {
611     (void)aid;
612     recv_counter[0]++;
613     if (data != NULL)
614     {
615         gRecvFlag[0] = TRUE;
616         // Copy source is aligned to 2 bytes (not 4 bytes)
617         WBT_MpChildRecvHook((u8 *)data, length);
618     }
619     else
620     {
621         gRecvFlag[0] = FALSE;
622     }
623 }
624 
625 /*---------------------------------------------------------------------------*
626   Name:         BlockTransferCallback
627 
628   Description:  Block transfer status notification function
629 
630   Arguments:    arg: Callback pointer for the notification source WM function
631 
632   Returns:      None.
633  *---------------------------------------------------------------------------*/
BlockTransferCallback(void * arg)634 static void BlockTransferCallback(void *arg)
635 {
636     int connectMode = WH_GetConnectMode();
637 
638     switch (((WMCallback*)arg)->apiid)
639     {
640     case WM_APIID_START_MP:
641         {                              /* Begin MP state */
642            WMStartMPCallback *cb = (WMStartMPCallback *)arg;
643             switch (cb->state)
644             {
645             case WM_STATECODE_MP_START:
646                 if (connectMode == WH_CONNECTMODE_MP_PARENT)
647                 {
648                     ParentSendCallback();
649                 }
650                 else if (connectMode == WH_CONNECTMODE_MP_CHILD)
651                 {
652                     WBT_SetOwnAid(WH_GetCurrentAid());
653                     mfprintf(tc[2], "aid = %d\n", WH_GetCurrentAid());
654                     bt_start();
655                     ChildSendCallback();
656                 }
657                 break;
658             }
659         }
660         break;
661     case WM_APIID_SET_MP_DATA:
662         {                              /* Complete single MP communication */
663             if (connectMode == WH_CONNECTMODE_MP_PARENT)
664             {
665                 if (connected_bitmap != 0)
666                 {
667                     ParentSendCallback();
668                 }
669             }
670             else if (connectMode == WH_CONNECTMODE_MP_CHILD)
671             {
672                 ChildSendCallback();
673             }
674         }
675         break;
676     case WM_APIID_START_PARENT:
677         {                              /* Connect to a new child */
678             WMStartParentCallback *cb = (WMStartParentCallback *)arg;
679             if (connectMode == WH_CONNECTMODE_MP_PARENT)
680             {
681                 switch (cb->state)
682                 {
683                 case WM_STATECODE_CONNECTED:
684                     if (connected_bitmap == 0)
685                     {
686                         ParentSendCallback();
687                     }
688                     connected_bitmap |= (1 << cb->aid);
689                     break;
690                 case WM_STATECODE_DISCONNECTED:
691                     connected_bitmap &= ~(1 << cb->aid);
692                     break;
693                 }
694             }
695         }
696         break;
697     }
698 }
699 
700 
701 /*---------------------------------------------------------------------------*
702   Name:         ParentSendCallback
703 
704   Description:  Function that is called when a parent sends data to a child.
705 
706   Arguments:    None.
707 
708   Returns:      None.
709  *---------------------------------------------------------------------------*/
ParentSendCallback(void)710 void ParentSendCallback(void)
711 {
712     const u16 size = (u16)WBT_MpParentSendHook(gSendBuf, WC_PARENT_DATA_SIZE_MAX);
713     send_counter[0]++;
714     (void)WH_SendData(gSendBuf, size, NULL);
715 }
716 
717 
718 /*---------------------------------------------------------------------------*
719   Name:         ChildSendCallback
720 
721   Description:  Function that is called when a child receives data from a parent.
722 
723   Arguments:    None.
724 
725   Returns:      None.
726  *---------------------------------------------------------------------------*/
ChildSendCallback(void)727 void ChildSendCallback(void)
728 {
729     const u16 size = (u16)WBT_MpChildSendHook(gSendBuf, WC_CHILD_DATA_SIZE_MAX);
730     send_counter[0]++;
731     (void)WH_SendData(gSendBuf, size, NULL);
732 }
733 
734 /*---------------------------------------------------------------------------*
735   Name:         KeyRead
736 
737   Description:  Edits key input data.
738                 Detects press trigger, release trigger, and press-and-hold repeat.
739 
740   Arguments:    pKey: Structure that holds key input data to be edited.
741 
742   Returns:      None.
743  *---------------------------------------------------------------------------*/
KeyRead(KeyInfo * pKey)744 static void KeyRead(KeyInfo * pKey)
745 {
746     static u16 repeat_count[12];
747     int     i;
748     u16     r;
749 
750     r = PAD_Read();
751     pKey->trg = 0x0000;
752     pKey->up = 0x0000;
753     pKey->rep = 0x0000;
754 
755     for (i = 0; i < 12; i++)
756     {
757         if (r & (0x0001 << i))
758         {
759             if (!(pKey->cnt & (0x0001 << i)))
760             {
761                 pKey->trg |= (0x0001 << i);     // Press trigger
762                 repeat_count[i] = 1;
763             }
764             else
765             {
766                 if (repeat_count[i] > KEY_REPEAT_START)
767                 {
768                     pKey->rep |= (0x0001 << i); // Press-and-hold repeat
769                     repeat_count[i] = KEY_REPEAT_START - KEY_REPEAT_SPAN;
770                 }
771                 else
772                 {
773                     repeat_count[i]++;
774                 }
775             }
776         }
777         else
778         {
779             if (pKey->cnt & (0x0001 << i))
780             {
781                 pKey->up |= (0x0001 << i);      // Release trigger
782             }
783         }
784     }
785     pKey->cnt = r;                     // Unprocessed key input
786 }
787 
788 /*---------------------------------------------------------------------------*
789   Name:         ClearString
790 
791   Description:  Clears the virtual screen.
792 
793   Arguments:    None.
794 
795   Returns:      None.
796  *---------------------------------------------------------------------------*/
ClearString(int vram_num)797 static void ClearString(int vram_num)
798 {
799     MI_DmaClear32(0, (void *)&(g_screen[vram_num]), VRAM_SIZE);
800 }
801 
802 
803 /*---------------------------------------------------------------------------*
804   Name:         PrintString
805 
806   Description:  Positions the text string on the virtual screen. The string can be up to 32 chars.
807 
808   Arguments:    x: X-coordinate where character string starts (x 8 dots)
809                 y: Y-coordinate where character string starts (x 8 dots)
810                 palette: Specify text color by palette number
811                 text: Text string to position. Null-terminated.
812                 ...: Virtual argument
813 
814   Returns:      None.
815  *---------------------------------------------------------------------------*/
PrintString(s16 x,s16 y,u8 palette,char * text,...)816 static void PrintString(s16 x, s16 y, u8 palette, char *text, ...)
817 {
818     va_list vlist;
819     char    temp[32 + 2];
820     s32     i;
821 
822     va_start(vlist, text);
823     (void)OS_VSNPrintf(temp, 32, text, vlist);
824     va_end(vlist);
825     *(u16 *)(&temp[31]) = 0x0000;
826     for (i = 0;; i++)
827     {
828         if (temp[i] == 0x00)
829         {
830             break;
831         }
832         tc[1]->screen[(y * 32) + x + i] = (u16)((palette << 12) | temp[i]);
833     }
834 }
835 
836 
837 /*---------------------------------------------------------------------------*
838   Name:         InitializeAllocateSystem
839 
840   Description:  Initializes the memory allocation system within the main memory arena.
841 
842   Arguments:    None.
843 
844   Returns:      None.
845  *---------------------------------------------------------------------------*/
InitializeAllocateSystem(void)846 static void InitializeAllocateSystem(void)
847 {
848     void   *tempLo;
849     OSHeapHandle hh;
850 
851     mprintf(" arena lo = %08x\n", OS_GetMainArenaLo());
852     mprintf(" arena hi = %08x\n", OS_GetMainArenaHi());
853 
854     // Based on the premise that OS_Init has been already called
855     tempLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
856     OS_SetArenaLo(OS_ARENA_MAIN, tempLo);
857     hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
858     if (hh < 0)
859     {
860         OS_Panic("ARM9: Fail to create heap...\n");
861     }
862     hh = OS_SetCurrentHeap(OS_ARENA_MAIN, hh);
863 }
864 
865 
866 /*---------------------------------------------------------------------------*
867   End of file
868  *---------------------------------------------------------------------------*/
869