sl@0: // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // template\Template_Variant\Specific\xyin.cpp sl@0: // Implementation of a digitiser (touch-screen) driver. sl@0: // This code assumes that an interrupt is generated on pen-down and pen-up events. sl@0: // This file is part of the Template Base port sl@0: // We use this driver to exemplify the usage of Resource Management for shared resources, Peripheral "Sleep" sl@0: // and detection and notification of Wakeup events sl@0: // sl@0: // sl@0: sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include "mconf.h" sl@0: #include sl@0: #include "template_power.h" sl@0: sl@0: sl@0: sl@0: sl@0: // sl@0: // TO DO: (mandatory) sl@0: // sl@0: // Define the following constants that describe the digitiser position & dimensions sl@0: // This is only example code... you need to modify it for your hardware sl@0: sl@0: // digitiser origin & size in pixels sl@0: const TUint KConfigXyOffsetX = 0; // digitiser origin - same as display area sl@0: const TUint KConfigXyOffsetY = 0; sl@0: const TUint KConfigXyWidth = 640; // 640 pixels per line sl@0: const TUint KConfigXyHeight = 480; // 480 lines per panel sl@0: sl@0: // digitiser dimensions in digitiser co-ordinates sl@0: const TInt KConfigXyBitsX = 12; sl@0: const TInt KConfigXyBitsY = 12; sl@0: const TInt KConfigXySpreadX = 1 << KConfigXyBitsX; // maximum valid X spread sl@0: const TInt KConfigXySpreadY = 1 << KConfigXyBitsY; // maximum valid Y spread sl@0: const TInt KConfigXyMinX = 0; // minimum valid X value sl@0: const TInt KConfigXyMinY = 0; // minimum valid Y value sl@0: const TInt KConfigXyMaxX = KConfigXySpreadX - 1; // maximum valid X value sl@0: const TInt KConfigXyMaxY = KConfigXySpreadY - 1; // maximum valid Y value sl@0: sl@0: sl@0: // Define a 2x2 matrix and two constants Tx and Ty to convert digitiser co-ordinates sl@0: // to pixels such that sl@0: // sl@0: // (X<<16 Y<<16) = (x y) x (R11 R12) + (Tx Ty) sl@0: // (R21 R22) sl@0: // or : sl@0: // sl@0: // X = (x*R11 + y*R21 + TX) >> 16; sl@0: // Y = (x*R12 + y*R22 + TY) >> 16; sl@0: sl@0: // sl@0: // where x,y are digitiser coordinates, Tx,Ty are constant offsets and X,Y are screen sl@0: // coordinates. Left shifting by 16 bits is used so as not to lose precision. sl@0: // sl@0: // These are default values to be used before calibration has taken place sl@0: // These are best set by observation. sl@0: // The example values given below are for a digitiser whose origin is at bottom left sl@0: // (the screen origin is at top left) sl@0: const TInt KConfigXyR11 = (KConfigXyWidth << 16) / KConfigXySpreadX; // 10240 sl@0: const TInt KConfigXyR12 = 0; sl@0: const TInt KConfigXyR21 = 0; sl@0: const TInt KConfigXyR22 = - ((KConfigXyHeight << 16) / KConfigXySpreadY); // -7680 sl@0: const TInt KConfigXyTx = 0; sl@0: const TInt KConfigXyTy = (KConfigXyHeight << 16) / KConfigXySpreadY; sl@0: sl@0: // sl@0: // TO DO: (optional) sl@0: // sl@0: // Define the following constants that describe the digitiser behaviour sl@0: // This is only example code... you need to modify it for your hardware sl@0: sl@0: // After taking a sample, wait for the specified number of nano-kernel ticks (normally 1 ms) sl@0: // before taking the next sample sl@0: const TInt KInterSampleTime = 1; sl@0: sl@0: // After a group of samples has been processed by the DDigitiser::ProcessRawSample() DFC, sl@0: // wait for the specified number of nano-kernel ticks before taking the next sample sl@0: const TInt KInterGroupTime = 1; sl@0: sl@0: // After a pen-down interrupt, sl@0: // wait for the specified number of nano-kernel ticks before taking the next sample sl@0: const TInt KPenDownDelayTime = 2; sl@0: sl@0: // If powering up the device with the pen down, sl@0: // wait for the specified number of nano-kernel ticks before taking the next sample sl@0: const TInt KPenUpPollTime = 30; sl@0: sl@0: // After a pen-up interrupt, sl@0: // wait for the specified number of nano-kernel ticks before calling PenUp() sl@0: const TInt KPenUpDebounceTime = 10; sl@0: sl@0: // number of samples to discard on pen-down sl@0: const TInt KConfigXyPenDownDiscard = 1; sl@0: sl@0: // number of samples to discard on pen-up sl@0: const TInt KConfigXyPenUpDiscard = 1; sl@0: sl@0: // offset in pixels to cause movement in X direction sl@0: const TInt KConfigXyAccThresholdX = 12; sl@0: sl@0: // offset in pixels to cause movement in Y direction sl@0: const TInt KConfigXyAccThresholdY = 12; sl@0: sl@0: // number of samples to average - MUST be <= KMaxXYSamples sl@0: const TInt KConfigXyNumXYSamples = 2; sl@0: sl@0: // disregard extremal values in each 4-sample group sl@0: const TBool KConfigXyDisregardMinMax= EFalse; sl@0: sl@0: sl@0: sl@0: // obsolete constants : sl@0: const TInt KConfigXyDriveXRise = 0; sl@0: const TInt KConfigXyDriveYRise = 0; sl@0: const TInt KConfigXyMaxJumpX = 0; sl@0: const TInt KConfigXyMaxJumpY = 0; sl@0: sl@0: sl@0: sl@0: /****************************************************** sl@0: * Main Digitiser Class sl@0: ******************************************************/ sl@0: sl@0: // sl@0: // TO DO: (optional) sl@0: // sl@0: // Add any private functions and data you require sl@0: // sl@0: NONSHARABLE_CLASS(DTemplateDigitiser) : public DDigitiser sl@0: { sl@0: public: sl@0: enum TState sl@0: { sl@0: E_HW_PowerUp, sl@0: E_HW_PenUpDebounce, sl@0: E_HW_CollectSample sl@0: }; sl@0: sl@0: public: sl@0: // from DDigitiser - initialisation sl@0: DTemplateDigitiser(); sl@0: virtual TInt DoCreate(); sl@0: void SetDefaultConfig(); sl@0: sl@0: // from DDigitiser - signals to hardware-dependent code sl@0: virtual void WaitForPenDown(); sl@0: virtual void WaitForPenUp(); sl@0: virtual void WaitForPenUpDebounce(); sl@0: virtual void DigitiserOn(); sl@0: virtual void DigitiserOff(); sl@0: virtual void FilterPenMove(const TPoint& aPoint); sl@0: virtual void ResetPenMoveFilter(); sl@0: sl@0: // from DDigitiser - machine-configuration related things sl@0: virtual TInt DigitiserToScreen(const TPoint& aDigitiserPoint, TPoint& aScreenPoint); sl@0: virtual void ScreenToDigitiser(TInt& aX, TInt& aY); sl@0: virtual TInt SetXYInputCalibration(const TDigitizerCalibration& aCalibration); sl@0: virtual TInt CalibrationPoints(TDigitizerCalibration& aCalibration); sl@0: virtual TInt SaveXYInputCalibration(); sl@0: virtual TInt RestoreXYInputCalibration(TDigitizerCalibrationType aType); sl@0: virtual void DigitiserInfo(TDigitiserInfoV01& aInfo); sl@0: sl@0: // from DPowerHandler sl@0: virtual void PowerDown(TPowerState); sl@0: virtual void PowerUp(); sl@0: sl@0: public: sl@0: // implementation sl@0: void TakeSample(); sl@0: void PenInterrupt(); sl@0: void DigitiserPowerUp(); sl@0: void PowerUpDfc(); sl@0: sl@0: public: sl@0: NTimer iTimer; sl@0: NTimer iTimerInt; sl@0: TDfc iTakeReadingDfc; sl@0: TDfc iPowerDownDfc; sl@0: TDfc iPowerUpDfc; sl@0: TInt iSamplesCount; sl@0: TState iState; sl@0: TUint8 iPoweringDown; sl@0: sl@0: TSize iScreenSize; sl@0: TActualMachineConfig& iMachineConfig; sl@0: }; sl@0: sl@0: /****************************************************** sl@0: * Digitiser main code sl@0: ******************************************************/ sl@0: /** sl@0: Sample timer callback sl@0: Schedules a DFC to take a sample sl@0: sl@0: @param aPtr a pointer to DTemplateDigitiser sl@0: */ sl@0: LOCAL_C void timerExpired(TAny* aPtr) sl@0: { sl@0: DTemplateDigitiser* pD=(DTemplateDigitiser*)aPtr; sl@0: __KTRACE_OPT(KHARDWARE,Kern::Printf("T")); sl@0: pD->iTakeReadingDfc.Add(); sl@0: } sl@0: sl@0: /** sl@0: Debounce timer callback sl@0: schedules a DFC to process a pen-down interrupt sl@0: sl@0: @param aPtr a pointer to DTemplateDigitiser sl@0: */ sl@0: LOCAL_C void timerIntExpired(TAny* aPtr) sl@0: { sl@0: DTemplateDigitiser* pD=(DTemplateDigitiser*)aPtr; sl@0: __KTRACE_OPT(KHARDWARE,Kern::Printf("TI")); sl@0: // clear xy interrupt -> re-triggers the interrupt mechanism to catch the next IRQ sl@0: sl@0: // TO DO: (mandatory) sl@0: // Write to the appropriate hardware register to clear the digitiser interrupt sl@0: // sl@0: sl@0: pD->iTakeReadingDfc.Add(); sl@0: } sl@0: sl@0: /** sl@0: Pen-up/down interrupt handler sl@0: sl@0: @param aPtr a pointer to DTemplateDigitiser sl@0: */ sl@0: LOCAL_C void penInterrupt(TAny* aPtr) sl@0: { sl@0: DTemplateDigitiser* pD=(DTemplateDigitiser*)aPtr; sl@0: pD->PenInterrupt(); sl@0: } sl@0: sl@0: /** sl@0: DFC for taking a sample sl@0: sl@0: @param aPtr a pointer to DTemplateDigitiser sl@0: */ sl@0: LOCAL_C void takeReading(TAny* aPtr) sl@0: { sl@0: DTemplateDigitiser* pD=(DTemplateDigitiser*)aPtr; sl@0: pD->TakeSample(); sl@0: } sl@0: sl@0: /** sl@0: DFC for powering down the device sl@0: sl@0: @param aPtr a pointer to DTemplateDigitiser sl@0: */ sl@0: LOCAL_C void powerDownDfc(TAny* aPtr) sl@0: { sl@0: DTemplateDigitiser* pD=(DTemplateDigitiser*)aPtr; sl@0: pD->DigitiserOff(); sl@0: } sl@0: sl@0: /** sl@0: DFC for powering up the device sl@0: sl@0: @param aPtr a pointer to DTemplateDigitiser sl@0: */ sl@0: LOCAL_C void powerUpDfc(TAny* aPtr) sl@0: { sl@0: DTemplateDigitiser* pD=(DTemplateDigitiser*)aPtr; sl@0: pD->PowerUpDfc(); sl@0: } sl@0: sl@0: /** sl@0: Creates a new instance of DDigitiser. sl@0: Called by extension entry point (PIL) to create a DDigitiser-derived object. sl@0: sl@0: @return a pointer to a DTemplateDigitiser object sl@0: */ sl@0: DDigitiser* DDigitiser::New() sl@0: { sl@0: return new DTemplateDigitiser; sl@0: } sl@0: sl@0: /** sl@0: Default constructor sl@0: */ sl@0: DTemplateDigitiser::DTemplateDigitiser() : sl@0: iTimer(timerExpired,this), sl@0: iTimerInt(timerIntExpired,this), sl@0: iTakeReadingDfc(takeReading,this,5), sl@0: iPowerDownDfc(powerDownDfc,this,5), sl@0: iPowerUpDfc(powerUpDfc,this,5), sl@0: iMachineConfig(TheActualMachineConfig()) sl@0: { sl@0: iDfcQ = Kern::DfcQue0(); sl@0: iTakeReadingDfc.SetDfcQ(iDfcQ); sl@0: iPowerDownDfc.SetDfcQ(iDfcQ); sl@0: iPowerUpDfc.SetDfcQ(iDfcQ); sl@0: } sl@0: sl@0: /** sl@0: Perform hardware-dependent initialisation sl@0: sl@0: Called by platform independent layer sl@0: */ sl@0: TInt DTemplateDigitiser::DoCreate() sl@0: { sl@0: __KTRACE_OPT(KEXTENSION,Kern::Printf("DTemplateDigitiser::DoCreate")); sl@0: sl@0: if (Kern::ColdStart()) sl@0: { sl@0: __KTRACE_OPT(KEXTENSION,Kern::Printf("Resetting digitiser calibration")); sl@0: sl@0: // Emergency digitiser calibration values sl@0: iMachineConfig.iCalibration.iR11 = KConfigXyR11; sl@0: iMachineConfig.iCalibration.iR12 = KConfigXyR12; sl@0: iMachineConfig.iCalibration.iR21 = KConfigXyR21; sl@0: iMachineConfig.iCalibration.iR22 = KConfigXyR22; sl@0: iMachineConfig.iCalibration.iTx = KConfigXyTx; sl@0: iMachineConfig.iCalibration.iTy = KConfigXyTy; sl@0: } sl@0: sl@0: // register power handler sl@0: Add(); sl@0: DigitiserPowerUp(); sl@0: sl@0: // bind to the pen-up/down interrupt sl@0: TInt r=Interrupt::Bind(KIntIdDigitiser, penInterrupt, this); sl@0: if (r!=KErrNone) sl@0: return r; sl@0: sl@0: // set up the default configuration sl@0: SetDefaultConfig(); sl@0: sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: Initialise the DDigitiser::iCfg structure sl@0: */ sl@0: void DTemplateDigitiser::SetDefaultConfig() sl@0: { sl@0: iCfg.iPenDownDiscard = KConfigXyPenDownDiscard; // number of samples to discard on pen-down sl@0: iCfg.iPenUpDiscard = KConfigXyPenUpDiscard; // number of samples to discard on pen-up sl@0: iCfg.iDriveXRise = KConfigXyDriveXRise; // number of milliseconds to wait when driving horizontal edges sl@0: iCfg.iDriveYRise = KConfigXyDriveYRise; // number of milliseconds to wait when driving vertical edges sl@0: iCfg.iMinX = KConfigXyMinX; // minimum valid X value sl@0: iCfg.iMaxX = KConfigXyMaxX; // maximum valid X value sl@0: iCfg.iSpreadX = KConfigXySpreadX; // maximum valid X spread sl@0: iCfg.iMinY = KConfigXyMinY; // minimum valid Y value sl@0: iCfg.iMaxY = KConfigXyMaxY; // maximum valid Y value sl@0: iCfg.iSpreadY = KConfigXySpreadY; // maximum valid Y spread sl@0: iCfg.iMaxJumpX = KConfigXyMaxJumpX; // maximum X movement per sample (pixels) sl@0: iCfg.iMaxJumpY = KConfigXyMaxJumpY; // maximum Y movement per sample (pixels) sl@0: iCfg.iAccThresholdX = KConfigXyAccThresholdX; // offset in pixels to cause movement in X direction sl@0: iCfg.iAccThresholdY = KConfigXyAccThresholdY; // offset in pixels to cause movement in Y direction sl@0: iCfg.iNumXYSamples = KConfigXyNumXYSamples; // number of samples to average sl@0: iCfg.iDisregardMinMax = KConfigXyDisregardMinMax; // disregard extremal values in each 4-sample group sl@0: } sl@0: sl@0: /** sl@0: Takes a sample from the digitiser. sl@0: Called in the context of a DFC thread. sl@0: */ sl@0: void DTemplateDigitiser::TakeSample() sl@0: { sl@0: TTemplatePowerController::WakeupEvent(); // notify of pendown (wakeup event) and let the power controller sort sl@0: // out if it needs propagation sl@0: sl@0: TBool penDown = EFalse; sl@0: sl@0: // TO DO: (mandatory) sl@0: // Read from appropriate hardware register to determine whether digitiser panel is being touched sl@0: // Set penDown to ETrue if touched or EFalse if not touched. sl@0: // sl@0: sl@0: __KTRACE_OPT(KHARDWARE,Kern::Printf("TS: S%d PD%d Sp%d", (TInt)iState, penDown?1:0, iSamplesCount)); sl@0: sl@0: if (iState==E_HW_PowerUp) sl@0: { sl@0: // waiting for pen to go up after switch on due to pen down or through the HAL sl@0: // coverity[dead_error_condition] sl@0: // The next line should be reachable when this template file is edited for use sl@0: if (!penDown) // pen has gone up -> transition to new state sl@0: { sl@0: iState=E_HW_CollectSample; sl@0: iSamplesCount=0; // reset sample buffer sl@0: sl@0: // TO DO: (mandatory) sl@0: // Write to the appropriate hardware register to clear the digitiser interrupt sl@0: // sl@0: sl@0: // TO DO: (mandatory) sl@0: // Write to the appropriate hardware register(s) to allow the hardware sl@0: // to detect when the digitizer panel is touched sl@0: // sl@0: sl@0: Interrupt::Enable(KIntIdDigitiser); // enable pen-down interrupt sl@0: sl@0: // TO DO: (mandatory) sl@0: // Write to the appropriate hardware register to enable the digitiser interrupt sl@0: // sl@0: sl@0: } sl@0: else // pen is still down, wait a bit longer in this state sl@0: { sl@0: iTimer.OneShot(KPenUpPollTime); sl@0: } sl@0: return; sl@0: } sl@0: sl@0: if (!penDown) sl@0: { sl@0: if (iState==E_HW_PenUpDebounce) sl@0: { sl@0: iState=E_HW_CollectSample; // back to initial state, no samples collected sl@0: iSamplesCount=0; // reset sample buffer sl@0: // Need to lock the kernel to simulate ISR context and thus defer preemption, sl@0: // since PenUp() expects an ISR context and calls TDfc::Add(). sl@0: NKern::Lock(); sl@0: PenUp(); // adds DFC sl@0: NKern::Unlock(); sl@0: } sl@0: else // iState=E_HW_CollectSample sl@0: { sl@0: iState=E_HW_PenUpDebounce; sl@0: iTimer.OneShot(KPenUpDebounceTime); // wait a bit to make sure pen still up sl@0: } sl@0: return; sl@0: } sl@0: else if (iState==E_HW_PenUpDebounce) // pen down sl@0: { sl@0: // false alarm - pen is down again sl@0: iState=E_HW_CollectSample; // take a new set of samples sl@0: iSamplesCount=0; // reset sample buffer sl@0: } sl@0: // default: pen down and iState=E_HW_CollectSample sl@0: sl@0: // TO DO: (mandatory) sl@0: // Read from appropriate hardware register to get the current digitiser coordinates sl@0: // of the point that is being touched. Set aResults accordingly. sl@0: // This is only example code... you need to modify it for your hardware sl@0: // sl@0: TPoint aResults; sl@0: sl@0: // X axis sl@0: iX[iSamplesCount] = aResults.iX; sl@0: // Y axis sl@0: iY[iSamplesCount] = aResults.iY; sl@0: sl@0: __KTRACE_OPT(KHARDWARE,Kern::Printf("Raw: X=%d Y=%d",iX[iSamplesCount],iY[iSamplesCount])); sl@0: sl@0: // Put the hardware back into pen-detect mode sl@0: sl@0: // TO DO: (mandatory) sl@0: // Write to the appropriate hardware register(s) to allow the hardware sl@0: // to detect when the digitizer panel is touched sl@0: // sl@0: sl@0: // count samples collected - if it's less than minimum, sl@0: // schedule the reading of another sample sl@0: if (++iSamplesCount < iCfg.iNumXYSamples) // iX[] and iY[] are 4 levels deep in xyin.h... sl@0: { sl@0: if(KInterSampleTime > 0) // need to check this config param as it might be zero! sl@0: iTimer.OneShot(KInterSampleTime); // haven't got a complete group yet, so queue timer to sample again sl@0: else sl@0: iTakeReadingDfc.Enque(); sl@0: return; sl@0: } sl@0: sl@0: // Have a complete group of samples so pass up to processing layer (PIL) sl@0: sl@0: // Need to lock the kernel to simulate ISR context and thus defer preemption, sl@0: // since RawSampleValid() expects an ISR context and calls TDfc::Add(). sl@0: NKern::Lock(); sl@0: RawSampleValid(); // adds DFC sl@0: NKern::Unlock(); sl@0: } sl@0: sl@0: /** sl@0: Request for an interrupt to be generated when the pen is next down sl@0: Called by PIL at startup or when pen leaves digitiser after pen-up event issued sl@0: */ sl@0: void DTemplateDigitiser::WaitForPenDown() sl@0: { sl@0: // Called at startup or when pen leaves digitiser after pen-up event issued sl@0: __KTRACE_OPT(KHARDWARE,Kern::Printf("WD: PowerDownMask %x",iPoweringDown)); sl@0: if (iPoweringDown) sl@0: { sl@0: // powering down sl@0: sl@0: // TO DO: (mandatory) sl@0: // Write to the appropriate hardware register(s) to allow the hardware sl@0: // to detect when the digitizer panel is touched and wakes up the system if in standby sl@0: // sl@0: sl@0: // sl@0: // TO DO: (optional) sl@0: // sl@0: // Relinquish request on power resources sl@0: // This will place the peripheral hardware in a low power "Sleep" mode which is Interrupt detection capable sl@0: // EXAMPLE ONLY sl@0: // sl@0: TemplateResourceManager* aManager = TTemplatePowerController::ResourceManager(); sl@0: aManager -> ModifyToLevel(TemplateResourceManager::AsynchMlResourceUsedByXOnly, 50 /* a percentage */); sl@0: aManager -> SharedBResource1() -> Release(); sl@0: sl@0: iPoweringDown = EFalse; sl@0: PowerDownDone(); sl@0: } sl@0: else sl@0: { sl@0: sl@0: // TO DO: (mandatory) sl@0: // Write to the appropriate hardware register to clear the digitiser interrupt sl@0: // sl@0: sl@0: // TO DO: (mandatory) sl@0: // Write to the appropriate hardware register(s) to allow the hardware sl@0: // to detect when the digitizer panel is touched sl@0: // sl@0: sl@0: if ((iTimer.iState == NTimer::EIdle) && (iTimerInt.iState == NTimer::EIdle)) sl@0: Interrupt::Enable(KIntIdDigitiser); // enable pen-down interrupt sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Called by PIL after it has processed a group of raw samples while pen is down. sl@0: Used to indicate that the iX, iY buffers may be re-used sl@0: */ sl@0: void DTemplateDigitiser::WaitForPenUp() sl@0: { sl@0: __KTRACE_OPT(KHARDWARE,Kern::Printf("WU")); sl@0: iState = E_HW_CollectSample; sl@0: iSamplesCount = 0; // reset sample buffer sl@0: if(KInterGroupTime > 0) // need to check this config param as it might be zero! sl@0: iTimer.OneShot(KInterGroupTime); sl@0: else sl@0: iTakeReadingDfc.Enque(); sl@0: } sl@0: sl@0: /** sl@0: Called by PIL if the group of samples collected is not good enough sl@0: Used to indicate that the iX, iY buffers may be re-used sl@0: */ sl@0: void DTemplateDigitiser::WaitForPenUpDebounce() sl@0: { sl@0: __KTRACE_OPT(KHARDWARE,Kern::Printf("WUDB")); sl@0: iState = E_HW_CollectSample; sl@0: iSamplesCount = 0; // reset sample buffer sl@0: if(KInterGroupTime > 0) // need to check this config param as it might be zero! sl@0: iTimer.OneShot(KInterGroupTime); sl@0: else sl@0: iTakeReadingDfc.Enque(); sl@0: } sl@0: sl@0: /** sl@0: Pen up/down interrupt service routine (ISR) sl@0: */ sl@0: void DTemplateDigitiser::PenInterrupt() sl@0: { sl@0: __KTRACE_OPT(KHARDWARE,Kern::Printf("I")); sl@0: sl@0: sl@0: Interrupt::Clear(KIntIdDigitiser); // should already have been cleared sl@0: sl@0: // TO DO: (mandatory) sl@0: // Read from appropriate hardware register to determine whether digitiser panel is being touched sl@0: // Set penDown to ETrue if touched or EFalse if not touched. sl@0: // This is only example code... you need to modify it for your hardware sl@0: TBool penDown = EFalse; sl@0: sl@0: // coverity[dead_error_condition] sl@0: if(!penDown) // pen up sl@0: { sl@0: sl@0: // TO DO: (mandatory) sl@0: // Write to the appropriate hardware register to clear the digitiser interrupt sl@0: // sl@0: sl@0: // TO DO: (mandatory) sl@0: // Write to the appropriate hardware register(s) to allow the hardware sl@0: // to detect when the digitizer panel is touched sl@0: // sl@0: sl@0: return; // ... and exit! sl@0: } sl@0: sl@0: Interrupt::Disable(KIntIdDigitiser); // do NOT disable the capability to generate interrupts at the source sl@0: sl@0: if (KPenDownDelayTime>0) // need to check this config param as it might be zero! sl@0: iTimerInt.OneShot(KPenDownDelayTime); // start a debounce timer which will queue a DFC to process the interrupt sl@0: else sl@0: { sl@0: sl@0: // TO DO: (mandatory) sl@0: // Write to the appropriate hardware register to clear the digitiser interrupt sl@0: // This will re-trigger the interrupt mechanism to catch the next interrupt... sl@0: // sl@0: sl@0: iTakeReadingDfc.Add(); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: DPowerHandler pure virtual sl@0: */ sl@0: void DTemplateDigitiser::PowerUp() sl@0: { sl@0: iPowerUpDfc.Enque(); // queue a DFC in this driver's context sl@0: } sl@0: sl@0: /** sl@0: Called by power up DFC sl@0: */ sl@0: void DTemplateDigitiser::PowerUpDfc() sl@0: { sl@0: __KTRACE_OPT(KPOWER, Kern::Printf("DTemplateDigitiser::PowerUpDfc()")); sl@0: DigitiserOn(); sl@0: PowerUpDone(); // must be called from a different thread than PowerUp() sl@0: } sl@0: sl@0: /** sl@0: Turn the digitiser on sl@0: May be called as a result of a power transition or from the HAL sl@0: If called from HAL, then the digitiser may be already be on (iPointerOn == ETrue) sl@0: */ sl@0: void DTemplateDigitiser::DigitiserOn() sl@0: { sl@0: __KTRACE_OPT(KPOWER,Kern::Printf("DTemplateDigitiser::DigitiserOn() iPointerOn=%d", iPointerOn)); sl@0: sl@0: if (!iPointerOn) // may have been powered up already sl@0: DigitiserPowerUp(); sl@0: } sl@0: sl@0: /** sl@0: Power-up the digitiser. Assumes digitiser is off. sl@0: */ sl@0: void DTemplateDigitiser::DigitiserPowerUp() sl@0: { sl@0: __KTRACE_OPT(KPOWER, Kern::Printf("DigitiserPowerUp")); sl@0: iPointerOn = ETrue; // now turned on sl@0: sl@0: // TO DO: (mandatory) sl@0: // Write to the appropriate hardware register to clear the digitiser interrupt sl@0: // sl@0: sl@0: // sl@0: // TO DO: (optional) sl@0: // sl@0: // Reassert request on power resources sl@0: // This will move the peripheral hardware out of low power "Sleep" mode back to fully operational sl@0: // EXAMPLE ONLY sl@0: // sl@0: TemplateResourceManager* aManager = TTemplatePowerController::ResourceManager(); sl@0: aManager -> ModifyToLevel(TemplateResourceManager::AsynchMlResourceUsedByXOnly, 100 /* a percentage */); sl@0: aManager -> SharedBResource1() -> Use(); sl@0: sl@0: // TO DO: (mandatory) sl@0: // Write to the appropriate hardware register(s) to allow the hardware sl@0: // to detect when the digitizer panel is touched sl@0: // sl@0: sl@0: iState = E_HW_PowerUp; // so we wait for pen up if necessary sl@0: iTakeReadingDfc.Enque(); sl@0: } sl@0: sl@0: /** sl@0: DPowerHandler pure virtual sl@0: sl@0: @param aPowerState the current power state sl@0: */ sl@0: void DTemplateDigitiser::PowerDown(TPowerState /*aPowerState*/) sl@0: { sl@0: iPoweringDown = ETrue; sl@0: iPowerDownDfc.Enque(); // queue a DFC in this driver's context sl@0: } sl@0: sl@0: /** sl@0: Turn the digitiser off sl@0: May be called as a result of a power transition or from the HAL sl@0: If called from Power Manager, then the digitiser may be already be off (iPointerOn == EFalse) sl@0: if the platform is in silent running mode sl@0: */ sl@0: void DTemplateDigitiser::DigitiserOff() sl@0: { sl@0: __KTRACE_OPT(KPOWER,Kern::Printf("DTemplateDigitiser::DigitiserOff() iPointerOn=%d", iPointerOn)); sl@0: if (iPointerOn) // can have been powered down from HAL sl@0: { sl@0: iPointerOn = EFalse; sl@0: Interrupt::Disable(KIntIdDigitiser); sl@0: sl@0: // TO DO: (mandatory) sl@0: // Write to the appropriate hardware register to disable the digitiser interrupt sl@0: // sl@0: sl@0: iTimer.Cancel(); sl@0: iTimerInt.Cancel(); sl@0: iTakeReadingDfc.Cancel(); sl@0: if (iState != E_HW_CollectSample) sl@0: { sl@0: // Need to lock the kernel to simulate ISR context and thus defer preemption, sl@0: // since PenUp() expects an ISR context and calls TDfc::Add(). sl@0: NKern::Lock(); sl@0: PenUp(); // adds DFC (will call WaitForPenDown) sl@0: NKern::Unlock(); sl@0: } sl@0: else sl@0: { sl@0: sl@0: // TO DO: (mandatory) sl@0: // Write to the appropriate hardware register(s) to allow the hardware sl@0: // to detect when the digitizer panel is touched and wakes up the system if in standby sl@0: // sl@0: sl@0: // sl@0: // TO DO: (optional) sl@0: // sl@0: // Relinquish request on power resources as we are being powered down sl@0: // This will place the peripheral hardware in a low power "Sleep" mode which is Interrupt detection capable sl@0: // EXAMPLE ONLY sl@0: // sl@0: TemplateResourceManager* aManager = TTemplatePowerController::ResourceManager(); sl@0: aManager -> ModifyToLevel(TemplateResourceManager::AsynchMlResourceUsedByXOnly, 0 /* a percentage */); sl@0: aManager -> SharedBResource1() -> Release(); sl@0: sl@0: if (iPoweringDown) // came here through PowerDown sl@0: { sl@0: iPoweringDown = EFalse; sl@0: PowerDownDone(); sl@0: } sl@0: } sl@0: } sl@0: else // already powered down (by HAL) sl@0: { sl@0: if (iPoweringDown) // came here through PowerDown sl@0: { sl@0: iPoweringDown = EFalse; sl@0: PowerDownDone(); sl@0: } sl@0: } sl@0: } sl@0: sl@0: sl@0: sl@0: sl@0: /** sl@0: Convert digitiser coordinates to screen coordinates sl@0: sl@0: @param aDigitiserPoint the digitiser coordinates sl@0: @param aScreenPoint A TPoint supplied by the caller. sl@0: On return, set to the converted screen coordinates in pixels. sl@0: sl@0: @return KErrNone if successful sl@0: */ sl@0: TInt DTemplateDigitiser::DigitiserToScreen(const TPoint& aDigitiserPoint, TPoint& aScreenPoint) sl@0: { sl@0: NKern::LockSystem(); sl@0: TInt R11 = iMachineConfig.iCalibration.iR11; sl@0: TInt R12 = iMachineConfig.iCalibration.iR12; sl@0: TInt R21 = iMachineConfig.iCalibration.iR21; sl@0: TInt R22 = iMachineConfig.iCalibration.iR22; sl@0: TInt TX = iMachineConfig.iCalibration.iTx; sl@0: TInt TY = iMachineConfig.iCalibration.iTy; sl@0: NKern::UnlockSystem(); sl@0: TInt X = aDigitiserPoint.iX; sl@0: TInt Y = aDigitiserPoint.iY; sl@0: sl@0: aScreenPoint.iX = (X*R11 + Y*R21 + TX) >> 16; sl@0: aScreenPoint.iY = (X*R12 + Y*R22 + TY) >> 16; sl@0: sl@0: __KTRACE_OPT(KHARDWARE,Kern::Printf("DtS: Dp.x %d, Dp.y %d, Sp.x %d, Sp.y %d", X,Y,aScreenPoint.iX,aScreenPoint.iY)); sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Convert screen coordinates back into digitiser coordinates sl@0: using the current constants from the superpage sl@0: sl@0: @param aX The screen X coordinate in pixels; On return, set to the digitiser X coordinate. sl@0: @param aY The screen Y coordinate in pixels; On return, set to the digitiser Y coordinate. sl@0: */ sl@0: void DTemplateDigitiser::ScreenToDigitiser(TInt& aX, TInt& aY) sl@0: { sl@0: NKern::LockSystem(); sl@0: Int64 R11 = iMachineConfig.iCalibration.iR11; sl@0: Int64 R12 = iMachineConfig.iCalibration.iR12; sl@0: Int64 R21 = iMachineConfig.iCalibration.iR21; sl@0: Int64 R22 = iMachineConfig.iCalibration.iR22; sl@0: Int64 TX = iMachineConfig.iCalibration.iTx; sl@0: Int64 TY = iMachineConfig.iCalibration.iTy; sl@0: NKern::UnlockSystem(); sl@0: Int64 X = aX; sl@0: Int64 Y = aY; sl@0: // sl@0: // Xd=(Xs<<16)*R22-(Ys<<16)*R21-(TX*R22)+(TY*R21) sl@0: // ------------------------------------------- sl@0: // (R22*R11)-(R21*R12) sl@0: // sl@0: // sl@0: // Yd=(Xs<<16)*R12-(Ys<<16)*R11-(TX*R12)+(TY*R11) sl@0: // ------------------------------------------- sl@0: // (R21*R12)-(R22*R11) sl@0: // sl@0: // where Xd and Yd are digitiser coordinates sl@0: // Xs and Ys are supplied screen coordinates sl@0: // sl@0: X<<=16; sl@0: Y<<=16; sl@0: sl@0: Int64 d=Int64(R21)*Int64(R12)-Int64(R22)*Int64(R11); sl@0: sl@0: Int64 r=(X*R12)-(Y*R11)-(TX*R12)+(TY*R11); sl@0: sl@0: r=r/d; sl@0: sl@0: aY=(TInt)r; sl@0: sl@0: r=(X*R22)-(Y*R21)-(TX*R22)+(TY*R21); sl@0: sl@0: r=r/(-d); sl@0: sl@0: aX=(TInt)r; sl@0: } sl@0: sl@0: /** sl@0: Calculate values for R11, R12, R21, R22, TX and TY sl@0: sl@0: @param aCalibration the screen coordinates of points touched sl@0: @return KErrNone if successful sl@0: */ sl@0: TInt DTemplateDigitiser::SetXYInputCalibration(const TDigitizerCalibration& aCalibration) sl@0: { sl@0: TInt R11,R12,R21,R22,TX,TY; sl@0: // sl@0: // Get coords of expected points sl@0: // sl@0: TDigitizerCalibration cal; sl@0: TInt ret=CalibrationPoints(cal); sl@0: if (ret!=KErrNone) sl@0: return ret; sl@0: sl@0: TInt Xp1=cal.iTl.iX; sl@0: TInt Yp1=cal.iTl.iY; sl@0: TInt Xp2=cal.iBl.iX; sl@0: TInt Yp2=cal.iBl.iY; sl@0: TInt Xp3=cal.iBr.iX; sl@0: TInt Yp3=cal.iBr.iY; sl@0: // sl@0: // Get coords of points touched in screen coordinates sl@0: // sl@0: TInt X1=aCalibration.iTl.iX; sl@0: TInt Y1=aCalibration.iTl.iY; sl@0: TInt X2=aCalibration.iBl.iX; sl@0: TInt Y2=aCalibration.iBl.iY; sl@0: TInt X3=aCalibration.iBr.iX; sl@0: TInt Y3=aCalibration.iBr.iY; sl@0: // sl@0: // Convert back to raw digitiser coordinates sl@0: // sl@0: ScreenToDigitiser(X1,Y1); sl@0: ScreenToDigitiser(X2,Y2); sl@0: ScreenToDigitiser(X3,Y3); sl@0: // sl@0: // (Y1-Y2)(Xp1-Xp3) - (Y1-Y3)(Xp1-Xp2) sl@0: // ----------------------------------- = R11 sl@0: // (Y1-Y2)(X1-X3) - (Y1-Y3)(X1-X2) sl@0: // sl@0: Int64 r=((Int64(Y1-Y2)*Int64(Xp1-Xp3))-(Int64(Y1-Y3)*Int64(Xp1-Xp2))); sl@0: r<<=16; sl@0: r/=(Int64(Y1-Y2)*Int64(X1-X3)-Int64(Y1-Y3)*Int64(X1-X2)); sl@0: R11=(TInt)r; sl@0: // sl@0: // (Y1-Y2)(Yp1-Yp3) - (Y1-Y3)(Yp1-Yp2) sl@0: // ----------------------------------- = R12 sl@0: // (Y1-Y2)(X1-X3) - (Y1-Y3)(X1-X2) sl@0: // sl@0: r=((Int64(Y1-Y2)*Int64(Yp1-Yp3))-(Int64(Y1-Y3)*Int64(Yp1-Yp2))); sl@0: r<<=16; sl@0: r/=(Int64(Y1-Y2)*Int64(X1-X3)-Int64(Y1-Y3)*Int64(X1-X2)); sl@0: R12=(TInt)r; sl@0: // sl@0: // (X1-X3)(Xp2-Xp3) - (X2-X3)(Xp1-Xp3) sl@0: // ----------------------------------- = R21 sl@0: // (Y2-Y3)(X1-X3) - (Y1-Y3)(X2-X3) sl@0: // sl@0: r=(((X1-X3)*(Xp2-Xp3))-((X2-X3)*(Xp1-Xp3))); sl@0: r<<=16; sl@0: r/=(Int64(Y2-Y3)*Int64(X1-X3)-Int64(Y1-Y3)*Int64(X2-X3)); sl@0: R21=(TInt)r; sl@0: // sl@0: // (X1-X3)(Yp2-Yp3) - (X2-X3)(Yp1-Yp3) sl@0: // ----------------------------------- = R22 sl@0: // (Y2-Y3)(X1-X3) - (Y1-Y3)(X2-X3) sl@0: // sl@0: r=((Int64(X1-X3)*Int64(Yp2-Yp3))-(Int64(X2-X3)*Int64(Yp1-Yp3))); sl@0: r<<=16; sl@0: r/=(Int64(Y2-Y3)*Int64(X1-X3)-Int64(Y1-Y3)*Int64(X2-X3)); sl@0: R22=(TInt)r; sl@0: // sl@0: // TX = Xp1 - X1*R11 - Y1*R21 sl@0: // sl@0: TX=(Xp1<<16)-(X1*R11)-(Y1*R21); sl@0: // sl@0: // TY = Yp1 - X1*R12 - Y1*R22 sl@0: // sl@0: TY=(Yp1<<16)-(X1*R12)-(Y1*R22); sl@0: sl@0: // sl@0: // Write new values into the superpage sl@0: // sl@0: NKern::LockSystem(); sl@0: iMachineConfig.iCalibration.iR11 = R11; sl@0: iMachineConfig.iCalibration.iR12 = R12; sl@0: iMachineConfig.iCalibration.iR21 = R21; sl@0: iMachineConfig.iCalibration.iR22 = R22; sl@0: iMachineConfig.iCalibration.iTx = TX; sl@0: iMachineConfig.iCalibration.iTy = TY; sl@0: NKern::UnlockSystem(); sl@0: sl@0: return(KErrNone); sl@0: } sl@0: sl@0: /** sl@0: Informs the user-side calibration application where to draw sl@0: the cross-hairs on the screen sl@0: sl@0: @param aCalibration On return contains the for points on the screen (in screen coordinates) sl@0: where the cross-hairs should be drawn sl@0: @return KErrNone if succcessful sl@0: */ sl@0: TInt DTemplateDigitiser::CalibrationPoints(TDigitizerCalibration& aCalibration) sl@0: { sl@0: TVideoInfoV01Buf buf; sl@0: TVideoInfoV01& vidinfo=buf(); sl@0: TInt r = Kern::HalFunction(EHalGroupDisplay, EDisplayHalCurrentModeInfo, (TAny*)&buf, NULL); sl@0: if (r!=KErrNone) sl@0: return r; sl@0: iScreenSize=vidinfo.iSizeInPixels; sl@0: sl@0: aCalibration.iBl.iX = aCalibration.iTl.iX = iScreenSize.iWidth/10; sl@0: aCalibration.iTr.iY = aCalibration.iTl.iY = iScreenSize.iHeight/10; sl@0: aCalibration.iBr.iY = aCalibration.iBl.iY = iScreenSize.iHeight-iScreenSize.iHeight/10; sl@0: aCalibration.iTr.iX = aCalibration.iBr.iX = iScreenSize.iWidth-iScreenSize.iWidth/10; sl@0: return r; sl@0: } sl@0: /** sl@0: Saves the digitiser calibration to the persistent machine configuration area sl@0: so that it can be restored after a power-down/up sl@0: sl@0: @return KErrNone if succcessful sl@0: */ sl@0: TInt DTemplateDigitiser::SaveXYInputCalibration() sl@0: { sl@0: NKern::LockSystem(); sl@0: iMachineConfig.iCalibrationSaved = iMachineConfig.iCalibration; sl@0: NKern::UnlockSystem(); sl@0: return(KErrNone); sl@0: } sl@0: sl@0: /** sl@0: Restores the digitiser calibration from the persistent machine configuration area sl@0: following a power-up sl@0: sl@0: @param aType indicates whether to restore factory or saved settings sl@0: @return KErrNone if succcessful sl@0: */ sl@0: TInt DTemplateDigitiser::RestoreXYInputCalibration(TDigitizerCalibrationType aType) sl@0: { sl@0: TInt r=KErrNone; sl@0: NKern::LockSystem(); sl@0: switch (aType) sl@0: { sl@0: case EFactory: sl@0: iMachineConfig.iCalibration=iMachineConfig.iCalibrationFactory; sl@0: break; sl@0: case ESaved: sl@0: iMachineConfig.iCalibration=iMachineConfig.iCalibrationSaved; sl@0: break; sl@0: default: sl@0: r=KErrNotSupported; sl@0: break; sl@0: } sl@0: NKern::UnlockSystem(); sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: Gets the digitiser configuration information sl@0: sl@0: @param aInfo On return, contains information about the digitiser's dimensions etc. sl@0: */ sl@0: void DTemplateDigitiser::DigitiserInfo(TDigitiserInfoV01& aInfo) sl@0: { sl@0: __KTRACE_OPT(KEXTENSION,Kern::Printf("DTemplateDigitiser::DigitiserInfo")); sl@0: aInfo.iDigitiserSize.iWidth=KConfigXyWidth; sl@0: aInfo.iDigitiserSize.iHeight=KConfigXyHeight; sl@0: aInfo.iOffsetToDisplay.iX=KConfigXyOffsetX; sl@0: aInfo.iOffsetToDisplay.iY=KConfigXyOffsetY; sl@0: } sl@0: sl@0: /** sl@0: Issues a pen move event if the distance from the last point is greater than the threshold sl@0: sl@0: @param aPoint the pen position in screen coordinates sl@0: */ sl@0: void DTemplateDigitiser::FilterPenMove(const TPoint& aPoint) sl@0: { sl@0: TPoint offset=aPoint; sl@0: offset.iX-=iLastPos.iX; sl@0: offset.iY-=iLastPos.iY; sl@0: if (Abs(offset.iX)>=iCfg.iAccThresholdX || Abs(offset.iY)>=iCfg.iAccThresholdY) sl@0: { sl@0: iLastPos=aPoint; sl@0: IssuePenMoveEvent(aPoint); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Reset the pen move filter sl@0: */ sl@0: void DTemplateDigitiser::ResetPenMoveFilter() sl@0: { sl@0: } sl@0: