--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/localconnectivityservice/dun/atext/src/DunAtCmdPusher.cpp Mon Jan 18 21:03:15 2010 +0200
@@ -0,0 +1,429 @@
+/*
+* Copyright (c) 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: 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& aCommand )
+ {
+ FTRACE(FPrint( _L("CDunAtCmdPusher::IssueRequest()") ));
+ FTRACE(FPrint( _L("CDunAtCmdPusher::IssueRequest() send ATEXT:") ));
+ FTRACE(FPrintRaw(aCommand) );
+ if ( iAtPushState != EDunStateIdle )
+ {
+ FTRACE(FPrint( _L("CDunAtCmdPusher::IssueRequest() (not ready) complete") ));
+ return KErrNotReady;
+ }
+ iStatus = KRequestPending;
+ iAtCmdExt->HandleCommand( iStatus,
+ aCommand,
+ 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()") ));
+ 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;
+ SetEndOfCmdLine();
+ 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;
+ FTRACE(FPrint( _L("CDunAtCmdPusher::SetEndOfCmdLine() complete") ));
+ }
+
+// ---------------------------------------------------------------------------
+// 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();
+ if ( recvBufferLength <= okBufferLength )
+ {
+ FTRACE(FPrint( _L("CDunAtCmdPusher::CheckAndRemoveOkString() (ERROR) 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 = &iRecvBuffer;
+ if ( !aRecvBuffer )
+ {
+ sendBuffer = iOkBuffer;
+ }
+ 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
+// ---------------------------------------------------------------------------
+//
+void CDunAtCmdPusher::ManageReplyTypeChange()
+ {
+ FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChange()") ));
+ switch ( iReplyType )
+ {
+ case EReplyTypeOther:
+ {
+ FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChange() EReplyTypeOther") ));
+ iNoErrorReceived = ETrue;
+ CheckAndRemoveOkString();
+ SendReplyData();
+ }
+ break;
+ case EReplyTypeOk:
+ {
+ FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChange() EReplyTypeOk") ));
+ // 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 );
+ }
+ }
+ break;
+ case EReplyTypeError:
+ {
+ FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChange() EReplyTypeError") ));
+ if ( iNoErrorReceived )
+ {
+ iAtCmdExt->ReportExternalHandleCommandError();
+ }
+ SendReplyData();
+ }
+ break;
+ default:
+ {
+ FTRACE(FPrint( _L("CDunAtCmdPusher::ManageReplyTypeChange() EReplyTypeUndefined") ));
+ 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 )
+ {
+ iCallback->NotifyEndOfCmdLineProcessing();
+ iAtPushState = EDunStateIdle;
+ 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") ));
+ }