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