sl@0
|
1 |
// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
|
sl@0
|
2 |
// All rights reserved.
|
sl@0
|
3 |
// This component and the accompanying materials are made available
|
sl@0
|
4 |
// under the terms of the License "Eclipse Public License v1.0"
|
sl@0
|
5 |
// which accompanies this distribution, and is available
|
sl@0
|
6 |
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
sl@0
|
7 |
//
|
sl@0
|
8 |
// Initial Contributors:
|
sl@0
|
9 |
// Nokia Corporation - initial contribution.
|
sl@0
|
10 |
//
|
sl@0
|
11 |
// Contributors:
|
sl@0
|
12 |
//
|
sl@0
|
13 |
// Description:
|
sl@0
|
14 |
// template\template_variant\camerasc\camerasc_sensor.cpp
|
sl@0
|
15 |
// Implementation of the template shared chunk camera physical device driver (PDD).
|
sl@0
|
16 |
// This file is part of the Template Base port
|
sl@0
|
17 |
//
|
sl@0
|
18 |
//
|
sl@0
|
19 |
|
sl@0
|
20 |
/**
|
sl@0
|
21 |
@file
|
sl@0
|
22 |
*/
|
sl@0
|
23 |
|
sl@0
|
24 |
#include "camerasc_plat.h"
|
sl@0
|
25 |
#include <kernel/cache.h>
|
sl@0
|
26 |
|
sl@0
|
27 |
// XXX - Temporary structure containing a logo to be displayed. Remove this when
|
sl@0
|
28 |
// changing this template into a "real" camera driver
|
sl@0
|
29 |
#include "logoyuv2.cpp"
|
sl@0
|
30 |
|
sl@0
|
31 |
|
sl@0
|
32 |
#define RGBtoBGR565(red, green, blue) (((blue & 0xf8) << 8) | ((green & 0xfc) << 3) | ((red & 0xf8) >> 3));
|
sl@0
|
33 |
|
sl@0
|
34 |
#define YUVtoYUV565(luma, blueC, redC) (((luma & 0xf8) << 8) | ((blueC & 0xfc) << 3) | ((redC & 0xf8) >> 3));
|
sl@0
|
35 |
|
sl@0
|
36 |
// Frame sizes and their associated frame rates supported by the Template sensor. This selection was
|
sl@0
|
37 |
// obtained by observation of typical formats supported by phones already on the market; It is arbitrary
|
sl@0
|
38 |
// and can be easily added to if desired
|
sl@0
|
39 |
static const SDevCamFrameSize FrameSizes[] =
|
sl@0
|
40 |
{
|
sl@0
|
41 |
{ 320, 240, 1, 30 } , // QVGA - 0.075 MP
|
sl@0
|
42 |
// XXX: Although not used in this template driver, the following are suggested standard frame sizes
|
sl@0
|
43 |
// that should be implemented in your camera driver, as well as 320 x 240 above. Remember to change
|
sl@0
|
44 |
// KNumFrameSizes below if you change the number of sizes defined in here!
|
sl@0
|
45 |
{ 640, 480, 1, 30 }, // VGA - 0.3 MP
|
sl@0
|
46 |
{ 800, 600, 1, 30 }, // SVGA - 0.5 MP
|
sl@0
|
47 |
{ 1024, 768, 1, 30 }, // XGA - 0.8 MP
|
sl@0
|
48 |
{ 2048, 1536, 1, 15 }, // QXGA - 3 MP
|
sl@0
|
49 |
//{ 2560, 1600, 1, 30 } // WQXGA - 4.1 MP
|
sl@0
|
50 |
};
|
sl@0
|
51 |
|
sl@0
|
52 |
// This constant must be updated if the number of frame sizes listed above changes
|
sl@0
|
53 |
static const TInt KNumFrameSizes = sizeof(FrameSizes) / sizeof(SDevCamFrameSize);
|
sl@0
|
54 |
|
sl@0
|
55 |
// Pixel formats supported by the three different capture modes. These are mapped onto the appropriate
|
sl@0
|
56 |
// array of supported frame rates by the FrameSizeCaps() function
|
sl@0
|
57 |
static const SDevCamPixelFormat PixelFormats[] =
|
sl@0
|
58 |
{
|
sl@0
|
59 |
// Image pixel formats
|
sl@0
|
60 |
{ EUidPixelFormatYUV_422Interleaved, KNumFrameSizes, 2 },
|
sl@0
|
61 |
|
sl@0
|
62 |
// Video pixel formats
|
sl@0
|
63 |
{ EUidPixelFormatYUV_422Interleaved, KNumFrameSizes, 2 },
|
sl@0
|
64 |
|
sl@0
|
65 |
// View finder pixel formats
|
sl@0
|
66 |
{ EUidPixelFormatYUV_422Interleaved, KNumFrameSizes, 2 }
|
sl@0
|
67 |
|
sl@0
|
68 |
};
|
sl@0
|
69 |
|
sl@0
|
70 |
// These constants must be updated if the number of pixel formats listed above changes
|
sl@0
|
71 |
static const TInt KNumImagePixelFormats = 1;
|
sl@0
|
72 |
static const TInt KNumVideoPixelFormats = 1;
|
sl@0
|
73 |
static const TInt KNumViewFinderPixelFormats = 1;
|
sl@0
|
74 |
|
sl@0
|
75 |
// Alternate logo images after this many frames
|
sl@0
|
76 |
static const TInt KAlternateLogoFrameInterval = 5;
|
sl@0
|
77 |
|
sl@0
|
78 |
static void ImageTimerCallback(TAny* aSensorIf)
|
sl@0
|
79 |
{
|
sl@0
|
80 |
DTemplateSensorIf* sensor = (DTemplateSensorIf*) aSensorIf;
|
sl@0
|
81 |
|
sl@0
|
82 |
// XXX - Call the buffer done function in the sensor class. In this case we are just emulating the
|
sl@0
|
83 |
// interrupt and DFC callback that would happen when an image is captured, so we always pass in KErrNone.
|
sl@0
|
84 |
// In a real driver, we would read the hardware here to check that the capture happened successfully and
|
sl@0
|
85 |
// would pass in the appropriate error code
|
sl@0
|
86 |
sensor->BufferDoneCallback(KErrNone);
|
sl@0
|
87 |
}
|
sl@0
|
88 |
|
sl@0
|
89 |
/**
|
sl@0
|
90 |
Saves a configuration specifying such details as dimensions and pixel format in which the sensor should
|
sl@0
|
91 |
capture images.
|
sl@0
|
92 |
@param aConfig A TCameraConfigV02 structure containing the settings to be used.
|
sl@0
|
93 |
@return KErrNone if successful, otherwise one of the other system wide error codes.
|
sl@0
|
94 |
*/
|
sl@0
|
95 |
TInt DSensorIf::SetConfig(const TCameraConfigV02& aConfig)
|
sl@0
|
96 |
{
|
sl@0
|
97 |
// Manual settings for flash mode, focus, white balance etc. are not supported by the sensor,
|
sl@0
|
98 |
// so check for these and return KErrNotSupported if they have been requested
|
sl@0
|
99 |
if ((aConfig.iFlashMode != ECamFlashNone) ||
|
sl@0
|
100 |
(aConfig.iExposureMode != ECamExposureAuto) ||
|
sl@0
|
101 |
(aConfig.iZoom != 0) /*||
|
sl@0
|
102 |
(aConfig.iWhiteBalanceMode != ECamWBAuto) ||
|
sl@0
|
103 |
(aConfig.iContrast != ECamContrastAuto) ||
|
sl@0
|
104 |
(aConfig.iBrightness != ECamBrightnessAuto)*/)
|
sl@0
|
105 |
{
|
sl@0
|
106 |
// XXX: Remove this once support is addded for these modes
|
sl@0
|
107 |
return KErrNotSupported;
|
sl@0
|
108 |
}
|
sl@0
|
109 |
|
sl@0
|
110 |
// As well as saving the configuration, also save copies of the width and height for easy access,
|
sl@0
|
111 |
// as they are accessed frequently, as well as the offset in bytes between lines
|
sl@0
|
112 |
iConfig = aConfig;
|
sl@0
|
113 |
iWidth = aConfig.iFrameSize.iWidth;
|
sl@0
|
114 |
iHeight = aConfig.iFrameSize.iHeight;
|
sl@0
|
115 |
iLineOffset = (iWidth * iConfig.iPixelFormat.iPixelWidthInBytes);
|
sl@0
|
116 |
|
sl@0
|
117 |
return KErrNone;
|
sl@0
|
118 |
}
|
sl@0
|
119 |
|
sl@0
|
120 |
/**
|
sl@0
|
121 |
Constructor for the Template sensor class.
|
sl@0
|
122 |
*/
|
sl@0
|
123 |
|
sl@0
|
124 |
DTemplateSensorIf::DTemplateSensorIf(MSensorObserver& aObserver, TDfcQue* aDFCQueue)
|
sl@0
|
125 |
: iDFCQueue(aDFCQueue)
|
sl@0
|
126 |
{
|
sl@0
|
127 |
iObserver = &aObserver;
|
sl@0
|
128 |
iXDirection = iYDirection = 1;
|
sl@0
|
129 |
|
sl@0
|
130 |
iCounter = 0;
|
sl@0
|
131 |
iFlipSwitch = EFalse;
|
sl@0
|
132 |
}
|
sl@0
|
133 |
|
sl@0
|
134 |
/**
|
sl@0
|
135 |
Second stage constructor for the Template sensor class.
|
sl@0
|
136 |
|
sl@0
|
137 |
@return KErrNone if successful, otherwise one of the other system wide error codes.
|
sl@0
|
138 |
*/
|
sl@0
|
139 |
TInt DTemplateSensorIf::DoCreate()
|
sl@0
|
140 |
{
|
sl@0
|
141 |
__KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::DoCreate()"));
|
sl@0
|
142 |
|
sl@0
|
143 |
TInt r = KErrNone;
|
sl@0
|
144 |
|
sl@0
|
145 |
for (TInt index = 0; index < KTotalCameraRequests; ++index)
|
sl@0
|
146 |
{
|
sl@0
|
147 |
if ((iImageTimerDFCs[index] = new TDfc(ImageTimerCallback, this, iDFCQueue, 0)) == NULL)
|
sl@0
|
148 |
{
|
sl@0
|
149 |
r = KErrNoMemory;
|
sl@0
|
150 |
|
sl@0
|
151 |
break;
|
sl@0
|
152 |
}
|
sl@0
|
153 |
}
|
sl@0
|
154 |
|
sl@0
|
155 |
__KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::DoCreate() => Returning %d", r));
|
sl@0
|
156 |
|
sl@0
|
157 |
return r;
|
sl@0
|
158 |
}
|
sl@0
|
159 |
|
sl@0
|
160 |
/**
|
sl@0
|
161 |
Destructor for the Template sensor class.
|
sl@0
|
162 |
*/
|
sl@0
|
163 |
DTemplateSensorIf::~DTemplateSensorIf()
|
sl@0
|
164 |
{
|
sl@0
|
165 |
for (TInt index = 0; index < KTotalCameraRequests; ++index)
|
sl@0
|
166 |
{
|
sl@0
|
167 |
iImageTimers[index].Cancel();
|
sl@0
|
168 |
delete iImageTimerDFCs[index];
|
sl@0
|
169 |
}
|
sl@0
|
170 |
}
|
sl@0
|
171 |
|
sl@0
|
172 |
/**
|
sl@0
|
173 |
Called by the underlying sensor class when an image has been captured.
|
sl@0
|
174 |
@param aResult KErrNone if the image was captured successfully, otherwise one of
|
sl@0
|
175 |
the other system wide error codes.
|
sl@0
|
176 |
@return KErrNone if successful, otherwise one of the other system wide error codes.
|
sl@0
|
177 |
*/
|
sl@0
|
178 |
TInt DTemplateSensorIf::BufferDoneCallback(TInt aResult)
|
sl@0
|
179 |
{
|
sl@0
|
180 |
TInt r = KErrNone;
|
sl@0
|
181 |
|
sl@0
|
182 |
NKern::LockedDec(iPendingRequests);
|
sl@0
|
183 |
|
sl@0
|
184 |
TLinAddr linAddr;
|
sl@0
|
185 |
TPhysAddr physAddr;
|
sl@0
|
186 |
|
sl@0
|
187 |
// Call the LDD to let it know that an image capture has completed. If the LDD needs more images
|
sl@0
|
188 |
// to be captured, then it will return KErrNone and the virtual and physical addresses of the
|
sl@0
|
189 |
// next buffer to be filled will be returned in linAddr and physAddr respectively. Note that as
|
sl@0
|
190 |
// will as starting a capture of an image in here, the LDD may also call CaptureNextImage() to start
|
sl@0
|
191 |
// capture as well
|
sl@0
|
192 |
r = iObserver->NotifyImageCaptureEvent(aResult, linAddr, physAddr);
|
sl@0
|
193 |
|
sl@0
|
194 |
if (r == KErrNone)
|
sl@0
|
195 |
{
|
sl@0
|
196 |
iNextRequest = ((iNextRequest + 1) % KTotalCameraRequests);
|
sl@0
|
197 |
NKern::LockedInc(iPendingRequests);
|
sl@0
|
198 |
|
sl@0
|
199 |
// XXX: Temporary code to be removed in a real driver. Fill the buffer for testing
|
sl@0
|
200 |
// with user side code
|
sl@0
|
201 |
FillBuffer(linAddr);
|
sl@0
|
202 |
|
sl@0
|
203 |
// XXX: Send buffer to sensor. Normally the address of the buffer passed in in aLinAddr and
|
sl@0
|
204 |
// aPhysAddr would be programmed into the sensor and/or bus hardware here and an interrupt
|
sl@0
|
205 |
// would be generated when the iamge had been captured into the buffer. In this simulated
|
sl@0
|
206 |
// driver we will use a nanokernel timer to simulate this process
|
sl@0
|
207 |
iImageTimers[iNextRequest].OneShot(iImageTimerTicks, *iImageTimerDFCs[iNextRequest]);
|
sl@0
|
208 |
}
|
sl@0
|
209 |
|
sl@0
|
210 |
return r;
|
sl@0
|
211 |
}
|
sl@0
|
212 |
|
sl@0
|
213 |
/**
|
sl@0
|
214 |
Fills a buffer with a white background with a moving logo on top.
|
sl@0
|
215 |
@param aBuffer Pointer to the buffer to be filled.
|
sl@0
|
216 |
*/
|
sl@0
|
217 |
void DTemplateSensorIf::FillBuffer(TLinAddr aBuffer)
|
sl@0
|
218 |
{
|
sl@0
|
219 |
const TUint8* LogoData = Logo.iPixelData;
|
sl@0
|
220 |
const TUint8* LogoData2 = Logo.iPixelData2;
|
sl@0
|
221 |
TInt index = 0;
|
sl@0
|
222 |
TInt numPixels = (iConfig.iFrameSize.iWidth * iConfig.iFrameSize.iHeight);
|
sl@0
|
223 |
TUint yC, uC, vC;
|
sl@0
|
224 |
TUint16* buffer = (TUint16*) aBuffer;
|
sl@0
|
225 |
|
sl@0
|
226 |
// Alternate between the two logos for cheesy animation effect
|
sl@0
|
227 |
if( ++iCounter == KAlternateLogoFrameInterval )
|
sl@0
|
228 |
{
|
sl@0
|
229 |
iFlipSwitch ^= 1;
|
sl@0
|
230 |
iCounter = 0;
|
sl@0
|
231 |
}
|
sl@0
|
232 |
|
sl@0
|
233 |
|
sl@0
|
234 |
// Set the "photo" background to be all white
|
sl@0
|
235 |
memset(buffer, 0xff, (numPixels * 2));
|
sl@0
|
236 |
|
sl@0
|
237 |
// Point to the correct location in the buffer at which to render the logo
|
sl@0
|
238 |
buffer += ((iY * iConfig.iFrameSize.iWidth) + iX);
|
sl@0
|
239 |
|
sl@0
|
240 |
// Iterate through the data for the logo and copy it into the "photo"
|
sl@0
|
241 |
for (TUint y = 0; y < Logo.iHeight; ++y)
|
sl@0
|
242 |
{
|
sl@0
|
243 |
for (TUint x = 0; x < Logo.iWidth; ++x)
|
sl@0
|
244 |
{
|
sl@0
|
245 |
// The logo is in 24 bit BGR format so read each pixel and convert it to 16 bit BGR565
|
sl@0
|
246 |
// before writing it into the "photo" buffer
|
sl@0
|
247 |
if( iFlipSwitch )
|
sl@0
|
248 |
{
|
sl@0
|
249 |
yC = LogoData[index];
|
sl@0
|
250 |
uC = LogoData[index + 1];
|
sl@0
|
251 |
vC = LogoData[index + 2];
|
sl@0
|
252 |
}
|
sl@0
|
253 |
else
|
sl@0
|
254 |
{
|
sl@0
|
255 |
yC = LogoData2[index];
|
sl@0
|
256 |
uC = LogoData2[index + 1];
|
sl@0
|
257 |
vC = LogoData2[index + 2];
|
sl@0
|
258 |
}
|
sl@0
|
259 |
|
sl@0
|
260 |
*buffer++ = YUVtoYUV565(yC, uC, vC);
|
sl@0
|
261 |
// Point to the next source pixel
|
sl@0
|
262 |
index += 3;
|
sl@0
|
263 |
}
|
sl@0
|
264 |
|
sl@0
|
265 |
// Point to the start of the next line in the buffer, taking into account that the logo
|
sl@0
|
266 |
// is narrower than the buffer
|
sl@0
|
267 |
buffer += (iConfig.iFrameSize.iWidth - Logo.iWidth);
|
sl@0
|
268 |
}
|
sl@0
|
269 |
|
sl@0
|
270 |
// Bounce the logo around in the X direction. This will take effect the next time this is called
|
sl@0
|
271 |
iX += iXDirection;
|
sl@0
|
272 |
|
sl@0
|
273 |
if (iX <= 0)
|
sl@0
|
274 |
{
|
sl@0
|
275 |
iX = 0;
|
sl@0
|
276 |
iXDirection = -iXDirection;
|
sl@0
|
277 |
}
|
sl@0
|
278 |
else if (iX >= (TInt) (iConfig.iFrameSize.iWidth - Logo.iWidth))
|
sl@0
|
279 |
{
|
sl@0
|
280 |
iX = (iConfig.iFrameSize.iWidth - Logo.iWidth);
|
sl@0
|
281 |
iXDirection = -iXDirection;
|
sl@0
|
282 |
}
|
sl@0
|
283 |
|
sl@0
|
284 |
// Bounce the logo around in the Y direction. This will take effect the next time this is called
|
sl@0
|
285 |
iY += iYDirection;
|
sl@0
|
286 |
|
sl@0
|
287 |
if (iY <= 0)
|
sl@0
|
288 |
{
|
sl@0
|
289 |
iY = 0;
|
sl@0
|
290 |
iYDirection = -iYDirection;
|
sl@0
|
291 |
}
|
sl@0
|
292 |
else if (iY >= (TInt) (iConfig.iFrameSize.iHeight - Logo.iHeight))
|
sl@0
|
293 |
{
|
sl@0
|
294 |
iY = (iConfig.iFrameSize.iHeight - Logo.iHeight);
|
sl@0
|
295 |
iYDirection = -iYDirection;
|
sl@0
|
296 |
}
|
sl@0
|
297 |
|
sl@0
|
298 |
// Now flush the cache to memory, taking into account the size of each pixel. This is not normally
|
sl@0
|
299 |
// necessary but given that we are emulating a camera driver in software we must ensure that the
|
sl@0
|
300 |
// cache is flushed to memory. This is because in a real driver the buffer will have been filled
|
sl@0
|
301 |
// by DMA so upon return to the LDD, the LDD will discard the contents of the cache to ensure the
|
sl@0
|
302 |
// DMA-written data is ok. In the case of filling the buffer using the CPU in this virtual camera
|
sl@0
|
303 |
// driver, that would result in the data being discarded!
|
sl@0
|
304 |
Cache::SyncMemoryBeforeDmaWrite((TLinAddr) aBuffer, (numPixels * iConfig.iPixelFormat.iPixelWidthInBytes));
|
sl@0
|
305 |
}
|
sl@0
|
306 |
|
sl@0
|
307 |
/**
|
sl@0
|
308 |
Based on the capture mode and pixel format passed in, copies an array of supported SFrameSize
|
sl@0
|
309 |
structures into a buffer supplied by the LDD. These frame sizes and their associated frame rates
|
sl@0
|
310 |
will reflect the capabilities of the given capture mode and pixel format.
|
sl@0
|
311 |
@param aCaptureMode The capture mode for which to obtain the supported frame sizes.
|
sl@0
|
312 |
@param aUidPixelFormat The UID of the pixel format (as defined in \epoc32\include\pixelformats.h)
|
sl@0
|
313 |
for which to obtain the supported frame sizes.
|
sl@0
|
314 |
@param aFrameSizeCapsBuf A reference to a descriptor that contains a buffer into which to place
|
sl@0
|
315 |
the frame size structures. It is up to the LDD to ensure that this is
|
sl@0
|
316 |
large enough to hold all of the frame sizes.
|
sl@0
|
317 |
@return Always KErrNone.
|
sl@0
|
318 |
*/
|
sl@0
|
319 |
TInt DTemplateSensorIf::FrameSizeCaps(TDevCamCaptureMode /*aCaptureMode*/, TUidPixelFormat /*aUidPixelFormat*/, TDes8& aFrameSizeCapsBuf)
|
sl@0
|
320 |
{
|
sl@0
|
321 |
TPtrC8 sourceFrameSizes((const TUint8*) FrameSizes, sizeof(FrameSizes));
|
sl@0
|
322 |
|
sl@0
|
323 |
// Ensure the buffer passed in from the LDD is large enough and copy the requested frame sizes
|
sl@0
|
324 |
if (aFrameSizeCapsBuf.Size() < sourceFrameSizes.Size())
|
sl@0
|
325 |
{
|
sl@0
|
326 |
Kern::Printf("*** ECapsBufferTooSmall: %d vs %d",
|
sl@0
|
327 |
aFrameSizeCapsBuf.Size(),
|
sl@0
|
328 |
sourceFrameSizes.Size());
|
sl@0
|
329 |
Kern::Fault("camerasc", ECapsBufferTooSmall);
|
sl@0
|
330 |
}
|
sl@0
|
331 |
|
sl@0
|
332 |
//__ASSERT_DEBUG((aFrameSizeCapsBuf.Size() >= sourceFrameSizes.Size()), Kern::Fault("camerasc", ECapsBufferTooSmall));
|
sl@0
|
333 |
aFrameSizeCapsBuf = sourceFrameSizes;
|
sl@0
|
334 |
|
sl@0
|
335 |
return KErrNone;
|
sl@0
|
336 |
}
|
sl@0
|
337 |
|
sl@0
|
338 |
/**
|
sl@0
|
339 |
Allocates a buffer large enough to hold the TCameraCapsV02 structure and its succeeding array of
|
sl@0
|
340 |
pixel formats, and populates the structure and array with information about the capabilities of
|
sl@0
|
341 |
the sensor.
|
sl@0
|
342 |
@param aCameraCaps Reference to a pointer into which to place the pointer to allocated buffer
|
sl@0
|
343 |
@return Size of the capabilities structure if successful, otherwise one of the other system wide
|
sl@0
|
344 |
error codes.
|
sl@0
|
345 |
*/
|
sl@0
|
346 |
TInt DTemplateSensorIf::GetCaps(TCameraCapsV02*& aCameraCaps)
|
sl@0
|
347 |
{
|
sl@0
|
348 |
// Allocate a buffer large enough to hold the TCameraCapsV02 structure and the array of pixel formats
|
sl@0
|
349 |
// that will follow it
|
sl@0
|
350 |
TInt r = (sizeof(TCameraCapsV02) + sizeof(PixelFormats));
|
sl@0
|
351 |
TUint8* capsBuffer = new TUint8[r];
|
sl@0
|
352 |
|
sl@0
|
353 |
if (capsBuffer)
|
sl@0
|
354 |
{
|
sl@0
|
355 |
aCameraCaps = (TCameraCapsV02*) capsBuffer;
|
sl@0
|
356 |
|
sl@0
|
357 |
// No special modes are supported at the moment
|
sl@0
|
358 |
aCameraCaps->iFlashModes = ECamFlashNone;
|
sl@0
|
359 |
aCameraCaps->iExposureModes = ECamExposureAuto; // or None?
|
sl@0
|
360 |
// do we still need whitebalance mode filed?
|
sl@0
|
361 |
aCameraCaps->iWhiteBalanceModes = ECamWBAuto | ECamWBDaylight | ECamWBCloudy | ECamWBTungsten | ECamWBFluorescent | ECamWBFlash | ECamWBSnow | ECamWBBeach;
|
sl@0
|
362 |
aCameraCaps->iMinZoom = 0;
|
sl@0
|
363 |
aCameraCaps->iMaxZoom = 0;
|
sl@0
|
364 |
aCameraCaps->iCapsMisc = KCamMiscContrast | KCamMiscBrightness | KCamMiscColorEffect;
|
sl@0
|
365 |
|
sl@0
|
366 |
// There isn't really such thing as inwards or outwards orientation on an SDP, but we'll pretend it's
|
sl@0
|
367 |
// an outwards facing camera
|
sl@0
|
368 |
aCameraCaps->iOrientation = ECamOrientationOutwards;
|
sl@0
|
369 |
|
sl@0
|
370 |
// Initialise the number of different pixel formats supported
|
sl@0
|
371 |
aCameraCaps->iNumImagePixelFormats = KNumImagePixelFormats;
|
sl@0
|
372 |
aCameraCaps->iNumVideoPixelFormats = KNumVideoPixelFormats;
|
sl@0
|
373 |
aCameraCaps->iNumViewFinderPixelFormats = KNumViewFinderPixelFormats;
|
sl@0
|
374 |
|
sl@0
|
375 |
for (TInt i = 0; i < ECamAttributeMax; i++)
|
sl@0
|
376 |
{
|
sl@0
|
377 |
if (ECamAttributeColorEffect == (TDevCamDynamicAttribute)(i))
|
sl@0
|
378 |
{
|
sl@0
|
379 |
// WhiteBalance
|
sl@0
|
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.
|
sl@0
|
381 |
// As this is fake driver, There doesn't seem to be any major issue though.
|
sl@0
|
382 |
aCameraCaps->iDynamicRange[i].iMin = ECamWBAuto;
|
sl@0
|
383 |
aCameraCaps->iDynamicRange[i].iMax = ECamWBBeach;
|
sl@0
|
384 |
aCameraCaps->iDynamicRange[i].iDefault = ECamWBAuto;
|
sl@0
|
385 |
}
|
sl@0
|
386 |
else
|
sl@0
|
387 |
{
|
sl@0
|
388 |
// TBC :: Contrast, Brightness
|
sl@0
|
389 |
aCameraCaps->iDynamicRange[i].iMin = 0;
|
sl@0
|
390 |
aCameraCaps->iDynamicRange[i].iMax = 6;
|
sl@0
|
391 |
aCameraCaps->iDynamicRange[i].iDefault = 3;
|
sl@0
|
392 |
}
|
sl@0
|
393 |
}
|
sl@0
|
394 |
|
sl@0
|
395 |
// Setup some descriptors pointing to the pixel format array and the array passed in by the LDD
|
sl@0
|
396 |
// (located at the end of the TCameraCapsV02 structure) and copy the pixel format array
|
sl@0
|
397 |
TPtrC8 sourcePixelFormats((const TUint8*) PixelFormats, sizeof(PixelFormats));
|
sl@0
|
398 |
TPtr8 destPixelFormats((capsBuffer + sizeof(TCameraCapsV02)), sizeof(PixelFormats), sizeof(PixelFormats));
|
sl@0
|
399 |
destPixelFormats = sourcePixelFormats;
|
sl@0
|
400 |
}
|
sl@0
|
401 |
else
|
sl@0
|
402 |
{
|
sl@0
|
403 |
r = KErrNoMemory;
|
sl@0
|
404 |
}
|
sl@0
|
405 |
|
sl@0
|
406 |
return r;
|
sl@0
|
407 |
}
|
sl@0
|
408 |
|
sl@0
|
409 |
/**
|
sl@0
|
410 |
Powers up the sensor hardware.
|
sl@0
|
411 |
@return KErrNone if successful, otherwise one of the other system wide error codes.
|
sl@0
|
412 |
*/
|
sl@0
|
413 |
TInt DTemplateSensorIf::RequestPower()
|
sl@0
|
414 |
{
|
sl@0
|
415 |
__KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::RequestPower()"));
|
sl@0
|
416 |
|
sl@0
|
417 |
TInt r = KErrNone;
|
sl@0
|
418 |
|
sl@0
|
419 |
__KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::RequestPower() => Returning %d", r));
|
sl@0
|
420 |
|
sl@0
|
421 |
return r;
|
sl@0
|
422 |
}
|
sl@0
|
423 |
|
sl@0
|
424 |
/**
|
sl@0
|
425 |
Powers down the sensor hardware.
|
sl@0
|
426 |
@return KErrNone if successful, otherwise one of the other system wide error codes.
|
sl@0
|
427 |
*/
|
sl@0
|
428 |
TInt DTemplateSensorIf::RelinquishPower()
|
sl@0
|
429 |
{
|
sl@0
|
430 |
__KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::RelinquishPower()"));
|
sl@0
|
431 |
|
sl@0
|
432 |
TInt r = KErrNone;
|
sl@0
|
433 |
|
sl@0
|
434 |
__KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::RelinquishPower() => Returning %d", r));
|
sl@0
|
435 |
|
sl@0
|
436 |
return r;
|
sl@0
|
437 |
}
|
sl@0
|
438 |
|
sl@0
|
439 |
/**
|
sl@0
|
440 |
Begins capture of the next image into the buffer provided. This function assumes that
|
sl@0
|
441 |
Start() has already been called to start capture. However, Stop() may also have been
|
sl@0
|
442 |
subsequently called (for example to pause capture) and in this case, this function will
|
sl@0
|
443 |
handle restarting the sensor.
|
sl@0
|
444 |
@param aLinAddr A virtual pointer to the buffer into which to capture the image.
|
sl@0
|
445 |
@param aPhysAddr A physical pointer to the buffer into which to capture the image.
|
sl@0
|
446 |
This points to the same memory as aLinAddr.
|
sl@0
|
447 |
@return KErrNone if successful.
|
sl@0
|
448 |
KErrNotReady if there are no free requests to capture the image.
|
sl@0
|
449 |
Otherwise one of the other system wide error codes.
|
sl@0
|
450 |
*/
|
sl@0
|
451 |
TInt DTemplateSensorIf::CaptureNextImage(TLinAddr aLinAddr, TPhysAddr /*aPhysAddr*/)
|
sl@0
|
452 |
{
|
sl@0
|
453 |
TInt r = KErrNone;
|
sl@0
|
454 |
|
sl@0
|
455 |
// Only start capturing the next image if there are any pending request slots available
|
sl@0
|
456 |
if (iPendingRequests < KTotalCameraRequests)
|
sl@0
|
457 |
{
|
sl@0
|
458 |
// Queue a transfer on the next available channel and indicate that the channel is
|
sl@0
|
459 |
// in use
|
sl@0
|
460 |
iNextRequest = ((iNextRequest + 1) % KTotalCameraRequests);
|
sl@0
|
461 |
NKern::LockedInc(iPendingRequests);
|
sl@0
|
462 |
|
sl@0
|
463 |
// XXX: Temporary code to be removed in a real driver. Fill the buffer for testing
|
sl@0
|
464 |
// with user side code. This is to simulate an image being captured into the buffer that
|
sl@0
|
465 |
// has been passed in in aLinAddr. As well as aLinAddr, which points to the virtual
|
sl@0
|
466 |
// address of the buffer, the LDD will pass in the physical address as well, in aPhysAddr.
|
sl@0
|
467 |
// Depending on the underlying sensor hardware and/or bus in use, you will have to choose
|
sl@0
|
468 |
// which of these to use
|
sl@0
|
469 |
FillBuffer(aLinAddr);
|
sl@0
|
470 |
|
sl@0
|
471 |
// XXX: Send buffer to sensor. Normally the address of the buffer passed in in aLinAddr and
|
sl@0
|
472 |
// aPhysAddr would be programmed into the sensor and/or bus hardware here and an interrupt
|
sl@0
|
473 |
// would be generated when the iamge had been captured into the buffer. In this simulated
|
sl@0
|
474 |
// driver we will use a nanokernel timer to simulate this process
|
sl@0
|
475 |
iImageTimers[iNextRequest].OneShot(iImageTimerTicks, *iImageTimerDFCs[iNextRequest]);
|
sl@0
|
476 |
|
sl@0
|
477 |
// If capturing has not yet started or has been paused by Stop(), start it
|
sl@0
|
478 |
if (!(iEnabled))
|
sl@0
|
479 |
{
|
sl@0
|
480 |
iEnabled = ETrue;
|
sl@0
|
481 |
}
|
sl@0
|
482 |
}
|
sl@0
|
483 |
else
|
sl@0
|
484 |
{
|
sl@0
|
485 |
r = KErrNotReady;
|
sl@0
|
486 |
}
|
sl@0
|
487 |
|
sl@0
|
488 |
return r;
|
sl@0
|
489 |
}
|
sl@0
|
490 |
|
sl@0
|
491 |
/**
|
sl@0
|
492 |
Begins capture of the first image into the buffer provided. This function is similar to
|
sl@0
|
493 |
CaptureNextImage(), except that it will perform any extra sensor intitialisation required
|
sl@0
|
494 |
to start capture.
|
sl@0
|
495 |
@param aCaptureMode The capture mode for which to start capturing.
|
sl@0
|
496 |
@param aLinAddr A virtual pointer to the buffer into which to capture the image.
|
sl@0
|
497 |
@param aPhysAddr A physical pointer to the buffer into which to capture the image.
|
sl@0
|
498 |
This points to the same memory as aLinAddr.
|
sl@0
|
499 |
@return KErrNone if successful
|
sl@0
|
500 |
KErrInUse if capture is already under way.
|
sl@0
|
501 |
KErrNotSupported if the frame size and/or frame rate are out of range.
|
sl@0
|
502 |
Otherwise one of the other system wide error codes.
|
sl@0
|
503 |
*/
|
sl@0
|
504 |
TInt DTemplateSensorIf::Start(TDevCamCaptureMode /*aCaptureMode*/, TLinAddr aLinAddr, TPhysAddr aPhysAddr)
|
sl@0
|
505 |
{
|
sl@0
|
506 |
__KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::Start()"));
|
sl@0
|
507 |
|
sl@0
|
508 |
TInt r = KErrNone;
|
sl@0
|
509 |
|
sl@0
|
510 |
// XXX - In a real camera driver, in here we would initialise start the capturing process in here.
|
sl@0
|
511 |
// When an image is captured, the sensor hardware (or maybe the CSI bus) will generate an
|
sl@0
|
512 |
// which will then be enqueued into the DFC queue that was passed into the constructor of
|
sl@0
|
513 |
// the sensor class. It is important to do the DFC processing in this DFC queue rather than
|
sl@0
|
514 |
// a separate one because it ensures that fucntions in the PDD and LDD are called in a serialised
|
sl@0
|
515 |
// manner, without the need for mutexts. In this example camera driver we will convert the
|
sl@0
|
516 |
// framerate into a nanokernel tick count and will use an NTimer.OneShot() call to simulate
|
sl@0
|
517 |
// the sensor interrupt and DFC callback. Divides are slow so we'll calculate the tick count
|
sl@0
|
518 |
// here and will save it for later use
|
sl@0
|
519 |
iImageTimerTicks = ((1000000 / NKern::TickPeriod()) / iConfig.iFrameRate);
|
sl@0
|
520 |
|
sl@0
|
521 |
// XXX - Once the one off hardware initialisation has been done for starting a new capture, then
|
sl@0
|
522 |
// subsequent captures can usually reuse the same code in CaptureNextImage() for starting
|
sl@0
|
523 |
// the next capture
|
sl@0
|
524 |
r = CaptureNextImage(aLinAddr, aPhysAddr);
|
sl@0
|
525 |
|
sl@0
|
526 |
__KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::Start() => Returning %d", r));
|
sl@0
|
527 |
|
sl@0
|
528 |
return r;
|
sl@0
|
529 |
}
|
sl@0
|
530 |
|
sl@0
|
531 |
/**
|
sl@0
|
532 |
Stops capturing any image capture that is currently in progress. This function will act
|
sl@0
|
533 |
more like a Pause() than a Stop() capturing can be restarted from where it was stopped.
|
sl@0
|
534 |
*/
|
sl@0
|
535 |
TInt DTemplateSensorIf::Stop()
|
sl@0
|
536 |
{
|
sl@0
|
537 |
__KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::Stop()"));
|
sl@0
|
538 |
|
sl@0
|
539 |
iEnabled = EFalse;
|
sl@0
|
540 |
iPendingRequests = iNextRequest = 0;
|
sl@0
|
541 |
|
sl@0
|
542 |
// XXX - Cancel all of our pending image timer callbacks. In a real driver we would write to the
|
sl@0
|
543 |
// sensor and/or bus hardware here to cause them to cancel any pending image captures
|
sl@0
|
544 |
for (TInt index = 0; index < KTotalCameraRequests; ++index)
|
sl@0
|
545 |
{
|
sl@0
|
546 |
iImageTimers[index].Cancel();
|
sl@0
|
547 |
}
|
sl@0
|
548 |
|
sl@0
|
549 |
__KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::Stop()"));
|
sl@0
|
550 |
|
sl@0
|
551 |
return KErrNone;
|
sl@0
|
552 |
}
|