1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - WM - demos - wmPadRead-child
3   File:     main.c
4 
5   Copyright 2007-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-08-31#$
14   $Rev: 11030 $
15   $Author: tominaga_masafumi $
16  *---------------------------------------------------------------------------*/
17 
18 //
19 // This is the child program distributed by the mpdldemo/mpdlntr2rvl demo included with RevoEX, a development kit for the Wii's wireless features.
20 //
21 // It communicates with the Wii and sends button input.
22 //
23 
24 /*
25  * This demo uses the WH library for wireless communications, but does not perform wireless shutdown processing.
26  *
27  * For details on WH library wireless shutdown processing, see the comments at the top of the WH library source code or the wm/dataShare-Model demo.
28  *
29  *
30  */
31 
32 #ifdef SDK_TWL
33 #include <twl.h>
34 #else
35 #include <nitro.h>
36 #endif
37 
38 #include <nitro/wm.h>
39 #include "data.h"
40 #include "wh.h"
41 
42 #include "tpdata.h"
43 
44 /*---------------------------------------------------------------------------*
45     Constant definitions
46  *---------------------------------------------------------------------------*/
47 #define PICTURE_FRAME_PER_GAME_FRAME    1
48 
49 /* The GGID used in this demo */
50 #define MY_GGID SDK_MAKEGGID_SYSTEM(0x20)
51 
52 #define DMA_NO  3
53 
54 #define SAMPLING_BUFFER_SIZE ( 1024 * 1024 ) // 1M
55 
56 #define FFT_NSHIFT      9
57 #define FFT_N           (1 << FFT_NSHIFT)
58 
59 /*---------------------------------------------------------------------------*
60     Variable Definitions
61  *---------------------------------------------------------------------------*/
62 
63 static WMBssDesc mbParentBssDesc ATTRIBUTE_ALIGN(32);
64 static BOOL isMultiBooted;
65 
66 static GXOamAttr oamBak[128];
67 
68 typedef struct MyPadData {
69     u16 keyData;
70     u8 touchPanel_x;
71     u8 touchPanel_y;
72     u8 mic;
73     u8 touch;
74     u8 padding[2];
75 } MyPadData;
76 
77 // Send/receive buffer for display
78 static MyPadData gRecvData[1 + WH_CHILD_MAX]; // Touch information for all players, delivered by the parent
79 static BOOL gRecvFlag[1 + WH_CHILD_MAX];
80 
81 u16     keyData;
82 
83 static GXOamAttr gOam[128];
84 
85 TPData  raw_point;
86 TPData  disp_point;
87 TPCalibrateParam calibrate;
88 
89 static BOOL input_mic;
90 static MICAutoParam gMicAutoParam;
91 static u8 *gMicData;
92 
93 
94 // FFT buffers
95 static fx16 sinTable[FFT_N - FFT_N / 4];
96 #ifdef USE_FFTREAL
97 static fx16 sinTable2[(FFT_N - FFT_N / 4) / 2];
98 static fx32 data[FFT_N];
99 #else
100 static fx32 data[FFT_N * 2];
101 #endif
102 static s32 power[FFT_N/2+1];
103 static s32 smoothedPower[FFT_N/2+1];
104 
105 /*---------------------------------------------------------------------------*
106     Function Declarations
107  *---------------------------------------------------------------------------*/
108 static void InitializeAllocateSystem(void);
109 static void SetPoint16x16(int objNo, u16 pos_x, u16 pos_y, int charNo, int paletteNo);
110 static void Initialize(void);
111 static BOOL DoConnect(void);
112 static void DoPadSharing(void);
113 static BOOL CheckMicData(void *address);
114 static void ObjSet(int objNo, int x, int y, int charNo, int paletteNo);
115 static void VBlankIntr(void);
116 
117 
118 //================================================================================
119 /*---------------------------------------------------------------------------*
120   Name:         NitroMain / TwlMain
121 
122   Description:  Main
123 
124   Arguments:    None.
125 
126   Returns:      None.
127  *---------------------------------------------------------------------------*/
128 #ifdef SDK_TWL
TwlMain()129 void TwlMain()
130 #else
131 void NitroMain()
132 #endif
133 {
134     Initialize();
135 
136     // Initialize shared data
137     MI_CpuClear8( gRecvData, sizeof(gRecvData) );
138 
139     // The local host checks to see if it is a child started from multiboot.
140     isMultiBooted = MB_IsMultiBootChild();
141 
142     if (isMultiBooted)
143     {
144         //--------------------------------------------------------------
145         // If it was started from multi-boot, it will be reset once, and communication will be disconnected.
146         // The child maintains the BssDesc of the parent that booted it. Use this information to reconnect to the parent.
147         //
148         // There is no particular problem with extracting the MAC address from BssDesc, then specifying that MAC address and scanning for and connecting to that parent. However, to connect to the parent directly using the stored BssDesc, it is necessary to set the parent's and child's communications size and transfer mode to match ahead of time.
149         //
150         //
151         //
152         //--------------------------------------------------------------
153 
154         /*
155          * Gets parent data for reconnecting to the parent.
156          * The WMBssDesc used for the connection must be 32-byte aligned.
157          * When reconnecting without using the parent's MAC address to rescan, make the KS/CS flags and the maximum send size match in advance for the parent and the child.
158          *
159          * All of these values may be 0 if you rescan before connecting.
160          */
161         MB_ReadMultiBootParentBssDesc(&mbParentBssDesc,
162                                       WH_PARENT_MAX_SIZE, // Maximum parent send size
163                                       WH_CHILD_MAX_SIZE,  // Maximum child send size
164                                       0,   // Reserved region (always 0)
165                                       0);  // Reserved region (always 0)
166     }
167 
168     while (TRUE)
169     {
170         int connectedFlag = FALSE;
171 
172         // Initialize wireless
173         if (!WH_Initialize())
174         {
175             OS_Panic("WH_Initialize failed.");
176         }
177 
178         connectedFlag = DoConnect();
179         // At this point the transition to the child state is complete
180 
181         if (connectedFlag)
182         {
183             DoPadSharing();
184             // Control does not return here until exiting from communication mode
185         }
186 
187         WH_Finalize();
188     }
189 }
190 
Initialize(void)191 void Initialize(void)
192 {
193     //================ Initialization
194     //---- OS Initialization
195     OS_Init();
196 
197     //---- TP Initialization
198     TP_Init();
199 
200     // Get CalibrateParameter from FlashMemory
201     if (!TP_GetUserInfo(&calibrate))
202     {
203         OS_Panic("FATAL ERROR: can't read UserOwnerInfo\n");
204     }
205     else
206     {
207         OS_Printf("Get Calibration Parameter from NVRAM\n");
208     }
209 
210     TP_SetCalibrateParam(&calibrate);
211 
212     //---- GX Initialization
213     GX_Init();
214 
215     //================ Initial settings
216     //---- All Power ON
217     GX_SetPower(GX_POWER_ALL);
218 
219     //----  Enable V-Blank interrupt
220     (void)OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
221     (void)OS_EnableIrqMask(OS_IE_V_BLANK);
222     (void)OS_EnableIrq();
223 
224     //---- V-Blank occurrence settings
225     (void)GX_VBlankIntr(TRUE);
226 
227     //---- Clear VRAM
228     GX_SetBankForLCDC(GX_VRAM_LCDC_ALL);
229     MI_CpuClearFast((void *)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE);
230     (void)GX_DisableBankForLCDC();
231 
232     //---- OAM and palette clear
233     MI_CpuFillFast((void *)HW_OAM, 192, HW_OAM_SIZE);
234     MI_CpuClearFast((void *)HW_PLTT, HW_PLTT_SIZE);
235 
236     MI_CpuFillFast((void *)HW_DB_OAM, 192, HW_DB_OAM_SIZE);
237     MI_CpuClearFast((void *)HW_DB_PLTT, HW_DB_PLTT_SIZE);
238 
239     //---- Set bank A for OBJ
240     GX_SetBankForOBJ(GX_VRAM_OBJ_128_A);
241 
242     GX_SetBankForSubOBJ(GX_VRAM_SUB_OBJ_128_D);
243 
244     //---- Set to graphics display mode
245     GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BG0_AS_2D);
246 
247     //---- Set only OBJ display ON
248     GX_SetVisiblePlane(GX_PLANEMASK_OBJ);
249 
250     //---- Used with 32-KB OBJ in 2D mapping mode
251     GX_SetOBJVRamModeChar(GX_OBJVRAMMODE_CHAR_2D);
252 
253     //---- Data load
254     GX_LoadOBJ( sampleCharData, 0, sizeof(sampleCharData) );
255     GX_LoadOBJPltt( samplePlttData, 0, sizeof(samplePlttData) );
256 
257     GXS_SetGraphicsMode(GX_BGMODE_0);    // BGMODE 0
258 
259     GXS_SetVisiblePlane(GX_PLANEMASK_OBJ);       // Make OBJ visible
260     GXS_SetOBJVRamModeBmp(GX_OBJVRAMMODE_BMP_1D_128K);   // 2D mapping OBJ
261 
262     /* Load character bitmap data */
263     GXS_LoadOBJ( sampleCharData, 0, sizeof(sampleCharData) );
264     GXS_LoadOBJPltt( samplePlttData, 0, sizeof(samplePlttData) );
265 
266     //---- Move hidden OBJ off screen
267     MI_DmaFill32(DMA_NO, oamBak, 0xc0, sizeof(oamBak));
268 
269     //================ Miscellaneous initialization
270 
271     /////////////////////
272     // Memory allocation
273     InitializeAllocateSystem();
274 
275     /////////////////////
276     // Microphone-related initialization
277 
278     //---- MIC Initialization
279     MIC_Init();
280 
281     //---- PMIC Initialization
282     PM_Init();
283     // AMP on
284     (void)PM_SetAmp(PM_AMP_ON);
285     // Adjust AMP gain
286     (void)PM_SetAmpGain(PM_AMPGAIN_80);
287 
288     // Auto sampling settings
289     // Because the memory allocated with OS_Alloc is 32-byte aligned, other memory is not destroyed even if the cache is manipulated
290     //
291     gMicData = (u8 *)OS_Alloc(SAMPLING_BUFFER_SIZE);
292     // Perform 12-bit sampling to increase the accuracy of Fourier transforms
293     gMicAutoParam.type = MIC_SAMPLING_TYPE_12BIT;
294     gMicAutoParam.buffer = (void *)gMicData;
295     gMicAutoParam.size = SAMPLING_BUFFER_SIZE;
296     gMicAutoParam.loop_enable = TRUE;
297     gMicAutoParam.full_callback = NULL;
298 #ifdef SDK_TWL
299     gMicAutoParam.rate = MIC_SAMPLING_RATE_8180;
300     (void)MIC_StartLimitedSampling(&gMicAutoParam);
301 #else   // ifdef SDK_TWL
302     gMicAutoParam.rate = MIC_SAMPLING_RATE_8K;
303     (void)MIC_StartAutoSampling(&gMicAutoParam);
304 #endif  // ifdef SDK_TWL else
305 
306     /////////////////////
307     // FFT-related
308 
309     MATH_MakeFFTSinTable(sinTable, FFT_NSHIFT);
310 #ifdef USE_FFTREAL
311     MATH_MakeFFTSinTable(sinTable2, FFT_NSHIFT - 1);
312 #endif
313 
314     //Start display
315     OS_WaitVBlankIntr();
316     GX_DispOn();
317 
318     GXS_DispOn();
319 }
320 
DoConnect(void)321 BOOL DoConnect(void)
322 {
323     s32 retry = 0;
324     enum
325     {
326         MAX_RETRY = 5
327     };
328 
329     ObjSet(0, 100, 80, 'C', 4);
330     ObjSet(1, 110, 80, 'O', 4);
331     ObjSet(2, 120, 80, 'N', 4);
332     ObjSet(3, 130, 80, 'N', 4);
333     ObjSet(4, 140, 80, 'E', 4);
334     ObjSet(5, 150, 80, 'C', 4);
335     ObjSet(6, 160, 80, 'T', 4);
336     MI_CpuClear8( (GXOamAttr *)&oamBak[7], sizeof(GXOamAttr) * 12);
337 
338     //---- Wait for V-Blank interrupt completion
339     OS_WaitVBlankIntr();
340 
341     // If this is multiboot, use the GGID declared by the parent device.
342     //   Normally, this should match MY_GGID.
343     WH_SetGgid(isMultiBooted ? mbParentBssDesc.gameInfo.ggid : MY_GGID);
344     retry = 0;
345 
346     while (TRUE)
347     {
348         // Distributes processes based on communication status
349         switch (WH_GetSystemState())
350         {
351         case WH_SYSSTATE_CONNECT_FAIL:
352             {
353                 // Because the internal WM state is invalid if the WM_StartConnect function fails, WM_Reset must be called once to reset the state to IDLE
354                 //
355                 WH_Reset();
356             }
357             break;
358         case WH_SYSSTATE_IDLE:
359             {
360                 if (retry < MAX_RETRY)
361                 {
362                     // Scan for a parent device and connect.
363                     //   When the local device was multibooted, use the parent device BSSID it remembers and connect only to the parent device that was the multiboot source.
364                     //
365                     (void)WH_ChildConnectAuto(WH_CONNECTMODE_DS_CHILD, isMultiBooted ? mbParentBssDesc.bssid : NULL, 0);
366                     retry++;
367                     break;
368                 }
369                 // If connection to parent is not possible after MAX_RETRY, display ERROR
370             }
371         case WH_SYSSTATE_ERROR:
372             return FALSE;
373 
374         case WH_SYSSTATE_DATASHARING:
375             return TRUE;
376 
377         case WH_SYSSTATE_BUSY:
378         case WH_SYSSTATE_SCANNING:
379         case WH_SYSSTATE_CONNECTED:
380         default:
381             break;
382         }
383 
384         OS_WaitVBlankIntr();
385     }
386 
387     // Can't reach here
388     return FALSE;
389 }
390 
DoPadSharing(void)391 void DoPadSharing(void)
392 {
393     int myAid;
394     myAid = WM_GetAID();
395 
396     //================ Main loop
397     while (TRUE)
398     {
399         // Draw Marker by calibrated point
400         while (TP_RequestRawSampling(&raw_point) != 0)
401         {
402         };
403         TP_GetCalibratedPoint(&disp_point, &raw_point);
404 
405         if (disp_point.touch)
406         {
407             SetPoint16x16(0, disp_point.x, disp_point.y, myAid + '0', 1);
408 
409             switch (disp_point.validity)
410             {
411             case TP_VALIDITY_VALID:
412                 OS_TPrintf("( %d, %d ) -> ( %d, %d )\n", raw_point.x, raw_point.y, disp_point.x,
413                            disp_point.y);
414                 break;
415             case TP_VALIDITY_INVALID_X:
416                 OS_TPrintf("( *%d, %d ) -> ( *%d, %d )\n", raw_point.x, raw_point.y, disp_point.x,
417                            disp_point.y);
418                 break;
419             case TP_VALIDITY_INVALID_Y:
420                 OS_TPrintf("( %d, *%d ) -> ( %d, *%d )\n", raw_point.x, raw_point.y, disp_point.x,
421                            disp_point.y);
422                 break;
423             case TP_VALIDITY_INVALID_XY:
424                 OS_TPrintf("( *%d, *%d ) -> ( *%d, *%d )\n", raw_point.x, raw_point.y, disp_point.x,
425                            disp_point.y);
426                 break;
427             }
428         }
429         //---- Wait for V-Blank interrupt completion
430         OS_WaitVBlankIntr();
431 
432         //---- Load pad data
433         keyData = PAD_Read();
434 
435         {
436             static MyPadData sendData ATTRIBUTE_ALIGN(32);
437             int i;
438 
439             // Prepare data to send
440             MI_CpuClear8(&sendData, sizeof(sendData));
441             sendData.keyData = (u16)(keyData | (PAD_DetectFold() ? PAD_DETECT_FOLD_MASK : 0));
442             sendData.touch        = (u8)disp_point.touch;
443             sendData.touchPanel_x = (u8)disp_point.x;
444             sendData.touchPanel_y = (u8)disp_point.y;
445             sendData.mic = (u8)input_mic;
446 
447             if ( WH_StepDS((void*)&sendData) )
448             {
449                 for (i = 0; i < (1 + WH_CHILD_MAX); i++)
450                 {
451                     u8* data;
452 
453                     data = (u8 *)WH_GetSharedDataAdr((u16)i);
454 
455                     if (data != NULL)
456                     {
457                         gRecvFlag[i] = TRUE;
458                         MI_CpuCopy8(data, &gRecvData[i], sizeof(gRecvData[0]));
459                     }
460                     else
461                     {
462                         gRecvFlag[i] = FALSE;
463                     }
464                 }
465             }
466         }
467 
468         //---- Display pad information as OBJ
469         ObjSet(0, 200, 90, 'A', (keyData & PAD_BUTTON_A) ? 1 : 2);
470         ObjSet(1, 180, 95, 'B', (keyData & PAD_BUTTON_B) ? 1 : 2);
471 
472         ObjSet(2, 60, 50, 'L', (keyData & PAD_BUTTON_L) ? 1 : 2);
473         ObjSet(3, 180, 50, 'R', (keyData & PAD_BUTTON_R) ? 1 : 2);
474 
475         ObjSet(4, 60, 80, 'U', (keyData & PAD_KEY_UP) ? 1 : 2);
476         ObjSet(5, 60, 100, 'D', (keyData & PAD_KEY_DOWN) ? 1 : 2);
477         ObjSet(6, 50, 90, 'L', (keyData & PAD_KEY_LEFT) ? 1 : 2);
478         ObjSet(7, 70, 90, 'R', (keyData & PAD_KEY_RIGHT) ? 1 : 2);
479 
480         ObjSet(8, 130, 95, 'S', (keyData & PAD_BUTTON_START) ? 1 : 2);
481         ObjSet(9, 110, 95, 'S', (keyData & PAD_BUTTON_SELECT) ? 1 : 2);
482 
483         ObjSet(10, 200, 75, 'X', (keyData & PAD_BUTTON_X) ? 1 : 2);
484         ObjSet(11, 180, 80, 'Y', (keyData & PAD_BUTTON_Y) ? 1 : 2);
485 
486         //---- Display Folding Detect Status with OBJ
487         ObjSet(12, 120, 30, 'F', (PAD_DetectFold())? 1 : 2);
488 
489         ObjSet(13, 100, 5, 'A', 4);
490         ObjSet(14, 110, 5, 'I', 4);
491         ObjSet(15, 120, 5, 'D', 4);
492         ObjSet(16, 130, 5, (myAid / 10) ? (myAid / 10) + '0' : ' ', 4);
493         ObjSet(17, 140, 5, (myAid % 10) + '0', 4);
494 
495         // Microphone input check
496         input_mic = CheckMicData(MIC_GetLastSamplingAddress());
497         ObjSet(18, 120, 120, 'M', input_mic ? 1 : 2);
498 
499         if( WH_GetSystemState() != WH_SYSSTATE_DATASHARING )
500         {
501             break;
502         }
503 
504         // Render all players' touch information from the received information
505         {
506             int i;
507 
508             for(i = 0; i < WH_CHILD_MAX + 1; i++)
509             {
510                 if( i != myAid && gRecvData[i].touch )
511                 {
512                     SetPoint16x16(i+1, gRecvData[i].touchPanel_x, gRecvData[i].touchPanel_y, '0'+i, 2);
513                 }
514             }
515         }
516     }
517 }
518 
519 //--------------------------------------------------------------------------------
520 //  Set OBJ
521 //
ObjSet(int objNo,int x,int y,int charNo,int paletteNo)522 void ObjSet(int objNo, int x, int y, int charNo, int paletteNo)
523 {
524     G2_SetOBJAttr((GXOamAttr *)&oamBak[objNo],
525                   x,
526                   y,
527                   0,
528                   GX_OAM_MODE_NORMAL,
529                   FALSE,
530                   GX_OAM_EFFECT_NONE, GX_OAM_SHAPE_8x8, GX_OAM_COLOR_16, charNo, paletteNo, 0);
531 }
532 
533 
534 //--------------------------------------------------------------------------------
535 //    V-Blank interrupt process
536 //
VBlankIntr(void)537 void VBlankIntr(void)
538 {
539     //---- OAM updating
540     DC_FlushRange(oamBak, sizeof(oamBak));
541     /* I/O register is accessed using DMA operation, so cache wait is not needed */
542     // DC_WaitWriteBufferEmpty();
543     MI_DmaCopy32(DMA_NO, oamBak, (void *)HW_OAM, sizeof(oamBak));
544 
545     /* Flush cache of OAM buffers to main memory */
546     DC_FlushRange(gOam, sizeof(gOam));
547     /* I/O register is accessed using DMA operation, so cache wait is not needed */
548     // DC_WaitWriteBufferEmpty();
549     GXS_LoadOAM(gOam, 0, sizeof(gOam));
550     MI_DmaFill32(3, gOam, 192, sizeof(gOam));       // Clear OAM buffer
551 
552     //---- Interrupt check flag
553     OS_SetIrqCheckFlag(OS_IE_V_BLANK);
554 }
555 
556 /*---------------------------------------------------------------------------*
557   Name:         InitializeAllocateSystem
558 
559   Description:  Initializes the memory allocation system within the main memory arena.
560 
561   Arguments:    None.
562 
563   Returns:      None.
564  *---------------------------------------------------------------------------*/
InitializeAllocateSystem(void)565 static void InitializeAllocateSystem(void)
566 {
567     void   *tempLo;
568     OSHeapHandle hh;
569 
570     // Based on the premise that OS_Init has been already called
571     tempLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
572     OS_SetArenaLo(OS_ARENA_MAIN, tempLo);
573     hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
574     if (hh < 0)
575     {
576         OS_Panic("ARM9: Fail to create heap...\n");
577     }
578     hh = OS_SetCurrentHeap(OS_ARENA_MAIN, hh);
579 }
580 
581 /*---------------------------------------------------------------------------*
582   Name:         SetPoint16x16
583 
584   Description:  Displays a 16x16 OBJ at indicated point.
585 
586   Arguments:    x: Position X
587                 y: Position Y
588 
589   Returns:      None.
590  *---------------------------------------------------------------------------*/
SetPoint16x16(int objNo,u16 pos_x,u16 pos_y,int charNo,int paletteNo)591 static void SetPoint16x16(int objNo, u16 pos_x, u16 pos_y, int charNo, int paletteNo)
592 {
593     G2_SetOBJAttr((GXOamAttr *)&gOam[objNo],
594                   pos_x - 8,
595                   pos_y - 8,
596                   0,
597                   GX_OAM_MODE_NORMAL,
598                   FALSE,
599                   GX_OAM_EFFECT_NONE, GX_OAM_SHAPE_8x8, GX_OAM_COLOR_16, charNo, paletteNo, 0);
600 }
601 
602 /*---------------------------------------------------------------------------*
603   Name:         CheckMicData
604 
605   Arguments:    address: Mic sampling data
606 
607   Returns:      Whether mic input exists.
608  *---------------------------------------------------------------------------*/
CheckMicData(void * address)609 static BOOL CheckMicData(void *address)
610 {
611     s32     i;
612 
613     u16    *p;
614 
615     // If sampling has never been performed, do nothing and stop.
616     // (Because it would delete memory cache(s) unrelated to the microphone)
617     if ((address < gMicData) || (address >= (gMicData + SAMPLING_BUFFER_SIZE)))
618     {
619         return FALSE;
620     }
621 
622     // Apply a FFT for the FFT_N most recent sampling values
623     // With 12-bit sampling, each value is two bytes
624     p = (u16 *)((u32)address - (FFT_N-1)*2);
625     if ((u32)p < (u32)gMicData)
626     {
627         p = (u16 *)((u32)p + SAMPLING_BUFFER_SIZE);
628     }
629     DC_InvalidateRange((void *)((u32)p & 0xffffffe0), 32);
630     for (i = 0; i < FFT_N; i++)
631     {
632 #ifdef USE_FFTREAL
633         data[i] = ((*p) << (FX32_SHIFT - (16 - 12)));
634 #else
635         data[i * 2] = ((*p) << (FX32_SHIFT - (16 - 12)));
636         data[i * 2 + 1] = 0; // Substitute 0 in the imaginary part
637 #endif
638         p++;
639         if ((u32)p >= (u32)(gMicData + SAMPLING_BUFFER_SIZE))
640         {
641             p = (u16 *)((u32)p - SAMPLING_BUFFER_SIZE);
642         }
643         if (((u32)p % 32) == 0)
644         {
645             DC_InvalidateRange(p, 32);
646         }
647     }
648 
649 #ifdef USE_FFTREAL
650     MATH_FFTReal(data, FFT_NSHIFT, sinTable, sinTable2);
651 #else
652     MATH_FFT(data, FFT_NSHIFT, sinTable);
653 #endif
654 
655     // Do not calculate above FFT_N/2, because only conjugated, inverted values of FFT_N/2 and below will be yielded
656     for (i = 0; i <= FFT_N/2; i++)
657     {
658         fx32 real;
659         fx32 imm;
660 
661 #ifdef USE_FFTREAL
662         if (0 < i  && i < FFT_N/2)
663         {
664             real = data[i * 2];
665             imm  = data[i * 2 + 1];
666         }
667         else
668         {
669             if (i == 0)
670             {
671                 real = data[0];
672             }
673             else // i == FFT_N/2
674             {
675                 real = data[1];
676             }
677             imm  = 0;
678         }
679 #else
680         real = data[i * 2];
681         imm  = data[i * 2 + 1];
682 #endif
683 
684         // Calculate the power of each frequency
685         // If only the relative value size is necessary, omitting the sqrt can result in a speed increase
686         power[i] = FX_Whole(FX_Sqrt(FX_MUL(real, real) + FX_MUL(imm, imm)));
687 
688         // Record the accumulated time values for the power of each frequency
689         // Perform damping a little at a time
690         smoothedPower[i] += power[i] - (smoothedPower[i]/8);
691     }
692 
693     // Microphone input check
694     {
695         s32 totalPower = 0;
696 
697 #define FILTER_LOW 12    // ((8000 Hz/2)/(FFT_N/2)) * 12 = 187.5 Hz
698 #define FILTER_HIGH 64   // ((8000 Hz/2)/(FFT_N/2)) * 64 = 1000.5 Hz
699         for (i = FILTER_LOW; i < FILTER_HIGH; i++)
700         {
701             totalPower += smoothedPower[i];
702         }
703         //OS_TPrintf("totalPower = %d, ave = %d\n", totalPower, totalPower/(FILTER_HIGH-FILTER_LOW));
704         // Check whether the input value is above a fixed amount
705         if (totalPower > (FILTER_HIGH-FILTER_LOW)*64)
706         {
707             return TRUE;
708         }
709     }
710     return FALSE;
711 }
712 
713 /*====== End of main.c ======*/
714