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             while (CAMERA_IsBusy() == TRUE)
456             {
457                 ;
458             }
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 
465             PM_GoSleepMode(PM_TRIGGER_COVER_OPEN | PM_TRIGGER_CARD, 0, 0);
466 
467             // Restart DSP after recovering from sleep
468             {
469                 FSFile  file[1];
470                 int     slotB;
471                 int     slotC;
472 
473                 slotB = 0xFF;
474                 slotC = 0xFF;
475                 // For simplification, this sample uses files in static memory
476                 FS_InitFile(file);
477                 DSPi_OpenStaticComponentG711Core(file);
478                 if (!DSP_LoadG711(file, slotB, slotC))
479                 {
480                     OS_TPanic("failed to load G.711 DSP-component! (lack of WRAM-B/C)");
481                 }
482                 (void)FS_CloseFile(file);
483             }
484             // Because the camera is also in standby, make it active
485             result = CAMERA_I2CActivate(current_camera);
486             if(result == CAMERA_RESULT_FATAL_ERROR)
487                 OS_Panic("CAMERA FATAL ERROR\n");
488             CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
489             CAMERA_ClearBuffer();
490             CAMERA_StartCapture();
491             stabilizedCount = 0;
492         }
493 
494         if(DEMO_IS_TRIG(PAD_BUTTON_A) && (shoot_flag == 0) && (movie_flag == 0))
495         {
496             while(DSP_PlayShutterSound(StrmBuf_shutter, len_shutter) == FALSE)
497             {
498             }
499             // When taking still photos with the outer camera, temporarily turn the outer camera LED off
500             if(current_camera == CAMERA_SELECT_OUT)
501             {
502                 if(CAMERA_SwitchOffLED() != CAMERA_RESULT_SUCCESS)
503                     OS_TPanic("CAMERA_SwitchOffLED was failed.\n");
504             }
505             OS_Sleep(200);
506             shoot_flag = 1;
507         }
508 
509         if(DEMO_IS_TRIG(PAD_BUTTON_Y) && (movie_flag == 0) && (shoot_flag == 0))
510         {
511             while(DSP_PlayShutterSound(StrmBuf_begin, len_begin) == FALSE)
512             {
513             }
514             movie_buffer_count = 0;
515             movie_flag = 1;
516             // When filming video with the outer camera, make the outer camera LED blink
517             if(current_camera == CAMERA_SELECT_OUT)
518             {
519                 if(CAMERA_SetLED(TRUE) != CAMERA_RESULT_SUCCESS)
520                     OS_TPanic("CAMERA_SetLED(TRUE) was failed.\n");
521             }
522         }
523         else if(((DEMO_IS_TRIG(PAD_BUTTON_Y)) && (movie_flag == 1)) || (movie_flag == 2))
524         {
525             while(DSP_PlayShutterSound(StrmBuf_end, len_end) == FALSE)
526             {
527             }
528             movie_flag = 0;
529             // When the outer camera finishes filming a video, the outer camera LED is turned on again
530             if(current_camera == CAMERA_SELECT_OUT)
531             {
532                 if(CAMERA_SetLED(FALSE) != CAMERA_RESULT_SUCCESS)
533                     OS_TPanic("CAMERA_SetLED(FALSE) was failed.\n");
534             }
535         }
536 
537         if(DEMO_IS_TRIG(PAD_BUTTON_B) && (movie_flag == 0))
538         {
539             movie_flag = 3;
540         }
541 
542         if(DEMO_IS_TRIG(PAD_BUTTON_X) && (movie_flag == 0))
543         {
544             switchFlag = TRUE;
545         }
546 
547         OS_WaitVBlankIntr();
548 
549         if(shoot_flag == 2)
550         {
551             GXS_LoadBG3Bmp((void*)((int)shoot_buffer), 0, BYTES_PER_LINE * HEIGHT);
552             shoot_flag = 0;
553         }
554 
555         if(movie_flag == 3)
556         {
557             static int frame = 0;
558             static int vsync = 0;
559 
560             if(vsync == 0) // The camera is 15 fps, so update the screen once per every four V-Blanks
561             {
562                 GXS_LoadBG3Bmp((void*)(movie_buffer+WIDTH*HEIGHT*frame), 0, BYTES_PER_LINE * HEIGHT);
563                 frame++;
564                 if(frame >= movie_buffer_count)
565                 {
566                     frame = 0;
567                     movie_flag = 0;
568                 }
569             }
570             vsync = ++vsync % 4;
571         }
572 
573         // Main sound processing
574         while (SND_RecvCommandReply(SND_COMMAND_NOBLOCK) != NULL)
575         {
576         }
577         (void)SND_FlushCommand(SND_COMMAND_NOBLOCK);
578     }
579 }
580