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