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-09-24#$
14 $Rev: 11063 $
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 // 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 MI_StopNDma(NDMA_NO);
375 result = CAMERA_I2CActivate(CAMERA_SELECT_NONE);
376 if(result == CAMERA_RESULT_FATAL_ERROR)
377 OS_Panic("CAMERA FATAL ERROR\n");
378 wp_pending = TRUE; // Also use same frame next time
379 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
380 CAMERA_ClearBuffer();
381 CAMERA_StartCapture();
382
383 PM_GoSleepMode(PM_TRIGGER_COVER_OPEN | PM_TRIGGER_CARD, 0, 0);
384
385 // Restart DSP after recovering from sleep
386 {
387 FSFile file[1];
388 int slotB;
389 int slotC;
390
391 slotB = 0xFF;
392 slotC = 0xFF;
393 // For simplification, this sample uses files in static memory
394 FS_InitFile(file);
395 DSPi_OpenStaticComponentG711Core(file);
396 if (!DSP_LoadG711(file, slotB, slotC))
397 {
398 OS_TPanic("failed to load G.711 DSP-component! (lack of WRAM-B/C)");
399 }
400 (void)FS_CloseFile(file);
401 }
402 // Because the camera is also in standby, make it active
403 result = CAMERA_I2CActivate(current_camera);
404 if(result == CAMERA_RESULT_FATAL_ERROR)
405 OS_Panic("CAMERA FATAL ERROR\n");
406 stabilizedCount = 0;
407 }
408
409 if(DEMO_IS_TRIG(PAD_BUTTON_A) && (shoot_flag == 0))
410 {
411 while(DSP_PlayShutterSound(StrmBuf, len) == FALSE)
412 {
413 }
414 // When taking still photos, temporarily turn the outer camera LED OFF
415 if(current_camera == CAMERA_SELECT_OUT)
416 {
417 if(CAMERA_SwitchOffLED() != CAMERA_RESULT_SUCCESS)
418 OS_TPanic("CAMERA_SwitchOffLED was failed.\n");
419 }
420 OS_Sleep(200);
421 shoot_flag = 1;
422 }
423
424 if(DEMO_IS_TRIG(PAD_BUTTON_X))
425 {
426 switchFlag = TRUE;
427 }
428
429 OS_WaitVBlankIntr();
430
431 if(shoot_flag == 2)
432 {
433 GXS_LoadBG3Bmp((void*)((int)shoot_buffer), 0, BYTES_PER_LINE * HEIGHT);
434 shoot_flag = 0;
435 }
436
437 // Main sound processing
438 while (SND_RecvCommandReply(SND_COMMAND_NOBLOCK) != NULL)
439 {
440 }
441 (void)SND_FlushCommand(SND_COMMAND_NOBLOCK);
442 }
443 }
444