1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - CAMERA - demos - simpleShoot-2
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-04-21#$
14 $Rev: 10434 $
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_shutter[STRM_BUF_SIZE] ATTRIBUTE_ALIGN(32);
51 static u32 len_shutter;
52 static char StrmBuf_begin[STRM_BUF_SIZE] ATTRIBUTE_ALIGN(32);
53 static u32 len_begin;
54 static char StrmBuf_end[STRM_BUF_SIZE] ATTRIBUTE_ALIGN(32);
55 static u32 len_end;
56
57 // Filename
58 static const char filename_shutter[] = "shutter_sound/shutter_sound_32730.wav";
59 static const char filename_begin[] = "videorec_sound/videorec_sound_begin_32730.wav";
60 static const char filename_end[] = "videorec_sound/videorec_sound_end_32730.wav";
61
DebugReport(void)62 static void DebugReport(void)
63 {
64 OS_TPrintf("\nCapture to No.%d\tDisplay from No.%d\n", wp, rp);
65 }
PendingCapture(void)66 static void PendingCapture(void)
67 {
68 wp_pending = TRUE;
69 }
70
71 // Buffer storing photographed/filmed images
72 static u16 shoot_buffer[WIDTH*HEIGHT] ATTRIBUTE_ALIGN(32);
73 static int shoot_flag = 0;
74
75 // REC icon
76 extern u16 _binary_rec_icon_nbfs[];
77
78 static u16* movie_buffer; // Video buffer
79 static u32 movie_buffer_max_count = 0;
80 static u32 movie_buffer_count = 0;
81 static int movie_flag = 0;
82
83 static CAMERASelect current_camera = CAMERA_SELECT_IN;
84
85 //--------------------------------------------------------------------------------
86 // V-Blank interrupt process
87 //
VBlankIntr(void)88 void VBlankIntr(void)
89 {
90 OS_SetIrqCheckFlag(OS_IE_V_BLANK);
91 if (wp == rp)
92 {
93 rp ^= 1;
94 MI_CpuCopyFast(buffer[rp], (void*)HW_LCDC_VRAM_A, BYTES_PER_LINE * HEIGHT);
95 if(movie_flag == 1)
96 {
97 int i = 0;
98 MI_CpuCopy(_binary_rec_icon_nbfs+1, (void*)(HW_LCDC_VRAM_A + sizeof(u16)*1), sizeof(u16) * 30);
99 for(i = 1; i < 12; i++)
100 MI_CpuCopy(_binary_rec_icon_nbfs+32*i, (void*)(HW_LCDC_VRAM_A + sizeof(u16)*256*i), sizeof(u16) * 32);
101 MI_CpuCopy(_binary_rec_icon_nbfs+32*12+1, (void*)(HW_LCDC_VRAM_A + sizeof(u16)*256*12+sizeof(u16)*1), sizeof(u16) * 30);
102 }
103 DC_InvalidateRange(buffer[rp], BYTES_PER_LINE * HEIGHT);
104 if(movie_flag == 1)
105 {
106 MI_CpuCopyFast(buffer[rp], (void*)(movie_buffer+(WIDTH*HEIGHT*movie_buffer_count)), BYTES_PER_LINE * HEIGHT);
107 movie_buffer_count++;
108 if(movie_buffer_count > movie_buffer_max_count)
109 movie_flag = 2;
110 }
111 }
112 if(shoot_flag == 1)
113 {
114 MI_CpuCopyFast(buffer[rp], (void*)shoot_buffer, BYTES_PER_LINE * HEIGHT);
115 shoot_flag = 2;
116 }
117 }
118
119 //--------------------------------------------------------------------------------
120 // Camera initialization (only the Init- and I2C-related initialization)
121 //
CameraInit(void)122 BOOL CameraInit(void)
123 {
124 CAMERAResult result;
125 result = CAMERA_Init();
126 if(result == CAMERA_RESULT_FATAL_ERROR)
127 OS_TPanic("CAMERA_Init was failed.");
128 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
129 return FALSE;
130
131 result = CAMERA_I2CEffect(CAMERA_SELECT_IN, CAMERA_EFFECT_NONE);
132 if (result != CAMERA_RESULT_SUCCESS)
133 {
134 OS_TPrintf("CAMERA_I2CEffect was failed. (%d)\n", result);
135 }
136
137 result = CAMERA_I2CActivate(current_camera);
138 if (result == CAMERA_RESULT_FATAL_ERROR)
139 OS_TPanic("CAMERA_I2CActivate was failed. (%d)\n", result);
140 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
141 return FALSE;
142 stabilizedCount = 0;
143
144 return TRUE;
145 }
146
147 //--------------------------------------------------------------------------------
148 // Camera interrupt process (occurs both when there is an error and for Vsync)
149 //
150 #define PRINT_RATE 32
CameraIntrError(CAMERAResult result)151 void CameraIntrError(CAMERAResult result)
152 {
153 #pragma unused(result)
154 OS_TPrintf("Error was occurred.\n");
155 // Camera stop processing
156 CAMERA_StopCapture();
157 MI_StopNDma(NDMA_NO);
158 CAMERA_ClearBuffer();
159 wp_pending = TRUE; // Also use same frame next time
160 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
161 CAMERA_StartCapture();
162 }
163
CameraIntrReboot(CAMERAResult result)164 void CameraIntrReboot(CAMERAResult result)
165 {
166 if(result == CAMERA_RESULT_FATAL_ERROR)
167 {
168 return; // Restore was not possible, even after restarting camera
169 }
170 CameraIntrError(result); // DMA synchronization might have drifted, so realign
171 }
172
CameraIntrVsync(CAMERAResult result)173 void CameraIntrVsync(CAMERAResult result)
174 {
175 #pragma unused(result)
176 if(stabilizedCount <= 30)
177 stabilizedCount++;
178 if(switchFlag)
179 {
180 current_camera = (current_camera == CAMERA_SELECT_IN ? CAMERA_SELECT_OUT : CAMERA_SELECT_IN);
181 result = CAMERA_I2CActivate(current_camera);
182 if(result == CAMERA_RESULT_FATAL_ERROR)
183 OS_Panic("CAMERA FATAL ERROR\n");
184 stabilizedCount = 0;
185 switchFlag = FALSE;
186 }
187 }
188
CameraDmaRecvIntr(void * arg)189 void CameraDmaRecvIntr(void* arg)
190 {
191 #pragma unused(arg)
192 MI_StopNDma(NDMA_NO);
193
194 if (CAMERA_IsBusy() == TRUE)
195 {
196 OS_TPrintf(".");
197 if (MI_IsNDmaBusy(NDMA_NO)) // Check whether image transfer is complete
198 {
199 OS_TPrintf("DMA was not done until VBlank.\n");
200 MI_StopNDma(NDMA_NO);
201 }
202 // Start the next frame capture
203 if (wp_pending)
204 {
205 wp_pending = FALSE;
206 }
207 else
208 {
209 // Capture results are not displayed on screen until camera is stable
210 // 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.
211 //
212 if(stabilizedCount > 4)
213 {
214 wp ^= 1;
215 }
216 }
217 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
218 }
219
220 {
221 static OSTick begin = 0;
222 static int count = 0;
223 if (begin == 0)
224 {
225 begin = OS_GetTick();
226 }
227 else if (++count == PRINT_RATE)
228 {
229 OSTick uspf = OS_TicksToMicroSeconds(OS_GetTick() - begin) / count;
230 int mfps = (int)(1000000000LL / uspf);
231 OS_TPrintf("%2d.%03d fps\n", mfps / 1000, mfps % 1000);
232 count = 0;
233 begin = OS_GetTick();
234 }
235 }
236 }
237
TwlMain(void)238 void TwlMain(void)
239 {
240 int vram_slot = 0, count = 0;
241 CAMERAResult result;
242
243 //---------------------------------------------------------------------------
244 // Initialize:
245 // Enable IRQ interrupts and initialize VRAM
246 //---------------------------------------------------------------------------
247 DEMOInitCommon();
248 DEMOInitVRAM();
249
250 // DMA is not used in GX (the old DMA conflicts with camera DMA)
251 (void)GX_SetDefaultDMA(GX_DMA_NOT_USE);
252
253 GX_SetBankForSubBG(GX_VRAM_SUB_BG_128_C);
254
255 GXS_SetGraphicsMode(GX_BGMODE_3);
256
257 GXS_SetVisiblePlane(GX_PLANEMASK_BG3);
258 G2S_SetBG3Priority(0);
259 G2S_BG3Mosaic(FALSE);
260
261 G2S_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x00000);
262
263 MI_CpuClearFast(shoot_buffer, WIDTH*HEIGHT*sizeof(u16));
264 GXS_LoadBG3Bmp(shoot_buffer, 0, WIDTH*HEIGHT*sizeof(u16));
265
266 GXS_DispOn();
267
268 // Initialization
269 OS_InitThread();
270 OS_InitTick();
271 OS_InitAlarm();
272 MI_InitNDmaConfig();
273 FS_Init( FS_DMA_NOT_USE );
274
275 // V-Blank interrupt settings
276 OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
277 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
278 (void)OS_EnableIrq();
279 (void)GX_VBlankIntr(TRUE);
280 (void)OS_EnableInterrupts();
281
282 // VRAM display mode
283 GX_SetBankForLCDC(GX_VRAM_LCDC_A);
284 MI_CpuClearFast((void*)HW_LCDC_VRAM_A, BYTES_PER_LINE * HEIGHT);
285 wp = 0;
286 rp = 1;
287 wp_pending = TRUE;
288 stabilizedCount = 0;
289 switchFlag = FALSE;
290 GX_SetGraphicsMode(GX_DISPMODE_VRAM_A, GX_BGMODE_0, GX_BG0_AS_2D);
291 OS_WaitVBlankIntr();
292 GX_DispOn();
293
294 movie_buffer_max_count = ((u32)OS_GetMainArenaHi() - (u32)OS_GetMainArenaLo()) / (BYTES_PER_LINE * HEIGHT) - 2;
295 movie_buffer = (u16*)OS_AllocFromMainArenaLo( (u32)OS_GetMainArenaHi() - (u32)OS_GetMainArenaLo(), 32);
296
297 // Initialize camera
298 (void)CameraInit();
299
300 // Configure DMA interrupt
301 (void)OS_EnableIrqMask(OS_IE_NDMA1);
302
303 // Camera VSYNC interrupt callback
304 CAMERA_SetVsyncCallback(CameraIntrVsync);
305
306 // Camera error interrupt callback
307 CAMERA_SetBufferErrorCallback(CameraIntrError);
308
309 // Camera restart completion callback
310 CAMERA_SetRebootCallback(CameraIntrReboot);
311
312 CAMERA_SetTrimmingParams(0, 0, WIDTH, HEIGHT);
313 CAMERA_SetTrimming(TRUE);
314 CAMERA_SetOutputFormat(CAMERA_OUTPUT_RGB);
315 CAMERA_SetTransferLines(CAMERA_GET_MAX_LINES(WIDTH));
316
317 // Start capturing
318 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
319 CAMERA_ClearBuffer();
320 CAMERA_StartCapture();
321 OS_TPrintf("Camera is shooting a movie...\n");
322
323 DEMOStartDisplay();
324
325 // Initialize the DSP shutter sound
326 {
327 FSFile file[1];
328 int slotB;
329 int slotC;
330 // 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
331 //
332 (void)MI_FreeWram_B(MI_WRAM_ARM9);
333 (void)MI_CancelWram_B(MI_WRAM_ARM9);
334 (void)MI_FreeWram_C(MI_WRAM_ARM9);
335 (void)MI_CancelWram_C(MI_WRAM_ARM9);
336 slotB = 0xFF;
337 slotC = 0xFF;
338 // For simplification, this sample uses files in static memory
339 FS_InitFile(file);
340 DSPi_OpenStaticComponentG711Core(file);
341 if (!DSP_LoadG711(file, slotB, slotC))
342 {
343 OS_TPanic("failed to load G.711 DSP-component! (lack of WRAM-B/C)");
344 }
345 (void)FS_CloseFile(file);
346
347 // Initialize extended sound features
348 SNDEX_Init();
349
350 // Load the shutter sound
351 {
352 FSFile file[1];
353 SNDEXFrequency freq;
354
355 if(SNDEX_GetI2SFrequency(&freq) != SNDEX_RESULT_SUCCESS)
356 {
357 OS_Panic("failed SNDEX_GetI2SFrequency");
358 }
359 // The initial I2S operating frequency should be 32.73 kHz
360 if(freq != SNDEX_FREQUENCY_32730)
361 {
362 OS_Panic("default value is SNDEX_FREQUENCY_32730");
363 }
364
365 FS_InitFile(file);
366 // Load the 32.73-kHz shutter sound
367 if( !FS_OpenFileEx(file, filename_shutter, FS_FILEMODE_R) )
368 {
369 OS_Panic("failed FS_OpenFileEx");
370 }
371 len_shutter = FS_GetFileLength(file);
372 if( FS_ReadFile(file, StrmBuf_shutter, (s32)len_shutter) == -1)
373 {
374 OS_Panic("failed FS_ReadFile");
375 }
376 (void)FS_CloseFile(file);
377 DC_StoreRange(StrmBuf_shutter, len_shutter);
378
379 FS_InitFile(file);
380 // Load the 32.73-kHz video filming start sound
381 if( !FS_OpenFileEx(file, filename_begin, FS_FILEMODE_R) )
382 {
383 OS_Panic("failed FS_OpenFileEx");
384 }
385 len_begin = FS_GetFileLength(file);
386 if( FS_ReadFile(file, StrmBuf_begin, (s32)len_begin) == -1)
387 {
388 OS_Panic("failed FS_ReadFile");
389 }
390 (void)FS_CloseFile(file);
391 DC_StoreRange(StrmBuf_begin, len_begin);
392
393 FS_InitFile(file);
394 // Load the 32.73-kHz video filming end sound
395 if( !FS_OpenFileEx(file, filename_end, FS_FILEMODE_R) )
396 {
397 OS_Panic("failed FS_OpenFileEx");
398 }
399 len_end = FS_GetFileLength(file);
400 if( FS_ReadFile(file, StrmBuf_end, (s32)len_end) == -1)
401 {
402 OS_Panic("failed FS_ReadFile");
403 }
404 (void)FS_CloseFile(file);
405 DC_StoreRange(StrmBuf_end, len_end);
406 }
407 }
408
409 /* Initialize sound */
410 SND_Init();
411 SND_AssignWaveArc((SNDBankData*)sound_bank_data, 0, (SNDWaveArc*)sound_wave_data);
412 SND_StartSeq(0, sound_seq_data, 0, (SNDBankData*)sound_bank_data);
413
414 while (1)
415 {
416 // Reading pad information and controls
417 DEMOReadKey();
418
419 if (PAD_DetectFold() == TRUE)
420 {
421 // Wait until the shutter sound is done if it is playing
422 while(DSP_IsShutterSoundPlaying())
423 {
424 OS_Sleep(100);
425 }
426
427 // When filming video, you must enter sleep mode after filming is complete
428 if((movie_flag == 1) || (movie_flag == 2))
429 {
430 while(DSP_PlayShutterSound(StrmBuf_end, len_end) == FALSE)
431 {
432 }
433 movie_flag = 0;
434 // When the outer camera finishes filming a video, the outer camera LED is turned on again
435 if(current_camera == CAMERA_SELECT_OUT)
436 {
437 if(CAMERA_SetLED(FALSE) != CAMERA_RESULT_SUCCESS)
438 OS_TPanic("CAMERA_SetLED(FALSE) was failed.\n");
439 }
440 // Enter sleep only after confirming that the video filming end sound has finished playing
441 while(DSP_IsShutterSoundPlaying())
442 {
443 OS_Sleep(100);
444 }
445 }
446
447
448 // Stop the DSP before sleeping
449 DSP_UnloadG711();
450
451 // Camera stop processing
452 CAMERA_StopCapture();
453 MI_StopNDma(NDMA_NO);
454 result = CAMERA_I2CActivate(CAMERA_SELECT_NONE);
455 if(result == CAMERA_RESULT_FATAL_ERROR)
456 OS_Panic("CAMERA FATAL ERROR\n");
457 wp_pending = TRUE; // Also use same frame next time
458 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
459 CAMERA_ClearBuffer();
460 CAMERA_StartCapture();
461
462 PM_GoSleepMode(PM_TRIGGER_COVER_OPEN | PM_TRIGGER_CARD, 0, 0);
463
464 // Restart DSP after recovering from sleep
465 {
466 FSFile file[1];
467 int slotB;
468 int slotC;
469
470 slotB = 0xFF;
471 slotC = 0xFF;
472 // For simplification, this sample uses files in static memory
473 FS_InitFile(file);
474 DSPi_OpenStaticComponentG711Core(file);
475 if (!DSP_LoadG711(file, slotB, slotC))
476 {
477 OS_TPanic("failed to load G.711 DSP-component! (lack of WRAM-B/C)");
478 }
479 (void)FS_CloseFile(file);
480 }
481 // Because the camera is also in standby, make it active
482 result = CAMERA_I2CActivate(current_camera);
483 if(result == CAMERA_RESULT_FATAL_ERROR)
484 OS_Panic("CAMERA FATAL ERROR\n");
485 stabilizedCount = 0;
486 }
487
488 if(DEMO_IS_TRIG(PAD_BUTTON_A) && (shoot_flag == 0) && (movie_flag == 0))
489 {
490 while(DSP_PlayShutterSound(StrmBuf_shutter, len_shutter) == FALSE)
491 {
492 }
493 // When taking still photos with the outer camera, temporarily turn the outer camera LED off
494 if(current_camera == CAMERA_SELECT_OUT)
495 {
496 if(CAMERA_SwitchOffLED() != CAMERA_RESULT_SUCCESS)
497 OS_TPanic("CAMERA_SwitchOffLED was failed.\n");
498 }
499 OS_Sleep(200);
500 shoot_flag = 1;
501 }
502
503 if(DEMO_IS_TRIG(PAD_BUTTON_Y) && (movie_flag == 0) && (shoot_flag == 0))
504 {
505 while(DSP_PlayShutterSound(StrmBuf_begin, len_begin) == FALSE)
506 {
507 }
508 movie_buffer_count = 0;
509 movie_flag = 1;
510 // When filming video with the outer camera, make the outer camera LED blink
511 if(current_camera == CAMERA_SELECT_OUT)
512 {
513 if(CAMERA_SetLED(TRUE) != CAMERA_RESULT_SUCCESS)
514 OS_TPanic("CAMERA_SetLED(TRUE) was failed.\n");
515 }
516 }
517 else if(((DEMO_IS_TRIG(PAD_BUTTON_Y)) && (movie_flag == 1)) || (movie_flag == 2))
518 {
519 while(DSP_PlayShutterSound(StrmBuf_end, len_end) == FALSE)
520 {
521 }
522 movie_flag = 0;
523 // When the outer camera finishes filming a video, the outer camera LED is turned on again
524 if(current_camera == CAMERA_SELECT_OUT)
525 {
526 if(CAMERA_SetLED(FALSE) != CAMERA_RESULT_SUCCESS)
527 OS_TPanic("CAMERA_SetLED(FALSE) was failed.\n");
528 }
529 }
530
531 if(DEMO_IS_TRIG(PAD_BUTTON_B) && (movie_flag == 0))
532 {
533 movie_flag = 3;
534 }
535
536 if(DEMO_IS_TRIG(PAD_BUTTON_X) && (movie_flag == 0))
537 {
538 switchFlag = TRUE;
539 }
540
541 OS_WaitVBlankIntr();
542
543 if(shoot_flag == 2)
544 {
545 GXS_LoadBG3Bmp((void*)((int)shoot_buffer), 0, BYTES_PER_LINE * HEIGHT);
546 shoot_flag = 0;
547 }
548
549 if(movie_flag == 3)
550 {
551 static int frame = 0;
552 static int vsync = 0;
553
554 if(vsync == 0) // The camera is 15 fps, so update the screen once per every four V-Blanks
555 {
556 GXS_LoadBG3Bmp((void*)(movie_buffer+WIDTH*HEIGHT*frame), 0, BYTES_PER_LINE * HEIGHT);
557 frame++;
558 if(frame >= movie_buffer_count)
559 {
560 frame = 0;
561 movie_flag = 0;
562 }
563 }
564 vsync = ++vsync % 4;
565 }
566
567 // Main sound processing
568 while (SND_RecvCommandReply(SND_COMMAND_NOBLOCK) != NULL)
569 {
570 }
571 (void)SND_FlushCommand(SND_COMMAND_NOBLOCK);
572 }
573 }
574