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