diff -r 000000000000 -r bde4ae8d615e os/kernelhwsrv/bsptemplate/asspandvariant/template_variant/camerasc/camerasc_sensor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/kernelhwsrv/bsptemplate/asspandvariant/template_variant/camerasc/camerasc_sensor.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,552 @@ +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// template\template_variant\camerasc\camerasc_sensor.cpp +// Implementation of the template shared chunk camera physical device driver (PDD). +// This file is part of the Template Base port +// +// + +/** + @file +*/ + +#include "camerasc_plat.h" +#include + +// XXX - Temporary structure containing a logo to be displayed. Remove this when +// changing this template into a "real" camera driver +#include "logoyuv2.cpp" + + +#define RGBtoBGR565(red, green, blue) (((blue & 0xf8) << 8) | ((green & 0xfc) << 3) | ((red & 0xf8) >> 3)); + +#define YUVtoYUV565(luma, blueC, redC) (((luma & 0xf8) << 8) | ((blueC & 0xfc) << 3) | ((redC & 0xf8) >> 3)); + +// Frame sizes and their associated frame rates supported by the Template sensor. This selection was +// obtained by observation of typical formats supported by phones already on the market; It is arbitrary +// and can be easily added to if desired +static const SDevCamFrameSize FrameSizes[] = + { + { 320, 240, 1, 30 } , // QVGA - 0.075 MP + // XXX: Although not used in this template driver, the following are suggested standard frame sizes + // that should be implemented in your camera driver, as well as 320 x 240 above. Remember to change + // KNumFrameSizes below if you change the number of sizes defined in here! + { 640, 480, 1, 30 }, // VGA - 0.3 MP + { 800, 600, 1, 30 }, // SVGA - 0.5 MP + { 1024, 768, 1, 30 }, // XGA - 0.8 MP + { 2048, 1536, 1, 15 }, // QXGA - 3 MP + //{ 2560, 1600, 1, 30 } // WQXGA - 4.1 MP + }; + +// This constant must be updated if the number of frame sizes listed above changes +static const TInt KNumFrameSizes = sizeof(FrameSizes) / sizeof(SDevCamFrameSize); + +// Pixel formats supported by the three different capture modes. These are mapped onto the appropriate +// array of supported frame rates by the FrameSizeCaps() function +static const SDevCamPixelFormat PixelFormats[] = + { + // Image pixel formats + { EUidPixelFormatYUV_422Interleaved, KNumFrameSizes, 2 }, + + // Video pixel formats + { EUidPixelFormatYUV_422Interleaved, KNumFrameSizes, 2 }, + + // View finder pixel formats + { EUidPixelFormatYUV_422Interleaved, KNumFrameSizes, 2 } + + }; + +// These constants must be updated if the number of pixel formats listed above changes +static const TInt KNumImagePixelFormats = 1; +static const TInt KNumVideoPixelFormats = 1; +static const TInt KNumViewFinderPixelFormats = 1; + +// Alternate logo images after this many frames +static const TInt KAlternateLogoFrameInterval = 5; + +static void ImageTimerCallback(TAny* aSensorIf) + { + DTemplateSensorIf* sensor = (DTemplateSensorIf*) aSensorIf; + + // XXX - Call the buffer done function in the sensor class. In this case we are just emulating the + // interrupt and DFC callback that would happen when an image is captured, so we always pass in KErrNone. + // In a real driver, we would read the hardware here to check that the capture happened successfully and + // would pass in the appropriate error code + sensor->BufferDoneCallback(KErrNone); + } + +/** +Saves a configuration specifying such details as dimensions and pixel format in which the sensor should +capture images. +@param aConfig A TCameraConfigV02 structure containing the settings to be used. +@return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt DSensorIf::SetConfig(const TCameraConfigV02& aConfig) + { + // Manual settings for flash mode, focus, white balance etc. are not supported by the sensor, + // so check for these and return KErrNotSupported if they have been requested + if ((aConfig.iFlashMode != ECamFlashNone) || + (aConfig.iExposureMode != ECamExposureAuto) || + (aConfig.iZoom != 0) /*|| + (aConfig.iWhiteBalanceMode != ECamWBAuto) || + (aConfig.iContrast != ECamContrastAuto) || + (aConfig.iBrightness != ECamBrightnessAuto)*/) + { + // XXX: Remove this once support is addded for these modes + return KErrNotSupported; + } + + // As well as saving the configuration, also save copies of the width and height for easy access, + // as they are accessed frequently, as well as the offset in bytes between lines + iConfig = aConfig; + iWidth = aConfig.iFrameSize.iWidth; + iHeight = aConfig.iFrameSize.iHeight; + iLineOffset = (iWidth * iConfig.iPixelFormat.iPixelWidthInBytes); + + return KErrNone; + } + +/** +Constructor for the Template sensor class. +*/ + +DTemplateSensorIf::DTemplateSensorIf(MSensorObserver& aObserver, TDfcQue* aDFCQueue) + : iDFCQueue(aDFCQueue) + { + iObserver = &aObserver; + iXDirection = iYDirection = 1; + + iCounter = 0; + iFlipSwitch = EFalse; + } + +/** +Second stage constructor for the Template sensor class. + +@return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt DTemplateSensorIf::DoCreate() + { + __KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::DoCreate()")); + + TInt r = KErrNone; + + for (TInt index = 0; index < KTotalCameraRequests; ++index) + { + if ((iImageTimerDFCs[index] = new TDfc(ImageTimerCallback, this, iDFCQueue, 0)) == NULL) + { + r = KErrNoMemory; + + break; + } + } + + __KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::DoCreate() => Returning %d", r)); + + return r; + } + +/** +Destructor for the Template sensor class. +*/ +DTemplateSensorIf::~DTemplateSensorIf() + { + for (TInt index = 0; index < KTotalCameraRequests; ++index) + { + iImageTimers[index].Cancel(); + delete iImageTimerDFCs[index]; + } + } + +/** +Called by the underlying sensor class when an image has been captured. +@param aResult KErrNone if the image was captured successfully, otherwise one of + the other system wide error codes. +@return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt DTemplateSensorIf::BufferDoneCallback(TInt aResult) + { + TInt r = KErrNone; + + NKern::LockedDec(iPendingRequests); + + TLinAddr linAddr; + TPhysAddr physAddr; + + // Call the LDD to let it know that an image capture has completed. If the LDD needs more images + // to be captured, then it will return KErrNone and the virtual and physical addresses of the + // next buffer to be filled will be returned in linAddr and physAddr respectively. Note that as + // will as starting a capture of an image in here, the LDD may also call CaptureNextImage() to start + // capture as well + r = iObserver->NotifyImageCaptureEvent(aResult, linAddr, physAddr); + + if (r == KErrNone) + { + iNextRequest = ((iNextRequest + 1) % KTotalCameraRequests); + NKern::LockedInc(iPendingRequests); + + // XXX: Temporary code to be removed in a real driver. Fill the buffer for testing + // with user side code + FillBuffer(linAddr); + + // XXX: Send buffer to sensor. Normally the address of the buffer passed in in aLinAddr and + // aPhysAddr would be programmed into the sensor and/or bus hardware here and an interrupt + // would be generated when the iamge had been captured into the buffer. In this simulated + // driver we will use a nanokernel timer to simulate this process + iImageTimers[iNextRequest].OneShot(iImageTimerTicks, *iImageTimerDFCs[iNextRequest]); + } + + return r; + } + +/** +Fills a buffer with a white background with a moving logo on top. +@param aBuffer Pointer to the buffer to be filled. +*/ +void DTemplateSensorIf::FillBuffer(TLinAddr aBuffer) + { + const TUint8* LogoData = Logo.iPixelData; + const TUint8* LogoData2 = Logo.iPixelData2; + TInt index = 0; + TInt numPixels = (iConfig.iFrameSize.iWidth * iConfig.iFrameSize.iHeight); + TUint yC, uC, vC; + TUint16* buffer = (TUint16*) aBuffer; + + // Alternate between the two logos for cheesy animation effect + if( ++iCounter == KAlternateLogoFrameInterval ) + { + iFlipSwitch ^= 1; + iCounter = 0; + } + + + // Set the "photo" background to be all white + memset(buffer, 0xff, (numPixels * 2)); + + // Point to the correct location in the buffer at which to render the logo + buffer += ((iY * iConfig.iFrameSize.iWidth) + iX); + + // Iterate through the data for the logo and copy it into the "photo" + for (TUint y = 0; y < Logo.iHeight; ++y) + { + for (TUint x = 0; x < Logo.iWidth; ++x) + { + // The logo is in 24 bit BGR format so read each pixel and convert it to 16 bit BGR565 + // before writing it into the "photo" buffer + if( iFlipSwitch ) + { + yC = LogoData[index]; + uC = LogoData[index + 1]; + vC = LogoData[index + 2]; + } + else + { + yC = LogoData2[index]; + uC = LogoData2[index + 1]; + vC = LogoData2[index + 2]; + } + + *buffer++ = YUVtoYUV565(yC, uC, vC); + // Point to the next source pixel + index += 3; + } + + // Point to the start of the next line in the buffer, taking into account that the logo + // is narrower than the buffer + buffer += (iConfig.iFrameSize.iWidth - Logo.iWidth); + } + + // Bounce the logo around in the X direction. This will take effect the next time this is called + iX += iXDirection; + + if (iX <= 0) + { + iX = 0; + iXDirection = -iXDirection; + } + else if (iX >= (TInt) (iConfig.iFrameSize.iWidth - Logo.iWidth)) + { + iX = (iConfig.iFrameSize.iWidth - Logo.iWidth); + iXDirection = -iXDirection; + } + + // Bounce the logo around in the Y direction. This will take effect the next time this is called + iY += iYDirection; + + if (iY <= 0) + { + iY = 0; + iYDirection = -iYDirection; + } + else if (iY >= (TInt) (iConfig.iFrameSize.iHeight - Logo.iHeight)) + { + iY = (iConfig.iFrameSize.iHeight - Logo.iHeight); + iYDirection = -iYDirection; + } + + // Now flush the cache to memory, taking into account the size of each pixel. This is not normally + // necessary but given that we are emulating a camera driver in software we must ensure that the + // cache is flushed to memory. This is because in a real driver the buffer will have been filled + // by DMA so upon return to the LDD, the LDD will discard the contents of the cache to ensure the + // DMA-written data is ok. In the case of filling the buffer using the CPU in this virtual camera + // driver, that would result in the data being discarded! + Cache::SyncMemoryBeforeDmaWrite((TLinAddr) aBuffer, (numPixels * iConfig.iPixelFormat.iPixelWidthInBytes)); + } + +/** +Based on the capture mode and pixel format passed in, copies an array of supported SFrameSize +structures into a buffer supplied by the LDD. These frame sizes and their associated frame rates +will reflect the capabilities of the given capture mode and pixel format. +@param aCaptureMode The capture mode for which to obtain the supported frame sizes. +@param aUidPixelFormat The UID of the pixel format (as defined in \epoc32\include\pixelformats.h) + for which to obtain the supported frame sizes. +@param aFrameSizeCapsBuf A reference to a descriptor that contains a buffer into which to place + the frame size structures. It is up to the LDD to ensure that this is + large enough to hold all of the frame sizes. +@return Always KErrNone. +*/ +TInt DTemplateSensorIf::FrameSizeCaps(TDevCamCaptureMode /*aCaptureMode*/, TUidPixelFormat /*aUidPixelFormat*/, TDes8& aFrameSizeCapsBuf) + { + TPtrC8 sourceFrameSizes((const TUint8*) FrameSizes, sizeof(FrameSizes)); + + // Ensure the buffer passed in from the LDD is large enough and copy the requested frame sizes + if (aFrameSizeCapsBuf.Size() < sourceFrameSizes.Size()) + { + Kern::Printf("*** ECapsBufferTooSmall: %d vs %d", + aFrameSizeCapsBuf.Size(), + sourceFrameSizes.Size()); + Kern::Fault("camerasc", ECapsBufferTooSmall); + } + + //__ASSERT_DEBUG((aFrameSizeCapsBuf.Size() >= sourceFrameSizes.Size()), Kern::Fault("camerasc", ECapsBufferTooSmall)); + aFrameSizeCapsBuf = sourceFrameSizes; + + return KErrNone; + } + +/** +Allocates a buffer large enough to hold the TCameraCapsV02 structure and its succeeding array of +pixel formats, and populates the structure and array with information about the capabilities of +the sensor. +@param aCameraCaps Reference to a pointer into which to place the pointer to allocated buffer +@return Size of the capabilities structure if successful, otherwise one of the other system wide + error codes. +*/ +TInt DTemplateSensorIf::GetCaps(TCameraCapsV02*& aCameraCaps) + { + // Allocate a buffer large enough to hold the TCameraCapsV02 structure and the array of pixel formats + // that will follow it + TInt r = (sizeof(TCameraCapsV02) + sizeof(PixelFormats)); + TUint8* capsBuffer = new TUint8[r]; + + if (capsBuffer) + { + aCameraCaps = (TCameraCapsV02*) capsBuffer; + + // No special modes are supported at the moment + aCameraCaps->iFlashModes = ECamFlashNone; + aCameraCaps->iExposureModes = ECamExposureAuto; // or None? + // do we still need whitebalance mode filed? + aCameraCaps->iWhiteBalanceModes = ECamWBAuto | ECamWBDaylight | ECamWBCloudy | ECamWBTungsten | ECamWBFluorescent | ECamWBFlash | ECamWBSnow | ECamWBBeach; + aCameraCaps->iMinZoom = 0; + aCameraCaps->iMaxZoom = 0; + aCameraCaps->iCapsMisc = KCamMiscContrast | KCamMiscBrightness | KCamMiscColorEffect; + + // There isn't really such thing as inwards or outwards orientation on an SDP, but we'll pretend it's + // an outwards facing camera + aCameraCaps->iOrientation = ECamOrientationOutwards; + + // Initialise the number of different pixel formats supported + aCameraCaps->iNumImagePixelFormats = KNumImagePixelFormats; + aCameraCaps->iNumVideoPixelFormats = KNumVideoPixelFormats; + aCameraCaps->iNumViewFinderPixelFormats = KNumViewFinderPixelFormats; + + for (TInt i = 0; i < ECamAttributeMax; i++) + { + if (ECamAttributeColorEffect == (TDevCamDynamicAttribute)(i)) + { + // WhiteBalance + // 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. + // As this is fake driver, There doesn't seem to be any major issue though. + aCameraCaps->iDynamicRange[i].iMin = ECamWBAuto; + aCameraCaps->iDynamicRange[i].iMax = ECamWBBeach; + aCameraCaps->iDynamicRange[i].iDefault = ECamWBAuto; + } + else + { + // TBC :: Contrast, Brightness + aCameraCaps->iDynamicRange[i].iMin = 0; + aCameraCaps->iDynamicRange[i].iMax = 6; + aCameraCaps->iDynamicRange[i].iDefault = 3; + } + } + + // Setup some descriptors pointing to the pixel format array and the array passed in by the LDD + // (located at the end of the TCameraCapsV02 structure) and copy the pixel format array + TPtrC8 sourcePixelFormats((const TUint8*) PixelFormats, sizeof(PixelFormats)); + TPtr8 destPixelFormats((capsBuffer + sizeof(TCameraCapsV02)), sizeof(PixelFormats), sizeof(PixelFormats)); + destPixelFormats = sourcePixelFormats; + } + else + { + r = KErrNoMemory; + } + + return r; + } + +/** +Powers up the sensor hardware. +@return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt DTemplateSensorIf::RequestPower() + { + __KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::RequestPower()")); + + TInt r = KErrNone; + + __KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::RequestPower() => Returning %d", r)); + + return r; + } + +/** +Powers down the sensor hardware. +@return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt DTemplateSensorIf::RelinquishPower() + { + __KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::RelinquishPower()")); + + TInt r = KErrNone; + + __KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::RelinquishPower() => Returning %d", r)); + + return r; + } + +/** +Begins capture of the next image into the buffer provided. This function assumes that +Start() has already been called to start capture. However, Stop() may also have been +subsequently called (for example to pause capture) and in this case, this function will +handle restarting the sensor. +@param aLinAddr A virtual pointer to the buffer into which to capture the image. +@param aPhysAddr A physical pointer to the buffer into which to capture the image. + This points to the same memory as aLinAddr. +@return KErrNone if successful. + KErrNotReady if there are no free requests to capture the image. + Otherwise one of the other system wide error codes. +*/ +TInt DTemplateSensorIf::CaptureNextImage(TLinAddr aLinAddr, TPhysAddr /*aPhysAddr*/) + { + TInt r = KErrNone; + + // Only start capturing the next image if there are any pending request slots available + if (iPendingRequests < KTotalCameraRequests) + { + // Queue a transfer on the next available channel and indicate that the channel is + // in use + iNextRequest = ((iNextRequest + 1) % KTotalCameraRequests); + NKern::LockedInc(iPendingRequests); + + // XXX: Temporary code to be removed in a real driver. Fill the buffer for testing + // with user side code. This is to simulate an image being captured into the buffer that + // has been passed in in aLinAddr. As well as aLinAddr, which points to the virtual + // address of the buffer, the LDD will pass in the physical address as well, in aPhysAddr. + // Depending on the underlying sensor hardware and/or bus in use, you will have to choose + // which of these to use + FillBuffer(aLinAddr); + + // XXX: Send buffer to sensor. Normally the address of the buffer passed in in aLinAddr and + // aPhysAddr would be programmed into the sensor and/or bus hardware here and an interrupt + // would be generated when the iamge had been captured into the buffer. In this simulated + // driver we will use a nanokernel timer to simulate this process + iImageTimers[iNextRequest].OneShot(iImageTimerTicks, *iImageTimerDFCs[iNextRequest]); + + // If capturing has not yet started or has been paused by Stop(), start it + if (!(iEnabled)) + { + iEnabled = ETrue; + } + } + else + { + r = KErrNotReady; + } + + return r; + } + +/** +Begins capture of the first image into the buffer provided. This function is similar to +CaptureNextImage(), except that it will perform any extra sensor intitialisation required +to start capture. +@param aCaptureMode The capture mode for which to start capturing. +@param aLinAddr A virtual pointer to the buffer into which to capture the image. +@param aPhysAddr A physical pointer to the buffer into which to capture the image. + This points to the same memory as aLinAddr. +@return KErrNone if successful + KErrInUse if capture is already under way. + KErrNotSupported if the frame size and/or frame rate are out of range. + Otherwise one of the other system wide error codes. +*/ +TInt DTemplateSensorIf::Start(TDevCamCaptureMode /*aCaptureMode*/, TLinAddr aLinAddr, TPhysAddr aPhysAddr) + { + __KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::Start()")); + + TInt r = KErrNone; + + // XXX - In a real camera driver, in here we would initialise start the capturing process in here. + // When an image is captured, the sensor hardware (or maybe the CSI bus) will generate an + // which will then be enqueued into the DFC queue that was passed into the constructor of + // the sensor class. It is important to do the DFC processing in this DFC queue rather than + // a separate one because it ensures that fucntions in the PDD and LDD are called in a serialised + // manner, without the need for mutexts. In this example camera driver we will convert the + // framerate into a nanokernel tick count and will use an NTimer.OneShot() call to simulate + // the sensor interrupt and DFC callback. Divides are slow so we'll calculate the tick count + // here and will save it for later use + iImageTimerTicks = ((1000000 / NKern::TickPeriod()) / iConfig.iFrameRate); + + // XXX - Once the one off hardware initialisation has been done for starting a new capture, then + // subsequent captures can usually reuse the same code in CaptureNextImage() for starting + // the next capture + r = CaptureNextImage(aLinAddr, aPhysAddr); + + __KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::Start() => Returning %d", r)); + + return r; + } + +/** +Stops capturing any image capture that is currently in progress. This function will act +more like a Pause() than a Stop() capturing can be restarted from where it was stopped. +*/ +TInt DTemplateSensorIf::Stop() + { + __KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::Stop()")); + + iEnabled = EFalse; + iPendingRequests = iNextRequest = 0; + + // XXX - Cancel all of our pending image timer callbacks. In a real driver we would write to the + // sensor and/or bus hardware here to cause them to cancel any pending image captures + for (TInt index = 0; index < KTotalCameraRequests; ++index) + { + iImageTimers[index].Cancel(); + } + + __KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::Stop()")); + + return KErrNone; + }