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