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