--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hti/HtiFramework/src/HtiCommAdapter.cpp Tue Feb 02 01:57:15 2010 +0200
@@ -0,0 +1,545 @@
+/*
+* 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: CHtiCommAdapter implementation
+*
+*/
+
+
+#include "HtiCommAdapter.h"
+#include "HtiDispatcher.h"
+#include "HTICommPluginInterface.h"
+#include "HtiMessage.h"
+#include "HtiNotifier.h"
+
+#include "HTILogging.h"
+
+//default value for max message size for incoming messages
+//used if value in constructor is not valid (<0)
+const static TInt KMaxMessageSize = 10 * 1024; // 10 KB
+
+const static TInt KHtiCommPriority = 2;
+
+_LIT( KCommPanic, "HtiCommAdapter" );
+
+CHtiCommAdapter* CHtiCommAdapter::NewLC( CHTICommPluginInterface* aCommPlugin,
+ CHtiDispatcher* aDispatcher, TInt aMaxMsgSize )
+ {
+ CHtiCommAdapter* obj = new (ELeave) CHtiCommAdapter( aDispatcher,
+ aCommPlugin, aMaxMsgSize );
+ CleanupStack::PushL( obj );
+ obj->ConstructL();
+ return obj;
+ }
+
+CHtiCommAdapter* CHtiCommAdapter::NewL( CHTICommPluginInterface* aCommPlugin,
+ CHtiDispatcher* aDispatcher, TInt aMaxMsgSize )
+ {
+ CHtiCommAdapter* obj = NewLC( aCommPlugin, aDispatcher, aMaxMsgSize );
+ CleanupStack::Pop();
+ return obj;
+ }
+
+CHtiCommAdapter::CHtiCommAdapter( CHtiDispatcher* aDispatcher,
+ CHTICommPluginInterface* aCommPlugin,
+ TInt aMaxMsgSize )
+ :CActive( KHtiCommPriority ),
+ iState( EIdle ),
+ iDispatcher( aDispatcher ),
+ iCommPlugin( aCommPlugin ),
+ iBufferPtr( NULL, 0 ),
+ iMsgToReceive( NULL ),
+ iMsgToSend( NULL ),
+ iMsgToSendPtr( NULL, 0 ),
+ iMsgToSendOffset( 0 ),
+ iSkipLength( 0 ),
+ iMaxMessageSize( aMaxMsgSize > 0 ? aMaxMsgSize : KMaxMessageSize )
+ {
+ HTI_LOG_FORMAT( "MaxMsgSize %d", iMaxMessageSize );
+ };
+
+CHtiCommAdapter::~CHtiCommAdapter()
+ {
+ HTI_LOG_FUNC_IN( "CHtiCommAdapter::~CHtiCommAdapter" );
+ Cancel();
+
+ delete iBuffer;
+ delete iLeftovers;
+
+ delete iMsgToReceive;
+ delete iMsgToSend;
+
+ HTI_LOG_FUNC_OUT( "CHtiCommAdapter::~CHtiCommAdapter" );
+ }
+
+void CHtiCommAdapter::ConstructL()
+ {
+ HTI_LOG_FUNC_IN( "CHtiCommAdapter::ConstructL" );
+
+ //allocate recommended buffer plus some extra space
+ //needed to handle msg parsing
+ iBuffer = HBufC8::NewL( iCommPlugin->GetReceiveBufferSize() +
+ CHtiMessage::MinHeaderSize() );
+
+ iBuffer->Des().SetLength( iCommPlugin->GetReceiveBufferSize() );
+ iBufferPtr.Set( iBuffer->Des().LeftTPtr(
+ iCommPlugin->GetReceiveBufferSize() ) );
+
+ iLeftovers = HBufC8::NewL( CHtiMessage::MinHeaderSize() );
+
+ CActiveScheduler::Add( this );
+ HTI_LOG_FUNC_OUT( "CHtiCommAdapter::ConstructL" );
+ }
+
+void CHtiCommAdapter::ReceiveMessage()
+ {
+ ReceiveMessage( EFalse );
+ }
+
+void CHtiCommAdapter::ReceiveMessage( TBool aContinue )
+ {
+ HTI_LOG_FUNC_IN( "CHtiCommAdapter::ReceiveMessage" );
+
+ iState = aContinue?EReceivingCont:EReceiving;
+ iCommPlugin->Receive( iBufferPtr, iStatus );
+ SetActive();
+
+ HTI_LOG_FUNC_OUT( "CHtiCommAdapter::ReceiveMessage" );
+ }
+
+void CHtiCommAdapter::SendMessage( CHtiMessage* aMessage )
+ {
+ HTI_LOG_FUNC_IN( "CCommAdapter::SendMessage" );
+ iState = ESending;
+ if ( aMessage != NULL )
+ {
+ HTI_LOG_TEXT( "send first packet" );
+ iMsgToSend = aMessage;
+ iMsgToSendOffset = 0;
+
+ //first send header
+ iMsgToSendPtr.Set( iMsgToSend->Header() );
+ }
+ else if ( iMsgToSend != NULL )
+ {
+ //send next chunk
+ if ( iMsgToSend->BodySize() <=
+ ( iMsgToSendOffset + iCommPlugin->GetSendBufferSize() ) )
+ {
+ HTI_LOG_TEXT( "send remainder" );
+ iMsgToSendPtr.Set( iMsgToSend->Body().Mid( iMsgToSendOffset ) );
+ iMsgToSendOffset = iMsgToSend->BodySize(); //last sending
+ }
+ else
+ {
+ HTI_LOG_TEXT( "send packet" );
+ iMsgToSendPtr.Set( iMsgToSend->Body().Mid( iMsgToSendOffset,
+ iCommPlugin->GetSendBufferSize() ) );
+ iMsgToSendOffset += iCommPlugin->GetSendBufferSize();
+ }
+ }
+ else
+ {
+ User::Panic( KCommPanic, KErrGeneral );
+ }
+
+ iCommPlugin->Send( iMsgToSendPtr, iStatus );
+ SetActive();
+
+ HTI_LOG_FUNC_OUT( "CCommAdapter::SendMessage" );
+ }
+
+void CHtiCommAdapter::Reset()
+ {
+ HTI_LOG_FUNC_IN( "CHtiCommAdapter::Reset" );
+ Cancel();
+ //receiving msg
+ delete iMsgToReceive;
+ iMsgToReceive = NULL;
+
+ //send msg
+ delete iMsgToSend;
+ iMsgToSend = NULL;
+ iMsgToSendOffset = 0;
+
+ //empty buffers
+ iLeftovers->Des().Zero();
+ iBuffer->Des().Zero();
+ iSkipLength = 0;
+
+ //set idle
+ iState = EIdle;
+
+ HTI_LOG_FUNC_OUT( "CHtiCommAdapter::Reset" );
+ }
+
+void CHtiCommAdapter::RunL()
+ {
+ HTI_LOG_FUNC_IN( "CHtiCommAdapter::RunL" );
+ HTI_LOG_FORMAT( "iStatus %d", iStatus.Int() );
+
+ //handle reset code common for all states
+ if ( iStatus == KErrComModuleReset )
+ {
+ HTI_LOG_TEXT( "Reset received from comm module" );
+ //reset dispatcher
+ iDispatcher->Reset();
+ //dispatcher will call Reset() for comm adapters and reissue requests
+ return;
+ }
+
+ //check for critical (unrecoverable) communication errors
+ else if ( iStatus == KErrServerTerminated )
+ {
+ if ( iDispatcher->GetShowErrorDialogs() )
+ {
+ User::Panic( KCommPanic, KErrServerTerminated );
+ }
+ else
+ {
+ User::Exit( KErrServerTerminated );
+ }
+ }
+ // USB errors from d32usbc.h
+ else if ( -6700 > iStatus.Int() && iStatus.Int() > -6712 )
+ {
+ if ( iDispatcher->GetShowErrorDialogs() )
+ {
+ TBuf<48> errorText;
+ errorText.Append( _L( "USB connection lost (" ) );
+ errorText.AppendNum( iStatus.Int() );
+ errorText.Append( _L( "). HTI stopped." ) );
+ CHtiNotifier::ShowErrorL( errorText );
+ }
+ User::Exit( KErrDisconnected );
+ }
+ else if ( iStatus == KErrDisconnected )
+ {
+ // This happens if Bluetooth connection is lost.
+ if ( iDispatcher->GetShowErrorDialogs() )
+ {
+ CHtiNotifier::ShowErrorL(
+ _L( "Connection lost. HTI stopped." ), KErrDisconnected );
+ }
+ User::Exit( KErrDisconnected );
+ }
+
+ switch ( iState )
+ {
+ case EReceiving:
+ //process
+ HTI_LOG_TEXT( "EReceiving" );
+ if ( iStatus == KErrNone )
+ {
+ iBuffer->Des().SetLength( iBufferPtr.Length() );
+ TRAPD( err, HandleReceiveL() );
+ if ( err != KErrNone )
+ {
+ HTI_LOG_FORMAT( "Error in HandleReceiveL %d", err );
+
+ delete iMsgToReceive;
+ iMsgToReceive = NULL;
+
+ iDispatcher->Notify( err );
+
+ ReceiveMessage();
+ }
+ }
+ else
+ {
+ HTI_LOG_FORMAT( "Error %d, reissue request", iStatus.Int() );
+ iDispatcher->Notify( iStatus.Int() );
+ ReceiveMessage();
+ }
+ break;
+ case EReceivingCont:
+ //process
+ HTI_LOG_TEXT( "EReceivingCont" );
+ if ( iStatus == KErrNone )
+ {
+ iBuffer->Des().SetLength( iBufferPtr.Length() );
+ TRAPD( err, HandleReceiveContL() );
+ if ( err != KErrNone )
+ {
+ HTI_LOG_FORMAT( "Error in HandleReceiveContL %d", err );
+
+ delete iMsgToReceive;
+ iMsgToReceive = NULL;
+
+ iDispatcher->Notify( err );
+
+ ReceiveMessage();
+ }
+ }
+ else
+ {
+ HTI_LOG_FORMAT( "Error %d, reissue request", iStatus.Int() );
+ HTI_LOG_TEXT( "and dismiss received HTI msg beginning" );
+ delete iMsgToReceive;
+ iMsgToReceive = NULL;
+
+ iDispatcher->Notify( iStatus.Int() );
+
+ ReceiveMessage();
+ }
+ break;
+ case ESending:
+ HTI_LOG_TEXT( "ESending" );
+ if ( iStatus == KErrNone )
+ {
+ HandleSend();
+ }
+ else
+ {
+ HTI_LOG_FORMAT( "Error %d, stop sending, go to EIdle", iStatus.Int() );
+
+ delete iMsgToSend;
+ iMsgToSend = NULL;
+ iMsgToSendOffset = 0;
+ iState = EIdle;
+
+ iDispatcher->Notify( iStatus.Int() );
+ }
+ break;
+ case EIdle:
+ //ERROR
+ HTI_LOG_TEXT( "EIdle" );
+ User::Panic( KCommPanic, KErrGeneral );
+ break;
+ default:
+ //ERROR
+ HTI_LOG_TEXT( "default" );
+ User::Panic( KCommPanic, KErrGeneral );
+ };
+
+ HTI_LOG_FUNC_OUT( "CHtiCommAdapter::RunL" );
+ }
+
+void CHtiCommAdapter::HandleReceiveL()
+ {
+ TBool toContinue = EFalse; //for reissuing state
+
+ if ( iLeftovers->Length() > 0 )
+ {
+ HTI_LOG_TEXT( "handle leftovers" );
+ //if something left from previous time
+ //insert it to the buffer beggining
+ //check that there is enough space (should be)
+ if ( iBuffer->Length() + iLeftovers->Length() <=
+ iBuffer->Des().MaxLength() )
+ {
+ iBuffer->Des().Insert( 0, *iLeftovers );
+ }
+ else
+ {
+ //error
+ HTI_LOG_TEXT( "iMsgToReceive contain too much leftovers, drop them" );
+ }
+
+ iLeftovers->Des().Zero();
+ }
+
+ //use loop cause can be several HTI messages in iBuffer
+ while ( iBuffer->Length() >= CHtiMessage::MinHeaderSize() )
+ {
+ HTI_LOG_FORMAT( "iBuffer.Length() %d", iBuffer->Length() );
+ HTI_LOG_TEXT( "check header" );
+
+ if ( CHtiMessage::CheckValidHtiHeader( *iBuffer ) )
+ {
+ HTI_LOG_TEXT( "valid header" );
+ TInt msgSize = CHtiMessage::Size( *iBuffer );
+ HTI_LOG_FORMAT( "msgSize %d", msgSize );
+ HTI_LOG_HEX( iBuffer->Des().Ptr(), 14 );
+
+ __ASSERT_ALWAYS( iMsgToReceive == NULL,
+ User::Panic( KCommPanic, KErrGeneral ) );
+
+ //check msgSize is acceptable
+ if ( msgSize > iMaxMessageSize )
+ {
+ //send err message
+ iDispatcher->DispatchOutgoingErrorMessage( EHtiErrBigMessage );
+ iSkipLength = msgSize;
+ }
+ else if ( msgSize > iDispatcher->GetFreeMemory() )
+ {
+ //send err message
+ iDispatcher->DispatchOutgoingErrorMessage( EHtiErrNoMemory );
+ iSkipLength = msgSize;
+ }
+ else
+ {
+ iMsgToReceive = CHtiMessage::NewL( *iBuffer );
+ }
+
+ if ( iMsgToReceive == NULL )
+ {
+ HTI_LOG_TEXT( "skip message" );
+ if ( iSkipLength > iBuffer->Length() )
+ {
+ iSkipLength -= iBuffer->Length();
+ iBuffer->Des().Zero();
+ // and continue to receive HTI message
+ //switch state to EReceiveCont
+ toContinue = ETrue;
+ }
+ else
+ {
+ //should not be here, but just in case
+ iBuffer->Des().Delete( 0, iSkipLength );
+ iSkipLength = 0;
+ }
+ }
+ else if ( iMsgToReceive->IsBodyComplete() )
+ {
+ HTI_LOG_TEXT( "handle small message" );
+ //iMsgToReceive is already contain whole HTI message
+ iDispatcher->DispatchIncomingMessage( iMsgToReceive );
+
+ //delete sent msg from buffer (and procces the rest)
+ iBuffer->Des().Delete( 0, iMsgToReceive->Size() );
+ iMsgToReceive = NULL;
+ }
+ else
+ {
+ HTI_LOG_TEXT( "start receive big message" );
+ //clear it to leave loop
+ iBuffer->Des().Zero();
+ // and continue to receive HTI message
+ //switch state to EReceiveCont
+ toContinue = ETrue;
+ }
+ }
+ else
+ {
+ HTI_LOG_TEXT( "invalid header, dismiss buffer and reissue request" );
+ HTI_LOG_HEX( iBuffer->Des().Ptr(), 14 );
+ // clear all buffer cause don't know where is valid header starts
+ // and wait for the next packet
+ iBuffer->Des().Zero(); //to leave loop
+ }
+ }
+
+ if ( iBuffer->Length() > 0 )
+ {
+ HTI_LOG_FORMAT( "copy leftovers %d", iBuffer->Length() );
+ //header beggining left in the buffer
+ //copy it to iLeftovers
+ ( *iLeftovers ) = ( *iBuffer );
+ }
+ //reissue request
+ ReceiveMessage( toContinue );
+ }
+
+void CHtiCommAdapter::HandleReceiveContL()
+ {
+ HTI_LOG_FORMAT( "In buffer: %d", iBuffer->Length() );
+ TBool toContinue = ETrue;
+
+ if ( iMsgToReceive != NULL && iSkipLength == 0 )
+ {
+ //add new packet to a message
+ TInt copyLen = iMsgToReceive->AddToBody( *iBuffer );
+
+ //delete what we copied to the message
+ iBuffer->Des().Delete( 0, copyLen );
+
+ if ( iMsgToReceive->IsBodyComplete() )
+ {
+ HTI_LOG_FORMAT( "body complete: %d", iMsgToReceive->BodySize() );
+
+ iDispatcher->DispatchIncomingMessage( iMsgToReceive );
+ iMsgToReceive = NULL;
+
+ //message complete, go to state EReceive
+ toContinue = EFalse;
+ }
+ }
+ else if ( iSkipLength > 0 )
+ {
+ HTI_LOG_FORMAT( "continue skipping, remains %d", iSkipLength );
+
+ if ( iSkipLength > iBuffer->Length() )
+ {
+ iSkipLength -= iBuffer->Length();
+ iBuffer->Des().Zero();
+ }
+ else
+ {
+ //skip last bytes
+ iBuffer->Des().Delete( 0, iSkipLength );
+ iSkipLength = 0;
+
+ toContinue = EFalse;
+ }
+ }
+
+ if ( iBuffer->Length() > 0 )
+ {
+ //process remainder and reissue in HandleReceiveL()
+ HandleReceiveL();
+ }
+ else
+ {
+ //reissue
+ ReceiveMessage(toContinue);
+ }
+ }
+
+void CHtiCommAdapter::HandleSend()
+ {
+ if ( iMsgToSendOffset < iMsgToSend->BodySize() )
+ {
+ //reissuse sending
+ SendMessage( NULL );
+ }
+ else
+ {
+ HTI_LOG_TEXT( "finish send, go to idle" );
+ iMsgToSendOffset = 0;
+ delete iMsgToSend;
+ iMsgToSend = NULL;
+ iState = EIdle;
+ iDispatcher->Notify( KErrNone );
+ }
+ }
+
+TInt CHtiCommAdapter::RunError( TInt aError )
+ {
+ TInt err = aError;
+ switch ( aError )
+ {
+ case KErrNoMemory:
+ break;
+ case KErrNotFound:
+ break;
+ }
+ return err;
+ }
+
+void CHtiCommAdapter::DoCancel()
+ {
+ switch ( iState )
+ {
+ case EReceiving:
+ case EReceivingCont:
+ iCommPlugin->CancelReceive();
+ break;
+ case ESending:
+ iCommPlugin->CancelSend();
+ break;
+ default:
+ break;
+ }
+ }