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