examples/Qt/sensorgesture/CoverGesture/coverrecognizer.cpp

00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
00004 ** All rights reserved.
00005 ** Contact: Nokia Corporation
00006 **
00007 **
00008 ** $QT_BEGIN_LICENSE:BSD$
00009 ** You may use this file under the terms of the BSD license as follows:
00010 **
00011 ** "Redistribution and use in source and binary forms, with or without
00012 ** modification, are permitted provided that the following conditions are
00013 ** met:
00014 **   * Redistributions of source code must retain the above copyright
00015 **     notice, this list of conditions and the following disclaimer.
00016 **   * Redistributions in binary form must reproduce the above copyright
00017 **     notice, this list of conditions and the following disclaimer in
00018 **     the documentation and/or other materials provided with the
00019 **     distribution.
00020 **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
00021 **     the names of its contributors may be used to endorse or promote
00022 **     products derived from this software without specific prior written
00023 **     permission.
00024 **
00025 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00026 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00027 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00028 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00029 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00030 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00031 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00032 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00033 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00034 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00035 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
00036 ** $QT_END_LICENSE$
00037 **
00038 ****************************************************************************/
00039 // User includes
00040 #include "coverrecognizer.h"
00041 
00042 // Constants
00043 // We would prefer accelerometer running at 2g range. 
00044 const qreal idealRange = 19.62;
00045 // Default z value for moving average filter
00046 const qreal movingAverageDefaultZ = 10.0/movingAverageSamples;
00047 // Minimum time the phone should be covered and lying flat, face up and still before the
00048 // recognized signal is emmited. Time in ms.
00049 const uint minimumCoverTimeMS = 500;
00050 
00051 
00052 // Namespace needed to use Qt Mobility APIs
00053 // (defined in qmobilityglobal.h but implicitly included from any Qt Mobility header)
00054 QTM_USE_NAMESPACE
00055 
00060 CoverRecognizer::CoverRecognizer()
00061 {
00062     mAccSensor = new QAccelerometer();
00063     // Call the filter_accelerometer() function when new accelerometet data is ready.
00064     connect(mAccSensor, SIGNAL(readingChanged()), this, SLOT(filter_accelerometer()));
00065     
00066     mProxSensor = new QProximitySensor();
00067     // Call the filter_proximity() function when new proximity data is ready.
00068     connect(mProxSensor, SIGNAL(readingChanged()), this, SLOT(filter_proximity()));
00069     
00070     mElapsedTimer = new QElapsedTimer();
00071     
00072     // Initialize moving average filter data index to 0.
00073     mMovingAverageIndex = 0;    
00074 }
00075 
00079 CoverRecognizer::~CoverRecognizer()
00080 {
00081     delete mAccSensor;
00082     delete mProxSensor;
00083     delete mElapsedTimer;
00084 }
00085 
00090 bool CoverRecognizer::start()
00091 {
00092     // Test if accelerometer is functional, by starting it.
00093     bool result = mAccSensor->start();
00094     // If accelerometer is functional we can continue start up of gesture detection.
00095     if (result) {
00096         // Stop accelerometer again, since it is not needed yet.
00097         mAccSensor->stop();
00098         // Find the closest available accelerometer range to 2g.
00099         qoutputrangelist outputRangeList = mAccSensor->outputRanges();
00100         int numOfItems = outputRangeList.count();
00101         if (0 < numOfItems) {
00102             qreal rangeDiff = qAbs(outputRangeList.first().maximum - idealRange);
00103             int selectedIndex(0);
00104             for (int i(1); i < numOfItems; ++i) {
00105                 if (qAbs(outputRangeList.at(i).maximum - idealRange) < rangeDiff) {
00106                     // This is closer to 2g range than the previously checked one.
00107                     selectedIndex = i;
00108                     rangeDiff = qAbs(outputRangeList.at(i).maximum - idealRange);
00109                 }
00110             }
00111             // Now we have the index to the range closest to 2g.
00112             mAccSensor->setOutputRange(selectedIndex);
00113         }
00114         
00115         // Start proximity sensor in order to start detecting gesture. result will now 
00116         // only be true if both accelerometer and proximity sensors are able to start.
00117         result &= mProxSensor->start();
00118     }
00119    
00120     return result;
00121 }
00122 
00126 void CoverRecognizer::stop()
00127 {   
00128     mAccSensor->stop();
00129     mProxSensor->stop();
00130 }
00131 
00135 void CoverRecognizer::filter_accelerometer()
00136 {
00137     QAccelerometerReading *accReading = mAccSensor->reading();
00138     if(mElapsedTimer->isValid())
00139     {
00140         // Moving average filter is used to smooth out outliers that can occur for
00141         // example when a hand hits the phone in order to cover it.
00142         mXValues[mMovingAverageIndex] = accReading->x()/movingAverageSamples;
00143         mYValues[mMovingAverageIndex] = accReading->y()/movingAverageSamples;
00144         mZValues[mMovingAverageIndex] = accReading->z()/movingAverageSamples;
00145         if(++mMovingAverageIndex >= movingAverageSamples)
00146         {
00147             mMovingAverageIndex = 0;
00148         }
00149         qreal xAvg = 0.0;
00150         qreal yAvg = 0.0;
00151         qreal zAvg = 0.0;
00152         for (int i = 0; i < movingAverageSamples; i++)
00153         {
00154             xAvg += mXValues[i];
00155             yAvg += mYValues[i];
00156             zAvg += mZValues[i];
00157         }
00158         
00159         // Test for accepted accelerometer values. Values are tested within a margin
00160         // to compensate for the phone being placed on surfaces that are not accurately 
00161         // perpendicular to the earths center of gravity (and accelerometer
00162         // inaccuracies).
00163         if(qAbs(xAvg) < 2 && qAbs(yAvg) < 2 && zAvg < 12 && zAvg > 7)
00164         {
00165             // Accelerometer values are within accepted range. Check if they have been
00166             // so for at least the minimum required amount of time.
00167             
00168             if(mElapsedTimer->elapsed() >= minimumCoverTimeMS)
00169             {
00170                 // The phone has been covered and lying flat, face up and still for the
00171                 // required minimum amount of time. Emit signal to user that cover
00172                 // gesture has occured.
00173                 emitSignal();
00174                 // Stop accelerometer sensor and timer. Note that proximity sensor is
00175                 // still running, so if user uncovers and covers phone again it will be
00176                 // detected.
00177                 mAccSensor->stop();
00178                 mElapsedTimer->invalidate();
00179             }
00180         }
00181         else
00182         {
00183             // Accelerometer values outside accepted range. The phone is not lying flat,
00184             // face up and still. Restart timer.
00185             mElapsedTimer->restart();
00186         }
00187     } else {
00188         // Do nothing.
00189         // Accelerometer is started and stopped during start() call. In case we get any
00190         // accelerometer data during that time we end up here.
00191     }
00192 }
00193 
00197 void CoverRecognizer::filter_proximity()
00198 {
00199     if (mProxSensor->reading()->close()) {
00200         // Phone is covered.
00201         // Reset moving average filter sample values to prevent old data from influencing
00202         // gesture detection.
00203         for (int i = 0; i < movingAverageSamples; i++)
00204         {
00205             mXValues[i] = 0.0;
00206             mYValues[i] = 0.0;
00207             mZValues[i] = movingAverageDefaultZ;
00208         }
00209         // Start accelerometer and timer to check if the phone is lying flat, face up and
00210         // still for the minimum required amount of time.
00211         mAccSensor->start();
00212         mElapsedTimer->start();
00213     } else {
00214         // Phone is no longer covered.
00215         // Stop accelerometer and timer since they are no longer needed.               
00216         mAccSensor->stop();
00217         mElapsedTimer->invalidate();
00218     }
00219        
00220 }
00221 
00225 void CoverRecognizer::emitSignal()
00226 {
00227     emit recognized(coverGestureType, QVariantHash()); 
00228 }

Generated by  doxygen 1.6.2