1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/bsptemplate/asspandvariant/template_variant/specific/xyin.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1037 @@
1.4 +// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// template\Template_Variant\Specific\xyin.cpp
1.18 +// Implementation of a digitiser (touch-screen) driver.
1.19 +// This code assumes that an interrupt is generated on pen-down and pen-up events.
1.20 +// This file is part of the Template Base port
1.21 +// We use this driver to exemplify the usage of Resource Management for shared resources, Peripheral "Sleep"
1.22 +// and detection and notification of Wakeup events
1.23 +//
1.24 +//
1.25 +
1.26 +
1.27 +#include <assp.h>
1.28 +#include <template_assp.h>
1.29 +#include <videodriver.h>
1.30 +#include "mconf.h"
1.31 +#include <drivers/xyin.h>
1.32 +#include "template_power.h"
1.33 +
1.34 +
1.35 +
1.36 +
1.37 +//
1.38 +// TO DO: (mandatory)
1.39 +//
1.40 +// Define the following constants that describe the digitiser position & dimensions
1.41 +// This is only example code... you need to modify it for your hardware
1.42 +
1.43 +// digitiser origin & size in pixels
1.44 +const TUint KConfigXyOffsetX = 0; // digitiser origin - same as display area
1.45 +const TUint KConfigXyOffsetY = 0;
1.46 +const TUint KConfigXyWidth = 640; // 640 pixels per line
1.47 +const TUint KConfigXyHeight = 480; // 480 lines per panel
1.48 +
1.49 +// digitiser dimensions in digitiser co-ordinates
1.50 +const TInt KConfigXyBitsX = 12;
1.51 +const TInt KConfigXyBitsY = 12;
1.52 +const TInt KConfigXySpreadX = 1 << KConfigXyBitsX; // maximum valid X spread
1.53 +const TInt KConfigXySpreadY = 1 << KConfigXyBitsY; // maximum valid Y spread
1.54 +const TInt KConfigXyMinX = 0; // minimum valid X value
1.55 +const TInt KConfigXyMinY = 0; // minimum valid Y value
1.56 +const TInt KConfigXyMaxX = KConfigXySpreadX - 1; // maximum valid X value
1.57 +const TInt KConfigXyMaxY = KConfigXySpreadY - 1; // maximum valid Y value
1.58 +
1.59 +
1.60 +// Define a 2x2 matrix and two constants Tx and Ty to convert digitiser co-ordinates
1.61 +// to pixels such that
1.62 +//
1.63 +// (X<<16 Y<<16) = (x y) x (R11 R12) + (Tx Ty)
1.64 +// (R21 R22)
1.65 +// or :
1.66 +//
1.67 +// X = (x*R11 + y*R21 + TX) >> 16;
1.68 +// Y = (x*R12 + y*R22 + TY) >> 16;
1.69 +
1.70 +//
1.71 +// where x,y are digitiser coordinates, Tx,Ty are constant offsets and X,Y are screen
1.72 +// coordinates. Left shifting by 16 bits is used so as not to lose precision.
1.73 +//
1.74 +// These are default values to be used before calibration has taken place
1.75 +// These are best set by observation.
1.76 +// The example values given below are for a digitiser whose origin is at bottom left
1.77 +// (the screen origin is at top left)
1.78 +const TInt KConfigXyR11 = (KConfigXyWidth << 16) / KConfigXySpreadX; // 10240
1.79 +const TInt KConfigXyR12 = 0;
1.80 +const TInt KConfigXyR21 = 0;
1.81 +const TInt KConfigXyR22 = - ((KConfigXyHeight << 16) / KConfigXySpreadY); // -7680
1.82 +const TInt KConfigXyTx = 0;
1.83 +const TInt KConfigXyTy = (KConfigXyHeight << 16) / KConfigXySpreadY;
1.84 +
1.85 +//
1.86 +// TO DO: (optional)
1.87 +//
1.88 +// Define the following constants that describe the digitiser behaviour
1.89 +// This is only example code... you need to modify it for your hardware
1.90 +
1.91 +// After taking a sample, wait for the specified number of nano-kernel ticks (normally 1 ms)
1.92 +// before taking the next sample
1.93 +const TInt KInterSampleTime = 1;
1.94 +
1.95 +// After a group of samples has been processed by the DDigitiser::ProcessRawSample() DFC,
1.96 +// wait for the specified number of nano-kernel ticks before taking the next sample
1.97 +const TInt KInterGroupTime = 1;
1.98 +
1.99 +// After a pen-down interrupt,
1.100 +// wait for the specified number of nano-kernel ticks before taking the next sample
1.101 +const TInt KPenDownDelayTime = 2;
1.102 +
1.103 +// If powering up the device with the pen down,
1.104 +// wait for the specified number of nano-kernel ticks before taking the next sample
1.105 +const TInt KPenUpPollTime = 30;
1.106 +
1.107 +// After a pen-up interrupt,
1.108 +// wait for the specified number of nano-kernel ticks before calling PenUp()
1.109 +const TInt KPenUpDebounceTime = 10;
1.110 +
1.111 +// number of samples to discard on pen-down
1.112 +const TInt KConfigXyPenDownDiscard = 1;
1.113 +
1.114 +// number of samples to discard on pen-up
1.115 +const TInt KConfigXyPenUpDiscard = 1;
1.116 +
1.117 +// offset in pixels to cause movement in X direction
1.118 +const TInt KConfigXyAccThresholdX = 12;
1.119 +
1.120 +// offset in pixels to cause movement in Y direction
1.121 +const TInt KConfigXyAccThresholdY = 12;
1.122 +
1.123 +// number of samples to average - MUST be <= KMaxXYSamples
1.124 +const TInt KConfigXyNumXYSamples = 2;
1.125 +
1.126 +// disregard extremal values in each 4-sample group
1.127 +const TBool KConfigXyDisregardMinMax= EFalse;
1.128 +
1.129 +
1.130 +
1.131 +// obsolete constants :
1.132 +const TInt KConfigXyDriveXRise = 0;
1.133 +const TInt KConfigXyDriveYRise = 0;
1.134 +const TInt KConfigXyMaxJumpX = 0;
1.135 +const TInt KConfigXyMaxJumpY = 0;
1.136 +
1.137 +
1.138 +
1.139 +/******************************************************
1.140 + * Main Digitiser Class
1.141 + ******************************************************/
1.142 +
1.143 +//
1.144 +// TO DO: (optional)
1.145 +//
1.146 +// Add any private functions and data you require
1.147 +//
1.148 +NONSHARABLE_CLASS(DTemplateDigitiser) : public DDigitiser
1.149 + {
1.150 +public:
1.151 + enum TState
1.152 + {
1.153 + E_HW_PowerUp,
1.154 + E_HW_PenUpDebounce,
1.155 + E_HW_CollectSample
1.156 + };
1.157 +
1.158 +public:
1.159 + // from DDigitiser - initialisation
1.160 + DTemplateDigitiser();
1.161 + virtual TInt DoCreate();
1.162 + void SetDefaultConfig();
1.163 +
1.164 + // from DDigitiser - signals to hardware-dependent code
1.165 + virtual void WaitForPenDown();
1.166 + virtual void WaitForPenUp();
1.167 + virtual void WaitForPenUpDebounce();
1.168 + virtual void DigitiserOn();
1.169 + virtual void DigitiserOff();
1.170 + virtual void FilterPenMove(const TPoint& aPoint);
1.171 + virtual void ResetPenMoveFilter();
1.172 +
1.173 + // from DDigitiser - machine-configuration related things
1.174 + virtual TInt DigitiserToScreen(const TPoint& aDigitiserPoint, TPoint& aScreenPoint);
1.175 + virtual void ScreenToDigitiser(TInt& aX, TInt& aY);
1.176 + virtual TInt SetXYInputCalibration(const TDigitizerCalibration& aCalibration);
1.177 + virtual TInt CalibrationPoints(TDigitizerCalibration& aCalibration);
1.178 + virtual TInt SaveXYInputCalibration();
1.179 + virtual TInt RestoreXYInputCalibration(TDigitizerCalibrationType aType);
1.180 + virtual void DigitiserInfo(TDigitiserInfoV01& aInfo);
1.181 +
1.182 + // from DPowerHandler
1.183 + virtual void PowerDown(TPowerState);
1.184 + virtual void PowerUp();
1.185 +
1.186 +public:
1.187 + // implementation
1.188 + void TakeSample();
1.189 + void PenInterrupt();
1.190 + void DigitiserPowerUp();
1.191 + void PowerUpDfc();
1.192 +
1.193 +public:
1.194 + NTimer iTimer;
1.195 + NTimer iTimerInt;
1.196 + TDfc iTakeReadingDfc;
1.197 + TDfc iPowerDownDfc;
1.198 + TDfc iPowerUpDfc;
1.199 + TInt iSamplesCount;
1.200 + TState iState;
1.201 + TUint8 iPoweringDown;
1.202 +
1.203 + TSize iScreenSize;
1.204 + TActualMachineConfig& iMachineConfig;
1.205 + };
1.206 +
1.207 +/******************************************************
1.208 + * Digitiser main code
1.209 + ******************************************************/
1.210 +/**
1.211 +Sample timer callback
1.212 +Schedules a DFC to take a sample
1.213 +
1.214 +@param aPtr a pointer to DTemplateDigitiser
1.215 +*/
1.216 +LOCAL_C void timerExpired(TAny* aPtr)
1.217 + {
1.218 + DTemplateDigitiser* pD=(DTemplateDigitiser*)aPtr;
1.219 + __KTRACE_OPT(KHARDWARE,Kern::Printf("T"));
1.220 + pD->iTakeReadingDfc.Add();
1.221 + }
1.222 +
1.223 +/**
1.224 +Debounce timer callback
1.225 +schedules a DFC to process a pen-down interrupt
1.226 +
1.227 +@param aPtr a pointer to DTemplateDigitiser
1.228 +*/
1.229 +LOCAL_C void timerIntExpired(TAny* aPtr)
1.230 + {
1.231 + DTemplateDigitiser* pD=(DTemplateDigitiser*)aPtr;
1.232 + __KTRACE_OPT(KHARDWARE,Kern::Printf("TI"));
1.233 + // clear xy interrupt -> re-triggers the interrupt mechanism to catch the next IRQ
1.234 +
1.235 + // TO DO: (mandatory)
1.236 + // Write to the appropriate hardware register to clear the digitiser interrupt
1.237 + //
1.238 +
1.239 + pD->iTakeReadingDfc.Add();
1.240 + }
1.241 +
1.242 +/**
1.243 +Pen-up/down interrupt handler
1.244 +
1.245 +@param aPtr a pointer to DTemplateDigitiser
1.246 +*/
1.247 +LOCAL_C void penInterrupt(TAny* aPtr)
1.248 + {
1.249 + DTemplateDigitiser* pD=(DTemplateDigitiser*)aPtr;
1.250 + pD->PenInterrupt();
1.251 + }
1.252 +
1.253 +/**
1.254 +DFC for taking a sample
1.255 +
1.256 +@param aPtr a pointer to DTemplateDigitiser
1.257 +*/
1.258 +LOCAL_C void takeReading(TAny* aPtr)
1.259 + {
1.260 + DTemplateDigitiser* pD=(DTemplateDigitiser*)aPtr;
1.261 + pD->TakeSample();
1.262 + }
1.263 +
1.264 +/**
1.265 +DFC for powering down the device
1.266 +
1.267 +@param aPtr a pointer to DTemplateDigitiser
1.268 +*/
1.269 +LOCAL_C void powerDownDfc(TAny* aPtr)
1.270 + {
1.271 + DTemplateDigitiser* pD=(DTemplateDigitiser*)aPtr;
1.272 + pD->DigitiserOff();
1.273 + }
1.274 +
1.275 +/**
1.276 +DFC for powering up the device
1.277 +
1.278 +@param aPtr a pointer to DTemplateDigitiser
1.279 +*/
1.280 +LOCAL_C void powerUpDfc(TAny* aPtr)
1.281 + {
1.282 + DTemplateDigitiser* pD=(DTemplateDigitiser*)aPtr;
1.283 + pD->PowerUpDfc();
1.284 + }
1.285 +
1.286 +/**
1.287 +Creates a new instance of DDigitiser.
1.288 +Called by extension entry point (PIL) to create a DDigitiser-derived object.
1.289 +
1.290 +@return a pointer to a DTemplateDigitiser object
1.291 +*/
1.292 +DDigitiser* DDigitiser::New()
1.293 + {
1.294 + return new DTemplateDigitiser;
1.295 + }
1.296 +
1.297 +/**
1.298 +Default constructor
1.299 +*/
1.300 +DTemplateDigitiser::DTemplateDigitiser() :
1.301 + iTimer(timerExpired,this),
1.302 + iTimerInt(timerIntExpired,this),
1.303 + iTakeReadingDfc(takeReading,this,5),
1.304 + iPowerDownDfc(powerDownDfc,this,5),
1.305 + iPowerUpDfc(powerUpDfc,this,5),
1.306 + iMachineConfig(TheActualMachineConfig())
1.307 + {
1.308 + iDfcQ = Kern::DfcQue0();
1.309 + iTakeReadingDfc.SetDfcQ(iDfcQ);
1.310 + iPowerDownDfc.SetDfcQ(iDfcQ);
1.311 + iPowerUpDfc.SetDfcQ(iDfcQ);
1.312 + }
1.313 +
1.314 +/**
1.315 +Perform hardware-dependent initialisation
1.316 +
1.317 +Called by platform independent layer
1.318 +*/
1.319 +TInt DTemplateDigitiser::DoCreate()
1.320 + {
1.321 + __KTRACE_OPT(KEXTENSION,Kern::Printf("DTemplateDigitiser::DoCreate"));
1.322 +
1.323 + if (Kern::ColdStart())
1.324 + {
1.325 + __KTRACE_OPT(KEXTENSION,Kern::Printf("Resetting digitiser calibration"));
1.326 +
1.327 + // Emergency digitiser calibration values
1.328 + iMachineConfig.iCalibration.iR11 = KConfigXyR11;
1.329 + iMachineConfig.iCalibration.iR12 = KConfigXyR12;
1.330 + iMachineConfig.iCalibration.iR21 = KConfigXyR21;
1.331 + iMachineConfig.iCalibration.iR22 = KConfigXyR22;
1.332 + iMachineConfig.iCalibration.iTx = KConfigXyTx;
1.333 + iMachineConfig.iCalibration.iTy = KConfigXyTy;
1.334 + }
1.335 +
1.336 + // register power handler
1.337 + Add();
1.338 + DigitiserPowerUp();
1.339 +
1.340 + // bind to the pen-up/down interrupt
1.341 + TInt r=Interrupt::Bind(KIntIdDigitiser, penInterrupt, this);
1.342 + if (r!=KErrNone)
1.343 + return r;
1.344 +
1.345 + // set up the default configuration
1.346 + SetDefaultConfig();
1.347 +
1.348 + return r;
1.349 + }
1.350 +
1.351 +/**
1.352 +Initialise the DDigitiser::iCfg structure
1.353 +*/
1.354 +void DTemplateDigitiser::SetDefaultConfig()
1.355 + {
1.356 + iCfg.iPenDownDiscard = KConfigXyPenDownDiscard; // number of samples to discard on pen-down
1.357 + iCfg.iPenUpDiscard = KConfigXyPenUpDiscard; // number of samples to discard on pen-up
1.358 + iCfg.iDriveXRise = KConfigXyDriveXRise; // number of milliseconds to wait when driving horizontal edges
1.359 + iCfg.iDriveYRise = KConfigXyDriveYRise; // number of milliseconds to wait when driving vertical edges
1.360 + iCfg.iMinX = KConfigXyMinX; // minimum valid X value
1.361 + iCfg.iMaxX = KConfigXyMaxX; // maximum valid X value
1.362 + iCfg.iSpreadX = KConfigXySpreadX; // maximum valid X spread
1.363 + iCfg.iMinY = KConfigXyMinY; // minimum valid Y value
1.364 + iCfg.iMaxY = KConfigXyMaxY; // maximum valid Y value
1.365 + iCfg.iSpreadY = KConfigXySpreadY; // maximum valid Y spread
1.366 + iCfg.iMaxJumpX = KConfigXyMaxJumpX; // maximum X movement per sample (pixels)
1.367 + iCfg.iMaxJumpY = KConfigXyMaxJumpY; // maximum Y movement per sample (pixels)
1.368 + iCfg.iAccThresholdX = KConfigXyAccThresholdX; // offset in pixels to cause movement in X direction
1.369 + iCfg.iAccThresholdY = KConfigXyAccThresholdY; // offset in pixels to cause movement in Y direction
1.370 + iCfg.iNumXYSamples = KConfigXyNumXYSamples; // number of samples to average
1.371 + iCfg.iDisregardMinMax = KConfigXyDisregardMinMax; // disregard extremal values in each 4-sample group
1.372 + }
1.373 +
1.374 +/**
1.375 +Takes a sample from the digitiser.
1.376 +Called in the context of a DFC thread.
1.377 +*/
1.378 +void DTemplateDigitiser::TakeSample()
1.379 + {
1.380 + TTemplatePowerController::WakeupEvent(); // notify of pendown (wakeup event) and let the power controller sort
1.381 + // out if it needs propagation
1.382 +
1.383 + TBool penDown = EFalse;
1.384 +
1.385 + // TO DO: (mandatory)
1.386 + // Read from appropriate hardware register to determine whether digitiser panel is being touched
1.387 + // Set penDown to ETrue if touched or EFalse if not touched.
1.388 + //
1.389 +
1.390 + __KTRACE_OPT(KHARDWARE,Kern::Printf("TS: S%d PD%d Sp%d", (TInt)iState, penDown?1:0, iSamplesCount));
1.391 +
1.392 + if (iState==E_HW_PowerUp)
1.393 + {
1.394 + // waiting for pen to go up after switch on due to pen down or through the HAL
1.395 + // coverity[dead_error_condition]
1.396 + // The next line should be reachable when this template file is edited for use
1.397 + if (!penDown) // pen has gone up -> transition to new state
1.398 + {
1.399 + iState=E_HW_CollectSample;
1.400 + iSamplesCount=0; // reset sample buffer
1.401 +
1.402 + // TO DO: (mandatory)
1.403 + // Write to the appropriate hardware register to clear the digitiser interrupt
1.404 + //
1.405 +
1.406 + // TO DO: (mandatory)
1.407 + // Write to the appropriate hardware register(s) to allow the hardware
1.408 + // to detect when the digitizer panel is touched
1.409 + //
1.410 +
1.411 + Interrupt::Enable(KIntIdDigitiser); // enable pen-down interrupt
1.412 +
1.413 + // TO DO: (mandatory)
1.414 + // Write to the appropriate hardware register to enable the digitiser interrupt
1.415 + //
1.416 +
1.417 + }
1.418 + else // pen is still down, wait a bit longer in this state
1.419 + {
1.420 + iTimer.OneShot(KPenUpPollTime);
1.421 + }
1.422 + return;
1.423 + }
1.424 +
1.425 + if (!penDown)
1.426 + {
1.427 + if (iState==E_HW_PenUpDebounce)
1.428 + {
1.429 + iState=E_HW_CollectSample; // back to initial state, no samples collected
1.430 + iSamplesCount=0; // reset sample buffer
1.431 + // Need to lock the kernel to simulate ISR context and thus defer preemption,
1.432 + // since PenUp() expects an ISR context and calls TDfc::Add().
1.433 + NKern::Lock();
1.434 + PenUp(); // adds DFC
1.435 + NKern::Unlock();
1.436 + }
1.437 + else // iState=E_HW_CollectSample
1.438 + {
1.439 + iState=E_HW_PenUpDebounce;
1.440 + iTimer.OneShot(KPenUpDebounceTime); // wait a bit to make sure pen still up
1.441 + }
1.442 + return;
1.443 + }
1.444 + else if (iState==E_HW_PenUpDebounce) // pen down
1.445 + {
1.446 + // false alarm - pen is down again
1.447 + iState=E_HW_CollectSample; // take a new set of samples
1.448 + iSamplesCount=0; // reset sample buffer
1.449 + }
1.450 + // default: pen down and iState=E_HW_CollectSample
1.451 +
1.452 + // TO DO: (mandatory)
1.453 + // Read from appropriate hardware register to get the current digitiser coordinates
1.454 + // of the point that is being touched. Set aResults accordingly.
1.455 + // This is only example code... you need to modify it for your hardware
1.456 + //
1.457 + TPoint aResults;
1.458 +
1.459 + // X axis
1.460 + iX[iSamplesCount] = aResults.iX;
1.461 + // Y axis
1.462 + iY[iSamplesCount] = aResults.iY;
1.463 +
1.464 + __KTRACE_OPT(KHARDWARE,Kern::Printf("Raw: X=%d Y=%d",iX[iSamplesCount],iY[iSamplesCount]));
1.465 +
1.466 + // Put the hardware back into pen-detect mode
1.467 +
1.468 + // TO DO: (mandatory)
1.469 + // Write to the appropriate hardware register(s) to allow the hardware
1.470 + // to detect when the digitizer panel is touched
1.471 + //
1.472 +
1.473 + // count samples collected - if it's less than minimum,
1.474 + // schedule the reading of another sample
1.475 + if (++iSamplesCount < iCfg.iNumXYSamples) // iX[] and iY[] are 4 levels deep in xyin.h...
1.476 + {
1.477 + if(KInterSampleTime > 0) // need to check this config param as it might be zero!
1.478 + iTimer.OneShot(KInterSampleTime); // haven't got a complete group yet, so queue timer to sample again
1.479 + else
1.480 + iTakeReadingDfc.Enque();
1.481 + return;
1.482 + }
1.483 +
1.484 + // Have a complete group of samples so pass up to processing layer (PIL)
1.485 +
1.486 + // Need to lock the kernel to simulate ISR context and thus defer preemption,
1.487 + // since RawSampleValid() expects an ISR context and calls TDfc::Add().
1.488 + NKern::Lock();
1.489 + RawSampleValid(); // adds DFC
1.490 + NKern::Unlock();
1.491 + }
1.492 +
1.493 +/**
1.494 +Request for an interrupt to be generated when the pen is next down
1.495 +Called by PIL at startup or when pen leaves digitiser after pen-up event issued
1.496 +*/
1.497 +void DTemplateDigitiser::WaitForPenDown()
1.498 + {
1.499 + // Called at startup or when pen leaves digitiser after pen-up event issued
1.500 + __KTRACE_OPT(KHARDWARE,Kern::Printf("WD: PowerDownMask %x",iPoweringDown));
1.501 + if (iPoweringDown)
1.502 + {
1.503 + // powering down
1.504 +
1.505 + // TO DO: (mandatory)
1.506 + // Write to the appropriate hardware register(s) to allow the hardware
1.507 + // to detect when the digitizer panel is touched and wakes up the system if in standby
1.508 + //
1.509 +
1.510 + //
1.511 + // TO DO: (optional)
1.512 + //
1.513 + // Relinquish request on power resources
1.514 + // This will place the peripheral hardware in a low power "Sleep" mode which is Interrupt detection capable
1.515 + // EXAMPLE ONLY
1.516 + //
1.517 + TemplateResourceManager* aManager = TTemplatePowerController::ResourceManager();
1.518 + aManager -> ModifyToLevel(TemplateResourceManager::AsynchMlResourceUsedByXOnly, 50 /* a percentage */);
1.519 + aManager -> SharedBResource1() -> Release();
1.520 +
1.521 + iPoweringDown = EFalse;
1.522 + PowerDownDone();
1.523 + }
1.524 + else
1.525 + {
1.526 +
1.527 + // TO DO: (mandatory)
1.528 + // Write to the appropriate hardware register to clear the digitiser interrupt
1.529 + //
1.530 +
1.531 + // TO DO: (mandatory)
1.532 + // Write to the appropriate hardware register(s) to allow the hardware
1.533 + // to detect when the digitizer panel is touched
1.534 + //
1.535 +
1.536 + if ((iTimer.iState == NTimer::EIdle) && (iTimerInt.iState == NTimer::EIdle))
1.537 + Interrupt::Enable(KIntIdDigitiser); // enable pen-down interrupt
1.538 + }
1.539 + }
1.540 +
1.541 +/**
1.542 +Called by PIL after it has processed a group of raw samples while pen is down.
1.543 +Used to indicate that the iX, iY buffers may be re-used
1.544 +*/
1.545 +void DTemplateDigitiser::WaitForPenUp()
1.546 + {
1.547 + __KTRACE_OPT(KHARDWARE,Kern::Printf("WU"));
1.548 + iState = E_HW_CollectSample;
1.549 + iSamplesCount = 0; // reset sample buffer
1.550 + if(KInterGroupTime > 0) // need to check this config param as it might be zero!
1.551 + iTimer.OneShot(KInterGroupTime);
1.552 + else
1.553 + iTakeReadingDfc.Enque();
1.554 + }
1.555 +
1.556 +/**
1.557 +Called by PIL if the group of samples collected is not good enough
1.558 +Used to indicate that the iX, iY buffers may be re-used
1.559 +*/
1.560 +void DTemplateDigitiser::WaitForPenUpDebounce()
1.561 + {
1.562 + __KTRACE_OPT(KHARDWARE,Kern::Printf("WUDB"));
1.563 + iState = E_HW_CollectSample;
1.564 + iSamplesCount = 0; // reset sample buffer
1.565 + if(KInterGroupTime > 0) // need to check this config param as it might be zero!
1.566 + iTimer.OneShot(KInterGroupTime);
1.567 + else
1.568 + iTakeReadingDfc.Enque();
1.569 + }
1.570 +
1.571 +/**
1.572 +Pen up/down interrupt service routine (ISR)
1.573 +*/
1.574 +void DTemplateDigitiser::PenInterrupt()
1.575 + {
1.576 + __KTRACE_OPT(KHARDWARE,Kern::Printf("I"));
1.577 +
1.578 +
1.579 + Interrupt::Clear(KIntIdDigitiser); // should already have been cleared
1.580 +
1.581 + // TO DO: (mandatory)
1.582 + // Read from appropriate hardware register to determine whether digitiser panel is being touched
1.583 + // Set penDown to ETrue if touched or EFalse if not touched.
1.584 + // This is only example code... you need to modify it for your hardware
1.585 + TBool penDown = EFalse;
1.586 +
1.587 + // coverity[dead_error_condition]
1.588 + if(!penDown) // pen up
1.589 + {
1.590 +
1.591 + // TO DO: (mandatory)
1.592 + // Write to the appropriate hardware register to clear the digitiser interrupt
1.593 + //
1.594 +
1.595 + // TO DO: (mandatory)
1.596 + // Write to the appropriate hardware register(s) to allow the hardware
1.597 + // to detect when the digitizer panel is touched
1.598 + //
1.599 +
1.600 + return; // ... and exit!
1.601 + }
1.602 +
1.603 + Interrupt::Disable(KIntIdDigitiser); // do NOT disable the capability to generate interrupts at the source
1.604 +
1.605 + if (KPenDownDelayTime>0) // need to check this config param as it might be zero!
1.606 + iTimerInt.OneShot(KPenDownDelayTime); // start a debounce timer which will queue a DFC to process the interrupt
1.607 + else
1.608 + {
1.609 +
1.610 + // TO DO: (mandatory)
1.611 + // Write to the appropriate hardware register to clear the digitiser interrupt
1.612 + // This will re-trigger the interrupt mechanism to catch the next interrupt...
1.613 + //
1.614 +
1.615 + iTakeReadingDfc.Add();
1.616 + }
1.617 + }
1.618 +
1.619 +/**
1.620 +DPowerHandler pure virtual
1.621 +*/
1.622 +void DTemplateDigitiser::PowerUp()
1.623 + {
1.624 + iPowerUpDfc.Enque(); // queue a DFC in this driver's context
1.625 + }
1.626 +
1.627 +/**
1.628 +Called by power up DFC
1.629 +*/
1.630 +void DTemplateDigitiser::PowerUpDfc()
1.631 + {
1.632 + __KTRACE_OPT(KPOWER, Kern::Printf("DTemplateDigitiser::PowerUpDfc()"));
1.633 + DigitiserOn();
1.634 + PowerUpDone(); // must be called from a different thread than PowerUp()
1.635 + }
1.636 +
1.637 +/**
1.638 +Turn the digitiser on
1.639 +May be called as a result of a power transition or from the HAL
1.640 +If called from HAL, then the digitiser may be already be on (iPointerOn == ETrue)
1.641 +*/
1.642 +void DTemplateDigitiser::DigitiserOn()
1.643 + {
1.644 + __KTRACE_OPT(KPOWER,Kern::Printf("DTemplateDigitiser::DigitiserOn() iPointerOn=%d", iPointerOn));
1.645 +
1.646 + if (!iPointerOn) // may have been powered up already
1.647 + DigitiserPowerUp();
1.648 + }
1.649 +
1.650 +/**
1.651 +Power-up the digitiser. Assumes digitiser is off.
1.652 +*/
1.653 +void DTemplateDigitiser::DigitiserPowerUp()
1.654 + {
1.655 + __KTRACE_OPT(KPOWER, Kern::Printf("DigitiserPowerUp"));
1.656 + iPointerOn = ETrue; // now turned on
1.657 +
1.658 + // TO DO: (mandatory)
1.659 + // Write to the appropriate hardware register to clear the digitiser interrupt
1.660 + //
1.661 +
1.662 + //
1.663 + // TO DO: (optional)
1.664 + //
1.665 + // Reassert request on power resources
1.666 + // This will move the peripheral hardware out of low power "Sleep" mode back to fully operational
1.667 + // EXAMPLE ONLY
1.668 + //
1.669 + TemplateResourceManager* aManager = TTemplatePowerController::ResourceManager();
1.670 + aManager -> ModifyToLevel(TemplateResourceManager::AsynchMlResourceUsedByXOnly, 100 /* a percentage */);
1.671 + aManager -> SharedBResource1() -> Use();
1.672 +
1.673 + // TO DO: (mandatory)
1.674 + // Write to the appropriate hardware register(s) to allow the hardware
1.675 + // to detect when the digitizer panel is touched
1.676 + //
1.677 +
1.678 + iState = E_HW_PowerUp; // so we wait for pen up if necessary
1.679 + iTakeReadingDfc.Enque();
1.680 + }
1.681 +
1.682 +/**
1.683 +DPowerHandler pure virtual
1.684 +
1.685 +@param aPowerState the current power state
1.686 +*/
1.687 +void DTemplateDigitiser::PowerDown(TPowerState /*aPowerState*/)
1.688 + {
1.689 + iPoweringDown = ETrue;
1.690 + iPowerDownDfc.Enque(); // queue a DFC in this driver's context
1.691 + }
1.692 +
1.693 +/**
1.694 +Turn the digitiser off
1.695 +May be called as a result of a power transition or from the HAL
1.696 +If called from Power Manager, then the digitiser may be already be off (iPointerOn == EFalse)
1.697 +if the platform is in silent running mode
1.698 +*/
1.699 +void DTemplateDigitiser::DigitiserOff()
1.700 + {
1.701 + __KTRACE_OPT(KPOWER,Kern::Printf("DTemplateDigitiser::DigitiserOff() iPointerOn=%d", iPointerOn));
1.702 + if (iPointerOn) // can have been powered down from HAL
1.703 + {
1.704 + iPointerOn = EFalse;
1.705 + Interrupt::Disable(KIntIdDigitiser);
1.706 +
1.707 + // TO DO: (mandatory)
1.708 + // Write to the appropriate hardware register to disable the digitiser interrupt
1.709 + //
1.710 +
1.711 + iTimer.Cancel();
1.712 + iTimerInt.Cancel();
1.713 + iTakeReadingDfc.Cancel();
1.714 + if (iState != E_HW_CollectSample)
1.715 + {
1.716 + // Need to lock the kernel to simulate ISR context and thus defer preemption,
1.717 + // since PenUp() expects an ISR context and calls TDfc::Add().
1.718 + NKern::Lock();
1.719 + PenUp(); // adds DFC (will call WaitForPenDown)
1.720 + NKern::Unlock();
1.721 + }
1.722 + else
1.723 + {
1.724 +
1.725 + // TO DO: (mandatory)
1.726 + // Write to the appropriate hardware register(s) to allow the hardware
1.727 + // to detect when the digitizer panel is touched and wakes up the system if in standby
1.728 + //
1.729 +
1.730 + //
1.731 + // TO DO: (optional)
1.732 + //
1.733 + // Relinquish request on power resources as we are being powered down
1.734 + // This will place the peripheral hardware in a low power "Sleep" mode which is Interrupt detection capable
1.735 + // EXAMPLE ONLY
1.736 + //
1.737 + TemplateResourceManager* aManager = TTemplatePowerController::ResourceManager();
1.738 + aManager -> ModifyToLevel(TemplateResourceManager::AsynchMlResourceUsedByXOnly, 0 /* a percentage */);
1.739 + aManager -> SharedBResource1() -> Release();
1.740 +
1.741 + if (iPoweringDown) // came here through PowerDown
1.742 + {
1.743 + iPoweringDown = EFalse;
1.744 + PowerDownDone();
1.745 + }
1.746 + }
1.747 + }
1.748 + else // already powered down (by HAL)
1.749 + {
1.750 + if (iPoweringDown) // came here through PowerDown
1.751 + {
1.752 + iPoweringDown = EFalse;
1.753 + PowerDownDone();
1.754 + }
1.755 + }
1.756 + }
1.757 +
1.758 +
1.759 +
1.760 +
1.761 +/**
1.762 +Convert digitiser coordinates to screen coordinates
1.763 +
1.764 +@param aDigitiserPoint the digitiser coordinates
1.765 +@param aScreenPoint A TPoint supplied by the caller.
1.766 + On return, set to the converted screen coordinates in pixels.
1.767 +
1.768 +@return KErrNone if successful
1.769 +*/
1.770 +TInt DTemplateDigitiser::DigitiserToScreen(const TPoint& aDigitiserPoint, TPoint& aScreenPoint)
1.771 + {
1.772 + NKern::LockSystem();
1.773 + TInt R11 = iMachineConfig.iCalibration.iR11;
1.774 + TInt R12 = iMachineConfig.iCalibration.iR12;
1.775 + TInt R21 = iMachineConfig.iCalibration.iR21;
1.776 + TInt R22 = iMachineConfig.iCalibration.iR22;
1.777 + TInt TX = iMachineConfig.iCalibration.iTx;
1.778 + TInt TY = iMachineConfig.iCalibration.iTy;
1.779 + NKern::UnlockSystem();
1.780 + TInt X = aDigitiserPoint.iX;
1.781 + TInt Y = aDigitiserPoint.iY;
1.782 +
1.783 + aScreenPoint.iX = (X*R11 + Y*R21 + TX) >> 16;
1.784 + aScreenPoint.iY = (X*R12 + Y*R22 + TY) >> 16;
1.785 +
1.786 + __KTRACE_OPT(KHARDWARE,Kern::Printf("DtS: Dp.x %d, Dp.y %d, Sp.x %d, Sp.y %d", X,Y,aScreenPoint.iX,aScreenPoint.iY));
1.787 +
1.788 + return KErrNone;
1.789 + }
1.790 +
1.791 +/**
1.792 +Convert screen coordinates back into digitiser coordinates
1.793 +using the current constants from the superpage
1.794 +
1.795 +@param aX The screen X coordinate in pixels; On return, set to the digitiser X coordinate.
1.796 +@param aY The screen Y coordinate in pixels; On return, set to the digitiser Y coordinate.
1.797 +*/
1.798 +void DTemplateDigitiser::ScreenToDigitiser(TInt& aX, TInt& aY)
1.799 + {
1.800 + NKern::LockSystem();
1.801 + Int64 R11 = iMachineConfig.iCalibration.iR11;
1.802 + Int64 R12 = iMachineConfig.iCalibration.iR12;
1.803 + Int64 R21 = iMachineConfig.iCalibration.iR21;
1.804 + Int64 R22 = iMachineConfig.iCalibration.iR22;
1.805 + Int64 TX = iMachineConfig.iCalibration.iTx;
1.806 + Int64 TY = iMachineConfig.iCalibration.iTy;
1.807 + NKern::UnlockSystem();
1.808 + Int64 X = aX;
1.809 + Int64 Y = aY;
1.810 + //
1.811 + // Xd=(Xs<<16)*R22-(Ys<<16)*R21-(TX*R22)+(TY*R21)
1.812 + // -------------------------------------------
1.813 + // (R22*R11)-(R21*R12)
1.814 + //
1.815 + //
1.816 + // Yd=(Xs<<16)*R12-(Ys<<16)*R11-(TX*R12)+(TY*R11)
1.817 + // -------------------------------------------
1.818 + // (R21*R12)-(R22*R11)
1.819 + //
1.820 + // where Xd and Yd are digitiser coordinates
1.821 + // Xs and Ys are supplied screen coordinates
1.822 + //
1.823 + X<<=16;
1.824 + Y<<=16;
1.825 +
1.826 + Int64 d=Int64(R21)*Int64(R12)-Int64(R22)*Int64(R11);
1.827 +
1.828 + Int64 r=(X*R12)-(Y*R11)-(TX*R12)+(TY*R11);
1.829 +
1.830 + r=r/d;
1.831 +
1.832 + aY=(TInt)r;
1.833 +
1.834 + r=(X*R22)-(Y*R21)-(TX*R22)+(TY*R21);
1.835 +
1.836 + r=r/(-d);
1.837 +
1.838 + aX=(TInt)r;
1.839 + }
1.840 +
1.841 +/**
1.842 +Calculate values for R11, R12, R21, R22, TX and TY
1.843 +
1.844 +@param aCalibration the screen coordinates of points touched
1.845 +@return KErrNone if successful
1.846 +*/
1.847 +TInt DTemplateDigitiser::SetXYInputCalibration(const TDigitizerCalibration& aCalibration)
1.848 + {
1.849 + TInt R11,R12,R21,R22,TX,TY;
1.850 + //
1.851 + // Get coords of expected points
1.852 + //
1.853 + TDigitizerCalibration cal;
1.854 + TInt ret=CalibrationPoints(cal);
1.855 + if (ret!=KErrNone)
1.856 + return ret;
1.857 +
1.858 + TInt Xp1=cal.iTl.iX;
1.859 + TInt Yp1=cal.iTl.iY;
1.860 + TInt Xp2=cal.iBl.iX;
1.861 + TInt Yp2=cal.iBl.iY;
1.862 + TInt Xp3=cal.iBr.iX;
1.863 + TInt Yp3=cal.iBr.iY;
1.864 + //
1.865 + // Get coords of points touched in screen coordinates
1.866 + //
1.867 + TInt X1=aCalibration.iTl.iX;
1.868 + TInt Y1=aCalibration.iTl.iY;
1.869 + TInt X2=aCalibration.iBl.iX;
1.870 + TInt Y2=aCalibration.iBl.iY;
1.871 + TInt X3=aCalibration.iBr.iX;
1.872 + TInt Y3=aCalibration.iBr.iY;
1.873 + //
1.874 + // Convert back to raw digitiser coordinates
1.875 + //
1.876 + ScreenToDigitiser(X1,Y1);
1.877 + ScreenToDigitiser(X2,Y2);
1.878 + ScreenToDigitiser(X3,Y3);
1.879 + //
1.880 + // (Y1-Y2)(Xp1-Xp3) - (Y1-Y3)(Xp1-Xp2)
1.881 + // ----------------------------------- = R11
1.882 + // (Y1-Y2)(X1-X3) - (Y1-Y3)(X1-X2)
1.883 + //
1.884 + Int64 r=((Int64(Y1-Y2)*Int64(Xp1-Xp3))-(Int64(Y1-Y3)*Int64(Xp1-Xp2)));
1.885 + r<<=16;
1.886 + r/=(Int64(Y1-Y2)*Int64(X1-X3)-Int64(Y1-Y3)*Int64(X1-X2));
1.887 + R11=(TInt)r;
1.888 + //
1.889 + // (Y1-Y2)(Yp1-Yp3) - (Y1-Y3)(Yp1-Yp2)
1.890 + // ----------------------------------- = R12
1.891 + // (Y1-Y2)(X1-X3) - (Y1-Y3)(X1-X2)
1.892 + //
1.893 + r=((Int64(Y1-Y2)*Int64(Yp1-Yp3))-(Int64(Y1-Y3)*Int64(Yp1-Yp2)));
1.894 + r<<=16;
1.895 + r/=(Int64(Y1-Y2)*Int64(X1-X3)-Int64(Y1-Y3)*Int64(X1-X2));
1.896 + R12=(TInt)r;
1.897 + //
1.898 + // (X1-X3)(Xp2-Xp3) - (X2-X3)(Xp1-Xp3)
1.899 + // ----------------------------------- = R21
1.900 + // (Y2-Y3)(X1-X3) - (Y1-Y3)(X2-X3)
1.901 + //
1.902 + r=(((X1-X3)*(Xp2-Xp3))-((X2-X3)*(Xp1-Xp3)));
1.903 + r<<=16;
1.904 + r/=(Int64(Y2-Y3)*Int64(X1-X3)-Int64(Y1-Y3)*Int64(X2-X3));
1.905 + R21=(TInt)r;
1.906 + //
1.907 + // (X1-X3)(Yp2-Yp3) - (X2-X3)(Yp1-Yp3)
1.908 + // ----------------------------------- = R22
1.909 + // (Y2-Y3)(X1-X3) - (Y1-Y3)(X2-X3)
1.910 + //
1.911 + r=((Int64(X1-X3)*Int64(Yp2-Yp3))-(Int64(X2-X3)*Int64(Yp1-Yp3)));
1.912 + r<<=16;
1.913 + r/=(Int64(Y2-Y3)*Int64(X1-X3)-Int64(Y1-Y3)*Int64(X2-X3));
1.914 + R22=(TInt)r;
1.915 + //
1.916 + // TX = Xp1 - X1*R11 - Y1*R21
1.917 + //
1.918 + TX=(Xp1<<16)-(X1*R11)-(Y1*R21);
1.919 + //
1.920 + // TY = Yp1 - X1*R12 - Y1*R22
1.921 + //
1.922 + TY=(Yp1<<16)-(X1*R12)-(Y1*R22);
1.923 +
1.924 + //
1.925 + // Write new values into the superpage
1.926 + //
1.927 + NKern::LockSystem();
1.928 + iMachineConfig.iCalibration.iR11 = R11;
1.929 + iMachineConfig.iCalibration.iR12 = R12;
1.930 + iMachineConfig.iCalibration.iR21 = R21;
1.931 + iMachineConfig.iCalibration.iR22 = R22;
1.932 + iMachineConfig.iCalibration.iTx = TX;
1.933 + iMachineConfig.iCalibration.iTy = TY;
1.934 + NKern::UnlockSystem();
1.935 +
1.936 + return(KErrNone);
1.937 + }
1.938 +
1.939 +/**
1.940 +Informs the user-side calibration application where to draw
1.941 +the cross-hairs on the screen
1.942 +
1.943 +@param aCalibration On return contains the for points on the screen (in screen coordinates)
1.944 + where the cross-hairs should be drawn
1.945 +@return KErrNone if succcessful
1.946 +*/
1.947 +TInt DTemplateDigitiser::CalibrationPoints(TDigitizerCalibration& aCalibration)
1.948 + {
1.949 + TVideoInfoV01Buf buf;
1.950 + TVideoInfoV01& vidinfo=buf();
1.951 + TInt r = Kern::HalFunction(EHalGroupDisplay, EDisplayHalCurrentModeInfo, (TAny*)&buf, NULL);
1.952 + if (r!=KErrNone)
1.953 + return r;
1.954 + iScreenSize=vidinfo.iSizeInPixels;
1.955 +
1.956 + aCalibration.iBl.iX = aCalibration.iTl.iX = iScreenSize.iWidth/10;
1.957 + aCalibration.iTr.iY = aCalibration.iTl.iY = iScreenSize.iHeight/10;
1.958 + aCalibration.iBr.iY = aCalibration.iBl.iY = iScreenSize.iHeight-iScreenSize.iHeight/10;
1.959 + aCalibration.iTr.iX = aCalibration.iBr.iX = iScreenSize.iWidth-iScreenSize.iWidth/10;
1.960 + return r;
1.961 + }
1.962 +/**
1.963 +Saves the digitiser calibration to the persistent machine configuration area
1.964 +so that it can be restored after a power-down/up
1.965 +
1.966 +@return KErrNone if succcessful
1.967 +*/
1.968 +TInt DTemplateDigitiser::SaveXYInputCalibration()
1.969 + {
1.970 + NKern::LockSystem();
1.971 + iMachineConfig.iCalibrationSaved = iMachineConfig.iCalibration;
1.972 + NKern::UnlockSystem();
1.973 + return(KErrNone);
1.974 + }
1.975 +
1.976 +/**
1.977 +Restores the digitiser calibration from the persistent machine configuration area
1.978 +following a power-up
1.979 +
1.980 +@param aType indicates whether to restore factory or saved settings
1.981 +@return KErrNone if succcessful
1.982 +*/
1.983 +TInt DTemplateDigitiser::RestoreXYInputCalibration(TDigitizerCalibrationType aType)
1.984 + {
1.985 + TInt r=KErrNone;
1.986 + NKern::LockSystem();
1.987 + switch (aType)
1.988 + {
1.989 + case EFactory:
1.990 + iMachineConfig.iCalibration=iMachineConfig.iCalibrationFactory;
1.991 + break;
1.992 + case ESaved:
1.993 + iMachineConfig.iCalibration=iMachineConfig.iCalibrationSaved;
1.994 + break;
1.995 + default:
1.996 + r=KErrNotSupported;
1.997 + break;
1.998 + }
1.999 + NKern::UnlockSystem();
1.1000 + return r;
1.1001 + }
1.1002 +
1.1003 +/**
1.1004 +Gets the digitiser configuration information
1.1005 +
1.1006 +@param aInfo On return, contains information about the digitiser's dimensions etc.
1.1007 +*/
1.1008 +void DTemplateDigitiser::DigitiserInfo(TDigitiserInfoV01& aInfo)
1.1009 + {
1.1010 + __KTRACE_OPT(KEXTENSION,Kern::Printf("DTemplateDigitiser::DigitiserInfo"));
1.1011 + aInfo.iDigitiserSize.iWidth=KConfigXyWidth;
1.1012 + aInfo.iDigitiserSize.iHeight=KConfigXyHeight;
1.1013 + aInfo.iOffsetToDisplay.iX=KConfigXyOffsetX;
1.1014 + aInfo.iOffsetToDisplay.iY=KConfigXyOffsetY;
1.1015 + }
1.1016 +
1.1017 +/**
1.1018 +Issues a pen move event if the distance from the last point is greater than the threshold
1.1019 +
1.1020 +@param aPoint the pen position in screen coordinates
1.1021 +*/
1.1022 +void DTemplateDigitiser::FilterPenMove(const TPoint& aPoint)
1.1023 + {
1.1024 + TPoint offset=aPoint;
1.1025 + offset.iX-=iLastPos.iX;
1.1026 + offset.iY-=iLastPos.iY;
1.1027 + if (Abs(offset.iX)>=iCfg.iAccThresholdX || Abs(offset.iY)>=iCfg.iAccThresholdY)
1.1028 + {
1.1029 + iLastPos=aPoint;
1.1030 + IssuePenMoveEvent(aPoint);
1.1031 + }
1.1032 + }
1.1033 +
1.1034 +/**
1.1035 +Reset the pen move filter
1.1036 +*/
1.1037 +void DTemplateDigitiser::ResetPenMoveFilter()
1.1038 + {
1.1039 + }
1.1040 +