diff -r 4096754ee773 -r 52a167391590 localconnectivityservice/dun/atext/src/DunAtCmdPusher.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/localconnectivityservice/dun/atext/src/DunAtCmdPusher.cpp Wed Sep 01 12:20:40 2010 +0100 @@ -0,0 +1,521 @@ +/* +* Copyright (c) 2010 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: AT command pusher for downstream +* +*/ + +/* + * Filtering categories for multiple commands on one line (DunAtCmdPusher.cpp) + * (here "OTHER" reply means a reply which is something else than "OK" and "ERROR") + * One reply: OK -> OK + * One reply: OTHER -> OTHER + * One reply: ERROR -> ERROR + * Two replies: OK, OK -> OK + * Two replies: OTHER, OTHER -> OTHER, OTHER + * Two replies: OK, OTHER -> OTHER + * Two replies: OTHER, OK -> OTHER + * Two replies: OK, ERROR -> ERROR + * Two replies: OTHER, ERROR -> OTHER, ERROR + * Note: "OK" replies are skipped. The "OK" string is stripped from the "OTHER" + * replies and manually added the the downstream as the last operation if either + * "OK" or "OTHER" was received before. + */ + +#include "DunAtCmdPusher.h" +#include "DunDownstream.h" +#include "DunDebug.h" + +// --------------------------------------------------------------------------- +// Two-phased constructor. +// --------------------------------------------------------------------------- +// +CDunAtCmdPusher* CDunAtCmdPusher::NewL( + RATExt* aAtCmdExt, + MDunAtCmdPusher* aCallback, + MDunStreamManipulator* aDownstream, + TDesC8* aOkBuffer ) + { + CDunAtCmdPusher* self = NewLC( aAtCmdExt, + aCallback, + aDownstream, + aOkBuffer ); + CleanupStack::Pop( self ); + return self; + } + +// --------------------------------------------------------------------------- +// Two-phased constructor. +// --------------------------------------------------------------------------- +// +CDunAtCmdPusher* CDunAtCmdPusher::NewLC( + RATExt* aAtCmdExt, + MDunAtCmdPusher* aCallback, + MDunStreamManipulator* aDownstream, + TDesC8* aOkBuffer ) + { + CDunAtCmdPusher* self = new (ELeave) CDunAtCmdPusher( aAtCmdExt, + aCallback, + aDownstream, + aOkBuffer ); + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + +// --------------------------------------------------------------------------- +// Destructor. +// --------------------------------------------------------------------------- +// +CDunAtCmdPusher::~CDunAtCmdPusher() + { + FTRACE(FPrint( _L("CDunAtCmdPusher::~CDunAtCmdPusher()") )); + ResetData(); + FTRACE(FPrint( _L("CDunAtCmdPusher::~CDunAtCmdPusher() complete") )); + } + +// --------------------------------------------------------------------------- +// Resets data to initial values +// --------------------------------------------------------------------------- +// +void CDunAtCmdPusher::ResetData() + { + FTRACE(FPrint( _L("CDunAtCmdPusher::ResetData()") )); + // APIs affecting this: + // IssueRequest() + Stop(); + // Internal + Initialize(); + FTRACE(FPrint( _L("CDunAtCmdPusher::ResetData() complete") )); + } + +// --------------------------------------------------------------------------- +// Starts AT command handling +// --------------------------------------------------------------------------- +// +TInt CDunAtCmdPusher::IssueRequest( TDesC8& aInput, TBool aNormalMode ) + { + FTRACE(FPrint( _L("CDunAtCmdPusher::IssueRequest()") )); + FTRACE(FPrint( _L("CDunAtCmdPusher::IssueRequest() send ATEXT:") )); + FTRACE(FPrintRaw(aInput) ); + if ( iAtPushState!=EDunStateIdle && aNormalMode ) + { + FTRACE(FPrint( _L("CDunAtCmdPusher::IssueRequest() (not ready) complete") )); + return KErrNotReady; + } + if ( iDownstream->IsDataInQueue(&iRecvBuffer) ) + { + FTRACE(FPrint( _L("CDunAtCmdPusher::IssueRequest() (in queue!) complete") )); + return KErrGeneral; + } + iStatus = KRequestPending; + iAtCmdExt->HandleCommand( iStatus, + aInput, + iRecvBuffer, + iReplyLeftPckg, + iReplyTypePckg ); + SetActive(); + iAtPushState = EDunStateAtCmdPushing; + FTRACE(FPrint( _L("CDunAtCmdPusher::IssueRequest() complete") )); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// Stops AT command handling +// --------------------------------------------------------------------------- +// +TInt CDunAtCmdPusher::Stop() + { + FTRACE(FPrint( _L("CDunAtCmdPusher::Stop()") )); + SetEndOfCmdLine(); + if ( iAtPushState != EDunStateAtCmdPushing ) + { + FTRACE(FPrint( _L("CDunAtCmdHandler::Stop() (not ready) complete" ))); + return KErrNotReady; + } + // As the EDunStateAtCmdHandling can be set even when the actual request + // has completed (when replying with NotifyDataPushComplete() and setting + // idle eventually), cancel the actual operation in DoCancel() + Cancel(); + iAtPushState = EDunStateIdle; + FTRACE(FPrint( _L("CDunAtCmdPusher::Stop() complete") )); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// Manages request to abort command handling +// --------------------------------------------------------------------------- +// +TInt CDunAtCmdPusher::ManageAbortRequest() + { + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageAbortRequest()") )); + if ( iAtPushState != EDunStateAtCmdPushing ) + { + FTRACE(FPrint( _L("CDunAtCmdHandler::ManageAbortRequest() (not ready) complete" ))); + return KErrNotReady; + } + if ( iCmdAbort ) + { + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageAbortRequest() (already exists) complete") )); + return KErrAlreadyExists; + } + TInt retTemp = iAtCmdExt->ReportHandleCommandAbort( iStop ); + if ( retTemp != KErrNone ) + { + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageAbortRequest() (ERROR) complete") )); + return retTemp; + } + iCmdAbort = ETrue; + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageAbortRequest() complete") )); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// Sets end of command line marker on for the possible series of AT commands. +// --------------------------------------------------------------------------- +// +void CDunAtCmdPusher::SetEndOfCmdLine() + { + FTRACE(FPrint( _L("CDunAtCmdPusher::SetEndOfCmdLine()") )); + iNoErrorReceived = EFalse; + iLastOkPush = EFalse; + iCmdAbort = EFalse; + iStop = EFalse; + iEditorMode = EFalse; + FTRACE(FPrint( _L("CDunAtCmdPusher::SetEndOfCmdLine() complete") )); + } + +// --------------------------------------------------------------------------- +// Gets the editor mode status +// --------------------------------------------------------------------------- +// +TBool CDunAtCmdPusher::EditorMode() + { + FTRACE(FPrint( _L("CDunAtCmdPusher::EditorMode()") )); + FTRACE(FPrint( _L("CDunAtCmdPusher::EditorMode() complete") )); + return iEditorMode; + } + +// --------------------------------------------------------------------------- +// CDunAtCmdPusher::CDunAtCmdPusher +// --------------------------------------------------------------------------- +// +CDunAtCmdPusher::CDunAtCmdPusher( RATExt* aAtCmdExt, + MDunAtCmdPusher* aCallback, + MDunStreamManipulator* aDownstream, + TDesC8* aOkBuffer ) : + CActive( EPriorityHigh ), + iAtCmdExt( aAtCmdExt ), + iCallback( aCallback ), + iDownstream( aDownstream ), + iOkBuffer( aOkBuffer ), + iReplyLeftPckg( iReplyBytesLeft ), + iReplyTypePckg( iReplyType ) + { + Initialize(); + } + +// --------------------------------------------------------------------------- +// CDunAtCmdPusher::ConstructL +// --------------------------------------------------------------------------- +// +void CDunAtCmdPusher::ConstructL() + { + FTRACE(FPrint( _L("CDunAtCmdPusher::ConstructL()") )); + if ( !iAtCmdExt || !iCallback || !iDownstream || !iOkBuffer ) + { + User::Leave( KErrGeneral ); + } + CActiveScheduler::Add( this ); + FTRACE(FPrint( _L("CDunAtCmdPusher::ConstructL() complete") )); + } + +// --------------------------------------------------------------------------- +// Initializes this class +// --------------------------------------------------------------------------- +// +void CDunAtCmdPusher::Initialize() + { + // Don't initialize iAtCmdExt here (it is set through NewL) + // Don't initialize iCallback here (it is set through NewL) + // Don't initialize iDownstream here (it is set through NewL) + // Don't initialize iOkBuffer here (it is set through NewL) + iAtPushState = EDunStateIdle; + iReplyBytesLeft = 0; + iReplyType = EReplyTypeUndefined; + SetEndOfCmdLine(); + } + +// --------------------------------------------------------------------------- +// Sets state to idle and notifies about subcommand handling completion +// --------------------------------------------------------------------------- +// +void CDunAtCmdPusher::SetToIdleAndNotifyEnd( TInt aError ) + { + FTRACE(FPrint( _L("CDunAtCmdPusher::SetToIdleAndNotifyEnd()") )); + iCmdAbort = EFalse; + iAtPushState = EDunStateIdle; + iCallback->NotifyEndOfProcessing( aError ); + FTRACE(FPrint( _L("CDunAtCmdPusher::SetToIdleAndNotifyEnd() complete") )); + } + +// --------------------------------------------------------------------------- +// Checks if "OK" (verbose) or "0" (numeric) string or exists at the end of +// buffer and removes it +// --------------------------------------------------------------------------- +// +TInt CDunAtCmdPusher::CheckAndRemoveOkString() + { + FTRACE(FPrint( _L("CDunAtCmdPusher::CheckAndRemoveOkString()") )); + TInt recvBufferLength = iRecvBuffer.Length(); + TInt okBufferLength = iOkBuffer->Length(); + // Skip the removal if removing not possible, if removal results in zero + // length (plugin should have used KErrReplyTypeOk) or if string to be + // removed is zero. + // Note also that if plugin sends a final reply when quiet mode is on, DUN + // can't remove the possibly existing result code as it is different from + // iOkReply (zero length). + if ( recvBufferLength<=okBufferLength || okBufferLength<=0 ) + { + FTRACE(FPrint( _L("CDunAtCmdPusher::CheckAndRemoveOkString() (skip) complete") )); + return KErrGeneral; + } + TInt lengthWithNoOk = recvBufferLength - okBufferLength; + TPtr8 recvBufferDes( &iRecvBuffer[lengthWithNoOk], okBufferLength, okBufferLength ); + if ( recvBufferDes.Compare(*iOkBuffer) != 0 ) + { + FTRACE(FPrint( _L("CDunAtCmdPusher::CheckAndRemoveOkString() (not found) complete") )); + return KErrNotFound; + } + iRecvBuffer.SetLength( lengthWithNoOk ); + FTRACE(FPrint( _L("CDunAtCmdPusher::CheckAndRemoveOkString() complete") )); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// Sends reply data to downstream +// --------------------------------------------------------------------------- +// +void CDunAtCmdPusher::SendReplyData( TBool aRecvBuffer ) + { + FTRACE(FPrint( _L("CDunAtCmdPusher::SendReplyData()") )); + TDesC8* sendBuffer = iOkBuffer; + if ( aRecvBuffer ) + { + sendBuffer = &iRecvBuffer; + // Check if last block of long push and remove "OK" if exists + if ( iReplyType==EReplyTypeOther && iReplyBytesLeft==0 ) + { + CheckAndRemoveOkString(); + } + } + FTRACE(FPrint( _L("CDunAtCmdPusher::SendReplyData() send reply:") )); + FTRACE(FPrintRaw(*sendBuffer) ); + iDownstream->NotifyDataPushRequest( sendBuffer, this ); + FTRACE(FPrint( _L("CDunAtCmdPusher::SendReplyData() complete") )); + } + +// --------------------------------------------------------------------------- +// Manages change in reply type to EReplyTypeOther +// --------------------------------------------------------------------------- +// +void CDunAtCmdPusher::ManageReplyTypeChangeToOther() + { + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChangeToOther()") )); + iNoErrorReceived = ETrue; + SendReplyData(); + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChangeToOther() complete") )); + } + +// --------------------------------------------------------------------------- +// Manages change in reply type to EReplyTypeOk +// --------------------------------------------------------------------------- +// +void CDunAtCmdPusher::ManageReplyTypeChangeToOk() + { + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChangeToOk()") )); + // Skip the "OK" replies if not last. Only push the "OK" reply at the end. + // iStop changes it so that the we have to send the "OK" immediately and + // only stop with NotifyDataPushComplete() + TBool found = iCallback->NotifyNextCommandPeekRequest(); + if ( !found || iStop ) + { + SendReplyData(); + } + else + { + iNoErrorReceived = ETrue; + SetToIdleAndNotifyEnd( KErrNone ); + } + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChangeToOk() complete") )); + } + +// --------------------------------------------------------------------------- +// Manages change in reply type to EReplyTypeError +// --------------------------------------------------------------------------- +// +void CDunAtCmdPusher::ManageReplyTypeChangeToError() + { + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChangeToError()") )); + if ( iNoErrorReceived ) + { + iAtCmdExt->ReportExternalHandleCommandError(); + } + SendReplyData(); + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChangeToError() complete") )); + } + +// --------------------------------------------------------------------------- +// Manages change in reply type to EReplyTypeEditor +// --------------------------------------------------------------------------- +// +void CDunAtCmdPusher::ManageReplyTypeChangeToEditor() + { + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChangeToEditor()") )); + if ( !iEditorMode ) + { + // First change to editor mode: manage it as EReplyTypeOther (prompt) + iEditorMode = ETrue; + ManageReplyTypeChangeToOther(); + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChangeToEditor() (editor) complete") )); + return; + } + // The same reply to editor mode as before: no reply, only notification for + // echo/forwarding purposes + iCallback->NotifyEditorModeReply(); + // Do nothing after notifying. The next ForwardEditorModeInput() triggers + // the next call of this function. + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChangeToEditor() complete") )); + } + +// --------------------------------------------------------------------------- +// Manages change in reply type +// --------------------------------------------------------------------------- +// +void CDunAtCmdPusher::ManageReplyTypeChange() + { + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChange()") )); + switch ( iReplyType ) + { + case EReplyTypeOther: + { + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChange() EReplyTypeOther") )); + iEditorMode = EFalse; + ManageReplyTypeChangeToOther(); + } + break; + case EReplyTypeOk: + { + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChange() EReplyTypeOk") )); + iEditorMode = EFalse; + ManageReplyTypeChangeToOk(); + } + break; + case EReplyTypeError: + { + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChange() EReplyTypeError") )); + iEditorMode = EFalse; + ManageReplyTypeChangeToError(); + } + break; + case EReplyTypeEditor: + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChange() EReplyTypeEditor") )); + ManageReplyTypeChangeToEditor(); + break; + default: + { + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChange() EReplyTypeUndefined") )); + iEditorMode = EFalse; + SetToIdleAndNotifyEnd( KErrNone ); + } + break; + } + FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChange() complete") )); + } + +// --------------------------------------------------------------------------- +// From class CActive. +// Gets called when AT command handled +// --------------------------------------------------------------------------- +// +void CDunAtCmdPusher::RunL() + { + FTRACE(FPrint( _L("CDunAtCmdPusher::RunL()") )); + TInt retTemp = iStatus.Int(); + if ( retTemp != KErrNone ) + { + SetToIdleAndNotifyEnd( retTemp ); + FTRACE(FPrint( _L("CDunAtCmdPusher::RunL() (ERROR) complete (%d)"), retTemp)); + return; + } + ManageReplyTypeChange(); + FTRACE(FPrint( _L("CDunAtCmdPusher::RunL() complete") )); + } + +// --------------------------------------------------------------------------- +// From class CActive. +// Gets called on cancel +// --------------------------------------------------------------------------- +// +void CDunAtCmdPusher::DoCancel() + { + FTRACE(FPrint( _L("CDunAtCmdPusher::DoCancel()") )); + iAtCmdExt->CancelHandleCommand(); + FTRACE(FPrint( _L("CDunAtCmdPusher::DoCancel() complete") )); + } + +// --------------------------------------------------------------------------- +// From class MDunCompletionReporter. +// Gets called when data push is complete +// --------------------------------------------------------------------------- +// +void CDunAtCmdPusher::NotifyDataPushComplete( TBool /*aAllPushed*/ ) + { + FTRACE(FPrint( _L("CDunAtCmdPusher::NotifyDataPushComplete()") )); + // First check if error or stop condition detected + if ( iReplyType==EReplyTypeError || iStop ) + { + SetEndOfCmdLine(); + iAtPushState = EDunStateIdle; + iCallback->NotifyEndOfCmdLineProcessing(); + FTRACE(FPrint( _L("CDunAtCmdPusher::NotifyDataPushComplete() (error reply) complete") )); + return; + } + // Secondly check only the case where push restart is required + if ( iReplyType==EReplyTypeOther && iReplyBytesLeft>0 ) + { + iAtCmdExt->GetNextPartOfReply( iRecvBuffer, iReplyBytesLeft ); + SendReplyData(); + FTRACE(FPrint( _L("CDunAtCmdPusher::NotifyDataPushComplete() (push restart) complete") )); + return; + } + // Next check the case where other than "OK" and "ERROR" reply is received + // and that is the last one in the command line. Then just send "OK". + if ( !iLastOkPush && iReplyType==EReplyTypeOther ) + { + TBool found = iCallback->NotifyNextCommandPeekRequest(); + if ( !found ) + { + // Force iReplyType here to match the correct one in NotifyDataPushComplete() + iReplyType = EReplyTypeOk; + iLastOkPush = ETrue; + SendReplyData( EFalse ); + FTRACE(FPrint( _L("CDunAtCmdPusher::NotifyDataPushComplete() (last OK) complete") )); + return; + } + // Now the next command was found so just fall through + } + // As a last step just set to idle + SetToIdleAndNotifyEnd( KErrNone ); + FTRACE(FPrint( _L("CDunAtCmdPusher::NotifyDataPushComplete() complete") )); + }