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