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