--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/telephonyserverplugins/simtsy/src/CSimDtmf.cpp Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,492 @@
+// Copyright (c) 2001-2009 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:
+// Implements the functionality required to provide DMTF transmission services.
+//
+//
+
+/**
+ @file
+*/
+
+#include <testconfigfileparser.h>
+#include "CSimDtmf.h"
+#include "CSimPhone.h"
+#include "CSimVoiceCall.h"
+#include "Simlog.h"
+
+const TInt KPauseDuration=2; //< The duration of a "pause" DTMF character.
+const TInt KDtmfToneDuration=3; //< The duration of a standard DTMF character (tone or "pause").
+
+CSimDtmf* CSimDtmf::NewL(CSimPhone* aPhone)
+/**
+ * Standard two-phase constructor.
+ * @param aPhone The parent phone object.
+ * @return CSimDtmf The new signal strength class.
+ */
+ {
+ CSimDtmf* self=new(ELeave) CSimDtmf(aPhone);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+CSimDtmf::CSimDtmf(CSimPhone* aPhone)
+ : iPhone(aPhone)
+/**
+ * Trivial first phase construction.
+ * @param aPhone The parent phone object.
+ */
+ {
+ }
+
+void CSimDtmf::ConstructL()
+/**
+ * Second phase construction. Create instances of the necessary heap-based
+ * objects and read in the DTMF information from the configuration file.
+ *
+ * Entries in the configuration file will take the following format:
+ * "XXX= <Yyy>, <Zzz>"
+ * A number of these entries may be included to create a signal strength profile
+ * for the duration of the test.
+ */
+ {
+ iTimer=CSimTimer::NewL(iPhone);
+ }
+
+CSimDtmf::~CSimDtmf()
+/**
+ * Standard destructor. Destroy the heap-based object owned by this object.
+ */
+ {
+ delete iDtmfData;
+ delete iTimer;
+ }
+
+TInt CSimDtmf::GetDtmfCaps(TTsyReqHandle aReqHandle,TDes8* aPckg1)
+/**
+ * Retrieve DMTF capability information. This function completes the
+ * client's request synchronously.
+ *
+ * @param aReqHandle The request handle associated with this request.
+ * @param aPckg1 The first parameter package. This will be populated with the
+ * capability data to be returned.
+ * @return TInt Standard error value.
+ */
+ {
+ TPckg<TUint32>* dtmfCapsPckg=(TPckg<TUint32>*)aPckg1;
+ TUint32& dtmfCaps=(*dtmfCapsPckg)();
+
+ dtmfCaps= RMobilePhone::KCapsSendDTMFString |
+ RMobilePhone::KCapsSendDTMFSingleTone;
+ iPhone->ReqCompleted(aReqHandle,KErrNone);
+ return KErrNone;
+ }
+
+TInt CSimDtmf::NotifyDtmfCapsChange(TTsyReqHandle /*aReqHandle*/,TDes8* /*aPckg1*/)
+/**
+ * Register a client's interest in being notified when the DMTF Caps change.
+ * Since the capabilities remain static, this request is not completed.
+ *
+ * @param aReqHandle The handle associated with this request.
+ * @param aPckg1 The first parameter package. This is populated with the changed
+ * capability information.
+ * @return TInt Standard error value.
+ */
+ {
+ return KErrNone;
+ }
+
+void CSimDtmf::NotifyDtmfCapsChangeCancel(TTsyReqHandle aReqHandle)
+/**
+ * Cancel a previous request to be notified of a change in DTMF capabilities.
+ */
+ {
+ iPhone->ReqCompleted(aReqHandle,KErrCancel);
+ }
+
+TInt CSimDtmf::SendDTMFTones(TTsyReqHandle aReqHandle,TDes* aPckg1)
+/**
+ * Send a series of DMTF tones.
+ *
+ * @param aReqHandle The request handle associated with this request.
+ * @param aPckg1 The first parameter package. This will be populated with the
+ * DTMF tone data to be sent.
+ * @return TInt Standard error value.
+ */
+ {
+ TInt ret=SetDtmfCall();
+ if(ret!=KErrNone)
+ {
+ iPhone->ReqCompleted(aReqHandle,KErrEtelCallNotActive);
+ return KErrNone;
+ }
+
+ if(aPckg1->Length()==0)
+ {
+ iPhone->ReqCompleted(aReqHandle,KErrNone);
+ return KErrNone;
+ }
+
+ iDtmfData=HBufC::New(aPckg1->Length());
+ if(iDtmfData==NULL)
+ {
+ iPhone->ReqCompleted(aReqHandle,KErrNoMemory);
+ return KErrNone;
+ }
+ iDtmfData->Des().Copy(*aPckg1);
+
+ iDtmfString=ETrue;
+ iDtmfStringIndex=0;
+ iDtmfStringReqPending=aReqHandle;
+ ret=ActionEvent(EEventStartDtmfString,(*iDtmfData)[iDtmfStringIndex]);
+ if(ret!=KErrNone)
+ {
+ CompleteDtmfStringTx(ret);
+ }
+ return KErrNone;
+ }
+
+TInt CSimDtmf::StartDTMFTone(TTsyReqHandle aReqHandle,TDes8* aPckg1)
+/**
+ * Send a single DMTF tone.
+ *
+ * @param aReqHandle The request handle associated with this request.
+ * @param aPckg1 The first parameter package. This will be populated with the
+ * DTMF tone to be sent.
+ * @return TInt Standard error value.
+ */
+ {
+ TInt ret=SetDtmfCall();
+ if(ret!=KErrNone)
+ {
+ iPhone->ReqCompleted(aReqHandle,KErrEtelCallNotActive);
+ return KErrNone;
+ }
+
+ TPckg<TChar>* tonePckg=(TPckg<TChar>*)aPckg1;
+ TChar& tone=(*tonePckg)();
+
+ ret=ActionEvent(EEventStartDtmfTone,tone);
+ iPhone->ReqCompleted(aReqHandle,ret);
+ return KErrNone;
+ }
+
+TInt CSimDtmf::StopDTMFTone(TTsyReqHandle aReqHandle)
+/**
+ * Stop transmission of a single DMTF tone.
+ *
+ * @param aReqHandle The request handle associated with this request.
+ * @return TInt Standard error value.
+ */
+ {
+ __ASSERT_ALWAYS(CheckForActiveVoiceCall(),SimPanic(EIllegalDtmfReq));
+ TInt ret=ActionEvent(EEventStopDtmfTone);
+ iPhone->ReqCompleted(aReqHandle,ret);
+ return KErrNone;
+ }
+
+TInt CSimDtmf::NotifyStopInDTMFString(TTsyReqHandle aReqHandle)
+/**
+ * Register a client's interest in being notified of when a stop tone is reached.
+ * @param aReqHandle The request handle associated with this request.
+ * @return TInt Standard error value.
+ */
+ {
+ __ASSERT_ALWAYS(!iNotifyStopChar,SimPanic(EIllegalDtmfEvent));
+ iNotifyStopChar=ETrue;
+ iNotifyStopReqHandle=aReqHandle;
+ return KErrNone;
+ }
+
+void CSimDtmf::NotifyStopInDTMFStringCancel()
+/**
+ * Cancel a client's interest in being notified of when a stop tone is reach.
+ */
+ {
+ if(iNotifyStopChar)
+ {
+ iNotifyStopChar=EFalse;
+ iPhone->ReqCompleted(iNotifyStopReqHandle,KErrCancel);
+ }
+ }
+
+TInt CSimDtmf::ContinueDtmfStringSending(TTsyReqHandle aReqHandle,TDes8* aPckg1)
+/**
+ * Continue transmitting a DTMF String after a wait character has been hit.
+ * @param aPckg1 The first request package, which contains an indication of
+ * whether the request should be continued.
+ * @param aReqHandle The request handle associated with this request.
+ * @return TInt Standard error value.
+ */
+ {
+ if(!CheckForActiveVoiceCall())
+ {
+ iPhone->ReqCompleted(aReqHandle,KErrNotReady);
+ return KErrNone;
+ }
+
+ TPckg<TBool>* contPckg=(TPckg<TBool>*)aPckg1;
+ TBool& cont=(*contPckg)();
+
+ if(cont)
+ {
+ TInt ret=ActionEvent(EEventContinueDtmf);
+ iPhone->ReqCompleted(aReqHandle,ret);
+ }
+ else
+ {
+ TInt ret=ActionEvent(EEventTerminateDtmf);
+ iPhone->ReqCompleted(aReqHandle,ret);
+ }
+ return KErrNone;
+ }
+
+TInt CSimDtmf::ActionEvent(TEvent aEvent)
+/**
+ * Shell function for events that don't pass a DTMF tone character.
+ * @param aEvent The event to be actioned.
+ * @return TInt Standard error return.
+ */
+ {
+ const TChar KNullChar(0);
+ return ActionEvent(aEvent,KNullChar);
+ }
+
+TInt CSimDtmf::ActionEvent(TEvent aEvent,const TChar& aTone)
+/**
+ * Action a DTMF event.
+ * @param aEvent The event to be actioned.
+ * @param aTone Optionally, a tone associated with the event.
+ * @return TInt Standard error return.
+ */
+ {
+ TInt ret = KErrNone;
+ switch(aEvent)
+ {
+ case EEventStartDtmfString:
+ if(iState==ETxTone)
+ return KErrInUse;
+ ret = ProcessTone(aTone,ETrue);
+ return ret;
+
+ case EEventStartDtmfTone:
+ if(iState==ETxTone)
+ return KErrInUse;
+ ret = ProcessTone(aTone,EFalse);
+ return ret;
+
+ case EEventTimer:
+ __ASSERT_ALWAYS(iState==ETxTone,SimPanic(EIllegalDtmfEvent));
+ __ASSERT_ALWAYS(iDtmfString,SimPanic(EIllegalDtmfEvent));
+ LOGMISC1("Completed sending DTMF Tone");
+ iDtmfStringIndex++;
+ if(iDtmfStringIndex<iDtmfData->Length())
+ ret = ProcessTone((*iDtmfData)[iDtmfStringIndex],ETrue);
+ else
+ {
+ iState=EIdle;
+ CompleteDtmfStringTx(KErrNone);
+ }
+ return ret;
+
+ case EEventStopDtmfTone:
+ if(iDtmfString)
+ return KErrInUse;
+ if(iState!=ETxTone) // If there's been no StartDtmfTone, then return an error.
+ return KErrUnknown;
+ LOGMISC1("Stopping DTMF Tone");
+ iState=EIdle;
+ return KErrNone;
+
+ case EEventContinueDtmf:
+ if(iState!=EStopped)
+ return KErrUnknown;
+ __ASSERT_ALWAYS(iDtmfString,SimPanic(EIllegalDtmfEvent));
+ LOGMISC1("Continuing Transmitting a DTMF string after a wait");
+ iDtmfStringIndex++;
+ if(iDtmfStringIndex<iDtmfData->Length())
+ ret = ProcessTone((*iDtmfData)[iDtmfStringIndex],ETrue);
+ else
+ {
+ iState=EIdle;
+ CompleteDtmfStringTx(KErrNone);
+ }
+ return ret;
+
+ case EEventTerminateDtmf:
+ if(iState==EStopped)
+ {
+ __ASSERT_ALWAYS(iDtmfString,SimPanic(EIllegalDtmfEvent));
+ iState=EIdle;
+ CompleteDtmfStringTx(KErrAccessDenied);
+ return KErrNone;
+ }
+ else
+ return KErrUnknown;
+ case EEventCallClosure:
+ if(iDtmfString)
+ {
+ iTimer->Cancel();
+ CompleteDtmfStringTx(KErrEtelNoCarrier);
+ }
+ iState=EIdle;
+ return KErrNone;
+ }
+
+ SimPanic(EIllegalDtmfEvent);
+ return KErrNone; // Dummy to stop compiler error.
+ }
+
+/**
+Process a tone, i.e. check the tone's validity and, if necessary, start the timer.
+
+@param aTone The DTMF character to be processed.
+@param aStartTimer A flag indicating whether the timer should be started.
+ The timer is not required for the single DTMF tone transmissions.
+@return TInt Standard error return.
+*/
+TInt CSimDtmf::ProcessTone(const TChar& aTone, TBool aStartTimer)
+ {
+ const TChar wait('w');
+ const TChar pause('p');
+
+ if(aTone==wait)
+ {
+ LOGMISC1("Starting to perform a DTMF wait; character w");
+ iState=EStopped;
+ CheckNotification();
+ return KErrNone;
+ }
+ else if(aTone.IsDigit()||(aTone>='A')&&(aTone<='D'))
+ {
+ LOGMISC2("Starting to send DTMF Tone %c", TUint(aTone));
+ iState=ETxTone;
+ if(aStartTimer)
+ {
+ iTimer->Start(KDtmfToneDuration,this);
+ }
+ return KErrNone;
+ }
+ else if(aTone==pause)
+ {
+ if(!aStartTimer)
+ {
+ return KErrArgument; // can't tx a single "pause" character
+ }
+ LOGMISC1("Starting to perform a DTMF pause; character p");
+ iState=ETxTone;
+ iTimer->Start(KPauseDuration,this);
+ return KErrNone;
+ }
+ return KErrArgument; // Illegal DTMF character.
+ }
+
+void CSimDtmf::CompleteDtmfStringTx(TInt aStatus)
+/**
+ * Complete a DTMF string transmission.
+ * @param aStatus Completion value.
+ */
+ {
+ iDtmfString=EFalse;
+ delete iDtmfData;
+ iDtmfData=NULL;
+ iPhone->ReqCompleted(iDtmfStringReqPending,aStatus);
+ }
+
+void CSimDtmf::CheckNotification()
+/**
+ * If pending, complete a DTMF "wait" command notification.
+ */
+ {
+ if(iNotifyStopChar)
+ {
+ iNotifyStopChar=EFalse;
+ iPhone->ReqCompleted(iNotifyStopReqHandle,KErrNone);
+ }
+ }
+
+TInt CSimDtmf::SetDtmfCall()
+/**
+ * Set a pointer to this class in the active voice call class, so that the call class
+ * can callback if the call becomes inactive.
+ * @return TInt Standard error return.
+ */
+ {
+ CSimVoiceCall* call;
+ TInt ret=iPhone->FindActiveVoiceCall(call);
+ if(ret!=KErrNone)
+ return ret;
+ call->SetDtmfSession(this);
+ return ret;
+ }
+
+TBool CSimDtmf::CheckForActiveVoiceCall()
+/**
+ * Check the active call DTMF pointer is pointing to this class.
+ * @return TBool ETrue if the call's pointer is correctly set. EFalse if not.
+ */
+ {
+ CSimVoiceCall* call;
+ TInt ret=iPhone->FindActiveVoiceCall(call);
+ if(ret!=KErrNone)
+ return EFalse;
+ if(call->GetDtmfSession()==this)
+ return ETrue;
+ return EFalse;
+ }
+
+
+void CSimDtmf::TimerCallBack(TInt /*aId*/)
+/**
+ * The timer callback function. This function will be called when the timer
+ * completes. It indicates a DTMF tone completion. So, the action event function
+ * is called to advance the class' state.
+ *
+ * @param aId This parameter is unused. It is only required for CSimXxx classes
+ * that have more than one timer instance and need to identify which
+ * timer has expired.
+ */
+ {
+ TInt ret=ActionEvent(EEventTimer);
+ __ASSERT_ALWAYS(ret==KErrNone,SimPanic(EIllegalDtmfEvent));
+ }
+
+void CSimDtmf::CallClosureCallback()
+ {
+ TInt ret=ActionEvent(EEventCallClosure);
+ __ASSERT_ALWAYS(ret==KErrNone,SimPanic(EIllegalDtmfEvent));
+ }
+
+const CTestConfigSection* CSimDtmf::CfgFile()
+/**
+ * Returns a pointer to the current configuration file section.
+ *
+ * @return CTestConfigSection A pointer to the current configuration file section.
+ */
+ {
+ return iPhone->CfgFile();
+ }
+
+void CSimDtmf::SendDTMFTonesCancel()
+/**
+Cancels pending SendDTMFTone
+*/
+ {
+ iState=EIdle;
+ if(iTimer->Running())
+ iTimer->Cancel();
+ CompleteDtmfStringTx(KErrCancel);
+
+ }