os/kernelhwsrv/bsptemplate/asspandvariant/template_variant/camerasc/camerasc_sensor.cpp
Update contrib.
1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // template\template_variant\camerasc\camerasc_sensor.cpp
15 // Implementation of the template shared chunk camera physical device driver (PDD).
16 // This file is part of the Template Base port
24 #include "camerasc_plat.h"
25 #include <kernel/cache.h>
27 // XXX - Temporary structure containing a logo to be displayed. Remove this when
28 // changing this template into a "real" camera driver
29 #include "logoyuv2.cpp"
32 #define RGBtoBGR565(red, green, blue) (((blue & 0xf8) << 8) | ((green & 0xfc) << 3) | ((red & 0xf8) >> 3));
34 #define YUVtoYUV565(luma, blueC, redC) (((luma & 0xf8) << 8) | ((blueC & 0xfc) << 3) | ((redC & 0xf8) >> 3));
36 // Frame sizes and their associated frame rates supported by the Template sensor. This selection was
37 // obtained by observation of typical formats supported by phones already on the market; It is arbitrary
38 // and can be easily added to if desired
39 static const SDevCamFrameSize FrameSizes[] =
41 { 320, 240, 1, 30 } , // QVGA - 0.075 MP
42 // XXX: Although not used in this template driver, the following are suggested standard frame sizes
43 // that should be implemented in your camera driver, as well as 320 x 240 above. Remember to change
44 // KNumFrameSizes below if you change the number of sizes defined in here!
45 { 640, 480, 1, 30 }, // VGA - 0.3 MP
46 { 800, 600, 1, 30 }, // SVGA - 0.5 MP
47 { 1024, 768, 1, 30 }, // XGA - 0.8 MP
48 { 2048, 1536, 1, 15 }, // QXGA - 3 MP
49 //{ 2560, 1600, 1, 30 } // WQXGA - 4.1 MP
52 // This constant must be updated if the number of frame sizes listed above changes
53 static const TInt KNumFrameSizes = sizeof(FrameSizes) / sizeof(SDevCamFrameSize);
55 // Pixel formats supported by the three different capture modes. These are mapped onto the appropriate
56 // array of supported frame rates by the FrameSizeCaps() function
57 static const SDevCamPixelFormat PixelFormats[] =
59 // Image pixel formats
60 { EUidPixelFormatYUV_422Interleaved, KNumFrameSizes, 2 },
62 // Video pixel formats
63 { EUidPixelFormatYUV_422Interleaved, KNumFrameSizes, 2 },
65 // View finder pixel formats
66 { EUidPixelFormatYUV_422Interleaved, KNumFrameSizes, 2 }
70 // These constants must be updated if the number of pixel formats listed above changes
71 static const TInt KNumImagePixelFormats = 1;
72 static const TInt KNumVideoPixelFormats = 1;
73 static const TInt KNumViewFinderPixelFormats = 1;
75 // Alternate logo images after this many frames
76 static const TInt KAlternateLogoFrameInterval = 5;
78 static void ImageTimerCallback(TAny* aSensorIf)
80 DTemplateSensorIf* sensor = (DTemplateSensorIf*) aSensorIf;
82 // XXX - Call the buffer done function in the sensor class. In this case we are just emulating the
83 // interrupt and DFC callback that would happen when an image is captured, so we always pass in KErrNone.
84 // In a real driver, we would read the hardware here to check that the capture happened successfully and
85 // would pass in the appropriate error code
86 sensor->BufferDoneCallback(KErrNone);
90 Saves a configuration specifying such details as dimensions and pixel format in which the sensor should
92 @param aConfig A TCameraConfigV02 structure containing the settings to be used.
93 @return KErrNone if successful, otherwise one of the other system wide error codes.
95 TInt DSensorIf::SetConfig(const TCameraConfigV02& aConfig)
97 // Manual settings for flash mode, focus, white balance etc. are not supported by the sensor,
98 // so check for these and return KErrNotSupported if they have been requested
99 if ((aConfig.iFlashMode != ECamFlashNone) ||
100 (aConfig.iExposureMode != ECamExposureAuto) ||
101 (aConfig.iZoom != 0) /*||
102 (aConfig.iWhiteBalanceMode != ECamWBAuto) ||
103 (aConfig.iContrast != ECamContrastAuto) ||
104 (aConfig.iBrightness != ECamBrightnessAuto)*/)
106 // XXX: Remove this once support is addded for these modes
107 return KErrNotSupported;
110 // As well as saving the configuration, also save copies of the width and height for easy access,
111 // as they are accessed frequently, as well as the offset in bytes between lines
113 iWidth = aConfig.iFrameSize.iWidth;
114 iHeight = aConfig.iFrameSize.iHeight;
115 iLineOffset = (iWidth * iConfig.iPixelFormat.iPixelWidthInBytes);
121 Constructor for the Template sensor class.
124 DTemplateSensorIf::DTemplateSensorIf(MSensorObserver& aObserver, TDfcQue* aDFCQueue)
125 : iDFCQueue(aDFCQueue)
127 iObserver = &aObserver;
128 iXDirection = iYDirection = 1;
131 iFlipSwitch = EFalse;
135 Second stage constructor for the Template sensor class.
137 @return KErrNone if successful, otherwise one of the other system wide error codes.
139 TInt DTemplateSensorIf::DoCreate()
141 __KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::DoCreate()"));
145 for (TInt index = 0; index < KTotalCameraRequests; ++index)
147 if ((iImageTimerDFCs[index] = new TDfc(ImageTimerCallback, this, iDFCQueue, 0)) == NULL)
155 __KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::DoCreate() => Returning %d", r));
161 Destructor for the Template sensor class.
163 DTemplateSensorIf::~DTemplateSensorIf()
165 for (TInt index = 0; index < KTotalCameraRequests; ++index)
167 iImageTimers[index].Cancel();
168 delete iImageTimerDFCs[index];
173 Called by the underlying sensor class when an image has been captured.
174 @param aResult KErrNone if the image was captured successfully, otherwise one of
175 the other system wide error codes.
176 @return KErrNone if successful, otherwise one of the other system wide error codes.
178 TInt DTemplateSensorIf::BufferDoneCallback(TInt aResult)
182 NKern::LockedDec(iPendingRequests);
187 // Call the LDD to let it know that an image capture has completed. If the LDD needs more images
188 // to be captured, then it will return KErrNone and the virtual and physical addresses of the
189 // next buffer to be filled will be returned in linAddr and physAddr respectively. Note that as
190 // will as starting a capture of an image in here, the LDD may also call CaptureNextImage() to start
192 r = iObserver->NotifyImageCaptureEvent(aResult, linAddr, physAddr);
196 iNextRequest = ((iNextRequest + 1) % KTotalCameraRequests);
197 NKern::LockedInc(iPendingRequests);
199 // XXX: Temporary code to be removed in a real driver. Fill the buffer for testing
200 // with user side code
203 // XXX: Send buffer to sensor. Normally the address of the buffer passed in in aLinAddr and
204 // aPhysAddr would be programmed into the sensor and/or bus hardware here and an interrupt
205 // would be generated when the iamge had been captured into the buffer. In this simulated
206 // driver we will use a nanokernel timer to simulate this process
207 iImageTimers[iNextRequest].OneShot(iImageTimerTicks, *iImageTimerDFCs[iNextRequest]);
214 Fills a buffer with a white background with a moving logo on top.
215 @param aBuffer Pointer to the buffer to be filled.
217 void DTemplateSensorIf::FillBuffer(TLinAddr aBuffer)
219 const TUint8* LogoData = Logo.iPixelData;
220 const TUint8* LogoData2 = Logo.iPixelData2;
222 TInt numPixels = (iConfig.iFrameSize.iWidth * iConfig.iFrameSize.iHeight);
224 TUint16* buffer = (TUint16*) aBuffer;
226 // Alternate between the two logos for cheesy animation effect
227 if( ++iCounter == KAlternateLogoFrameInterval )
234 // Set the "photo" background to be all white
235 memset(buffer, 0xff, (numPixels * 2));
237 // Point to the correct location in the buffer at which to render the logo
238 buffer += ((iY * iConfig.iFrameSize.iWidth) + iX);
240 // Iterate through the data for the logo and copy it into the "photo"
241 for (TUint y = 0; y < Logo.iHeight; ++y)
243 for (TUint x = 0; x < Logo.iWidth; ++x)
245 // The logo is in 24 bit BGR format so read each pixel and convert it to 16 bit BGR565
246 // before writing it into the "photo" buffer
249 yC = LogoData[index];
250 uC = LogoData[index + 1];
251 vC = LogoData[index + 2];
255 yC = LogoData2[index];
256 uC = LogoData2[index + 1];
257 vC = LogoData2[index + 2];
260 *buffer++ = YUVtoYUV565(yC, uC, vC);
261 // Point to the next source pixel
265 // Point to the start of the next line in the buffer, taking into account that the logo
266 // is narrower than the buffer
267 buffer += (iConfig.iFrameSize.iWidth - Logo.iWidth);
270 // Bounce the logo around in the X direction. This will take effect the next time this is called
276 iXDirection = -iXDirection;
278 else if (iX >= (TInt) (iConfig.iFrameSize.iWidth - Logo.iWidth))
280 iX = (iConfig.iFrameSize.iWidth - Logo.iWidth);
281 iXDirection = -iXDirection;
284 // Bounce the logo around in the Y direction. This will take effect the next time this is called
290 iYDirection = -iYDirection;
292 else if (iY >= (TInt) (iConfig.iFrameSize.iHeight - Logo.iHeight))
294 iY = (iConfig.iFrameSize.iHeight - Logo.iHeight);
295 iYDirection = -iYDirection;
298 // Now flush the cache to memory, taking into account the size of each pixel. This is not normally
299 // necessary but given that we are emulating a camera driver in software we must ensure that the
300 // cache is flushed to memory. This is because in a real driver the buffer will have been filled
301 // by DMA so upon return to the LDD, the LDD will discard the contents of the cache to ensure the
302 // DMA-written data is ok. In the case of filling the buffer using the CPU in this virtual camera
303 // driver, that would result in the data being discarded!
304 Cache::SyncMemoryBeforeDmaWrite((TLinAddr) aBuffer, (numPixels * iConfig.iPixelFormat.iPixelWidthInBytes));
308 Based on the capture mode and pixel format passed in, copies an array of supported SFrameSize
309 structures into a buffer supplied by the LDD. These frame sizes and their associated frame rates
310 will reflect the capabilities of the given capture mode and pixel format.
311 @param aCaptureMode The capture mode for which to obtain the supported frame sizes.
312 @param aUidPixelFormat The UID of the pixel format (as defined in \epoc32\include\pixelformats.h)
313 for which to obtain the supported frame sizes.
314 @param aFrameSizeCapsBuf A reference to a descriptor that contains a buffer into which to place
315 the frame size structures. It is up to the LDD to ensure that this is
316 large enough to hold all of the frame sizes.
317 @return Always KErrNone.
319 TInt DTemplateSensorIf::FrameSizeCaps(TDevCamCaptureMode /*aCaptureMode*/, TUidPixelFormat /*aUidPixelFormat*/, TDes8& aFrameSizeCapsBuf)
321 TPtrC8 sourceFrameSizes((const TUint8*) FrameSizes, sizeof(FrameSizes));
323 // Ensure the buffer passed in from the LDD is large enough and copy the requested frame sizes
324 if (aFrameSizeCapsBuf.Size() < sourceFrameSizes.Size())
326 Kern::Printf("*** ECapsBufferTooSmall: %d vs %d",
327 aFrameSizeCapsBuf.Size(),
328 sourceFrameSizes.Size());
329 Kern::Fault("camerasc", ECapsBufferTooSmall);
332 //__ASSERT_DEBUG((aFrameSizeCapsBuf.Size() >= sourceFrameSizes.Size()), Kern::Fault("camerasc", ECapsBufferTooSmall));
333 aFrameSizeCapsBuf = sourceFrameSizes;
339 Allocates a buffer large enough to hold the TCameraCapsV02 structure and its succeeding array of
340 pixel formats, and populates the structure and array with information about the capabilities of
342 @param aCameraCaps Reference to a pointer into which to place the pointer to allocated buffer
343 @return Size of the capabilities structure if successful, otherwise one of the other system wide
346 TInt DTemplateSensorIf::GetCaps(TCameraCapsV02*& aCameraCaps)
348 // Allocate a buffer large enough to hold the TCameraCapsV02 structure and the array of pixel formats
349 // that will follow it
350 TInt r = (sizeof(TCameraCapsV02) + sizeof(PixelFormats));
351 TUint8* capsBuffer = new TUint8[r];
355 aCameraCaps = (TCameraCapsV02*) capsBuffer;
357 // No special modes are supported at the moment
358 aCameraCaps->iFlashModes = ECamFlashNone;
359 aCameraCaps->iExposureModes = ECamExposureAuto; // or None?
360 // do we still need whitebalance mode filed?
361 aCameraCaps->iWhiteBalanceModes = ECamWBAuto | ECamWBDaylight | ECamWBCloudy | ECamWBTungsten | ECamWBFluorescent | ECamWBFlash | ECamWBSnow | ECamWBBeach;
362 aCameraCaps->iMinZoom = 0;
363 aCameraCaps->iMaxZoom = 0;
364 aCameraCaps->iCapsMisc = KCamMiscContrast | KCamMiscBrightness | KCamMiscColorEffect;
366 // There isn't really such thing as inwards or outwards orientation on an SDP, but we'll pretend it's
367 // an outwards facing camera
368 aCameraCaps->iOrientation = ECamOrientationOutwards;
370 // Initialise the number of different pixel formats supported
371 aCameraCaps->iNumImagePixelFormats = KNumImagePixelFormats;
372 aCameraCaps->iNumVideoPixelFormats = KNumVideoPixelFormats;
373 aCameraCaps->iNumViewFinderPixelFormats = KNumViewFinderPixelFormats;
375 for (TInt i = 0; i < ECamAttributeMax; i++)
377 if (ECamAttributeColorEffect == (TDevCamDynamicAttribute)(i))
380 // In case of white balance, we shouldn't use MIN and MAX values as some of them in between MIN and MAX can be missed out.
381 // As this is fake driver, There doesn't seem to be any major issue though.
382 aCameraCaps->iDynamicRange[i].iMin = ECamWBAuto;
383 aCameraCaps->iDynamicRange[i].iMax = ECamWBBeach;
384 aCameraCaps->iDynamicRange[i].iDefault = ECamWBAuto;
388 // TBC :: Contrast, Brightness
389 aCameraCaps->iDynamicRange[i].iMin = 0;
390 aCameraCaps->iDynamicRange[i].iMax = 6;
391 aCameraCaps->iDynamicRange[i].iDefault = 3;
395 // Setup some descriptors pointing to the pixel format array and the array passed in by the LDD
396 // (located at the end of the TCameraCapsV02 structure) and copy the pixel format array
397 TPtrC8 sourcePixelFormats((const TUint8*) PixelFormats, sizeof(PixelFormats));
398 TPtr8 destPixelFormats((capsBuffer + sizeof(TCameraCapsV02)), sizeof(PixelFormats), sizeof(PixelFormats));
399 destPixelFormats = sourcePixelFormats;
410 Powers up the sensor hardware.
411 @return KErrNone if successful, otherwise one of the other system wide error codes.
413 TInt DTemplateSensorIf::RequestPower()
415 __KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::RequestPower()"));
419 __KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::RequestPower() => Returning %d", r));
425 Powers down the sensor hardware.
426 @return KErrNone if successful, otherwise one of the other system wide error codes.
428 TInt DTemplateSensorIf::RelinquishPower()
430 __KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::RelinquishPower()"));
434 __KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::RelinquishPower() => Returning %d", r));
440 Begins capture of the next image into the buffer provided. This function assumes that
441 Start() has already been called to start capture. However, Stop() may also have been
442 subsequently called (for example to pause capture) and in this case, this function will
443 handle restarting the sensor.
444 @param aLinAddr A virtual pointer to the buffer into which to capture the image.
445 @param aPhysAddr A physical pointer to the buffer into which to capture the image.
446 This points to the same memory as aLinAddr.
447 @return KErrNone if successful.
448 KErrNotReady if there are no free requests to capture the image.
449 Otherwise one of the other system wide error codes.
451 TInt DTemplateSensorIf::CaptureNextImage(TLinAddr aLinAddr, TPhysAddr /*aPhysAddr*/)
455 // Only start capturing the next image if there are any pending request slots available
456 if (iPendingRequests < KTotalCameraRequests)
458 // Queue a transfer on the next available channel and indicate that the channel is
460 iNextRequest = ((iNextRequest + 1) % KTotalCameraRequests);
461 NKern::LockedInc(iPendingRequests);
463 // XXX: Temporary code to be removed in a real driver. Fill the buffer for testing
464 // with user side code. This is to simulate an image being captured into the buffer that
465 // has been passed in in aLinAddr. As well as aLinAddr, which points to the virtual
466 // address of the buffer, the LDD will pass in the physical address as well, in aPhysAddr.
467 // Depending on the underlying sensor hardware and/or bus in use, you will have to choose
468 // which of these to use
469 FillBuffer(aLinAddr);
471 // XXX: Send buffer to sensor. Normally the address of the buffer passed in in aLinAddr and
472 // aPhysAddr would be programmed into the sensor and/or bus hardware here and an interrupt
473 // would be generated when the iamge had been captured into the buffer. In this simulated
474 // driver we will use a nanokernel timer to simulate this process
475 iImageTimers[iNextRequest].OneShot(iImageTimerTicks, *iImageTimerDFCs[iNextRequest]);
477 // If capturing has not yet started or has been paused by Stop(), start it
492 Begins capture of the first image into the buffer provided. This function is similar to
493 CaptureNextImage(), except that it will perform any extra sensor intitialisation required
495 @param aCaptureMode The capture mode for which to start capturing.
496 @param aLinAddr A virtual pointer to the buffer into which to capture the image.
497 @param aPhysAddr A physical pointer to the buffer into which to capture the image.
498 This points to the same memory as aLinAddr.
499 @return KErrNone if successful
500 KErrInUse if capture is already under way.
501 KErrNotSupported if the frame size and/or frame rate are out of range.
502 Otherwise one of the other system wide error codes.
504 TInt DTemplateSensorIf::Start(TDevCamCaptureMode /*aCaptureMode*/, TLinAddr aLinAddr, TPhysAddr aPhysAddr)
506 __KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::Start()"));
510 // XXX - In a real camera driver, in here we would initialise start the capturing process in here.
511 // When an image is captured, the sensor hardware (or maybe the CSI bus) will generate an
512 // which will then be enqueued into the DFC queue that was passed into the constructor of
513 // the sensor class. It is important to do the DFC processing in this DFC queue rather than
514 // a separate one because it ensures that fucntions in the PDD and LDD are called in a serialised
515 // manner, without the need for mutexts. In this example camera driver we will convert the
516 // framerate into a nanokernel tick count and will use an NTimer.OneShot() call to simulate
517 // the sensor interrupt and DFC callback. Divides are slow so we'll calculate the tick count
518 // here and will save it for later use
519 iImageTimerTicks = ((1000000 / NKern::TickPeriod()) / iConfig.iFrameRate);
521 // XXX - Once the one off hardware initialisation has been done for starting a new capture, then
522 // subsequent captures can usually reuse the same code in CaptureNextImage() for starting
524 r = CaptureNextImage(aLinAddr, aPhysAddr);
526 __KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::Start() => Returning %d", r));
532 Stops capturing any image capture that is currently in progress. This function will act
533 more like a Pause() than a Stop() capturing can be restarted from where it was stopped.
535 TInt DTemplateSensorIf::Stop()
537 __KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::Stop()"));
540 iPendingRequests = iNextRequest = 0;
542 // XXX - Cancel all of our pending image timer callbacks. In a real driver we would write to the
543 // sensor and/or bus hardware here to cause them to cancel any pending image captures
544 for (TInt index = 0; index < KTotalCameraRequests; ++index)
546 iImageTimers[index].Cancel();
549 __KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::Stop()"));