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