1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - CAMERA - demos - simpleShoot-1
3   File:     main.c
4 
5   Copyright 2003-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:: 2010-05-20#$
14   $Rev: 11344 $
15   $Author: kitase_hirotake $
16  *---------------------------------------------------------------------------*/
17 
18 #include <twl.h>
19 #include "DEMO.h"
20 #include <twl/camera.h>
21 #include <twl/dsp.h>
22 #include <twl/dsp/common/g711.h>
23 
24 #include    "snd_data.h"
25 
26 #define NDMA_NO      1           // The NDMA number (0 to 3) to use
27 #define WIDTH       256         // Image width
28 #define HEIGHT      192         // Image height
29 
30 #define LINES_AT_ONCE   CAMERA_GET_MAX_LINES(WIDTH)     // Number of lines transferred in one cycle
31 #define BYTES_PER_LINE  CAMERA_GET_LINE_BYTES(WIDTH)    // Number of bytes in one line's transfer
32 
33 void VBlankIntr(void);
34 static BOOL CameraInit(void);
35 static void CameraIntrVsync(CAMERAResult result);
36 static void CameraIntrError(CAMERAResult result);
37 static void CameraIntrReboot(CAMERAResult result);
38 static void CameraDmaRecvIntr(void* arg);
39 
40 static int wp;  // Buffer while capturing data from camera
41 static int rp;  // Buffer most recently copied to VRAM
42 static BOOL wp_pending; // Data capture was cancelled (recapture to same buffer)
43 static u32 stabilizedCount;
44 static u16 buffer[2][WIDTH*HEIGHT] ATTRIBUTE_ALIGN(32);
45 
46 static BOOL switchFlag;
47 
48 #define STRM_BUF_SIZE 1024*64
49 
50 static char StrmBuf[STRM_BUF_SIZE] ATTRIBUTE_ALIGN(32);
51 static u32 len;
52 
53 // Filename
54 static const char filename1[] = "shutter_sound_32730.wav";
55 
DebugReport(void)56 static void DebugReport(void)
57 {
58     OS_TPrintf("\nCapture to No.%d\tDisplay from No.%d\n", wp, rp);
59 }
PendingCapture(void)60 static void PendingCapture(void)
61 {
62     wp_pending = TRUE;
63 }
64 
65 // Buffer storing photographed/filmed images
66 static u16 shoot_buffer[WIDTH*HEIGHT] ATTRIBUTE_ALIGN(32);
67 static int shoot_flag = 0;
68 
69 static CAMERASelect current_camera = CAMERA_SELECT_IN;
70 
71 //--------------------------------------------------------------------------------
72 //    V-Blank interrupt process
73 //
VBlankIntr(void)74 void VBlankIntr(void)
75 {
76     OS_SetIrqCheckFlag(OS_IE_V_BLANK);
77     if (wp == rp)
78     {
79         rp ^= 1;
80         MI_CpuCopyFast(buffer[rp], (void*)HW_LCDC_VRAM_A, BYTES_PER_LINE * HEIGHT);
81         DC_InvalidateRange(buffer[rp], BYTES_PER_LINE * HEIGHT);
82     }
83     if(shoot_flag == 1)
84     {
85         MI_CpuCopyFast(buffer[rp], (void*)shoot_buffer, BYTES_PER_LINE * HEIGHT);
86         shoot_flag = 2;
87     }
88 }
89 
90 //--------------------------------------------------------------------------------
91 //    Camera initialization (only the Init- and I2C-related initialization)
92 //
CameraInit(void)93 BOOL CameraInit(void)
94 {
95     CAMERAResult result;
96     result = CAMERA_Init();
97     if(result == CAMERA_RESULT_FATAL_ERROR)
98         OS_TPanic("CAMERA_Init was failed.");
99     if(result == CAMERA_RESULT_ILLEGAL_STATUS)
100         return FALSE;
101 
102     result = CAMERA_I2CEffect(current_camera, CAMERA_EFFECT_NONE);
103     if (result != CAMERA_RESULT_SUCCESS)
104     {
105         OS_TPrintf("CAMERA_I2CEffect was failed. (%d)\n", result);
106     }
107 
108     result = CAMERA_I2CActivate(current_camera);
109     if (result == CAMERA_RESULT_FATAL_ERROR)
110         OS_TPanic("CAMERA_I2CActivate was failed. (%d)\n", result);
111     if(result == CAMERA_RESULT_ILLEGAL_STATUS)
112         return FALSE;
113     stabilizedCount = 0;
114 
115     return TRUE;
116 }
117 
118 //--------------------------------------------------------------------------------
119 //    Camera interrupt process (occurs both when there is an error and for Vsync)
120 //
121 #define PRINT_RATE  32
CameraIntrError(CAMERAResult result)122 void CameraIntrError(CAMERAResult result)
123 {
124 #pragma unused(result)
125     OS_TPrintf("Error was occurred.\n");
126     // Camera stop processing
127     CAMERA_StopCapture();
128     MI_StopNDma(NDMA_NO);
129     CAMERA_ClearBuffer();
130     wp_pending = TRUE;      // Also use same frame next time
131     CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
132     CAMERA_StartCapture();
133 }
134 
CameraIntrReboot(CAMERAResult result)135 void CameraIntrReboot(CAMERAResult result)
136 {
137     if(result == CAMERA_RESULT_FATAL_ERROR)
138     {
139         return; // Restore was not possible, even after restarting camera
140     }
141     CameraIntrError(result); // DMA synchronization might have drifted, so realign
142 }
143 
CameraIntrVsync(CAMERAResult result)144 void CameraIntrVsync(CAMERAResult result)
145 {
146 #pragma unused(result)
147     if(stabilizedCount <= 30)
148         stabilizedCount++;
149     if(switchFlag)
150     {
151         current_camera = (current_camera == CAMERA_SELECT_IN ? CAMERA_SELECT_OUT : CAMERA_SELECT_IN);
152         result = CAMERA_I2CActivate(current_camera);
153         if(result == CAMERA_RESULT_FATAL_ERROR)
154             OS_Panic("CAMERA FATAL ERROR\n");
155         stabilizedCount = 0;
156         switchFlag = FALSE;
157     }
158 }
159 
CameraDmaRecvIntr(void * arg)160 void CameraDmaRecvIntr(void* arg)
161 {
162 #pragma unused(arg)
163     MI_StopNDma(NDMA_NO);
164 
165     if (CAMERA_IsBusy() == TRUE)
166     {
167         OS_TPrintf(".");
168         if (MI_IsNDmaBusy(NDMA_NO)) // Check whether image transfer is complete
169         {
170             OS_TPrintf("DMA was not done until VBlank.\n");
171             MI_StopNDma(NDMA_NO);
172         }
173         // Start the next frame capture
174         if (wp_pending)
175         {
176             wp_pending = FALSE;
177         }
178         else
179         {
180             // Capture results are not displayed on screen until camera is stable
181             // This demo waits the minimum of four camera frames required to avoid chromatic aberration, but if you want to wait until auto-exposure is stable, you need to wait 14 frames for an indoor shot or 30 for an outdoor one, as indicated in the Function Reference.
182             //
183             if(stabilizedCount > 4)
184             {
185                 wp ^= 1;
186             }
187         }
188         CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
189     }
190 
191     {
192         static OSTick begin = 0;
193         static int count = 0;
194         if (begin == 0)
195         {
196             begin = OS_GetTick();
197         }
198         else if (++count == PRINT_RATE)
199         {
200             OSTick uspf = OS_TicksToMicroSeconds(OS_GetTick() - begin) / count;
201             int mfps = (int)(1000000000LL / uspf);
202             OS_TPrintf("%2d.%03d fps\n", mfps / 1000, mfps % 1000);
203             count = 0;
204             begin = OS_GetTick();
205         }
206     }
207 }
208 
TwlMain(void)209 void TwlMain(void)
210 {
211     int     vram_slot = 0, count = 0;
212     CAMERAResult result;
213 
214     //---------------------------------------------------------------------------
215     // Initialize:
216     // Enable IRQ interrupts and initialize VRAM
217     //---------------------------------------------------------------------------
218     DEMOInitCommon();
219     DEMOInitVRAM();
220 
221     // When in NITRO mode, stopped by Panic
222     DEMOCheckRunOnTWL();
223 
224     // DMA is not used in GX (the old DMA conflicts with camera DMA)
225     (void)GX_SetDefaultDMA(GX_DMA_NOT_USE);
226 
227     GX_SetBankForSubBG(GX_VRAM_SUB_BG_128_C);
228 
229     GXS_SetGraphicsMode(GX_BGMODE_3);
230 
231     GXS_SetVisiblePlane(GX_PLANEMASK_BG3);
232     G2S_SetBG3Priority(0);
233     G2S_BG3Mosaic(FALSE);
234 
235     G2S_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x00000);
236 
237     MI_CpuClearFast(shoot_buffer, WIDTH*HEIGHT*sizeof(u16));
238     GXS_LoadBG3Bmp(shoot_buffer, 0, WIDTH*HEIGHT*sizeof(u16));
239 
240     GXS_DispOn();
241 
242     // Initialization
243     OS_InitThread();
244     OS_InitTick();
245     OS_InitAlarm();
246     FS_Init( FS_DMA_NOT_USE );
247 
248     // V-Blank interrupt settings
249     OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
250     (void)OS_EnableIrqMask(OS_IE_V_BLANK);
251     (void)OS_EnableIrq();
252     (void)GX_VBlankIntr(TRUE);
253     (void)OS_EnableInterrupts();
254 
255     // VRAM display mode
256     GX_SetBankForLCDC(GX_VRAM_LCDC_A);
257     MI_CpuClearFast((void*)HW_LCDC_VRAM_A, BYTES_PER_LINE * HEIGHT);
258     wp = 0;
259     rp = 1;
260     wp_pending = TRUE;
261     stabilizedCount = 0;
262     switchFlag = FALSE;
263     GX_SetGraphicsMode(GX_DISPMODE_VRAM_A, GX_BGMODE_0, GX_BG0_AS_2D);
264     OS_WaitVBlankIntr();
265     GX_DispOn();
266 
267     // Initialize camera
268     (void)CameraInit();
269 
270     // Configure DMA interrupt
271     (void)OS_EnableIrqMask(OS_IE_NDMA1);
272 
273     // Camera VSYNC interrupt callback
274     CAMERA_SetVsyncCallback(CameraIntrVsync);
275 
276     // Camera error interrupt callback
277     CAMERA_SetBufferErrorCallback(CameraIntrError);
278 
279     // Camera restart completion callback
280     CAMERA_SetRebootCallback(CameraIntrReboot);
281 
282     CAMERA_SetTrimmingParams(0, 0, WIDTH, HEIGHT);
283     CAMERA_SetTrimming(TRUE);
284     CAMERA_SetOutputFormat(CAMERA_OUTPUT_RGB);
285     CAMERA_SetTransferLines(CAMERA_GET_MAX_LINES(WIDTH));
286 
287     // Start capturing
288     CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
289     CAMERA_ClearBuffer();
290     CAMERA_StartCapture(); // The CAMERA_IsBusy function returns TRUE immediately because it is being called during a camera VSYNC
291     OS_TPrintf("Camera is shooting a movie...\n");
292 
293     DEMOStartDisplay();
294 
295     // Initialize the DSP shutter sound
296     {
297         FSFile  file[1];
298         int     slotB;
299         int     slotC;
300         // In this sample, all of the WRAM is allocated for the DSP, but for actual use, you would only need as many slots as were necessary
301         //
302         (void)MI_FreeWram_B(MI_WRAM_ARM9);
303         (void)MI_CancelWram_B(MI_WRAM_ARM9);
304         (void)MI_FreeWram_C(MI_WRAM_ARM9);
305         (void)MI_CancelWram_C(MI_WRAM_ARM9);
306         slotB = 0xFF;
307         slotC = 0xFF;
308         // For simplification, this sample uses files in static memory
309         FS_InitFile(file);
310         DSPi_OpenStaticComponentG711Core(file);
311         if (!DSP_LoadG711(file, slotB, slotC))
312         {
313             OS_TPanic("failed to load G.711 DSP-component! (lack of WRAM-B/C)");
314         }
315         (void)FS_CloseFile(file);
316 
317         // Initialize extended sound features
318         SNDEX_Init();
319 
320         // Load the shutter sound
321         {
322             FSFile file[1];
323             SNDEXFrequency freq;
324 
325             if(SNDEX_GetI2SFrequency(&freq) != SNDEX_RESULT_SUCCESS)
326             {
327                 OS_Panic("failed SNDEX_GetI2SFrequency");
328             }
329             // The initial I2S operating frequency should be 32.73 kHz
330             if(freq != SNDEX_FREQUENCY_32730)
331             {
332                 OS_Panic("default value is SNDEX_FREQUENCY_32730");
333             }
334 
335             FS_InitFile(file);
336             // Load the 32.73-kHz shutter sound
337             if( !FS_OpenFileEx(file, filename1, FS_FILEMODE_R) )
338             {
339                 OS_Panic("failed FS_OpenFileEx");
340             }
341             len = FS_GetFileLength(file);
342             OS_TPrintf("len = %d\n", len);
343             if( FS_ReadFile(file, StrmBuf, (s32)len) == -1)
344             {
345                 OS_Panic("failed FS_ReadFile");
346             }
347             (void)FS_CloseFile(file);
348             DC_StoreRange(StrmBuf, len);
349         }
350     }
351 
352     /* Initialize sound */
353     SND_Init();
354     SND_AssignWaveArc((SNDBankData*)sound_bank_data, 0, (SNDWaveArc*)sound_wave_data);
355     SND_StartSeq(0, sound_seq_data, 0, (SNDBankData*)sound_bank_data);
356 
357     while (1)
358     {
359         // Reading pad information and controls
360         DEMOReadKey();
361 
362         if (PAD_DetectFold() == TRUE)
363         {
364             // Wait until the shutter sound is done if it is playing
365             while(DSP_IsShutterSoundPlaying())
366             {
367                 OS_Sleep(100);
368             }
369             // Stop the DSP before sleeping
370             DSP_UnloadG711();
371 
372             // Camera stop processing
373             CAMERA_StopCapture();
374             while (CAMERA_IsBusy() == TRUE)
375             {
376                 ;
377             }
378             MI_StopNDma(NDMA_NO);
379             result = CAMERA_I2CActivate(CAMERA_SELECT_NONE);
380             if(result == CAMERA_RESULT_FATAL_ERROR)
381                 OS_Panic("CAMERA FATAL ERROR\n");
382             wp_pending = TRUE;      // Also use same frame next time
383 
384             PM_GoSleepMode(PM_TRIGGER_COVER_OPEN | PM_TRIGGER_CARD, 0, 0);
385 
386             // Restart DSP after recovering from sleep
387             {
388                 FSFile  file[1];
389                 int     slotB;
390                 int     slotC;
391 
392                 slotB = 0xFF;
393                 slotC = 0xFF;
394                 // For simplification, this sample uses files in static memory
395                 FS_InitFile(file);
396                 DSPi_OpenStaticComponentG711Core(file);
397                 if (!DSP_LoadG711(file, slotB, slotC))
398                 {
399                     OS_TPanic("failed to load G.711 DSP-component! (lack of WRAM-B/C)");
400                 }
401                 (void)FS_CloseFile(file);
402             }
403             // Because the camera is also in standby, make it active
404             result = CAMERA_I2CActivate(current_camera);
405             if(result == CAMERA_RESULT_FATAL_ERROR)
406                 OS_Panic("CAMERA FATAL ERROR\n");
407             CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
408             CAMERA_ClearBuffer();
409             CAMERA_StartCapture();
410             stabilizedCount = 0;
411         }
412 
413         if(DEMO_IS_TRIG(PAD_BUTTON_A) && (shoot_flag == 0))
414         {
415             while(DSP_PlayShutterSound(StrmBuf, len) == FALSE)
416             {
417             }
418             // When taking still photos, temporarily turn the outer camera LED OFF
419             if(current_camera == CAMERA_SELECT_OUT)
420             {
421                 if(CAMERA_SwitchOffLED() != CAMERA_RESULT_SUCCESS)
422                     OS_TPanic("CAMERA_SwitchOffLED was failed.\n");
423             }
424             OS_Sleep(200);
425             shoot_flag = 1;
426         }
427 
428         if(DEMO_IS_TRIG(PAD_BUTTON_X))
429         {
430             switchFlag = TRUE;
431         }
432 
433         OS_WaitVBlankIntr();
434 
435         if(shoot_flag == 2)
436         {
437             GXS_LoadBG3Bmp((void*)((int)shoot_buffer), 0, BYTES_PER_LINE * HEIGHT);
438             shoot_flag = 0;
439         }
440 
441         // Main sound processing
442         while (SND_RecvCommandReply(SND_COMMAND_NOBLOCK) != NULL)
443         {
444         }
445         (void)SND_FlushCommand(SND_COMMAND_NOBLOCK);
446     }
447 }
448