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