1 /****************************************************************************
3 ** Copyright (C) 2000-2008 TROLLTECH ASA. All rights reserved.
5 ** This file is part of the Opensource Edition of the Qtopia Toolkit.
7 ** This software is licensed under the terms of the GNU General Public
8 ** License (GPL) version 2.
10 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
12 ** Contact info@trolltech.com if any conditions of this licensing are
17 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
18 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 ****************************************************************************/
22 #include "vendor_ficgta01_p.h"
23 #include <qmodemindicators.h>
25 #include <qatresultparser.h>
31 #include <QTextStream>
34 #include <qmodemcallvolume.h>
35 #include <qmodemsiminfo.h>
37 static bool supportsStk = false;
39 #define DEFAULT_CHARSET QLatin1String("UCS2")
41 Ficgta01CallProvider::Ficgta01CallProvider( QModemService *service )
42 : QModemCallProvider( service )
44 service->primaryAtChat()->registerNotificationType
45 ( "%CPI:", this, SLOT(cpiNotification(QString)) );
46 service->primaryAtChat()->registerNotificationType
47 ( "%CNAP:", this, SLOT(cnapNotification(QString)) );
49 setUseMissedTimer(false);
50 setUseDetectTimer(false);
51 setTreatAcceptCommandFailedAsMissed(false);
54 Ficgta01CallProvider::~Ficgta01CallProvider()
58 QModemCallProvider::AtdBehavior Ficgta01CallProvider::atdBehavior() const
60 // When ATD reports OK or NO CARRIER, it indicates that it is
61 // back in command mode. We just want to ignore these in QModemCall
62 // as we will have %CPI that is going to give us the right state.
66 void Ficgta01CallProvider::abortDial( uint id, QPhoneCall::Scope scope )
68 // Use the ATH command to abort outgoing calls, instead of AT+CHLD=1.
69 //atchat()->chat( "ATH" );
71 // Use default behaviour of CR followed by AT+CHLD - seems to work better.
72 QModemCallProvider::abortDial( id, scope );
75 void Ficgta01CallProvider::cpiNotification( const QString& msg )
77 // Call progress notification for the FICGTA01 device.
78 // %CPI: <cId>,<msgType>,<ibt>,<tch>,[<dir>],[<mode>][,<number>,<type>[,<alpha>]]
79 // where <cId> is the call identifier, and <msgType> is one of:
80 // 0 = SETUP, 1 = DISCONNECT, 2 = ALERT, 3 = PROCEED,
81 // 4 = SYNCHRONIZATION, 5 = PROGRESS, 6 = CONNECTED,
82 // 7 = RELEASE, 8 = REJECT
83 // dir: 0 = mobile originated, 1 = mobile terminated, 2 = network initiaited mobile
84 // originated call, 3 = redialing mobile originated
86 uint identifier = QAtUtils::parseNumber( msg, posn );
88 uint status = QAtUtils::parseNumber( msg, posn );
89 QAtUtils::skipField( msg, posn );
90 QAtUtils::skipField( msg, posn );
91 uint direction = QAtUtils::parseNumber( msg, posn );
92 QModemCall *call = callForIdentifier( identifier );
94 if ( status == 6 && call &&
95 ( call->state() == QPhoneCall::Dialing ||
96 call->state() == QPhoneCall::Alerting ) ) {
98 // This is an indication that a "Dialing" connection
99 // is now in the "Connected" state.
100 call->setConnected();
102 } else if ( ( status == 1 || status == 7 ) && call &&
103 ( call->state() == QPhoneCall::Dialing ||
104 call->state() == QPhoneCall::Alerting ) ) {
106 // We never managed to connect.
107 hangupRemote( call );
109 } else if ( status == 2 && call &&
110 call->state() == QPhoneCall::Dialing ) {
112 // Call is moving from Dialing to Alerting.
113 call->setState( QPhoneCall::Alerting );
115 } else if ( ( status == 1 || status == 7 ) && call &&
116 ( call->state() == QPhoneCall::Connected ||
117 call->state() == QPhoneCall::Hold ) ) {
119 // This is an indication that the connection has been lost.
120 hangupRemote( call );
122 } else if ( ( status == 1 || status == 7 ) && call &&
123 call->state() == QPhoneCall::Incoming ) {
125 // This is an indication that an incoming call was missed.
126 call->setState( QPhoneCall::Missed );
128 } else if ( ( status == 2 || status == 4 || status == 0) && !call && direction == 1) {
130 // This is a newly waiting call. Treat it the same as "RING".
131 uint mode = QAtUtils::parseNumber( msg, posn );
133 if ( mode == 1 || mode == 6 || mode == 7 )
134 callType = "Data"; // No tr
135 else if ( mode == 2 || mode == 8 )
136 callType = "Fax"; // No tr
138 callType = "Voice"; // No tr
139 QString number = QAtUtils::nextString( msg, posn );
140 uint type = QAtUtils::parseNumber( msg, posn );
141 ringing( QAtUtils::decodeNumber( number, type ), callType, identifier );
143 // We got everything we need, indicate the call to the outside world
148 void Ficgta01CallProvider::cnapNotification( const QString& msg )
150 // Calling name presentation from the network.
152 QAtUtils::skipField( msg, posn ); // pres_mode
153 QAtUtils::skipField( msg, posn ); // dcs
154 QAtUtils::skipField( msg, posn ); // name_length
155 QString name = QAtUtils::nextString( msg, posn );
156 QModemCall *call = incomingCall();
158 call->emitNotification( QPhoneCall::CallingName, name );
162 * Reimplementation because we don't want the standard notifications
163 * as we have a CPI which should give us everything that we need.
165 * +CRING (CPI gives us the calltype)
166 * +CLIP (CPI gives us the number)
169 void Ficgta01CallProvider::resetModem()
171 // disable all of these and do not call the base class
172 atchat()->chat( "AT+CRC=0" );
173 service()->retryChat( "AT+CLIP=0" );
174 service()->retryChat( "AT+COLP=0" );
176 // enable callwaiting support
177 service()->retryChat( "AT+CCWA=1" );
180 // We need to set GSM as codec for that to work on the TI Calypso see
181 // https://docs.openmoko.org/trac/ticket/2038 for more information
182 QString Ficgta01CallProvider::dialServiceCommand(const QDialOptions& options) const
184 QTextCodec* codec = QAtUtils::codec(DEFAULT_CHARSET);
185 QString cmd = QString::fromLatin1("AT+CUSD=1,%1,15");
186 return cmd.arg(QAtUtils::quote(options.number(), codec));
189 // Use the enable the echo suppression for TI Calypso before dialing
190 QString Ficgta01CallProvider::dialVoiceCommand(const QDialOptions& options) const
192 Ficgta01ModemService::echoCancellation(atchat());
193 return QModemCallProvider::dialVoiceCommand(options);
196 // Use the enable the echo suppression for TI Calypso before accepting calls
197 QString Ficgta01CallProvider::acceptCallCommand( bool otherActiveCalls ) const
199 Ficgta01ModemService::echoCancellation(atchat());
200 return QModemCallProvider::acceptCallCommand(otherActiveCalls);
203 Ficgta01PhoneBook::Ficgta01PhoneBook( QModemService *service )
204 : QModemPhoneBook( service )
205 , m_phoneBookWasReady(false)
207 qLog(AtChat)<<"Ficgta01PhoneBook::Ficgta01PhoneBook";
208 connect(this, SIGNAL(queryFailed(const QString&)),
209 SLOT(slotQueryFailed(const QString&)));
212 Ficgta01PhoneBook::~Ficgta01PhoneBook()
216 bool Ficgta01PhoneBook::hasModemPhoneBookCache() const
221 bool Ficgta01PhoneBook::hasEmptyPhoneBookIndex() const
226 void Ficgta01PhoneBook::sendPhoneBooksReady()
228 m_phoneBookWasReady = true;
232 void Ficgta01PhoneBook::slotQueryFailed(const QString& book)
234 // We didn't say we are ready, ignore this
235 if (!m_phoneBookWasReady)
238 qLog(Modem) << "Phonebook query failed, ask to retry. " << book;
242 Ficgta01PinManager::Ficgta01PinManager( QModemService *service )
243 : QModemPinManager( service )
247 Ficgta01PinManager::~Ficgta01PinManager()
251 bool Ficgta01PinManager::emptyPinIsReady() const
257 // Known bands, by mask.
264 static BandInfo const bandInfo[] = {
269 /* {"GSM 850", 16}, */
270 {"Tripleband 900/1800/1900", 15},
272 #define numBands ((int)(sizeof(bandInfo) / sizeof(BandInfo)))
274 Ficgta01BandSelection::Ficgta01BandSelection( QModemService *service )
275 : QBandSelection( service->service(), service, Server )
277 this->service = service;
280 Ficgta01BandSelection::~Ficgta01BandSelection()
284 void Ficgta01BandSelection::requestBand()
286 service->primaryAtChat()->chat
287 ( "AT%BAND?", this, SLOT(bandQuery(bool,QAtResult)) );
290 void Ficgta01BandSelection::requestBands()
293 for ( int index = 0; index < numBands; ++index ) {
294 list += QString( bandInfo[index].name );
298 // service->primaryAtChat()->chat
299 // ( "AT%BAND=?", this, SLOT(bandList(bool,QAtResult)) );
302 void Ficgta01BandSelection::setBand( QBandSelection::BandMode mode, const QString& value )
304 if ( mode == Automatic ) {
305 service->primaryAtChat()->chat
306 ( "AT%BAND=0", this, SLOT(bandSet(bool,QAtResult)) );
309 QStringList names = value.split(", ");
310 foreach ( QString name, names ) {
312 for ( int index = 0; index < numBands; ++index ) {
313 if ( name == bandInfo[index].name ) {
314 bandValue |= bandInfo[index].value;
320 // The band name is not valid.
321 emit setBandResult( QTelephony::OperationNotSupported );
326 // No band names supplied.
327 emit setBandResult( QTelephony::OperationNotSupported );
330 service->primaryAtChat()->chat
331 ( "AT%BAND=1," + QString::number( bandValue ),
332 this, SLOT(bandSet(bool,QAtResult)) );
336 // Convert a band value into a name. Returns an empty list if unknown.
337 static QStringList bandValueToName( int bandValue )
340 for ( int index = 0; index < numBands; ++index ) {
341 if ( ( bandValue & bandInfo[index].value ) == bandInfo[index].value ) {
342 bandValue &= ~bandInfo[index].value;
343 bands += QString( bandInfo[index].name );
349 void Ficgta01BandSelection::bandQuery( bool, const QAtResult& result )
352 QAtResultParser parser( result );
354 qLog(AtChat)<<"bandQuery";
355 if ( parser.next( "%BAND:" ) ) {
356 bandValue = (int)parser.readNumeric();
358 // Command did not work, so assume "Auto".
361 for ( int index = 0; index < numBands; ++index ) {
362 if ( bandValue == bandInfo[index].value ) {
363 emit band( Manual, bandInfo[index].name );
367 emit band( Automatic, QString() );
371 // QAtResultParser parser( result );
373 // qLog(AtChat)<<"bandQuery";
374 // if ( parser.next( "%BAND:" ) ) {
375 // if ( parser.readNumeric() != 0 ) {
376 // bandValue = (int)parser.readNumeric();
377 // QStringList bands = bandValueToName( bandValue );
378 // if ( bands.size() > 0 ) {
379 // emit band( Manual, bands.join(", ") );
386 // emit band( Automatic, QString() );
390 void Ficgta01BandSelection::bandList( bool, const QAtResult& result )
392 QAtResultParser parser( result );
393 QStringList bandNames;
394 if ( parser.next( "%BAND:" ) ) {
396 parser.readList(); // Skip list of supported modes.
397 QList<QAtResultParser::Node> list = parser.readList();
398 foreach ( QAtResultParser::Node node, list ) {
400 if ( node.isNumber() ) {
401 bandNames += bandValueToName( (int)node.asNumber() );
402 qLog(AtChat)<< (int)node.asNumber();
403 } else if ( node.isRange() ) {
404 int first = (int)node.asFirst();
405 int last = (int)node.asLast();
406 qLog(AtChat)<<"isRange"<<first<<last;
407 while ( first <= last ) {
408 qLog(AtChat)<< bandValueToName( first ) << first;
409 bandNames += bandValueToName( first ).join(" | ");
415 emit bands( bandNames );
418 void Ficgta01BandSelection::bandSet( bool, const QAtResult& result )
420 emit setBandResult( (QTelephony::Result)result.resultCode() );
423 DummyCellBroadcast::DummyCellBroadcast(QModemService* service)
424 : QCellBroadcast(service->service(), service, QCommInterface::Server)
428 void DummyCellBroadcast::setChannels(const QList<int>&)
432 Ficgta01ModemService::Ficgta01ModemService
433 ( const QString& service, QSerialIODeviceMultiplexer *mux,
435 : QModemService( service, mux, parent )
436 , m_vibratorService( 0 )
438 , m_phoneBookIsReady( false )
439 , m_smsIsReady( false )
441 connect( this, SIGNAL(resetModem()), this, SLOT(reset()) );
443 // Register a wakeup command to ping the modem if we haven't
444 // sent anything during the last 5 seconds. This command may
445 // not get a response, but the modem should then become responsive
446 // to the next command that is sent afterwards.
447 primaryAtChat()->registerWakeupCommand( QChar(0x1a), 5000 );
449 // Attempt to reset the modem
454 // Turn on dynamic signal quality notifications.
455 // Register for "%CSQ" notifications to get signal quality updates.
456 primaryAtChat()->registerNotificationType
457 ( "%CSQ:", this, SLOT(csq(QString)) );
459 QTimer::singleShot( 2500, this, SLOT(firstCsqQuery()) );
461 // Modem dead detection for https://docs.openmoko.org/trac/ticket/1192
462 primaryAtChat()->registerNotificationType
463 ( "+CME ERROR: 512", this, SLOT(modemDied()));
466 // Enable %CPRI for ciphering indications.
467 // chat( "AT%CPRI=1" );
469 // Make the modem send unsolicited reports at any time
470 // the "user is not typing". i.e. don't intersperse unsolicited
471 // notifications and command echo as it will confuse QAtChat.
474 // Enable the reporting of timezone and local time information.
475 primaryAtChat()->registerNotificationType
476 ( "%CTZV:", this, SLOT(ctzv(QString)), true );
480 // Turn on call progress indications, with phone number information.
483 // Enable the work-around for the bouncy rubber calypso problem
484 csqTimer = new QTimer( this );
485 csqTimer->setSingleShot( true );
486 connect ( csqTimer, SIGNAL(timeout()), this, SLOT(csqTimeOut()) );
488 // Setup the default text codec to UCS2 for none English langs
489 setDefaultCharset(DEFAULT_CHARSET);
490 chat( "AT+CSCS=\""+ DEFAULT_CHARSET + "\"" );
492 // Turn on status notification messages for finding out when
493 // the SIM/phonebook/SMS is ready to use.
494 primaryAtChat()->registerNotificationType
495 ( "%CSTAT:", this, SLOT(cstatNotification(QString)) );
496 primaryAtChat()->chat( "AT%CSTAT=1" );
499 Ficgta01ModemService::~Ficgta01ModemService()
504 void Ficgta01ModemService::initialize()
506 if ( !supports<QPinManager>() )
507 addInterface( new Ficgta01PinManager( this ) );
509 if ( !supports<QPhoneBook>() ) {
510 m_phoneBook = new Ficgta01PhoneBook( this );
511 addInterface( m_phoneBook );
515 if ( !supports<QBandSelection>() )
516 addInterface( new Ficgta01BandSelection( this ) );
518 if ( !supports<QSimInfo>() ) {
519 QModemSimInfo* simInfo = new QModemSimInfo( this );
520 simInfo->setSimNotInsertedReason( QModemSimInfo::Reason_SimFailure );
521 addInterface( simInfo );
524 if ( !callProvider() )
525 setCallProvider( new Ficgta01CallProvider( this ) );
527 if ( !supports<QVibrateAccessory>() ) {
528 m_vibratorService = new Ficgta01VibrateAccessory( this );
529 addInterface( m_vibratorService );
532 if ( !supports<QCallVolume>() )
533 addInterface( new Ficgta01CallVolume(this));
535 if ( !supports<QPreferredNetworkOperators>() )
536 addInterface( new Ficgta01PreferredNetworkOperators(this));
538 // CBMs create an issue on suspend/resume disable for now #1530
539 if ( !supports<QCellBroadcast>() )
540 addInterface( new DummyCellBroadcast(this) );
543 QModemService::initialize();
546 void Ficgta01ModemService::csq( const QString& msg )
548 // Automatic signal quality update, in the range 0-31.
549 if ( msg.contains( QChar(',') ) ) {
551 uint rssi = QAtUtils::parseNumber( msg, posn );
553 // An rssi of "99" indicates invalid (i.e. loss of signal).
554 // We wish to be careful about reporting that, because the
555 // silly calypso will report that each and every time it
556 // changes cell sites, followed almost immediately by a new
557 // (valid) signal report. So we defer reporting the invalid
558 // signal, and wait to see if we get an new one first.
559 qLog(AtChat)<< "percentCSQ event, rssi: " << (int)(rssi);
561 if ( !csqTimer->isActive() )
562 csqTimer->start( 8000 ); // 8 second one-shot timer
564 if ( csqTimer->isActive() ) {
566 indicators()->setSignalQuality( (int)rssi, 31 );
572 void Ficgta01ModemService::csqTimeOut()
574 // Timeout on a signal quality notification, it must have been real
575 qLog(AtChat)<< "percentCSQ timer expired; reporting loss";
576 indicators()->setSignalQuality( -1, 31 );
580 void Ficgta01ModemService::firstCsqQuery()
582 // Perform an initial AT%CSQ? which should cause the modem to
583 // respond with a %CSQ notification. This is needed to shut
584 // off AT+CSQ polling in qmodemindicators.cpp when the modem is
585 // quiet and not sending periodic %CSQ notifications at startup.
589 void Ficgta01ModemService::ctzv( const QString& msg )
591 // Timezone information from the network. Format is "yy/mm/dd,hh:mm:ss+/-tz".
592 // There is no dst indicator according to the spec, but we parse an extra
593 // argument just in case future modem firmware versions fix this oversight.
594 // If there is no extra argument, the default value of zero will be used.
596 QString time = QAtUtils::nextString( msg, posn );
597 int dst = ((int)QAtUtils::parseNumber( msg, posn )) * 60;
598 int zoneIndex = time.length();
599 while ( zoneIndex > 0 && time[zoneIndex - 1] != QChar('-') &&
600 time[zoneIndex - 1] != QChar('+') )
603 if ( zoneIndex > 0 && time[zoneIndex - 1] == QChar('-') ) {
604 zoneOffset = time.mid(zoneIndex - 1).toInt() * 15;
605 } else if ( zoneIndex > 0 && time[zoneIndex - 1] == QChar('+') ) {
606 zoneOffset = time.mid(zoneIndex).toInt() * 15;
608 // Unknown timezone information.
613 timeString = time.mid(0, zoneIndex - 1);
616 QDateTime t = QDateTime::fromString(timeString, "yy/MM/dd,HH:mm:ss");
618 t = QDateTime::fromString(timeString, "yyyy/MM/dd,HH:mm:ss"); // Just in case.
619 QDateTime utc = QDateTime(t.date(), t.time(), Qt::UTC);
620 utc = utc.addSecs(-zoneOffset * 60);
621 indicators()->setNetworkTime( utc.toTime_t(), zoneOffset, dst );
624 void Ficgta01ModemService::configureDone( bool ok )
629 void Ficgta01ModemService::reset()
631 qLog(AtChat)<<" Ficgta01ModemService::reset()";
633 // // Turn on "%CNAP" notifications, which supply the caller's
634 // // name on an call. Only supported on some networks.
637 //begin really ugky hack
638 QSettings cfg("Trolltech", "PhoneProfile");
639 cfg.beginGroup("Profiles");
641 if( !cfg.value("PlaneMode",false).toBool()) {
642 chat("AT%NRG=0"); //force auto operations
645 // Set a default CBM state, disable all, setChannels on QCellBroadcast
646 // would enable them again. This should mean no (empty) CBM is accepted.
649 // chat("AT%COPS=0");
653 void Ficgta01ModemService::sendSuspendDone()
658 void Ficgta01ModemService::suspend()
660 qLog(AtChat)<<" Ficgta01ModemService::suspend()";
661 // Turn off cell id information on +CREG and +CGREG as it will
662 // cause unnecessary wakeups when moving between cells.
664 chat( "AT+CGREG=0" );
666 // Don't need these, just clutter (nothing uses these
667 // proprietary commands yet -- MJW)
668 //chat( "AT%CREG=0" );
669 //chat( "AT%CGREG=0" );
671 // Turn off cell broadcast location messages.
673 // Make sure the (useless) CIEV notifications are disabled too.
674 chat( "AT+CMER=0,0,0,0,0" );
676 chat( "AT%CSQ=0", this, SLOT(sendSuspendDone()) );
679 void Ficgta01ModemService::wake()
681 qLog(AtChat)<<" Ficgta01ModemService::wake()";
685 // chat( "AT%CWUP=1" );
688 // Turn cell id information back on.
690 chat( "AT+CGREG=2" );
692 // chat( "AT%CREG=2" );
693 // chat( "AT%CGREG=2" );
694 // Turn cell broadcast location messages back on again.
696 // Re-enable signal quality notifications when the system wakes up again.
697 // Turn on dynamic signal quality notifications.
703 // Modem state notification. It will tell us once the SIM is ready
704 // to give us access to the phonebook and SMS. To delay certain access
705 // we will also send simready from here...
706 void Ficgta01ModemService::cstatNotification( const QString& msg )
709 // %CSTAT: <entity>,<status>
712 // RDY (Ready when both PHB and SMS have reported they are ready)
713 QString entity = msg.mid(8, 3);
714 uint status = msg.mid(13).toInt();
716 // We are already ready, ignore
717 if (m_phoneBookIsReady && m_smsIsReady)
721 m_phoneBookIsReady = status;
722 else if (entity == "SMS")
723 m_smsIsReady = status;
724 else if (entity == "RDY") {
725 m_smsIsReady = status;
726 m_phoneBookIsReady = status;
729 if (m_smsIsReady && m_phoneBookIsReady) {
733 m_phoneBook->sendPhoneBooksReady();
738 // Modem dead detection for https://docs.openmoko.org/trac/ticket/1192
739 // The modem will not work with us anymore. We would need to make the AT
740 // command queue to freeze, fail all commands, we would need to reset the
741 // modem, force reinit (send the commands from all the c'tors again), make sure
742 // every application logic gets restarted. This will be a major effort. So the
743 // 2nd best thing is to detect the error and inform the user that he should
744 // restart his device. Currently I have no idea how often the error occurs
745 // and assume that it is not often at all.
747 // We do something unusual and open a QWidget from this plugin. This is okay
748 // as we will have a QtopiaApplication for the QCOP communication anyway. So
749 // there will be a GUI connection.
750 void Ficgta01ModemService::modemDied()
752 static bool claimedDead = false;
758 if (m_vibratorService)
759 m_vibratorService->setVibrateNow(true);
760 QMessageBox::information(0, tr("Modem Died"),
761 tr("The firmware of the modem appears to have crashed. "
762 "No further interaction with the modem will be possible. "
763 "Please restart the device."), QMessageBox::Ok);
764 if (m_vibratorService)
765 m_vibratorService->setVibrateNow(false);
768 void Ficgta01ModemService::echoCancellation(QAtChat * atChat)
770 Ficgta01ModemHiddenFeatures* hs = new Ficgta01ModemHiddenFeatures(atChat);
771 atChat->chat( "AT@ST=\"-26\"" ); // audio side tone: set to minimum
772 atChat->chat( "AT%N028B" ); // Long Echo Cancellation: active, -6db
773 atChat->chat( "AT%N0125" ); // Noise reduction: active, -6db
776 Ficgta01VibrateAccessory::Ficgta01VibrateAccessory
777 ( QModemService *service )
778 : QVibrateAccessoryProvider( service->service(), service )
780 setSupportsVibrateOnRing( true );
781 setSupportsVibrateNow( false );
784 Ficgta01VibrateAccessory::~Ficgta01VibrateAccessory()
788 void Ficgta01VibrateAccessory::setVibrateOnRing( const bool value )
790 qLog(AtChat) << __FUNCTION__ << value;
791 setVibrateNow(value);
794 void Ficgta01VibrateAccessory::setVibrateNow( const bool value )
796 qLog(AtChat) << __FUNCTION__ << value;
799 if ( value ) { //turn on
800 QFile trigger( "/sys/class/leds/neo1973:vibrator/trigger");
801 trigger.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
802 QTextStream out(&trigger);
806 QFile delayOn( "/sys/class/leds/neo1973:vibrator/delay_on");
807 delayOn.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
808 QTextStream out1(&delayOn);
812 QFile delayOff("/sys/class/leds/neo1973:vibrator/delay_off");
813 delayOff.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
814 QTextStream out2(&delayOff);
819 QFile trigger( "/sys/class/leds/neo1973:vibrator/trigger");
820 trigger.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
821 QTextStream out(&trigger);
826 QVibrateAccessoryProvider::setVibrateNow( value );
830 Ficgta01CallVolume::Ficgta01CallVolume(Ficgta01ModemService *service)
831 : QModemCallVolume(service)
833 this->service = service;
835 QtopiaIpcAdaptor *adaptor
836 = new QtopiaIpcAdaptor( "QPE/Ficgta01Modem", this );
838 // Set default, then query real value
839 setSpeakerVolumeRange(0, 5);
841 service->primaryAtChat()->chat("AT+CLVL=?", this, SLOT(volumeLevelRangeQueryDone(bool,QAtResult)) );
842 service->primaryAtChat()->chat("AT+CLVL?", this, SLOT(volumeLevelQueryDone(bool,QAtResult)) );
844 QtopiaIpcAdaptor::connect
845 ( adaptor, MESSAGE(setSpeakerVolumeRange(int, int)),
846 this, SLOT(setSpeakerVolumeRange(int,int)) );
848 QtopiaIpcAdaptor::connect
849 ( adaptor, MESSAGE(setMicVolumeRange(int, int)),
850 this, SLOT(setMicVolumeRange(int,int)) );
852 QtopiaIpcAdaptor::connect
853 ( adaptor, MESSAGE(setOutputVolume(int)),
854 this, SLOT(setSpeakerVolume(int)) );
855 QtopiaIpcAdaptor::connect
856 ( adaptor, MESSAGE(setMicVolume(int)),
857 this, SLOT(setMicrophoneVolume(int)) );
861 Ficgta01CallVolume::~Ficgta01CallVolume()
866 bool Ficgta01CallVolume::hasDelayedInit() const
871 void Ficgta01CallVolume::setSpeakerVolume( int volume )
874 int boundedVolume = qBound(value("MinimumSpeakerVolume").toInt(), volume,
875 value("MaximumSpeakerVolume").toInt());
877 setValue( "SpeakerVolume", boundedVolume );
878 volumeLevel = virtual2real(boundedVolume);
879 if (currentVolumeLevel == volumeLevel)
881 currentVolumeLevel = volumeLevel;
882 service->primaryAtChat()->chat("AT+CLVL="+QString::number(currentVolumeLevel));
883 emit speakerVolumeChanged(boundedVolume);
886 void Ficgta01CallVolume::setMicrophoneVolume( int volume )
888 int boundedVolume = qBound(value("MinimumMicrophoneVolume").toInt(), volume,
889 value("MaximumMicrophoneVolume").toInt());
891 setValue( "MicrophoneVolume", boundedVolume );
892 emit microphoneVolumeChanged(boundedVolume);
896 void Ficgta01CallVolume::setSpeakerVolumeRange(int min,int max)
898 setValue( "MinimumSpeakerVolume", min );
899 setValue( "MaximumSpeakerVolume", max );
902 void Ficgta01CallVolume::setMicVolumeRange(int min,int max)
904 setValue( "MinimumMicrophoneVolume", min );
905 setValue( "MaximumMicrophoneVolume", max );
908 void Ficgta01CallVolume::volumeLevelRangeQueryDone(bool ok,const QAtResult & result)
912 QAtResultParser parser( result );
913 if ( parser.next( "+CLVL:" ) ) {
914 QList<QAtResultParser::Node> nodes = parser.readList();
915 if (!nodes.isEmpty()) {
916 if (nodes.at(0).isRange()) {
917 minVolumeLevel = nodes.at(0).asFirst();
918 maxVolumeLevel = nodes.at(0).asLast();
924 void Ficgta01CallVolume::volumeLevelQueryDone(bool ok,const QAtResult & result)
929 QAtResultParser parser( result );
930 if ( parser.next( "+CLVL:" )) {
931 volumeLevel = (int) parser.readNumeric();
932 currentVolumeLevel = volumeLevel;
933 setSpeakerVolume(real2virtual(currentVolumeLevel));
937 int Ficgta01CallVolume::virtual2real(int volume)
940 int min = value("MinimumSpeakerVolume").toInt();
941 int max = value("MaximumSpeakerVolume").toInt();
942 if (minVolumeLevel >= maxVolumeLevel)
946 ans = volume * (maxVolumeLevel - minVolumeLevel);
947 ans = ans / (max - min);
951 int Ficgta01CallVolume::real2virtual(int volumeLevel)
954 int min = value("MinimumSpeakerVolume").toInt();
955 int max = value("MaximumSpeakerVolume").toInt();
956 if (minVolumeLevel >= maxVolumeLevel)
960 ans = volumeLevel * (max - min);
961 ans = ans / (maxVolumeLevel - minVolumeLevel);
965 Ficgta01PreferredNetworkOperators::Ficgta01PreferredNetworkOperators( QModemService *service )
966 : QModemPreferredNetworkOperators( service )
968 // We have to delete an entry before we can write operator details into it.
969 setDeleteBeforeUpdate( true );
971 // Quote operator numbers when modifying preferred operator entries.
972 setQuoteOperatorNumber( true );
975 Ficgta01PreferredNetworkOperators::~Ficgta01PreferredNetworkOperators()
979 Ficgta01ModemHiddenFeatures::Ficgta01ModemHiddenFeatures(QAtChat* atChat) :
985 Ficgta01ModemHiddenFeatures::~Ficgta01ModemHiddenFeatures()
989 void Ficgta01ModemHiddenFeatures::sendHiddenFeatureCommand(int code)
991 m_atChat->chat(atPrefix + QString::number(code, 16).toUpper().rightJustified(4, '0'));
994 void Ficgta01ModemHiddenFeatures::enableAEC(int type, bool longAEC = true)
996 if (type <= 0 && type >= -18 && (-type) % 6 == 0) {
997 int code = 0x0083 + (((-type) / 6) * 0x8);
1002 sendHiddenFeatureCommand(code);
1006 void Ficgta01ModemHiddenFeatures::enableNoiseReduction(int type)
1008 if (type <= 0 && type >= -18 && (-type) % 6 == 0) {
1009 int code = 0x0105 + (((-type) / 6) * 0x20);
1011 sendHiddenFeatureCommand(code);
1015 void Ficgta01ModemHiddenFeatures::enableNoiseReductionAEC()
1017 sendHiddenFeatureCommand(0x0187);
1020 void Ficgta01ModemHiddenFeatures::disableNoiseReductionAEC()
1022 sendHiddenFeatureCommand(0x0001);