1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - demos.TWL - snd - extraFunc
3   File:     main.c
4 
5   Copyright 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:: 2009-09-24#$
14   $Rev: 11063 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 
18 /*---------------------------------------------------------------------------*
19     A sample that uses the SNDEX library.
20 
21     USAGE:
22         UP, DOWN: Switch item to control.
23         LEFT, RIGHT: Set configuration related to selected item.
24 
25     HOWTO:
26         1. Initialize SNDEX library.
27         2. Call functions to set/get each configuration.
28  *---------------------------------------------------------------------------*/
29 
30 #include    <twl.h>
31 #include    "font.h"
32 #include    "snd_data.h"
33 #include    "DEMO.h"
34 
35 /*---------------------------------------------------------------------------*
36     Constant definitions
37  *---------------------------------------------------------------------------*/
38 #define     INDEX_MAX   4
39 
40 /*---------------------------------------------------------------------------*
41     Internal Variable Definitions
42  *---------------------------------------------------------------------------*/
43 static u16      screen[32 * 32] ATTRIBUTE_ALIGN(HW_CACHE_LINE_SIZE);
44 static s32      index   =   0;
45 
46 static SNDEXMute        mute    =   SNDEX_MUTE_OFF;
47 static SNDEXFrequency   freq    =   SNDEX_FREQUENCY_32730;
48 static u8               rate    =   0;
49 static u8               volume  =   0;
50 static BOOL             shutter =   FALSE;
51 
52 
53 /*---------------------------------------------------------------------------*
54     Internal Function Definitions
55  *---------------------------------------------------------------------------*/
56 static BOOL     CheckResult     (SNDEXResult result);
57 static void     UpdateScreen    (void);
58 static void     VBlankIntr      (void);
59 static void     PrintString     (s16 x, s16 y, u8 palette, char *text, ...);
60 static void VolumeSwitchCallback(SNDEXResult result, void* arg);
61 
62 /*---------------------------------------------------------------------------*
63   Name:         TwlMain
64 
65   Description:  Initialization and main loop.
66 
67   Arguments:    None.
68 
69   Returns:      None.
70  *---------------------------------------------------------------------------*/
71 void
TwlMain(void)72 TwlMain (void)
73 {
74     /* Initialization */
75     OS_Init();
76     GX_Init();
77     GX_DispOff();
78     GXS_DispOff();
79 
80     // When in NITRO mode, stopped by Panic
81     DEMOCheckRunOnTWL();
82 
83     /* Initializes display settings */
84     GX_SetBankForLCDC(GX_VRAM_LCDC_ALL);
85     MI_CpuClearFast((void*)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE);
86     (void)GX_DisableBankForLCDC();
87     MI_CpuFillFast((void*)HW_OAM, GX_LCD_SIZE_Y, HW_OAM_SIZE);
88     MI_CpuClearFast((void*)HW_PLTT, HW_PLTT_SIZE);
89     MI_CpuFillFast((void*)HW_DB_OAM, GX_LCD_SIZE_Y, HW_DB_OAM_SIZE);
90     MI_CpuClearFast((void*)HW_DB_PLTT, HW_DB_PLTT_SIZE);
91     GX_SetBankForBG(GX_VRAM_BG_128_A);
92     G2_SetBG0Control(GX_BG_SCRSIZE_TEXT_256x256,
93             GX_BG_COLORMODE_16,
94             GX_BG_SCRBASE_0xf800,      // SCR base block 31
95             GX_BG_CHARBASE_0x00000,    // CHR base block 0
96             GX_BG_EXTPLTT_01);
97     G2_SetBG0Priority(0);
98     GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BG0_AS_2D);
99     GX_SetVisiblePlane(GX_PLANEMASK_BG0);
100     GX_LoadBG0Char(d_CharData, 0, sizeof(d_CharData));
101     GX_LoadBGPltt(d_PaletteData, 0, sizeof(d_PaletteData));
102     MI_CpuClearFast((void*)screen, sizeof(screen));
103     DC_FlushRange(screen, sizeof(screen));
104     GX_LoadBG0Scr(screen, 0, sizeof(screen));
105 
106     /* Interrupt settings */
107     OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
108     (void)OS_EnableIrqMask(OS_IE_V_BLANK);
109     (void)GX_VBlankIntr(TRUE);
110     (void)OS_EnableIrq();
111     (void)OS_EnableInterrupts();
112 
113     /* Initialize sound */
114     SND_Init();
115     SND_AssignWaveArc((SNDBankData*)sound_bank_data, 0, (SNDWaveArc*)sound_wave_data);
116     SND_StartSeq(0, sound_seq_data, 0, (SNDBankData*)sound_bank_data);
117 
118     /* Initialize extended sound features */
119     SNDEX_Init();
120     (void)CheckResult(SNDEX_GetMute(&mute));
121     (void)CheckResult(SNDEX_GetI2SFrequency(&freq));
122     (void)CheckResult(SNDEX_GetDSPMixRate(&rate));
123     (void)CheckResult(SNDEX_GetVolume(&volume));
124     UpdateScreen();
125 
126     /* Set the callback function for when the volume button is pressed */
127     SNDEX_SetVolumeSwitchCallback(VolumeSwitchCallback, NULL);
128 
129     /* LCD display start */
130     GX_DispOn();
131     GXS_DispOn();
132 
133     {
134         u16     keyOld  =   PAD_Read();
135         u16     keyTrg;
136         u16     keyNow;
137         SNDEXHeadphone hp;
138 
139         /* Main loop */
140         while (TRUE)
141         {
142             /* Get key input data */
143             keyNow  =   PAD_Read();
144             keyTrg  =   (u16)((keyOld ^ keyNow) & keyNow);
145             keyOld  =   keyNow;
146 
147             /* Perform various operations in accordance with input */
148             if (keyTrg & PAD_KEY_UP)
149             {
150                 index   =   (index + INDEX_MAX - 1) % INDEX_MAX;
151             }
152             if (keyTrg & PAD_KEY_DOWN)
153             {
154                 index   =   (index + 1) % INDEX_MAX;
155             }
156             if (keyTrg & PAD_KEY_RIGHT)
157             {
158                 switch (index)
159                 {
160                 case 0: // Mute control
161                     if (mute == SNDEX_MUTE_OFF)
162                     {
163                         if (CheckResult(SNDEX_SetMute(SNDEX_MUTE_ON)) == TRUE)
164                         {
165                             mute    =   SNDEX_MUTE_ON;
166                         }
167                     }
168                     break;
169                 case 1: // I2S frequency control
170                     if (freq == SNDEX_FREQUENCY_32730)
171                     {
172                         if (CheckResult(SNDEX_SetI2SFrequency(SNDEX_FREQUENCY_47610)) == TRUE)
173                         {
174                             freq    =   SNDEX_FREQUENCY_47610;
175                         }
176                     }
177                     break;
178                 case 2: // DSP mix rate control
179                     if (rate < SNDEX_DSP_MIX_RATE_MAX)
180                     {
181                         if (CheckResult(SNDEX_SetDSPMixRate((u8)(rate + 1))) == TRUE)
182                         {
183                             rate ++;
184                         }
185                     }
186                     break;
187                 case 3: // Volume control
188                     if (volume < SNDEX_VOLUME_MAX)
189                     {
190                         if (CheckResult(SNDEX_SetVolume((u8)(volume + 1))) == TRUE)
191                         {
192                             volume ++;
193                         }
194                     }
195                     break;
196                 }
197             }
198             if (keyTrg & PAD_KEY_LEFT)
199             {
200                 switch (index)
201                 {
202                 case 0: // Mute control
203                     if (mute == SNDEX_MUTE_ON)
204                     {
205                         if (CheckResult(SNDEX_SetMute(SNDEX_MUTE_OFF)) == TRUE)
206                         {
207                             mute    =   SNDEX_MUTE_OFF;
208                         }
209                     }
210                     break;
211                 case 1: // I2S frequency control
212                     if (freq == SNDEX_FREQUENCY_47610)
213                     {
214                         if (CheckResult(SNDEX_SetI2SFrequency(SNDEX_FREQUENCY_32730)) == TRUE)
215                         {
216                             freq    =   SNDEX_FREQUENCY_32730;
217                         }
218                     }
219                     break;
220                 case 2: // DSP mix rate control
221                     if (rate > SNDEX_DSP_MIX_RATE_MIN)
222                     {
223                         if (CheckResult(SNDEX_SetDSPMixRate((u8)(rate - 1))) == TRUE)
224                         {
225                             rate --;
226                         }
227                     }
228                     break;
229                 case 3: // Volume control
230                     if (volume > SNDEX_VOLUME_MIN)
231                     {
232                         if (CheckResult(SNDEX_SetVolume((u8)(volume - 1))) == TRUE)
233                         {
234                             volume --;
235                         }
236                     }
237                     break;
238                 }
239             }
240             if (keyTrg & PAD_BUTTON_A)
241             {
242                 /* Determine if headphones are connected */
243                 if (SNDEX_PXI_RESULT_SUCCESS == SNDEX_IsConnectedHeadphone(&hp))
244                 {
245                     if (hp == SNDEX_HEADPHONE_CONNECT)
246                     {
247                         OS_TPrintf("Headphone is connected.\n");
248                     }
249                     else
250                     {
251                         OS_TPrintf("Headphone is unconnected.\n");
252                     }
253                 }
254             }
255 
256             /* Main sound processing */
257             while (SND_RecvCommandReply(SND_COMMAND_NOBLOCK) != NULL)
258             {
259             }
260             (void)SND_FlushCommand(SND_COMMAND_NOBLOCK);
261 
262             /* Make the 'volume' value change in response to changes in audio volume */
263             (void)CheckResult(SNDEX_GetVolume(&volume));
264 
265             /* Screen update */
266             UpdateScreen();
267 
268             /* Wait for V-Blank */
269             OS_WaitVBlankIntr();
270         }
271     }
272 }
273 
274 /*---------------------------------------------------------------------------*
275   Name:         CheckResult
276 
277   Description:  Confirms the results of SNDEX library function calls.
278 
279   Arguments:    result: Value returned from the function
280 
281   Returns:      BOOL: Returns TRUE when the function call was successful.
282                             Returns FALSE if there was a failure for any reason.
283  *---------------------------------------------------------------------------*/
284 static BOOL
CheckResult(SNDEXResult result)285 CheckResult (SNDEXResult result)
286 {
287     switch (result)
288     {
289     case SNDEX_RESULT_SUCCESS:
290         return TRUE;
291     case SNDEX_RESULT_BEFORE_INIT:
292         /* Before library initialization.
293             The SNDEX_Init function must be called before any other functions. */
294         OS_TWarning("Not initialized.\n");
295         break;
296     case SNDEX_RESULT_INVALID_PARAM:
297         /* Unknown parameter.
298             Review the argument(s) being passed to the function. */
299         OS_TWarning("Invalid parameter.\n");
300         break;
301     case SNDEX_RESULT_EXCLUSIVE:
302         /* Mutex is in effect.
303             Do not make consecutive calls of asynchronous functions or use the SNDEX library asynchronously from multiple threads.
304              */
305         OS_TWarning("Overlapped requests.\n");
306         break;
307     case SNDEX_RESULT_ILLEGAL_STATE:
308         /* Abnormal state.
309             The SNDEX library can only be used with TWL hardware.
310             Synchronous functions can't be called from within exception handlers.
311             When the CODEC is in DS Mode, you cannot switch to forced audio output.
312             When the CODEC is in DS Mode, when audio output is being forced, or when the microphone is auto-sampling, the I2S frequency cannot be changed.
313              */
314         OS_TWarning("In unavailable state.\n");
315         break;
316     case SNDEX_RESULT_PXI_SEND_ERROR:
317         /* PXI send error.
318             The data sending queue from ARM9 to ARM7 is full. Please wait a little before retrying so that ARM7 can delete data within the queue.
319              */
320         OS_TWarning("PXI queue full.\n");
321         break;
322     case SNDEX_RESULT_DEVICE_ERROR:
323         /* Failed to operate device.
324             An attempt was made to access an external CPU device (the microprocessor) to get or change volume, but that access failed.
325             If conditions don't improve even after multiple retries, consider it a success and move on, since the problem is likely caused by a runaway microprocessor, malfunctioning hardware, or some other thing not recoverable by software.
326 
327              */
328         OS_TWarning("Micro controller unusual.\n");
329         return TRUE;
330     case SNDEX_RESULT_FATAL_ERROR:
331     default:
332         /* Fatal error.
333             By the library's logic, this cannot occur. It's possible this occurred (1) when a PXI command was directly issued to ARM7 (ignoring the library's internal status management), (2) when memory damage resulted in inconsistencies in internal status management, or (3) when this was combined with an unexpected ARM7 component, or for some similar reason.
334 
335 
336              */
337         OS_TWarning("Fatal error.\n");
338         break;
339     }
340     return FALSE;
341 }
342 
343 /*---------------------------------------------------------------------------*
344   Name:         UpdateScreen
345 
346   Description:  Updates the displayed screen content.
347 
348   Arguments:    None.
349 
350   Returns:      None.
351  *---------------------------------------------------------------------------*/
352 static void
UpdateScreen(void)353 UpdateScreen (void)
354 {
355     /* Clear the virtual screen */
356     MI_CpuClearFast((void*)screen, sizeof(screen));
357 
358     /* Edit a string on the virtual screen */
359     PrintString(2, 1, 0xf, "Mute     : %d/1 [ %s ]", mute, ((mute == SNDEX_MUTE_OFF) ? "OFF" : "ON"));
360     PrintString(2, 3, 0xf, "I2S freq : %d/1 [ %s ]", freq, ((freq == SNDEX_FREQUENCY_32730) ? "32K" : "48K"));
361     PrintString(2, 5, 0xf, "DSP mix  : %d/8", rate);
362     PrintString(2, 7, 0xf, "Volume   : %d/%d", volume, (u8)SNDEX_VOLUME_MAX);
363 
364     PrintString(0, 11, 0xe, "- [A] : Check Headphone");
365     PrintString(0, 13, 0xe, "- [Volume Button] : Print log");
366 
367     /* Change the selected item's display color */
368     PrintString(0, (s16)(index * 2 + 1), 0xf, ">");
369     {
370         s32     i;
371         s32     j;
372 
373         for (i = 0; i < 32; i ++)
374         {
375             j   =   ((index * 2 + 1) * 32) + i;
376             screen[j]   &=  (u16)(~(0xf << 12));
377             screen[j]   |=  (u16)(0x4 << 12);
378         }
379     }
380 }
381 
382 /*---------------------------------------------------------------------------*
383   Name:         VBlankIntr
384 
385   Description:  V-Blank interrupt vector.
386 
387   Arguments:    None.
388 
389   Returns:      None.
390  *---------------------------------------------------------------------------*/
391 static void
VBlankIntr(void)392 VBlankIntr (void)
393 {
394     /* Reflect virtual screen in VRAM */
395     DC_FlushRange(screen, sizeof(screen));
396     GX_LoadBG0Scr(screen, 0, sizeof(screen));
397 
398     /* Sets the IRQ check flag */
399     OS_SetIrqCheckFlag(OS_IE_V_BLANK);
400 }
401 
402 /*---------------------------------------------------------------------------*
403   Name:         PrintString
404 
405   Description:  Positions the text string on the virtual screen. The string can be up to 32 chars.
406 
407   Arguments:    x: X-coordinate where character string starts (x 8 pixels).
408                 y: Y-coordinate where character string starts (x 8 pixels).
409                 palette: Specify text color by palette number.
410                 text: Text string to position. Null-terminated.
411                 ...: Virtual argument.
412 
413   Returns:      None.
414  *---------------------------------------------------------------------------*/
415 static void
PrintString(s16 x,s16 y,u8 palette,char * text,...)416 PrintString (s16 x, s16 y, u8 palette, char *text, ...)
417 {
418     va_list vlist;
419     char    temp[32 + 2];
420     s32     i;
421 
422     va_start(vlist, text);
423     (void)vsnprintf(temp, 33, text, vlist);
424     va_end(vlist);
425 
426     *((u16*)(&temp[32]))    =   0x0000;
427     for (i = 0; ; i++)
428     {
429         if (temp[i] == 0x00)
430         {
431             break;
432         }
433         screen[((y * 32) + x + i) % (32 * 32)] = (u16)((palette << 12) | temp[i]);
434     }
435 }
436 
437 /*---------------------------------------------------------------------------*
438   Name:         VolumeSwitchCallback
439 
440   Description:  Callback function executed when the volume button on the TWL is pressed.
441 
442   Arguments:    result: Result of pressing the volume button
443                 arg: Argument passed when this function is called as a callback function
444 
445 
446   Returns:      None.
447  *---------------------------------------------------------------------------*/
VolumeSwitchCallback(SNDEXResult result,void * arg)448 static void VolumeSwitchCallback(SNDEXResult result, void* arg)
449 {
450 #pragma unused( arg )
451 #pragma unused( result )
452 
453     /* SNDEX library functions cannot be used during callback processing.*
454      * SNDEX_RESULT_EXCLUSIVE is returned.                         */
455     OS_TPrintf("volume switch pressed.\n");
456 }
457