apply mwester patch for bug#1024 GSM modem re-registering problem
authorerin <erin@debian.tw.openmoko.com>
Tue, 7 Oct 2008 09:25:49 +0000 (17:25 +0800)
committererin <erin@debian.tw.openmoko.com>
Tue, 7 Oct 2008 09:25:49 +0000 (17:25 +0800)
devices/ficgta01/src/plugins/phonevendors/ficgta01/vendor_ficgta01.cpp
devices/ficgta01/src/plugins/phonevendors/ficgta01/vendor_ficgta01_p.h
src/libraries/qtopiaphonemodem/qmodemgprsnetworkregistration.cpp
src/libraries/qtopiaphonemodem/qmodemgprsnetworkregistration.h
src/libraries/qtopiaphonemodem/qmodemnetworkregistration.cpp
src/libraries/qtopiaphonemodem/qmodemnetworkregistration.h

index 2a2f5e2..63c2497 100644 (file)
@@ -462,6 +462,11 @@ Ficgta01ModemService::Ficgta01ModemService
 
     chat("AT+COPS=0");
 
+// Enable the work-around for the bouncy rubber calypso problem
+    csqTimer = new QTimer( this );
+    csqTimer->setSingleShot( true );
+    connect ( csqTimer, SIGNAL(timeout()), this, SLOT(csqTimeOut()) );
+
     // Setup the default text codec to UCS2 for none English langs
     chat( "AT+CSCS=\"UCS2\"" );
 
@@ -474,6 +479,7 @@ Ficgta01ModemService::Ficgta01ModemService
 
 Ficgta01ModemService::~Ficgta01ModemService()
 {
+    delete csqTimer;
 }
 
 void Ficgta01ModemService::initialize()
@@ -524,10 +530,34 @@ void Ficgta01ModemService::csq( const QString& msg )
     if ( msg.contains( QChar(',') ) ) {
         uint posn = 6;
         uint rssi = QAtUtils::parseNumber( msg, posn );
-        indicators()->setSignalQuality( (int)rssi, 31 );
+
+        // An rssi of "99" indicates invalid (i.e. loss of signal).
+        // We wish to be careful about reporting that, because the
+        // silly calypso will report that each and every time it
+        // changes cell sites, followed almost immediately by a new
+        // (valid) signal report.  So we defer reporting the invalid
+        // signal, and wait to see if we get an new one first.
+        qLog(AtChat)<< "percentCSQ event, rssi: " << (int)(rssi);
+        if ( rssi == 99 ) {
+            if ( !csqTimer->isActive() )
+               csqTimer->start( 8000 );  // 8 second one-shot timer
+        } else {
+            if ( csqTimer->isActive() ) {
+                csqTimer->stop();
+                indicators()->setSignalQuality( (int)rssi, 31 );
+            }
+        }
     }
 }
 
+void Ficgta01ModemService::csqTimeOut()
+{
+    // Timeout on a signal quality notification, it must have been real
+    qLog(AtChat)<< "percentCSQ timer expired; reporting loss";
+    indicators()->setSignalQuality( -1, 31 );
+}
+
+
 void Ficgta01ModemService::firstCsqQuery()
 {
     // Perform an initial AT%CSQ? which should cause the modem to
@@ -614,10 +644,16 @@ void Ficgta01ModemService::suspend()
     chat( "AT+CREG=0" );
     chat( "AT+CGREG=0" );
 
-    chat( "AT%CREG=0" );
-    chat( "AT%CGREG=0" );
+    // Don't need these, just clutter (nothing uses these
+    // proprietary commands yet -- MJW)
+    //chat( "AT%CREG=0" );
+    //chat( "AT%CGREG=0" );
 
     // Turn off cell broadcast location messages.
+
+    // Make sure the (useless) CIEV notifications are disabled too.
+    chat( "AT+CMER=0,0,0,0,0" );
+
     chat( "AT%CSQ=0", this, SLOT(sendSuspendDone()) );
 }
 
index 30f60c6..8fb9271 100644 (file)
@@ -128,6 +128,7 @@ public:
 
 private slots:
     void csq( const QString& msg );
+    void csqTimeOut();
     void firstCsqQuery();
 
     void ctzv( const QString& msg );
@@ -148,6 +149,7 @@ private:
 
     bool m_phoneBookIsReady;
     bool m_smsIsReady;
+    QTimer *csqTimer;
 };
 
 class  Ficgta01VibrateAccessory : public QVibrateAccessoryProvider
index b671937..979e5f7 100644 (file)
@@ -25,6 +25,8 @@
 #include <qatresult.h>
 #include <qatresultparser.h>
 #include <qatutils.h>
+#include <qtopialog.h>
+#include <qtimer.h>
 
 /*!
     \class QModemGprsNetworkRegistration
@@ -45,6 +47,7 @@ class QModemGprsNetworkRegistrationPrivate
 {
 public:
     QModemService *service;
+    QTimer *cgregTimer;
 };
 
 /*!
@@ -60,6 +63,12 @@ QModemGprsNetworkRegistration::QModemGprsNetworkRegistration
     service->primaryAtChat()->registerNotificationType
         ( "+CGREG:", this, SLOT(cgregNotify(QString)), true );
     connect( service, SIGNAL(resetModem()), this, SLOT(resetModem()) );
+
+    // Set up the one-shot timer that can be used to filter out outages
+    // (i.e. the "bouncy rubber calypso" problem with the Openmoko GTA01/GTA02)
+    d->cgregTimer = new QTimer( this );
+    d->cgregTimer->setSingleShot( true );
+    connect ( d->cgregTimer, SIGNAL(timeout ()), this, SLOT(cgregTimeOut()) );
 }
 
 /*!
@@ -105,12 +114,38 @@ void QModemGprsNetworkRegistration::cgregNotify( const QString& msg )
     uint stat = QAtUtils::parseNumber( msg, posn );
     QString lac = QAtUtils::nextString( msg, posn );
     QString ci = QAtUtils::nextString( msg, posn );
-    if ( !lac.isEmpty() && !ci.isEmpty() ) {
-        // We have location information after the state value.
-        updateRegistrationState( (QTelephony::RegistrationState)stat,
-                                 lac.toInt( 0, 16 ), ci.toInt( 0, 16 ) );
-    } else {
-        // We don't have any location information.
-        updateRegistrationState( (QTelephony::RegistrationState)stat );
-    }
+
+    // Don't be too hasty to call out a loss of network registration.
+    // Instead, start a one-shot timer -- and cancel the timer if
+    // if we get a positive registration before it expires.
+    if ( stat == 0 ) {
+        if ( !d->cgregTimer->isActive() ) {
+            d->cgregTimer->start( 10000 );  // 10 second one-shot timer
+            qLog(Modem) << "Started GPRS Loss-of-Registration timer.";
+       }
+     } else {
+        if ( d->cgregTimer->isActive() ) {
+            d->cgregTimer->stop();
+            qLog(Modem) << "Cancelled GPRS Loss-of-Registration timer.";
+       }
+        // If we have a positive registration here, go ahead and update
+        // the registration status.
+        if ( stat != 0 ) {
+            if ( !lac.isEmpty() && !ci.isEmpty() ) {
+                // We have location information after the state value.
+                updateRegistrationState( (QTelephony::RegistrationState)stat,
+                                          lac.toInt( 0, 16 ), ci.toInt( 0, 16 ) );
+            } else {
+                // We don't have any location information.
+                updateRegistrationState( (QTelephony::RegistrationState)stat );
+            }
+        }
+     }
+}
+
+void QModemGprsNetworkRegistration::cgregTimeOut()
+{
+    // Timeout on a de-register event; must have been legitimate; report it now.
+    qLog(Modem) << "GPRS Loss-of-Registration timer expired; reporting.";
+    updateRegistrationState( (QTelephony::RegistrationState)0 );
 }
index d92a488..4f81800 100644 (file)
@@ -40,6 +40,7 @@ private slots:
     void resetModem();
     void cgregQuery( bool ok, const QAtResult& result );
     void cgregNotify( const QString& msg );
+    void cgregTimeOut();
 
 private:
     QModemGprsNetworkRegistrationPrivate *d;
index 0524f98..0c9d7d4 100644 (file)
@@ -25,6 +25,9 @@
 #include <qatutils.h>
 #include <qatresult.h>
 #include <qatresultparser.h>
+#include <qtopialog.h>
+#include <qtimer.h>
+#include <qdatetime.h>
 
 /*!
     \class QModemNetworkRegistration
@@ -49,11 +52,44 @@ public:
         this->service = service;
         supportsOperatorTechnology = false;
         operatorId = -1;
+        currentLac = "";
+        currentCi = "";
+
+        nTotalLosses = 0;
+
+        nTotalBounces = 0;
+        tShortestBounceTime = 0;
+        tLongestBounceTime = 0;
+        tTotalBounceTime = 0;
+
+        nTotalUnsticks = 0;
+        tShortestStickTime = 0;
+        tLongestStickTime = 0;
+        tTotalStickTime = 0;
+
+        nTotalLacOperQueries = 0;
+        nTotalCiOperQueries = 0;
     }
 
     QModemService *service;
     bool supportsOperatorTechnology;
     int operatorId;
+    QString currentLac;
+    QString currentCi;
+    QTimer *cregTimer;
+    QTime lastTime;
+
+    int nTotalLosses;
+    int nTotalBounces;
+    int tShortestBounceTime;
+    int tLongestBounceTime;
+    int tTotalBounceTime;
+    int nTotalUnsticks;
+    int tShortestStickTime;
+    int tLongestStickTime;
+    int tTotalStickTime;
+    int nTotalLacOperQueries;
+    int nTotalCiOperQueries;
 };
 
 /*!
@@ -67,6 +103,13 @@ QModemNetworkRegistration::QModemNetworkRegistration( QModemService *service )
         ( "+CREG:", this, SLOT(cregNotify(QString)), true );
     service->connectToPost( "cfunDone", this, SLOT(cfunDone()) );
     connect( service, SIGNAL(resetModem()), this, SLOT(resetModem()) );
+
+    // Set up the one-shot timer that can be used to filter out outages
+    // (i.e. the "bouncy rubber calypso" problem with the Openmoko GTA01/GTA02)
+    d->cregTimer = new QTimer( this );
+    d->cregTimer->setSingleShot( true ); 
+    connect ( d->cregTimer, SIGNAL(timeout ()), this, SLOT(cregTimeOut()) );
+    d->lastTime.start();
 }
 
 /*!
@@ -171,18 +214,101 @@ void QModemNetworkRegistration::cregNotify( const QString& msg )
     uint stat = QAtUtils::parseNumber( msg, posn );
     QString lac = QAtUtils::nextString( msg, posn );
     QString ci = QAtUtils::nextString( msg, posn );
-    if ( !lac.isEmpty() && !ci.isEmpty() ) {
-        // We have location information after the state value.
-        updateRegistrationState( (QTelephony::RegistrationState)stat,
-                                 lac.toInt( 0, 16 ), ci.toInt( 0, 16 ) );
+
+    int t = d->lastTime.elapsed();
+    d->lastTime.restart();
+
+    // Don't be too hasty to call out a loss of network registration.
+    // Instead, start a one-shot timer -- and cancel the timer if
+    // if we get a positive registration before it expires.
+    if ( stat == 0 ) {
+
+        if ( !d->cregTimer->isActive() ) {
+            d->cregTimer->start( 9000 );  // 9 second one-shot timer
+            qLog(Modem) << "LoR -> Timer started. (ms=" << t << ")";
+
+            d->nTotalUnsticks++;
+            d->tTotalStickTime = d->tTotalStickTime + t;
+            if (t > d->tLongestStickTime)
+                d->tLongestStickTime = t;
+            if (t < d->tShortestStickTime || d->tShortestStickTime ==  0)
+                d->tShortestStickTime = t;
+        }
+
     } else {
-        // We don't have any location information.
-        updateRegistrationState( (QTelephony::RegistrationState)stat );
+
+        if ( d->cregTimer->isActive() ) {
+            d->cregTimer->stop();
+            qLog(Modem) << "LoR -> Timer cancelled. (ms=" << t << ")";
+
+            d->nTotalBounces++;
+            d->tTotalBounceTime = d->tTotalBounceTime + t;
+            if (t > d->tLongestBounceTime)
+                d->tLongestBounceTime = t;
+            if (t < d->tShortestBounceTime || d->tShortestBounceTime ==  0)
+                d->tShortestBounceTime = t;
+        }
+
+        // If we have a positive registration here, go ahead and update
+        // the registration status.
+
+        if ( stat != 0 ) {
+            if ( !lac.isEmpty() && !ci.isEmpty() ) {
+                // We have location information after the state value.
+                updateRegistrationState( (QTelephony::RegistrationState)stat,
+                                         lac.toInt( 0, 16 ), ci.toInt( 0, 16 ) );
+            } else {
+                // We don't have any location information.
+                updateRegistrationState( (QTelephony::RegistrationState)stat );
+            }
+        }
+
+        // Query for the operator name if home or roaming, and the lac or ci
+        // has actually changed.
+        if ( ( stat == 1 || stat == 5 ) &&
+             ( lac != d->currentLac ||
+               ci != d->currentCi ) ) {
+            queryCurrentOperator();
+
+            if ( lac != d->currentLac ) {
+                d->nTotalLacOperQueries++;
+                qLog(Modem) << "LoR -> Location changed; queryed operator.";
+            } else {
+                d->nTotalCiOperQueries++;
+                qLog(Modem) << "LoR -> Cell ID changed; queryed operator.";
+            }
+        }
+
+        // Save the new lac and ci values
+        d->currentLac = lac;
+        d->currentCi = ci;
+
+        // Log the statistics
+        qLog(Modem) <<
+            "LoR -> Lost reg:" << d->nTotalLosses <<
+            "Lac queries:" << d->nTotalLacOperQueries << 
+            "Ci queries:" << d->nTotalCiOperQueries;
+        qLog(Modem) <<
+            "LoR -> unsticks:" << d->nTotalUnsticks <<
+            "ms=(" << d->tShortestStickTime << "/" <<
+            (d->nTotalUnsticks ? (d->tTotalStickTime / d->nTotalUnsticks) : 0) <<
+            "/" << d->tLongestStickTime << ")";
+        qLog(Modem) << "LoR -> bounces:" << d->nTotalBounces <<
+            "ms=(" << d->tShortestBounceTime << "/" <<
+            (d->nTotalBounces ? (d->tTotalBounceTime / d->nTotalBounces) : 0) <<
+            "/" << d->tLongestBounceTime << ")";
     }
+}
 
-    // Query for the operator name if home or roaming.
-    if ( stat == 1 || stat == 5 )
-        queryCurrentOperator();
+void QModemNetworkRegistration::cregTimeOut()
+{
+    // Timeout on a de-register event; must have been legitimate; report it now.
+    d->currentLac = "";
+    d->currentCi = "";
+    qLog(Modem) << "LoR -> Timer expired (registration lost).";
+    d->nTotalLosses++;
+    updateRegistrationState( (QTelephony::RegistrationState)0 );
 }
 
 void QModemNetworkRegistration::cregQuery( bool, const QAtResult& result )
index dbf1d32..d7b92ee 100644 (file)
@@ -52,6 +52,7 @@ protected slots:
 
 private slots:
     void cregNotify( const QString& msg );
+    void cregTimeOut();
     void cregQuery( bool ok, const QAtResult& result );
     void copsDone( bool ok, const QAtResult& result );
     void copsNumericDone( bool ok, const QAtResult& result );