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