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