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:: 2009-06-15#$
14   $Rev: 10750 $
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     // DMA is not used in GX (the old DMA conflicts with camera DMA)
222     (void)GX_SetDefaultDMA(GX_DMA_NOT_USE);
223 
224     GX_SetBankForSubBG(GX_VRAM_SUB_BG_128_C);
225 
226     GXS_SetGraphicsMode(GX_BGMODE_3);
227 
228     GXS_SetVisiblePlane(GX_PLANEMASK_BG3);
229     G2S_SetBG3Priority(0);
230     G2S_BG3Mosaic(FALSE);
231 
232     G2S_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x00000);
233 
234     MI_CpuClearFast(shoot_buffer, WIDTH*HEIGHT*sizeof(u16));
235     GXS_LoadBG3Bmp(shoot_buffer, 0, WIDTH*HEIGHT*sizeof(u16));
236 
237     GXS_DispOn();
238 
239     // Initialization
240     OS_InitThread();
241     OS_InitTick();
242     OS_InitAlarm();
243     FS_Init( FS_DMA_NOT_USE );
244 
245     // V-Blank interrupt settings
246     OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
247     (void)OS_EnableIrqMask(OS_IE_V_BLANK);
248     (void)OS_EnableIrq();
249     (void)GX_VBlankIntr(TRUE);
250     (void)OS_EnableInterrupts();
251 
252     // VRAM display mode
253     GX_SetBankForLCDC(GX_VRAM_LCDC_A);
254     MI_CpuClearFast((void*)HW_LCDC_VRAM_A, BYTES_PER_LINE * HEIGHT);
255     wp = 0;
256     rp = 1;
257     wp_pending = TRUE;
258     stabilizedCount = 0;
259     switchFlag = FALSE;
260     GX_SetGraphicsMode(GX_DISPMODE_VRAM_A, GX_BGMODE_0, GX_BG0_AS_2D);
261     OS_WaitVBlankIntr();
262     GX_DispOn();
263 
264     // Initialize camera
265     (void)CameraInit();
266 
267     // Configure DMA interrupt
268     (void)OS_EnableIrqMask(OS_IE_NDMA1);
269 
270     // Camera VSYNC interrupt callback
271     CAMERA_SetVsyncCallback(CameraIntrVsync);
272 
273     // Camera error interrupt callback
274     CAMERA_SetBufferErrorCallback(CameraIntrError);
275 
276     // Camera restart completion callback
277     CAMERA_SetRebootCallback(CameraIntrReboot);
278 
279     CAMERA_SetTrimmingParams(0, 0, WIDTH, HEIGHT);
280     CAMERA_SetTrimming(TRUE);
281     CAMERA_SetOutputFormat(CAMERA_OUTPUT_RGB);
282     CAMERA_SetTransferLines(CAMERA_GET_MAX_LINES(WIDTH));
283 
284     // Start capturing
285     CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
286     CAMERA_ClearBuffer();
287     CAMERA_StartCapture(); // The CAMERA_IsBusy function will immediately return TRUE because it is being called during a camera VSYNC
288     OS_TPrintf("Camera is shooting a movie...\n");
289 
290     DEMOStartDisplay();
291 
292     // Initialize the DSP shutter sound
293     {
294         FSFile  file[1];
295         int     slotB;
296         int     slotC;
297         // 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
298         //
299         (void)MI_FreeWram_B(MI_WRAM_ARM9);
300         (void)MI_CancelWram_B(MI_WRAM_ARM9);
301         (void)MI_FreeWram_C(MI_WRAM_ARM9);
302         (void)MI_CancelWram_C(MI_WRAM_ARM9);
303         slotB = 0xFF;
304         slotC = 0xFF;
305         // For simplification, this sample uses files in static memory
306         FS_InitFile(file);
307         DSPi_OpenStaticComponentG711Core(file);
308         if (!DSP_LoadG711(file, slotB, slotC))
309         {
310             OS_TPanic("failed to load G.711 DSP-component! (lack of WRAM-B/C)");
311         }
312         (void)FS_CloseFile(file);
313 
314         // Initialize extended sound features
315         SNDEX_Init();
316 
317         // Load the shutter sound
318         {
319             FSFile file[1];
320             SNDEXFrequency freq;
321 
322             if(SNDEX_GetI2SFrequency(&freq) != SNDEX_RESULT_SUCCESS)
323             {
324                 OS_Panic("failed SNDEX_GetI2SFrequency");
325             }
326             // The initial I2S operating frequency should be 32.73 kHz
327             if(freq != SNDEX_FREQUENCY_32730)
328             {
329                 OS_Panic("default value is SNDEX_FREQUENCY_32730");
330             }
331 
332             FS_InitFile(file);
333             // Load the 32.73-kHz shutter sound
334             if( !FS_OpenFileEx(file, filename1, FS_FILEMODE_R) )
335             {
336                 OS_Panic("failed FS_OpenFileEx");
337             }
338             len = FS_GetFileLength(file);
339             OS_TPrintf("len = %d\n", len);
340             if( FS_ReadFile(file, StrmBuf, (s32)len) == -1)
341             {
342                 OS_Panic("failed FS_ReadFile");
343             }
344             (void)FS_CloseFile(file);
345             DC_StoreRange(StrmBuf, len);
346         }
347     }
348 
349     /* Initialize sound */
350     SND_Init();
351     SND_AssignWaveArc((SNDBankData*)sound_bank_data, 0, (SNDWaveArc*)sound_wave_data);
352     SND_StartSeq(0, sound_seq_data, 0, (SNDBankData*)sound_bank_data);
353 
354     while (1)
355     {
356         // Reading pad information and controls
357         DEMOReadKey();
358 
359         if (PAD_DetectFold() == TRUE)
360         {
361             // Wait until the shutter sound is done if it is playing
362             while(DSP_IsShutterSoundPlaying())
363             {
364                 OS_Sleep(100);
365             }
366             // Stop the DSP before sleeping
367             DSP_UnloadG711();
368 
369             // Camera stop processing
370             CAMERA_StopCapture();
371             MI_StopNDma(NDMA_NO);
372             result = CAMERA_I2CActivate(CAMERA_SELECT_NONE);
373             if(result == CAMERA_RESULT_FATAL_ERROR)
374                 OS_Panic("CAMERA FATAL ERROR\n");
375             wp_pending = TRUE;      // Also use same frame next time
376             CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
377             CAMERA_ClearBuffer();
378             CAMERA_StartCapture();
379 
380             PM_GoSleepMode(PM_TRIGGER_COVER_OPEN | PM_TRIGGER_CARD, 0, 0);
381 
382             // Restart DSP after recovering from sleep
383             {
384                 FSFile  file[1];
385                 int     slotB;
386                 int     slotC;
387 
388                 slotB = 0xFF;
389                 slotC = 0xFF;
390                 // For simplification, this sample uses files in static memory
391                 FS_InitFile(file);
392                 DSPi_OpenStaticComponentG711Core(file);
393                 if (!DSP_LoadG711(file, slotB, slotC))
394                 {
395                     OS_TPanic("failed to load G.711 DSP-component! (lack of WRAM-B/C)");
396                 }
397                 (void)FS_CloseFile(file);
398             }
399             // Because the camera is also in standby, make it active
400             result = CAMERA_I2CActivate(current_camera);
401             if(result == CAMERA_RESULT_FATAL_ERROR)
402                 OS_Panic("CAMERA FATAL ERROR\n");
403             stabilizedCount = 0;
404         }
405 
406         if(DEMO_IS_TRIG(PAD_BUTTON_A) && (shoot_flag == 0))
407         {
408             while(DSP_PlayShutterSound(StrmBuf, len) == FALSE)
409             {
410             }
411             // When taking still photos, temporarily turn the outer camera LED OFF
412             if(current_camera == CAMERA_SELECT_OUT)
413             {
414                 if(CAMERA_SwitchOffLED() != CAMERA_RESULT_SUCCESS)
415                     OS_TPanic("CAMERA_SwitchOffLED was failed.\n");
416             }
417             OS_Sleep(200);
418             shoot_flag = 1;
419         }
420 
421         if(DEMO_IS_TRIG(PAD_BUTTON_X))
422         {
423             switchFlag = TRUE;
424         }
425 
426         OS_WaitVBlankIntr();
427 
428         if(shoot_flag == 2)
429         {
430             GXS_LoadBG3Bmp((void*)((int)shoot_buffer), 0, BYTES_PER_LINE * HEIGHT);
431             shoot_flag = 0;
432         }
433 
434         // Main sound processing
435         while (SND_RecvCommandReply(SND_COMMAND_NOBLOCK) != NULL)
436         {
437         }
438         (void)SND_FlushCommand(SND_COMMAND_NOBLOCK);
439     }
440 }
441