--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothengine/btmac/src/BTMonoCmdHandler/btmcprotocol.cpp Mon Jan 18 20:28:57 2010 +0200
@@ -0,0 +1,1275 @@
+/*
+* Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+
+#include "atcodec.h"
+#include <mmtsy_names.h> // for etel
+#include <btengconstants.h>
+#include <btengdiscovery.h>
+#include <badesca.h>
+#include "btmcprotocol.h"
+#include "btmccallinghandler.h"
+#include "btmcphonestatus.h"
+#include "btmccallstatus.h"
+#include "btmcprotocolstatus.h"
+#include "btmcobserver.h"
+#include "btmcmobileline.h"
+#include "btmcnumber.h"
+#include "btmcoperator.h"
+
+#include "debug.h"
+
+// Service Level Monitoring
+const TInt KCmerFromHF = 0x01;
+const TInt KCmerFromAG = 0x02;
+const TInt KSLC_No3WayCalling = KCmerFromHF | KCmerFromAG;
+
+const TInt KChldFromHF = 0x04;
+const TInt KChldFromAG = 0x08;
+
+const TInt KSLC_3WayCalling = KChldFromHF | KChldFromAG;
+
+const TInt KBerUnknown = 99;
+
+const TInt KServiceSlcTimer = 1;
+const TInt KServiceSdpQuery = 2;
+const TInt KServiceGetSubscriber = 3;
+const TInt KServiceGetOperator = 4;
+const TInt KServiceCmdHandling = 5;
+
+const TInt KQueryIMEI = 6;
+const TInt KQueryIMSI = 7;
+
+const TInt KServiceFirstHspCkpdTrap = 8;
+
+CBtmcProtocol* CBtmcProtocol::NewL(
+ MBtmcObserver& aObserver, TBtmcProfileId aProfile, const TDesC8& aBTDevAddr, TBool aAccessoryInitiated)
+ {
+ CBtmcProtocol* self=new (ELeave) CBtmcProtocol(aObserver);
+ CleanupStack::PushL(self);
+ self->ConstructL(aProfile, aBTDevAddr, aAccessoryInitiated);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CBtmcProtocol::~CBtmcProtocol()
+ {
+ TRACE_FUNC_ENTRY
+ delete iCallingHandler;
+
+ delete iCmdHanldingActive;
+ delete iAtExt;
+
+ delete iTimerActive;
+ iTimer.Close();
+
+ delete iProtocolStatus;
+ delete iCallStatus;
+ delete iPhoneStatus;
+
+ delete iNumber;
+ delete iOperator;
+
+ delete iEtelQuery;
+ delete iBteng;
+
+ iPhone.Close();
+ iServer.UnloadPhoneModule(KMmTsyModuleName);
+ iServer.Close();
+ delete iOutgoPacketQueue;
+ TRACE_FUNC_EXIT
+ }
+
+void CBtmcProtocol::NewProtocolDataL(const TDesC8& aData)
+ {
+ TRACE_FUNC
+ TInt err = iInDataBuf.Append(aData);
+ if (err)
+ {
+ CATResult* nok = CATResult::NewLC(EATERROR);
+ SendResponseL(*nok);
+ CleanupStack::PopAndDestroy(nok);
+ }
+ else if (!iCmdHanldingActive->IsActive())
+ {
+ TRequestStatus* sta = &iCmdHanldingActive->iStatus;
+ *sta = KRequestPending;
+ User::RequestComplete(sta, KErrNone);
+ iCmdHanldingActive->GoActive();
+ }
+ }
+
+void CBtmcProtocol::SendResponseL(const CATResult& aResult)
+ {
+ TRACE_FUNC
+ iOutgoPacketQueue->InsertL(0, aResult.Des());
+ iCredit = iOutgoPacketQueue->MdcaCount();
+ DoSendProtocolDataL();
+ }
+
+void CBtmcProtocol::SendResponseL(const RPointerArray<CATResult>& aResults)
+ {
+ TRACE_FUNC
+ TInt count = aResults.Count();
+ for (TInt i = 0; i < count; i++)
+ {
+ iOutgoPacketQueue->InsertL(i, aResults[i]->Des());
+ }
+ iCredit = iOutgoPacketQueue->MdcaCount();
+ DoSendProtocolDataL();
+ }
+
+void CBtmcProtocol::SendUnsoltResultL(const CATResult& aResult)
+ {
+ TRACE_FUNC_ENTRY
+ if (aResult.Id() == EATVGS)
+ {
+ iOutgoPacketQueue->InsertL(0, aResult.Des());
+ iCredit++;
+ }
+ else
+ {
+ iOutgoPacketQueue->AppendL(aResult.Des());
+ if (!iCallingHandler->ActiveCmdHandling() && !iHandleCmdPending)
+ {
+ iCredit++;
+ }
+ }
+ DoSendProtocolDataL();
+ TRACE_FUNC_EXIT
+ }
+
+void CBtmcProtocol::CmdHandlingCompletedL()
+ {
+ TRACE_FUNC
+ iHandleCmdPending = EFalse;
+ TRequestStatus* sta = &iCmdHanldingActive->iStatus;
+ *sta = KRequestPending;
+ User::RequestComplete(sta, KErrNone);
+ iCmdHanldingActive->GoActive();
+ }
+
+TBtmcProtocolStatus& CBtmcProtocol::ProtocolStatus()
+ {
+ return *iProtocolStatus;
+ }
+
+void CBtmcProtocol::VoiceRecognitionError()
+ {
+ iPhoneStatus->SetRecognitionInitiator(EBTMonoVoiceRecognitionDefaultInitiator);
+ }
+
+void CBtmcProtocol::HandleNrecCompletedL(TInt aErr)
+ {
+ TATId id = aErr ? EATERROR : EATOK;
+ CATResult* nok = CATResult::NewLC(id);
+ SendResponseL(*nok);
+ CleanupStack::PopAndDestroy(nok);
+ CmdHandlingCompletedL();
+ }
+
+
+void CBtmcProtocol::ActivateRemoteVolumeControl()
+ {
+ TRACE_FUNC
+ if (iPhoneStatus)
+ iPhoneStatus->ActivateRemoteVolumeControl();
+ else
+ {
+ TRACE_INFO(_L("WARNING, null vol handler!"))
+ }
+ }
+
+void CBtmcProtocol::DeActivateRemoteVolumeControl()
+ {
+ TRACE_FUNC
+ if (iPhoneStatus)
+ iPhoneStatus->DeActivateRemoteVolumeControl();
+ else
+ {
+ TRACE_INFO(_L("WARNING, null vol handler!"))
+ }
+ }
+
+TInt CBtmcProtocol::GetRemoteSupportedFeature()
+ {
+ return iProtocolStatus->iAccSupportedFeature;
+ }
+
+TBool CBtmcProtocol::ActiveChldHandling() const
+ {
+ return iCallingHandler->ActiveChldHandling();
+ }
+
+void CBtmcProtocol::RequestCompletedL(CBtmcActive& aActive, TInt aErr)
+ {
+ TRACE_FUNC_ENTRY
+ switch (aActive.ServiceId())
+ {
+ case KServiceSlcTimer:
+ {
+ if (aErr == KErrNone)
+ {
+ StopTimer(KServiceSlcTimer);
+ iObserver.SlcIndicateL(EFalse);
+ }
+ break;
+ }
+ case KServiceSdpQuery:
+ {
+ }
+ case KServiceGetSubscriber:
+ {
+ delete iNumber;
+ iNumber = NULL;
+ CmdHandlingCompletedL();
+ break;
+ }
+ case KServiceGetOperator:
+ {
+ delete iOperator;
+ iOperator = NULL;
+ CmdHandlingCompletedL();
+ break;
+ }
+ case KServiceCmdHandling:
+ {
+ TRAPD(err, DoHandleCommandL());
+ if (err)
+ {
+ CATResult* nok = CATResult::NewLC(EATERROR);
+ SendResponseL(*nok);
+ CleanupStack::PopAndDestroy(nok);
+ CmdHandlingCompletedL();
+ }
+ break;
+ }
+ case KQueryIMSI:
+ {
+ TBuf8<RMobilePhone::KIMSISize> buf;
+ buf.Copy(iId);
+ CATResult* cimi = CATResult::NewLC(EATCIMI, EATReadResult, TATParam(buf));
+ SendResponseL(*cimi);
+ CleanupStack::PopAndDestroy(cimi);
+ CATResult* ok = CATResult::NewLC(EATOK);
+ SendResponseL(*ok);
+ CleanupStack::PopAndDestroy(ok);
+ CmdHandlingCompletedL();
+ break;
+ }
+ case KServiceFirstHspCkpdTrap:
+ {
+ // No handling here. From now on, any incoming CKPD command
+ // will be processed normally.
+ TRACE_INFO((_L("CKPD trapper terminated")));
+ break;
+ }
+ default:
+ break;
+ }
+ TRACE_FUNC_EXIT
+ }
+
+void CBtmcProtocol::CancelRequest(TInt aServiceId)
+ {
+ TRACE_FUNC_ENTRY
+ if (aServiceId == KServiceSlcTimer || aServiceId == KServiceFirstHspCkpdTrap )
+ {
+ iTimer.Cancel();
+ }
+ else if (aServiceId == KServiceSdpQuery)
+ {
+ iBteng->CancelRemoteSdpQuery();
+ }
+ TRACE_FUNC_EXIT
+ }
+
+CBtmcProtocol::CBtmcProtocol(MBtmcObserver& aObserver)
+ : iObserver(aObserver),
+ iSlcMask(0x00)
+ {
+ }
+
+void CBtmcProtocol::ConstructL(TBtmcProfileId aProfile, const TDesC8& aBTDevAddr, TBool aAccessoryInitiated)
+ {
+ TRACE_FUNC_ENTRY
+ iProtocolStatus = new (ELeave) TBtmcProtocolStatus();
+ iProtocolStatus->iProfile = aProfile;
+ iAccessoryInitiated = aAccessoryInitiated;
+ iProtocolStatus->iAGSupportedFeature = KBTAGSupportedFeatureV15;
+
+ LEAVE_IF_ERROR(iServer.Connect())
+ TInt err = iServer.LoadPhoneModule(KMmTsyModuleName);
+ if (err != KErrNone && err != KErrAlreadyExists)
+ LEAVE(err);
+ LEAVE_IF_ERROR(iPhone.Open(iServer, KMmTsyPhoneName))
+
+ iCallStatus = CBtmcCallStatus::NewL(*this, iPhone, aProfile);
+ iProtocolStatus->iCallBits = iCallStatus->CallStatusL();
+
+ iEtelQuery = CBtmcActive::NewL(*this, CActive::EPriorityStandard, KQueryIMEI);
+
+ iPhone.GetPhoneId(iEtelQuery->iStatus, iIdentity);
+ iEtelQuery->GoActive();
+
+ switch (aProfile)
+ {
+ case EBtmcHFP0105:
+ {
+ TRACE_INFO((_L("constructing option HFP 1.5")))
+ iPhoneStatus = CBtmcPhoneStatus::NewL(*this, iPhone, aProfile);
+ StartTimerL(KServiceSlcTimer, KSlcTimeout);
+ break;
+ }
+ case EBtmcHSP:
+ {
+ TRACE_INFO((_L("constructing option HSP")))
+ if (aBTDevAddr.Length() != KBTDevAddrSize)
+ {
+ LEAVE(KErrBadDescriptor);
+ }
+ iProtocolStatus->iSlc = ETrue;
+ iBteng = CBTEngDiscovery::NewL(this);
+ iBteng->RemoteSdpQuery(TBTDevAddr(aBTDevAddr), TUUID(EBTProfileHSP), KBTHSRemoteAudioVolumeControl);
+ if ( iAccessoryInitiated && ( iProtocolStatus->iCallBits & KCallConnectedBit ) )
+ {
+ TRACE_INFO((_L("Incoming HSP connected, start CKPD trapper")));
+ // In case of incoming HSP connection during a voice call,
+ // start timer to trap the CKPD command as part of the audio transfer of HSP.
+ // If the first CKPD command is received during this period, it will be ignored.
+ StartTimerL(KServiceFirstHspCkpdTrap, KFirstHspCkpdTimeout);
+ }
+ break;
+ }
+ default:
+ LEAVE(KErrArgument);
+ }
+ TRAP_IGNORE(iAtExt = CHFPAtCmdHandler::NewL(*this));
+ iOutgoPacketQueue = new (ELeave) CDesC8ArrayFlat(1);
+ iCallingHandler = CBtmcCallingHandler::NewL(*this);
+ iCmdHanldingActive = CBtmcActive::NewL(*this, CActive::EPriorityStandard, KServiceCmdHandling);
+ if (iProtocolStatus->iSlc)
+ {
+ iCallStatus->ReportCallStatusL();
+ }
+ iVolumeSyncFromAccessory = EFalse;
+ TRACE_FUNC_EXIT
+ }
+
+void CBtmcProtocol::DoHandleCommandL()
+ {
+ TRACE_FUNC
+ if (iHandleCmdPending)
+ {
+ return;
+ }
+ TBuf8<KMaxATSize> cmddes;
+ if (iInDataBuf.NextCommand(cmddes))
+ {
+ return;
+ }
+ if (cmddes.Length() == 0)
+ {
+ return;
+ }
+ TRACE_INFO_SEG(
+ {
+ TBuf8<KMaxATSize> buf;
+ buf = cmddes;
+ buf.Trim();
+ Trace(_L8("[HFP] [I] %S"), &buf);
+ })
+
+ CATCommand* cmd = NULL;
+ TRAPD(err, cmd = CATCommand::NewL(cmddes));
+ if (err)
+ {
+ if(iAtExt)
+ {
+ iAtExt->HandleCommand(cmddes, _L8("\n\rERROR\n\r"));
+ return;
+ }
+ CATResult* nok = CATResult::NewLC(EATERROR);
+ SendResponseL(*nok);
+ CleanupStack::PopAndDestroy(nok);
+ return;
+ }
+ CleanupStack::PushL(cmd);
+ iHandleCmdPending = ETrue;
+ TATId id = cmd->Id();
+ if (id == EATA ||
+ id == EATD2 ||
+ id == EATD1 ||
+ (id == EATCHLD && cmd->Type() != EATTestCmd)||
+ id == EATCHUP ||
+ id == EATVTS ||
+ (id == EATBVRA && cmd->Type() == EATWriteCmd) ||
+ id == EATBLDN )
+ {
+ if (id == EATBVRA)
+ {
+ TRACE_ASSERT(cmd->ParamNum() == 1, KErrArgument);
+ TATParam param = TATParam();
+ LEAVE_IF_ERROR(cmd->Parameter(0, param))
+ TInt value;
+ LEAVE_IF_ERROR(param.Int(value))
+ TBTMonoVoiceRecognitionInitiator initor;
+ initor = (value) ? EBTMonoVoiceRecognitionActivatedByRemote
+ : EBTMonoVoiceRecognitionDeactivatedByRemote;
+ iPhoneStatus->SetRecognitionInitiator(initor);
+ }
+ iCallingHandler->HandleCallingCmdL(*cmd);
+ }
+ else if ( id == EATCKPD )
+ {
+ if ( iTimerActive && iTimerActive->IsActive() )
+ {
+ // incoming HSP was just connected and the first CKPD is received,
+ // ignore this command as audio establishment will be done via Acc FW
+ StopTimer( KServiceFirstHspCkpdTrap );
+ TRACE_INFO((_L("First CKPD, do nothing")));
+ CATResult* nok = CATResult::NewLC( EATOK );
+ SendResponseL(*nok);
+ CleanupStack::PopAndDestroy(nok);
+ CmdHandlingCompletedL();
+ }
+ else
+ {
+ iCallingHandler->HandleCallingCmdL(*cmd);
+ }
+ }
+ else if (id == EATNREC && cmd->Type() == EATWriteCmd)
+ {
+ TRACE_ASSERT(cmd->ParamNum() == 1, KErrArgument);
+ TATParam param = TATParam();
+ LEAVE_IF_ERROR(cmd->Parameter(0, param))
+ TInt value;
+ LEAVE_IF_ERROR(param.Int(value))
+ if (!value &&
+ ServiceLevelConnected() )
+ {
+ //Always respond OK to +NREC=0
+ HandleNrecCompletedL(0);
+ }
+ else
+ {
+ LEAVE(KErrArgument);
+ }
+ }
+ else
+ {
+ // for HSP profile we support only VGS & VGM commands
+ // CKPD is handled elsewhere
+ if(iProtocolStatus->iProfile == EBtmcHSP &&
+ ((cmd->Id() != EATVGS &&
+ cmd->Id() != EATVGM)) )
+ {
+ LEAVE(KErrNotSupported);
+ }
+
+ switch (cmd->Type())
+ {
+ case EATTestCmd:
+ {
+ HandleTestCommandL(*cmd);
+ break;
+ }
+ case EATReadCmd:
+ {
+ HandleReadCommandL(*cmd);
+ break;
+ }
+ case EATWriteCmd:
+ {
+ HandleWriteCommandL(*cmd);
+ break;
+ }
+ case EATActionCmd:
+ {
+ HandleActionCommandL(*cmd);
+ break;
+ }
+ default:
+ LEAVE(KErrNotSupported);
+ }
+ }
+ CleanupStack::PopAndDestroy(cmd);
+
+ if (!iProtocolStatus->iSlc && ServiceLevelConnected())
+ {
+ StopTimer(KServiceSlcTimer);
+ if(iPhoneStatus)
+ {
+ iPhoneStatus->SetVolumeControlFeatureL(iProtocolStatus->iAccSupportedFeature & KHfFeatureBitVolumeControl);
+ iPhoneStatus->SetVoiceRecognitionControlL(iProtocolStatus->iAccSupportedFeature & KHfFeatureBitVoiceRecognition);
+ }
+ iProtocolStatus->iSlc = ETrue;
+ iCallStatus->ReportCallStatusL();
+ iObserver.SlcIndicateL(ETrue);
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CBtmcProtocol::HandleTestCommand
+//
+// Test Command handled by this method:
+// CHLD, BVRA, CIND, CCWA, CLIP
+// -----------------------------------------------------------------------------
+//
+void CBtmcProtocol::HandleTestCommandL(const CATCommand& aCmd)
+ {
+ TRACE_FUNC
+ RATResultPtrArray resarr;
+ ATObjArrayCleanupResetAndDestroyPushL(resarr);
+
+ TATParam param;
+ switch (aCmd.Id())
+ {
+ case EAT:
+ {
+ break;
+ }
+ case EATCHLD:
+ {
+ param = TATParam(KDesTestCodeCHLDv15);
+ iSlcMask = KSLC_3WayCalling;
+ break;
+ }
+ case EATBVRA:
+ {
+ param = TATParam(KDesTestCodeBVRA);
+ break;
+ }
+ case EATCIND:
+ {
+ param = TATParam(KDesTestCodeCINDv15);
+ break;
+ }
+ case EATCCWA:
+ {
+ param = TATParam(KDesTestCodeCCWA);
+ break;
+ }
+ case EATCLIP:
+ {
+ param = TATParam(KDesTestCodeCLIP);
+ break;
+ }
+ case EATCREG:
+ {
+ param = TATParam(KDesTestCodeCCWA); // it is the same (0,1)
+ break;
+ }
+ case EATCOLP:
+ {
+ param = TATParam(KDesTestCodeCCWA); // it is the same (0,1)
+ break;
+ }
+ default:
+ LEAVE(KErrNotFound);
+ }
+ if (param.Type() != EATNullParam)
+ {
+ CATResult* code = CATResult::NewL(aCmd.Id(), EATTestResult, param);
+ CleanupStack::PushL(code);
+ resarr.AppendL(code);
+ CleanupStack::Pop(code);
+ }
+ CATResult* ok = CATResult::NewL(EATOK);
+ CleanupStack::PushL(ok);
+ resarr.AppendL(ok);
+ CleanupStack::Pop(ok);
+ SendResponseL(resarr);
+ CleanupStack::PopAndDestroy(&resarr);
+ CmdHandlingCompletedL();
+ }
+
+// -----------------------------------------------------------------------------
+// CBtmcProtocol::HandleReadCommand
+//
+// Read Command handled by this method:
+// CIND, CLIP, COPS
+// -----------------------------------------------------------------------------
+//
+void CBtmcProtocol::HandleReadCommandL(const CATCommand& aCmd)
+ {
+ TRACE_FUNC
+ CATResult* code = NULL;
+ RArray<TATParam> params;
+ CleanupClosePushL(params);
+ TBool response = EFalse;
+ switch (aCmd.Id())
+ {
+ case EATCIND:
+ {
+ // Network status
+ if(!iPhoneStatus)
+ {
+ LEAVE(KErrNotSupported);
+ }
+
+ RMobilePhone::TMobilePhoneRegistrationStatus net =
+ iPhoneStatus->NetworkStatus();
+
+ if (net == RMobilePhone::ERegisteredOnHomeNetwork ||
+ net == RMobilePhone::ERegisteredRoaming)
+ {
+ LEAVE_IF_ERROR(params.Append(TATParam(EBTMonoATNetworkAvailable)))
+ }
+ else
+ {
+ LEAVE_IF_ERROR(params.Append(TATParam(EBTMonoATNetworkUnavailable)))
+ }
+
+ // call status
+ if ((iProtocolStatus->iCallBits & KCallConnectedBit) ||
+ (iProtocolStatus->iCallBits & KCallHoldBit))
+ {
+ LEAVE_IF_ERROR(params.Append(TATParam(EBTMonoATCallActive)))
+ }
+ else
+ {
+ LEAVE_IF_ERROR(params.Append(TATParam(EBTMonoATNoCall)))
+ }
+
+ // Call setup status
+ TInt callSetupInd = EBTMonoATNoCallSetup;
+
+ if (iProtocolStatus->iCallBits & KCallRingingBit)
+ {
+ callSetupInd = EBTMonoATCallRinging;
+ }
+ else if (iProtocolStatus->iCallBits & KCallDiallingBit)
+ {
+ callSetupInd = EBTMonoATCallDialling;
+ }
+ else if (iProtocolStatus->iCallBits & KCallConnectingBit)
+ {
+ callSetupInd = EBTMonoATCallConnecting;
+ }
+ LEAVE_IF_ERROR(params.Append(TATParam(callSetupInd)))
+ // call_setup == callsetup
+ LEAVE_IF_ERROR(params.Append(TATParam(callSetupInd)))
+
+ // Call held status
+ TInt callHeldInd = EBTMonoATNoCallHeld;
+ if( (iProtocolStatus->iCallBits & KCallHoldBit) && (iProtocolStatus->iCallBits & KCallConnectedBit) )
+ {
+ callHeldInd = EBTMonoATCallHeldAndActive;
+ }
+ else if(iProtocolStatus->iCallBits & KCallHoldBit)
+ {
+ callHeldInd = EBTMonoATCallHeldOnly;
+ }
+ LEAVE_IF_ERROR(params.Append(TATParam(callHeldInd)))
+ // signal status
+ LEAVE_IF_ERROR(params.Append(TATParam(iPhoneStatus->GetSignalStrength())))
+ // roaming status
+ if(net == RMobilePhone::ERegisteredRoaming)
+ {
+ LEAVE_IF_ERROR(params.Append(TATParam(1)))
+ }
+ else
+ {
+ LEAVE_IF_ERROR(params.Append(TATParam(0)))
+ }
+ // battery charge
+ LEAVE_IF_ERROR(params.Append(TATParam(iPhoneStatus->GetBatteryCharge())))
+
+ code = CATResult::NewL(EATCIND, EATReadResult, ¶ms);
+ response = ETrue;
+ break;
+ }
+ case EATCLIP:
+ {
+ LEAVE_IF_ERROR(params.Append(TATParam(iProtocolStatus->iCallerIdNotif)))
+ LEAVE_IF_ERROR(params.Append(TATParam(EBTMonoATCallerIdNetworkServiceUnknown)))
+ code = CATResult::NewL(EATCLIP, EATReadResult, ¶ms);
+ response = ETrue;
+ break;
+ }
+ case EATCOPS:
+ {
+ iOperator = CBtmcOperator::NewL(*this, *this, CActive::EPriorityStandard, KServiceGetOperator);
+ iOperator->GoActive();
+ break;
+ }
+ case EATCREG:
+ {
+ if(!iPhoneStatus)
+ {
+ LEAVE(KErrNotSupported);
+ }
+
+ RMobilePhone::TMobilePhoneRegistrationStatus net =
+ iPhoneStatus->NetworkStatus();
+ response = ETrue;
+ switch(net)
+ {
+ case RMobilePhone::ERegistrationUnknown:
+ {
+ LEAVE_IF_ERROR(params.Append(TATParam(EBTMonoCregEnableUnsolicited)))
+ LEAVE_IF_ERROR(params.Append(TATParam(EBTMonoCregNetworkServiceUnknown)))
+ code = CATResult::NewL(EATCREG, EATReadResult, ¶ms);
+ break;
+ }
+ case RMobilePhone::ENotRegisteredEmergencyOnly:
+ case RMobilePhone::ENotRegisteredNoService:
+ {
+ LEAVE_IF_ERROR(params.Append(TATParam(EBTMonoCregEnableUnsolicited)))
+ LEAVE_IF_ERROR(params.Append(TATParam(EBTMonoCregNetworkServiceNotRegistered)))
+ code = CATResult::NewL(EATCREG, EATReadResult, ¶ms);
+ break;
+ }
+ case RMobilePhone::ENotRegisteredSearching:
+ case RMobilePhone::ERegisteredBusy:
+ {
+ LEAVE_IF_ERROR(params.Append(TATParam(EBTMonoCregEnableUnsolicited)))
+ LEAVE_IF_ERROR(params.Append(TATParam(EBTMonoCregNetworkServiceNotRegisteredSearching)))
+ code = CATResult::NewL(EATCREG, EATReadResult, ¶ms);
+ break;
+ }
+ case RMobilePhone::ERegisteredOnHomeNetwork:
+ {
+ LEAVE_IF_ERROR(params.Append(TATParam(EBTMonoCregEnableUnsolicited)))
+ LEAVE_IF_ERROR(params.Append(TATParam(EBTMonoCregNetworkServiceHomeNetwork)))
+ code = CATResult::NewL(EATCREG, EATReadResult, ¶ms);
+ break;
+ }
+ case RMobilePhone::ERegistrationDenied:
+ {
+ LEAVE_IF_ERROR(params.Append(TATParam(EBTMonoCregEnableUnsolicited)))
+ LEAVE_IF_ERROR(params.Append(TATParam(EBTMonoCregNetworkServiceRegistrationDenied)))
+ code = CATResult::NewL(EATCREG, EATReadResult, ¶ms);
+ break;
+ }
+ case RMobilePhone::ERegisteredRoaming:
+ {
+ LEAVE_IF_ERROR(params.Append(TATParam(EBTMonoCregEnableUnsolicited)))
+ LEAVE_IF_ERROR(params.Append(TATParam(EBTMonoCregNetworkServiceRegisteredRoaming)))
+ code = CATResult::NewL(EATCREG, EATReadResult, ¶ms);
+ break;
+ }
+ default:
+ TRACE_INFO(_L("Error: default in CREG"));
+ break;
+ };
+ break;
+ }
+ case EATCSQ:
+ {
+ TRACE_INFO(_L("Requesting Signal strength"));
+ response = ETrue;
+ LEAVE_IF_ERROR(params.Append(TATParam(iPhoneStatus->GetRssiStrength())))
+ LEAVE_IF_ERROR(params.Append(TATParam(KBerUnknown)))
+ code = CATResult::NewL(EATCSQ, EATReadResult, ¶ms);
+ TRACE_INFO(_L("done"));
+ break;
+ }
+
+ case EATCGSN:
+ {
+ response = ETrue;
+ TBuf8<RMobilePhone::KPhoneSerialNumberSize> buf;
+ buf.Copy(iIdentity.iSerialNumber);
+ LEAVE_IF_ERROR(params.Append(TATParam(buf)))
+ code = CATResult::NewL(EATCGSN, EATReadResult, ¶ms);
+ break;
+ }
+ case EATCGMI:
+ {
+ response = ETrue;
+ TBuf8<RMobilePhone::KPhoneManufacturerIdSize> buf;
+ buf.Copy(iIdentity.iManufacturer);
+ LEAVE_IF_ERROR(params.Append(TATParam(buf)))
+ code = CATResult::NewL(EATCGMI, EATReadResult, ¶ms);
+ break;
+ }
+ case EATCGMM:
+ {
+ response = ETrue;
+ TBuf8<RMobilePhone::KPhoneModelIdSize> buf;
+ buf.Copy(iIdentity.iModel);
+ LEAVE_IF_ERROR(params.Append(TATParam(buf)))
+ code = CATResult::NewL(EATCGMM, EATReadResult, ¶ms);
+ break;
+ }
+ case EATCGMR:
+ {
+ response = ETrue;
+ TBuf8<RMobilePhone::KPhoneRevisionIdSize> buf;
+ buf.Copy(iIdentity.iRevision);
+ LEAVE_IF_ERROR(params.Append(TATParam(buf)))
+ code = CATResult::NewL(EATCGMR, EATReadResult, ¶ms);
+ break;
+ }
+ case EATCIMI:
+ {
+ iEtelQuery->SetServiceId(KQueryIMSI);
+ iPhone.GetSubscriberId(iEtelQuery->iStatus, iId);
+ iEtelQuery->GoActive();
+ break;
+ }
+ case EATCOLP:
+ {
+ response = ETrue;
+ LEAVE_IF_ERROR(params.Append(TATParam(TInt(iProtocolStatus->iOutgoingCallNotif))))
+ code = CATResult::NewL(EATCOLP, EATReadResult, ¶ms);
+ break;
+ }
+ default:
+ LEAVE(KErrNotSupported);
+ }
+ CleanupStack::PopAndDestroy(¶ms);
+ if (response)
+ {
+ RATResultPtrArray resarr;
+ ATObjArrayCleanupResetAndDestroyPushL(resarr);
+ CleanupStack::PushL(code);
+ resarr.AppendL(code);
+ CleanupStack::Pop(code);
+ CATResult* ok = CATResult::NewL(EATOK);
+ CleanupStack::PushL(ok);
+ resarr.AppendL(ok);
+ CleanupStack::Pop(ok);
+ SendResponseL(resarr);
+ CleanupStack::PopAndDestroy(&resarr);
+ CmdHandlingCompletedL();
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CBtmcProtocol::HandleWriteCommand
+//
+// Write Command handled by this method:
+// CHLD BVRA, CCWA, CLIP, VGS, VGM, CMEE, COPS
+// -----------------------------------------------------------------------------
+//
+void CBtmcProtocol::HandleWriteCommandL(const CATCommand& aCmd)
+ {
+ TRACE_FUNC
+ RATResultPtrArray resarr;
+ ATObjArrayCleanupResetAndDestroyPushL(resarr);
+ CATResult* code = NULL;
+ switch (aCmd.Id())
+ {
+ case EATCMER:
+ {
+ TRACE_ASSERT(aCmd.ParamNum() >= 4, KErrArgument);
+ TATParam param = TATParam();
+ LEAVE_IF_ERROR(aCmd.Parameter(0, param))
+ TInt value;
+ LEAVE_IF_ERROR(param.Int(value))
+ if (value == 3)
+ {
+ param = TATParam();
+ LEAVE_IF_ERROR(aCmd.Parameter(3, param))
+ LEAVE_IF_ERROR(param.Int(value))
+ iProtocolStatus->iIndicatorNotif = (value == 1) ?
+ KIndAllActivated : KIndAllDeActivated;
+ TRACE_INFO((_L("Indicators enabled: %d"), value))
+ }
+ iSlcMask = KSLC_No3WayCalling;
+ break;
+ }
+ case EATBRSF:
+ {
+ TRACE_ASSERT(aCmd.ParamNum() == 1, KErrArgument);
+ TATParam param = TATParam();
+ LEAVE_IF_ERROR(aCmd.Parameter(0, param))
+ TInt value;
+ LEAVE_IF_ERROR(param.Int(value))
+ iProtocolStatus->iAccSupportedFeature = value;
+ code = CATResult::NewL(EATBRSF, EATWriteResult,
+ TATParam(iProtocolStatus->iAGSupportedFeature));
+ break;
+ }
+ case EATCCWA:
+ {
+ TRACE_ASSERT(aCmd.ParamNum() == 1, KErrArgument);
+ TATParam param = TATParam();
+ LEAVE_IF_ERROR(aCmd.Parameter(0, param))
+ TInt value;
+ LEAVE_IF_ERROR(param.Int(value))
+ iProtocolStatus->iCallWaitingNotif = (TBTMonoATCallWaitingNotif)value;
+ break;
+ }
+ case EATCLIP:
+ {
+ TRACE_ASSERT(aCmd.ParamNum() == 1, KErrArgument);
+ TATParam param = TATParam();
+ LEAVE_IF_ERROR(aCmd.Parameter(0, param))
+ TInt value;
+ LEAVE_IF_ERROR(param.Int(value))
+ iProtocolStatus->iCallerIdNotif = (TBTMonoATCallerIdNotif) value ;
+ break;
+ }
+ case EATVGS:
+ {
+ TRACE_ASSERT(aCmd.ParamNum() == 1, KErrArgument);
+ TATParam param = TATParam();
+ LEAVE_IF_ERROR(aCmd.Parameter(0, param))
+ TInt value;
+ LEAVE_IF_ERROR(param.Int(value))
+ if (!iPhoneStatus)
+ {
+ iPhoneStatus = CBtmcPhoneStatus::NewL(*this, iPhone, iProtocolStatus->iProfile);
+ iPhoneStatus->SetVolumeControlFeatureL(ETrue);
+ }
+ if(iVolumeSyncFromAccessory)
+ {
+ iPhoneStatus->SetSpeakerVolumeL(value);
+ }
+ break;
+ }
+ case EATVGM:
+ {
+ TRACE_ASSERT(aCmd.ParamNum() == 1, KErrArgument);
+ TATParam param = TATParam();
+ LEAVE_IF_ERROR(aCmd.Parameter(0, param))
+ TInt value;
+ LEAVE_IF_ERROR(param.Int(value))
+ break;
+ }
+ case EATCMEE:
+ {
+ TRACE_ASSERT(aCmd.ParamNum() == 1, KErrArgument);
+ TATParam param = TATParam();
+ LEAVE_IF_ERROR(aCmd.Parameter(0, param))
+ TInt value;
+ LEAVE_IF_ERROR(param.Int(value))
+ iProtocolStatus->iAdvancedErrorCode = value;
+ break;
+ }
+ case EATCOPS:
+ {
+ break;
+ }
+ case EATBIA:
+ {
+ for(TInt i=0; i<aCmd.ParamNum(); i++)
+ {
+ TATParam param = TATParam();
+ aCmd.Parameter(i, param);
+ if(param.Type() == EATNullParam)
+ continue;
+ else
+ {
+ TInt value;
+ param.Int(value);
+ SetIndicatorL(i+1, value);
+ }
+ }
+ break;
+ }
+ case EATCREG:
+ {
+ TRACE_ASSERT(aCmd.ParamNum() == 1, KErrArgument);
+ TATParam param = TATParam();
+ LEAVE_IF_ERROR(aCmd.Parameter(0, param))
+ TInt value;
+ LEAVE_IF_ERROR(param.Int(value))
+ iProtocolStatus->iNetworkRegStatusNotif = TBool(value);
+ break;
+ }
+ case EATCOLP:
+ {
+ TRACE_ASSERT(aCmd.ParamNum() == 1, KErrArgument);
+ TATParam param = TATParam();
+ LEAVE_IF_ERROR(aCmd.Parameter(0, param))
+ TInt value;
+ LEAVE_IF_ERROR(param.Int(value))
+ iProtocolStatus->iOutgoingCallNotif = TBool(value);
+ break;
+ }
+ default:
+ LEAVE(KErrNotSupported);
+ }
+
+ if (code)
+ {
+ CleanupStack::PushL(code);
+ resarr.AppendL(code);
+ CleanupStack::Pop(code);
+ }
+ CATResult* ok = CATResult::NewL(EATOK);
+ CleanupStack::PushL(ok);
+ resarr.AppendL(ok);
+ CleanupStack::Pop(ok);
+ SendResponseL(resarr);
+ CleanupStack::PopAndDestroy(&resarr);
+
+ // solution to volume sync - phone will always send its volume status back to accessory
+
+ if( (aCmd.Id() == EATVGS) && (iVolumeSyncFromAccessory == EFalse) )
+ {
+ iVolumeSyncFromAccessory = ETrue;
+ TInt vol(KErrNotFound);
+
+ if(iPhoneStatus)
+ {
+ vol = iPhoneStatus->GetVolumeStatus();
+ }
+
+ if(vol > KErrNotFound) // volume exists
+ {
+ TATParam param = TATParam();
+ LEAVE_IF_ERROR(aCmd.Parameter(0, param))
+ TInt value;
+ LEAVE_IF_ERROR(param.Int(value))
+ if(value != vol)
+ {
+ CATResult* event = CATResult::NewLC(EATVGS, EATUnsolicitedResult, vol);
+ SendUnsoltResultL(*event);
+ CleanupStack::PopAndDestroy(event);
+ }
+ }
+ }
+ CmdHandlingCompletedL();
+ }
+
+
+// -----------------------------------------------------------------------------
+// CBtmcProtocol::HandleActionCommandL
+//
+// Action Command handled by this method:
+// CLCC CNUM
+// -----------------------------------------------------------------------------
+//
+void CBtmcProtocol::HandleActionCommandL(const CATCommand& aCmd)
+ {
+ TRACE_FUNC
+
+ switch (aCmd.Id())
+ {
+ case EATCNUM:
+ {
+ iNumber = CBtmcNumber::NewL(*this, *this, CActive::EPriorityStandard, KServiceGetSubscriber);
+ iNumber->GoActive();
+ break;
+ }
+ case EATCLCC:
+ {
+ iCallStatus->HandleClccL();
+ break;
+ }
+ case EATCGSN:
+ {
+ CATResult* code = NULL;
+ RArray<TATParam> params;
+ CleanupClosePushL(params);
+ TBuf8<RMobilePhone::KPhoneSerialNumberSize> buf;
+ buf.Copy(iIdentity.iSerialNumber);
+ LEAVE_IF_ERROR(params.Append(TATParam(buf)))
+ code = CATResult::NewL(EATCGSN, EATActionResult, ¶ms);
+ CleanupStack::PopAndDestroy(¶ms);
+ RATResultPtrArray resarr;
+ ATObjArrayCleanupResetAndDestroyPushL(resarr);
+ CleanupStack::PushL(code);
+ resarr.AppendL(code);
+ CleanupStack::Pop(code);
+ CATResult* ok = CATResult::NewL(EATOK);
+ CleanupStack::PushL(ok);
+ resarr.AppendL(ok);
+ CleanupStack::Pop(ok);
+ SendResponseL(resarr);
+ CleanupStack::PopAndDestroy(&resarr);
+ CmdHandlingCompletedL();
+ break;
+ }
+ default:
+ LEAVE(KErrNotSupported);
+ }
+ }
+
+void CBtmcProtocol::DoSendProtocolDataL()
+ {
+ TRACE_INFO((_L("credit %d"), iCredit))
+ TInt count = iOutgoPacketQueue->MdcaCount();
+ for (TInt i = 0; iCredit >0 && i < count; i++)
+ {
+ iCredit--;
+ TBuf8<KMaxATSize> buf;
+ buf.Copy(iOutgoPacketQueue->MdcaPoint(0));
+ iObserver.SendProtocolDataL(buf);
+ iOutgoPacketQueue->Delete(0);
+ }
+ }
+
+void CBtmcProtocol::StartTimerL(TInt aService, TInt aTimeout)
+ {
+ if (!iTimerActive)
+ {
+ TRACE_FUNC_ENTRY
+ iTimerActive = CBtmcActive::NewL(*this, CActive::EPriorityStandard, aService);
+ iTimer.CreateLocal();
+ iTimer.After(iTimerActive->iStatus, aTimeout);
+ iTimerActive->GoActive();
+ TRACE_FUNC_EXIT
+ }
+ else
+ {
+ TRACE_WARNING(_L("WARNING, timer is active already"))
+ }
+ }
+
+void CBtmcProtocol::StopTimer(TInt aService)
+ {
+ if (iTimerActive && iTimerActive->ServiceId() == aService)
+ {
+ TRACE_FUNC_ENTRY
+ delete iTimerActive;
+ iTimerActive = NULL;
+ iTimer.Close();
+ TRACE_FUNC_EXIT
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CBtmcProtocol::IsServiceLevelEstablished
+// -----------------------------------------------------------------------------
+//
+TBool CBtmcProtocol::ServiceLevelConnected() const
+ {
+ TRACE_FUNC
+ TRACE_INFO((_L("SLC 0x%02x"), iSlcMask))
+ if ((iProtocolStatus->iAccSupportedFeature & 0x02) &&
+ (iProtocolStatus->iAGSupportedFeature & 0x01) &&
+ (iSlcMask == KSLC_3WayCalling))
+ {
+ return ETrue;
+ }
+ if ((!(iProtocolStatus->iAccSupportedFeature & 0x02) ||
+ !(iProtocolStatus->iAGSupportedFeature & 0x01)) &&
+ (iSlcMask == KSLC_No3WayCalling))
+ {
+ return ETrue;
+ }
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CBtmcProtocol::ServiceAttributeSearchComplete
+// -----------------------------------------------------------------------------
+//
+void CBtmcProtocol::ServiceAttributeSearchComplete( TSdpServRecordHandle /*aHandle*/,
+ const RSdpResultArray& aAttr,
+ TInt aErr )
+ {
+ TRACE_FUNC
+ if((aErr == KErrNone || aErr == KErrEof) && aAttr.Count() && aAttr[0].iAttrValue.iValNumeric)
+ {
+ TRACE_INFO((_L("Remote volume control supported")))
+ TInt err = KErrNone;
+ if (!iPhoneStatus)
+ {
+ TRAP(err, iPhoneStatus = CBtmcPhoneStatus::NewL(*this, iPhone, iProtocolStatus->iProfile));
+ }
+
+ if (err == KErrNone)
+ {
+ TRAP_IGNORE(iPhoneStatus->SetVolumeControlFeatureL(ETrue));
+ iPhoneStatus->ActivateRemoteVolumeControl();
+ }
+ }
+
+ if(aErr)
+ {
+ delete iBteng;
+ iBteng = NULL;
+ }
+ }
+
+void CBtmcProtocol::SetIndicatorL(TInt aIndicator, TInt aValue)
+ {
+ TInt indBit( 0 );
+ switch(aIndicator)
+ {
+ case EBTMonoATNetworkIndicator:
+ indBit = KIndServiceBit;
+ break;
+ case EBTMonoATCallIndicator:
+ case EBTMonoATCallSetupIndicator:
+ case EBTMonoATCall_SetupIndicator:
+ case EBTMonoATCallHeldIndicator:
+ // call, call setup, call held indicators are mandatory.
+ break;
+ case EBTMonoATSignalStrengthIndicator:
+ indBit = KIndSignalBit;
+ break;
+ case EBTMonoATRoamingIndicator:
+ indBit = KIndRoamBit;
+ break;
+ case EBTMonoATBatteryChargeIndicator:
+ indBit = KIndChargeBit;
+ break;
+ default:
+ LEAVE(KErrArgument)
+ }
+ if ( indBit )
+ {
+ if ( aValue )
+ {
+ iProtocolStatus->iIndicatorNotif |= indBit;
+ }
+ else
+ {
+ iProtocolStatus->iIndicatorNotif &= ~indBit;
+ }
+ }
+ }
+void CBtmcProtocol::UnsolicitedResultFromATExtL(TInt aErr, const TDesC8& aAT)
+ {
+ TRACE_FUNC
+ if(aErr)
+ {
+ delete iAtExt;
+ iAtExt = NULL;
+ }
+ else
+ {
+ iOutgoPacketQueue->AppendL(aAT);
+ if (!iCallingHandler->ActiveCmdHandling() && !iHandleCmdPending)
+ {
+ iCredit++;
+ }
+ DoSendProtocolDataL();
+ }
+ }
+
+void CBtmcProtocol::ATExtHandleCommandCompletedL(TInt aErr, const TDesC8& aReply)
+ {
+ TRACE_FUNC
+ if(aErr)
+ {
+ CATResult* nok = CATResult::NewLC(EATERROR);
+ SendResponseL(*nok);
+ CleanupStack::PopAndDestroy(nok);
+ }
+ else
+ {
+ iOutgoPacketQueue->AppendL(aReply);
+ if (!iCallingHandler->ActiveCmdHandling() && !iHandleCmdPending)
+ {
+ iCredit++;
+ }
+ DoSendProtocolDataL();
+ }
+ }
+
+
+// End of file