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 // When in NITRO mode, stopped by Panic
251 DEMOCheckRunOnTWL();
252
253 // DMA is not used in GX (the old DMA conflicts with camera DMA)
254 (void)GX_SetDefaultDMA(GX_DMA_NOT_USE);
255
256 GX_SetBankForSubBG(GX_VRAM_SUB_BG_128_C);
257
258 GXS_SetGraphicsMode(GX_BGMODE_3);
259
260 GXS_SetVisiblePlane(GX_PLANEMASK_BG3);
261 G2S_SetBG3Priority(0);
262 G2S_BG3Mosaic(FALSE);
263
264 G2S_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x00000);
265
266 MI_CpuClearFast(shoot_buffer, WIDTH*HEIGHT*sizeof(u16));
267 GXS_LoadBG3Bmp(shoot_buffer, 0, WIDTH*HEIGHT*sizeof(u16));
268
269 GXS_DispOn();
270
271 // Initialization
272 OS_InitThread();
273 OS_InitTick();
274 OS_InitAlarm();
275 FS_Init( FS_DMA_NOT_USE );
276
277 // V-Blank interrupt settings
278 OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
279 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
280 (void)OS_EnableIrq();
281 (void)GX_VBlankIntr(TRUE);
282 (void)OS_EnableInterrupts();
283
284 // VRAM display mode
285 GX_SetBankForLCDC(GX_VRAM_LCDC_A);
286 MI_CpuClearFast((void*)HW_LCDC_VRAM_A, BYTES_PER_LINE * HEIGHT);
287 wp = 0;
288 rp = 1;
289 wp_pending = TRUE;
290 stabilizedCount = 0;
291 switchFlag = FALSE;
292 GX_SetGraphicsMode(GX_DISPMODE_VRAM_A, GX_BGMODE_0, GX_BG0_AS_2D);
293 OS_WaitVBlankIntr();
294 GX_DispOn();
295
296 movie_buffer_max_count = ((u32)OS_GetMainArenaHi() - (u32)OS_GetMainArenaLo()) / (BYTES_PER_LINE * HEIGHT) - 2;
297 movie_buffer = (u16*)OS_AllocFromMainArenaLo( (u32)OS_GetMainArenaHi() - (u32)OS_GetMainArenaLo(), 32);
298
299 // Initialize camera
300 (void)CameraInit();
301
302 // Configure DMA interrupt
303 (void)OS_EnableIrqMask(OS_IE_NDMA1);
304
305 // Camera VSYNC interrupt callback
306 CAMERA_SetVsyncCallback(CameraIntrVsync);
307
308 // Camera error interrupt callback
309 CAMERA_SetBufferErrorCallback(CameraIntrError);
310
311 // Camera restart completion callback
312 CAMERA_SetRebootCallback(CameraIntrReboot);
313
314 CAMERA_SetTrimmingParams(0, 0, WIDTH, HEIGHT);
315 CAMERA_SetTrimming(TRUE);
316 CAMERA_SetOutputFormat(CAMERA_OUTPUT_RGB);
317 CAMERA_SetTransferLines(CAMERA_GET_MAX_LINES(WIDTH));
318
319 // Start capturing
320 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
321 CAMERA_ClearBuffer();
322 CAMERA_StartCapture();
323 OS_TPrintf("Camera is shooting a movie...\n");
324
325 DEMOStartDisplay();
326
327 // Initialize the DSP shutter sound
328 {
329 FSFile file[1];
330 int slotB;
331 int slotC;
332 // 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
333 //
334 (void)MI_FreeWram_B(MI_WRAM_ARM9);
335 (void)MI_CancelWram_B(MI_WRAM_ARM9);
336 (void)MI_FreeWram_C(MI_WRAM_ARM9);
337 (void)MI_CancelWram_C(MI_WRAM_ARM9);
338 slotB = 0xFF;
339 slotC = 0xFF;
340 // For simplification, this sample uses files in static memory
341 FS_InitFile(file);
342 DSPi_OpenStaticComponentG711Core(file);
343 if (!DSP_LoadG711(file, slotB, slotC))
344 {
345 OS_TPanic("failed to load G.711 DSP-component! (lack of WRAM-B/C)");
346 }
347 (void)FS_CloseFile(file);
348
349 // Initialize extended sound features
350 SNDEX_Init();
351
352 // Load the shutter sound
353 {
354 FSFile file[1];
355 SNDEXFrequency freq;
356
357 if(SNDEX_GetI2SFrequency(&freq) != SNDEX_RESULT_SUCCESS)
358 {
359 OS_Panic("failed SNDEX_GetI2SFrequency");
360 }
361 // The initial I2S operating frequency should be 32.73 kHz
362 if(freq != SNDEX_FREQUENCY_32730)
363 {
364 OS_Panic("default value is SNDEX_FREQUENCY_32730");
365 }
366
367 FS_InitFile(file);
368 // Load the 32.73-kHz shutter sound
369 if( !FS_OpenFileEx(file, filename_shutter, FS_FILEMODE_R) )
370 {
371 OS_Panic("failed FS_OpenFileEx");
372 }
373 len_shutter = FS_GetFileLength(file);
374 if( FS_ReadFile(file, StrmBuf_shutter, (s32)len_shutter) == -1)
375 {
376 OS_Panic("failed FS_ReadFile");
377 }
378 (void)FS_CloseFile(file);
379 DC_StoreRange(StrmBuf_shutter, len_shutter);
380
381 FS_InitFile(file);
382 // Load the 32.73-kHz video filming start sound
383 if( !FS_OpenFileEx(file, filename_begin, FS_FILEMODE_R) )
384 {
385 OS_Panic("failed FS_OpenFileEx");
386 }
387 len_begin = FS_GetFileLength(file);
388 if( FS_ReadFile(file, StrmBuf_begin, (s32)len_begin) == -1)
389 {
390 OS_Panic("failed FS_ReadFile");
391 }
392 (void)FS_CloseFile(file);
393 DC_StoreRange(StrmBuf_begin, len_begin);
394
395 FS_InitFile(file);
396 // Load the 32.73-kHz video filming end sound
397 if( !FS_OpenFileEx(file, filename_end, FS_FILEMODE_R) )
398 {
399 OS_Panic("failed FS_OpenFileEx");
400 }
401 len_end = FS_GetFileLength(file);
402 if( FS_ReadFile(file, StrmBuf_end, (s32)len_end) == -1)
403 {
404 OS_Panic("failed FS_ReadFile");
405 }
406 (void)FS_CloseFile(file);
407 DC_StoreRange(StrmBuf_end, len_end);
408 }
409 }
410
411 /* Initialize sound */
412 SND_Init();
413 SND_AssignWaveArc((SNDBankData*)sound_bank_data, 0, (SNDWaveArc*)sound_wave_data);
414 SND_StartSeq(0, sound_seq_data, 0, (SNDBankData*)sound_bank_data);
415
416 while (1)
417 {
418 // Reading pad information and controls
419 DEMOReadKey();
420
421 if (PAD_DetectFold() == TRUE)
422 {
423 // Wait until the shutter sound is done if it is playing
424 while(DSP_IsShutterSoundPlaying())
425 {
426 OS_Sleep(100);
427 }
428
429 // When filming video, you must enter sleep mode after filming is complete
430 if((movie_flag == 1) || (movie_flag == 2))
431 {
432 while(DSP_PlayShutterSound(StrmBuf_end, len_end) == FALSE)
433 {
434 }
435 movie_flag = 0;
436 // When the outer camera finishes filming a video, the outer camera LED is turned on again
437 if(current_camera == CAMERA_SELECT_OUT)
438 {
439 if(CAMERA_SetLED(FALSE) != CAMERA_RESULT_SUCCESS)
440 OS_TPanic("CAMERA_SetLED(FALSE) was failed.\n");
441 }
442 // Enter sleep only after confirming that the video filming end sound has finished playing
443 while(DSP_IsShutterSoundPlaying())
444 {
445 OS_Sleep(100);
446 }
447 }
448
449
450 // Stop the DSP before sleeping
451 DSP_UnloadG711();
452
453 // Camera stop processing
454 CAMERA_StopCapture();
455 while (CAMERA_IsBusy() == TRUE)
456 {
457 ;
458 }
459 MI_StopNDma(NDMA_NO);
460 result = CAMERA_I2CActivate(CAMERA_SELECT_NONE);
461 if(result == CAMERA_RESULT_FATAL_ERROR)
462 OS_Panic("CAMERA FATAL ERROR\n");
463 wp_pending = TRUE; // Also use same frame next time
464
465 PM_GoSleepMode(PM_TRIGGER_COVER_OPEN | PM_TRIGGER_CARD, 0, 0);
466
467 // Restart DSP after recovering from sleep
468 {
469 FSFile file[1];
470 int slotB;
471 int slotC;
472
473 slotB = 0xFF;
474 slotC = 0xFF;
475 // For simplification, this sample uses files in static memory
476 FS_InitFile(file);
477 DSPi_OpenStaticComponentG711Core(file);
478 if (!DSP_LoadG711(file, slotB, slotC))
479 {
480 OS_TPanic("failed to load G.711 DSP-component! (lack of WRAM-B/C)");
481 }
482 (void)FS_CloseFile(file);
483 }
484 // Because the camera is also in standby, make it active
485 result = CAMERA_I2CActivate(current_camera);
486 if(result == CAMERA_RESULT_FATAL_ERROR)
487 OS_Panic("CAMERA FATAL ERROR\n");
488 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
489 CAMERA_ClearBuffer();
490 CAMERA_StartCapture();
491 stabilizedCount = 0;
492 }
493
494 if(DEMO_IS_TRIG(PAD_BUTTON_A) && (shoot_flag == 0) && (movie_flag == 0))
495 {
496 while(DSP_PlayShutterSound(StrmBuf_shutter, len_shutter) == FALSE)
497 {
498 }
499 // When taking still photos with the outer camera, temporarily turn the outer camera LED off
500 if(current_camera == CAMERA_SELECT_OUT)
501 {
502 if(CAMERA_SwitchOffLED() != CAMERA_RESULT_SUCCESS)
503 OS_TPanic("CAMERA_SwitchOffLED was failed.\n");
504 }
505 OS_Sleep(200);
506 shoot_flag = 1;
507 }
508
509 if(DEMO_IS_TRIG(PAD_BUTTON_Y) && (movie_flag == 0) && (shoot_flag == 0))
510 {
511 while(DSP_PlayShutterSound(StrmBuf_begin, len_begin) == FALSE)
512 {
513 }
514 movie_buffer_count = 0;
515 movie_flag = 1;
516 // When filming video with the outer camera, make the outer camera LED blink
517 if(current_camera == CAMERA_SELECT_OUT)
518 {
519 if(CAMERA_SetLED(TRUE) != CAMERA_RESULT_SUCCESS)
520 OS_TPanic("CAMERA_SetLED(TRUE) was failed.\n");
521 }
522 }
523 else if(((DEMO_IS_TRIG(PAD_BUTTON_Y)) && (movie_flag == 1)) || (movie_flag == 2))
524 {
525 while(DSP_PlayShutterSound(StrmBuf_end, len_end) == FALSE)
526 {
527 }
528 movie_flag = 0;
529 // When the outer camera finishes filming a video, the outer camera LED is turned on again
530 if(current_camera == CAMERA_SELECT_OUT)
531 {
532 if(CAMERA_SetLED(FALSE) != CAMERA_RESULT_SUCCESS)
533 OS_TPanic("CAMERA_SetLED(FALSE) was failed.\n");
534 }
535 }
536
537 if(DEMO_IS_TRIG(PAD_BUTTON_B) && (movie_flag == 0))
538 {
539 movie_flag = 3;
540 }
541
542 if(DEMO_IS_TRIG(PAD_BUTTON_X) && (movie_flag == 0))
543 {
544 switchFlag = TRUE;
545 }
546
547 OS_WaitVBlankIntr();
548
549 if(shoot_flag == 2)
550 {
551 GXS_LoadBG3Bmp((void*)((int)shoot_buffer), 0, BYTES_PER_LINE * HEIGHT);
552 shoot_flag = 0;
553 }
554
555 if(movie_flag == 3)
556 {
557 static int frame = 0;
558 static int vsync = 0;
559
560 if(vsync == 0) // The camera is 15 fps, so update the screen once per every four V-Blanks
561 {
562 GXS_LoadBG3Bmp((void*)(movie_buffer+WIDTH*HEIGHT*frame), 0, BYTES_PER_LINE * HEIGHT);
563 frame++;
564 if(frame >= movie_buffer_count)
565 {
566 frame = 0;
567 movie_flag = 0;
568 }
569 }
570 vsync = ++vsync % 4;
571 }
572
573 // Main sound processing
574 while (SND_RecvCommandReply(SND_COMMAND_NOBLOCK) != NULL)
575 {
576 }
577 (void)SND_FlushCommand(SND_COMMAND_NOBLOCK);
578 }
579 }
580