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\"" );
Ficgta01ModemService::~Ficgta01ModemService()
{
+ delete csqTimer;
}
void Ficgta01ModemService::initialize()
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
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()) );
}
#include <qatresult.h>
#include <qatresultparser.h>
#include <qatutils.h>
+#include <qtopialog.h>
+#include <qtimer.h>
/*!
\class QModemGprsNetworkRegistration
{
public:
QModemService *service;
+ QTimer *cgregTimer;
};
/*!
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()) );
}
/*!
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 );
}
#include <qatutils.h>
#include <qatresult.h>
#include <qatresultparser.h>
+#include <qtopialog.h>
+#include <qtimer.h>
+#include <qdatetime.h>
/*!
\class QModemNetworkRegistration
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;
};
/*!
( "+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();
}
/*!
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 )