adaptationlayer/dataport/dataport_csy/src/dptx2pn.cpp
changeset 0 63b37f68c1ce
child 5 8ccc39f9d787
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/adaptationlayer/dataport/dataport_csy/src/dptx2pn.cpp	Fri Nov 06 17:28:23 2009 +0000
@@ -0,0 +1,756 @@
+/*
+* Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "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 FILES
+#include "dpdef.h"           // dataport definitions
+#include "dpdataport.h"      // dataport main and c32 interface
+#include "dpbreak.h"         // break
+#include "dptx2pn.h"         // moves data from tx buffer to isc api
+#include "dpstd.h"           // fault codes etc.
+#include "dppif.h"           // pipe interface (pif)
+#include "dpflowctrl.h"      // flow control handling
+#include "dpdataconfig.h"    // configuration store
+#include "dpparityhandler.h" // parity bit handling in 7-bit data mode
+#include "pep_comm_types.h"  // pep_comm_types
+#include "dplog.h"           // dataport logging
+#include "osttracedefinitions.h"
+#ifdef OST_TRACE_COMPILER_IN_USE
+#include "dptx2pntraces.h"
+#endif
+
+// EXTERNAL DATA STRUCTURES
+// none
+
+// EXTERNAL FUNCTION PROTOTYPES
+// none
+
+// CONSTANTS
+// none
+
+// MACROS
+// none
+
+// LOCAL CONSTANTS AND MACROS
+// none
+
+// MODULE DATA STRUCTURES
+// none
+
+// LOCAL FUNCTION PROTOTYPES
+// none
+
+// FORWARD DECLARATIONS
+// none
+
+// ============================= LOCAL FUNCTIONS ===============================
+// none
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// ---------------------------------------------------------
+// C++ default constructor.
+//
+// ---------------------------------------------------------
+CDpTx2Pn::CDpTx2Pn(
+    CDpDataPort& aDataPort ) :
+    CActive( KDpTx2PnPriority ),
+    iDataPort( aDataPort ),
+    iBreak( iDataPort.BreakHandler() ),
+    iBufferTx( iDataPort.Tx() ),
+    iPifDcs( iDataPort.Pif() ),
+    iFlowCtrl( iDataPort.FlowCtrl() ),
+    iDataConfig( iDataPort.DataConfig() ),
+    iParityHandler( iDataPort.ParityHandler() ),
+    iTx( 0, 0 ),
+    iTxTail( 0, 0 ),
+    iRole( MDpDataClient::EDbDataClientReader )
+    {
+    OstTrace0( TRACE_NORMAL, CDPTX2PN_CDPTX2PN, "CDpTx2Pn::CDpTx2Pn" );
+    LOGM(" CDpTx2Pn::CDpTx2Pn");
+    }
+
+// ---------------------------------------------------------
+// CDpTx2Pn::ConstructL
+// Symbian 2nd phase constructor.
+// ---------------------------------------------------------
+void CDpTx2Pn::ConstructL()
+    {
+    OstTrace0( TRACE_NORMAL, CDPTX2PN_CONSTRUCTL, "CDpTx2Pn::ConstructL" );
+    LOGM(" CDpTx2Pn::ConstructL");
+
+    // If registering fails => can't do nothing here => must leave
+    User::LeaveIfError( iBufferTx.RegisterDataClient( *this ) );
+
+     //  initialise inner observer object
+    iDpTx2PnPifObserver.Init( this );
+    // register to PIF as observer
+    iPifDcs.Attach( iDpTx2PnPifObserver );
+    //  initialise inner observer object
+    iDpTx2PnFcObserver.Init( this );
+    // register to FlowCtrl as observer
+    iFlowCtrl.Attach( iDpTx2PnFcObserver );
+
+    CActiveScheduler::Add( this );
+
+    if ( !IsActive() )
+        {
+        iRequestActive = ETrue;
+        iStatus = KRequestPending;
+        SetActive();
+        }
+    //no else
+    }
+
+// ---------------------------------------------------------
+// CDpTx2Pn::NewL
+// Static constructor.
+// ---------------------------------------------------------
+CDpTx2Pn* CDpTx2Pn::NewL(
+    CDpDataPort& aDataPort )
+    {
+    OstTrace0( TRACE_NORMAL, CDPTX2PN_NEWL, "CDpTx2Pn::NewL" );
+    LOGM(" CDpTx2Pn::NewL");
+
+    CDpTx2Pn* self = new( ELeave ) CDpTx2Pn( aDataPort );
+
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+
+    return self;
+    }
+
+// ---------------------------------------------------------
+// CDpTx2Pn::~CDpTx2Pn
+// Destructor
+// ---------------------------------------------------------
+CDpTx2Pn::~CDpTx2Pn()
+    {
+    OstTrace0( TRACE_NORMAL, DUP1_CDPTX2PN_CDPTX2PN, "CDpTx2Pn::~CDpTx2Pn" );
+    LOGM(" CDpTx2Pn::~CDpTx2Pn");
+    DEBUG( "CDpTx2Pn::~CDpTx2Pn" )
+
+    // unregister from PIF as observer
+    iPifDcs.Detach( iDpTx2PnPifObserver );
+    // unregister from FlowCtrl as observer
+    iFlowCtrl.Detach( iDpTx2PnFcObserver );
+    }
+
+// ---------------------------------------------------------
+// CDpTx2Pn::RunL
+// This is called when Tx2Pn is signalled. Tx2Pn can be
+// signalled by using iDataPort.SignalTx2Pn() or inside
+// CDpTx2Pn class just calling ReleaseNotify().
+// ---------------------------------------------------------
+//
+void CDpTx2Pn::RunL()
+    {
+    OstTrace1( TRACE_NORMAL, CDPTX2PN_RUNL, "CDpTx2Pn::RunL - Port: %u", iDataPort.PortUnit() );
+    LOGM1("CDpTx2Pn::RunL - Port %d", iDataPort.PortUnit() );
+    DEBUG("CDpTx2Pn::RunL\r\n" )
+
+    TInt ret( KErrNone );
+    TBool isNotReady( EFalse );
+
+    // Request is completed
+    iRequestActive = EFalse;
+
+    if ( iStatus != KErrCancel )
+        {
+        if ( !IsFlowCtrlOn() )
+            {
+            // Call WritePn
+            ret = WritePn();
+
+            switch ( ret )
+                {
+                case KErrNone:
+                case KErrLocked:
+                    {
+                    // Ok, do nothing
+                    break;
+                    }
+                case KErrNotReady:
+                    {
+                    LOG1("CDpTx2Pn::RunL - Error: %d", ret );
+                    OstTrace1( TRACE_NORMAL, DUP1_CDPTX2PN_RUNL, "CDpTx2Pn:: - Error: %d", ret );
+                    // Try to recover from KErrNotReady fail
+                    if ( !IsActive() )
+                        {
+                        iRequestActive = ETrue;
+                        iStatus = KRequestPending;
+                        SetActive();
+                        }
+                    //no else
+                    isNotReady = ETrue;
+                    break;
+                    }
+                case KErrOverflow:
+                case KErrNoMemory:
+                    {
+                    LOG1("CDpTx2Pn::RunL - Error: %d", ret );
+                    OstTrace1( TRACE_NORMAL, DUP2_CDPTX2PN_RUNL, "CDpTx2Pn:: - Error: %d", ret );
+
+                    // KErrOverFlow (== ISC flow control on),
+                    // KErrNomemory (== other ISC problems, no memory)
+                    // => send failed
+                    // Keep data in buffer but release data element
+                    // (will be reserved again)
+                    if ( KErrNone == iBufferTx.ReadElement().Release( 0 ) )
+                        {
+                        // reset descriptors
+                        iTx.SetLength( 0 );
+                        iTxTail.SetLength( 0 );
+                        }
+                    break;
+                    }
+                default:
+                    {
+                    LOG1("CDpTx2Pn::RunL - Error: %d", ret );
+                    OstTrace1( TRACE_NORMAL, DUP3_CDPTX2PN_RUNL, "CDpTx2Pn:: - Error: %d", ret );
+
+                    // Something went wrong in WritePn method
+                    // e.g. element reservation, must leave.
+                    User::Leave(ret);
+                    break;
+                    }
+
+                } // switch ( ret )
+            }
+        else
+            {
+            LOG(" CDpTx2Pn::RunL, Flow control blocking");
+            OstTrace0( TRACE_NORMAL, DUP4_CDPTX2PN_RUNL, "CDpTx2Pn:: Flow control blocking" );
+            }
+
+        if ( !isNotReady )
+            {
+            // Transmit buffer empty, is client intrested about that
+            if ( 0 == ( iBufferTx.UsedBytes() ) && ( iOutBufIsEmptyNotify ) )
+                {
+                // We should notify client now.
+                iOutBufIsEmptyNotify = EFalse;
+                iDataPort.NotifyOutputEmptyCompleted( KErrNone );
+                }
+            //no else
+
+            // Set active again
+            if ( !IsActive() )
+                {
+                iRequestActive = ETrue;
+                iStatus = KRequestPending;
+                SetActive();
+                }
+            //no else
+
+            // Signal ourselves only if there is data in buffer and
+            // DP->DCS flow control is off.
+            if ( iBufferTx.UsedBytes() && !IsFlowCtrlOn() )
+                {
+                ReleaseNotify();
+                }
+            //no else
+            }
+        //no else
+        }
+    //no else
+
+    }
+
+// ---------------------------------------------------------
+// CDpTx2Pn::RunError
+// Leave in RunL() is handled here. Error code is returned,
+// when internal error has occured.
+// ---------------------------------------------------------
+//
+TInt CDpTx2Pn::RunError(
+    TInt aError )
+    {
+    OstTrace0( TRACE_NORMAL, CDPTX2PN_RUNERROR, "CDpTx2Pn::RunError" );
+    OstTraceExt2( TRACE_NORMAL, DUP1_CDPTX2PN_RUNERROR, "CDpTx2Pn:: Port: %u, error code: %d", iDataPort.PortUnit(), aError );
+
+    LOGM2("CDpTx2Pn::RunError - Port %d, error code: %d",
+        iDataPort.PortUnit(), aError );
+
+    return aError;
+    }
+
+// ---------------------------------------------------------
+// CDpTx2Pn::DoCancel
+// This method cancels this active object by
+// RequestComplete(). This method must be called directly
+// (not through Cancel()), when RunL() should be completed
+// with KErrCancel.
+// ---------------------------------------------------------
+//
+void CDpTx2Pn::DoCancel()
+    {
+    OstTrace0( TRACE_NORMAL, CDPTX2PN_DOCANCEL, "CDpTx2Pn::DoCancel" );
+    LOGM(" CDpTx2Pn::DoCancel");
+    DEBUG( "CDpTx2Pn::DoCancel\n" )
+
+    if ( iRequestActive )
+        {
+        // do the required signaling
+        iRequestActive = EFalse;
+        TRequestStatus* s = &iStatus;
+        User::RequestComplete( s, KErrCancel );
+        }
+    //no else
+    }
+
+// ---------------------------------------------------------
+// CDpTx2Pn::WritePn
+// Writes data to Isc Api.
+// ---------------------------------------------------------
+//
+TInt CDpTx2Pn::WritePn()
+    {
+    OstTrace0( TRACE_NORMAL, CDPTX2PN_WRITEPN, "CDpTx2Pn::WritePn" );
+    OstTrace1( TRACE_NORMAL, DUP1_CDPTX2PN_WRITEPN, "CDpTx2Pn:: Port: %u", iDataPort.PortUnit() );
+
+    LOGM1("CDpTx2Pn::WritePn - Port %d", iDataPort.PortUnit() );
+
+    TInt len( 0 );
+    TInt ret( KErrNone );
+
+    // check pipe is enabled
+    if ( iPifDcs.PipeState() != CDpPif::EDpPipeEnabled )
+        {
+        ret = KErrNotReady;
+        }
+    else if ( iBreakPending )
+        {
+        // length is as much as there is data before break,
+        // but maximum KDpMaximumTxReservationSize
+        if ( iBreakBytes > iBufferTx.MaxReservationSize() )
+            {
+            len = iBufferTx.MaxReservationSize();
+            }
+        else
+            {
+            len = iBreakBytes;
+            }
+        }
+    else
+        {
+        // length is as much as there is but maximum KDpMaximumTxReservationSize
+        if ( iBufferTx.UsedBytes() > iBufferTx.MaxReservationSize() )
+            {
+            len = iBufferTx.MaxReservationSize();
+            }
+        else
+            {
+            len = iBufferTx.UsedBytes();
+            }
+        }
+
+    // Length can be 0, if Tx buffer has been flushed.
+    // Try to recover with KErrNotReady error.
+    if ( ( 0 == len ) && ( KErrNone == ret ) )
+        {
+        ret = KErrNotReady;
+        }
+    else if ( KErrNone == ret )
+        {
+        LOG("  CDpTx2Pn::WritePn, Tx element reservation");
+        OstTrace0( TRACE_NORMAL, DUP2_CDPTX2PN_WRITEPN, "CDpTx2Pn:: Tx element reservation" );
+
+        // try reserve read element, descriptor set to iTx,
+        // possible tail into iTxTail
+        TInt result( iBufferTx.ReadElement().Reserve( len, iTx, iTxTail ) );
+
+        ret = HandleReturnValue( result );
+        }
+    //no else
+
+    return ret;
+    }
+
+// ---------------------------------------------------------
+// CDpTx2Pn::IsFlowCtrlOn
+// Is flow control on between DP->DCS. Returns also ETrue,
+// when pipe is not enabled.
+// ---------------------------------------------------------
+//
+TBool CDpTx2Pn::IsFlowCtrlOn()
+    {
+    OstTrace0( TRACE_NORMAL, CDPTX2PN_ISFLOWCTRLON, "CDpTx2Pn::IsFlowCtrlOn" );
+    LOGM(" CDpTx2Pn::IsFlowCtrlOn");
+
+    TBool ret( EFalse );
+
+    if ( EFlowControlOn == iFlowCtrl.FlowCtrlDp2Dcs() ||
+        CDpPif::EDpPipeEnabled != iPifDcs.PipeState() )
+        {
+        ret = ETrue;
+        }
+    else
+        {
+        ret = EFalse;
+        }
+
+    return ret;
+    }
+
+// ---------------------------------------------------------
+// CDpTx2Pn::ReleaseNotify
+// This method signals this active object.
+// ---------------------------------------------------------
+//
+void CDpTx2Pn::ReleaseNotify()
+    {
+    OstTrace0( TRACE_NORMAL, CDPTX2PN_RELEASENOTIFY, "CDpTx2Pn::ReleaseNotify" );
+    LOG(" CDpTx2Pn::ReleaseNotify");
+    DEBUG( "CDpTx2Pn::ReleaseNotify" )
+
+    // signal ourselves
+    if ( iRequestActive )
+        {
+        iRequestActive = EFalse;
+        TRequestStatus* s = &iStatus;
+        User::RequestComplete( s, KErrNone );
+        }
+    //no else
+    }
+
+// ---------------------------------------------------------
+// This method notifies that buffer is flushed. Classes which have access
+// to buffers are derived from this class. Derived class could override
+// this method, otherwise this default method will be used.
+// release this cactive object
+// ---------------------------------------------------------
+//
+void CDpTx2Pn::FlushNotify()
+    {
+    OstTrace0( TRACE_NORMAL, CDPTX2PN_FLUSHNOTIFY, "CDpTx2Pn::FlushNotify" );
+    LOGM(" CDpTx2Pn::FlushNotify()");
+
+    ReleaseNotify();
+    }
+
+// -----------------------------------------------------------------------------
+// CDpTx2Pn::Role
+// This method gets the role (reader/writer) of data client.
+// -----------------------------------------------------------------------------
+//
+TUint8 CDpTx2Pn::Role()
+    {
+    OstTrace0( TRACE_NORMAL, CDPTX2PN_ROLE, "CDpTx2Pn::Role" );
+
+    return iRole;
+    }
+
+// ---------------------------------------------------------
+// CDpTx2Pn::UpDate
+// Called after pipe state change and after flow control
+// state change.
+// ---------------------------------------------------------
+//
+void CDpTx2Pn::UpDate(
+    CDpSubject* /*aChangedSubject*/ )
+    {
+    OstTrace0( TRACE_NORMAL, CDPTX2PN_UPDATE, "CDpTx2Pn::UpDate" );
+    LOG(" CDpTx2Pn::UpDate");
+    DEBUG( "CDpTx2Pn::UpDate" )
+
+    // if there is data ready signal ourselves
+    if ( ( 0 < iBufferTx.UsedBytes() ) && ( !IsFlowCtrlOn() ) )
+        {
+        ReleaseNotify();
+        }
+    //no else
+    }
+
+// ---------------------------------------------------------
+// CDpTx2Pn::SetBreakBytes
+// Set up flag if there is some data to be send before break
+// (this is client->DCS break)
+// ---------------------------------------------------------
+//
+void CDpTx2Pn::SetBreakBytes(
+    const TInt aBreakBytes)
+    {
+    OstTrace0( TRACE_NORMAL, CDPTX2PN_SETBREAKBYTES, "CDpTx2Pn::SetBreakBytes" );
+    LOG(" CDpTx2Pn::SetBreakBytes");
+    DEBUG( "CDpTx2Pn::SetBreakBytes()" )
+
+    iBreakBytes = aBreakBytes;
+    // put break pending
+    iBreakPending = ETrue;
+    }
+
+// ---------------------------------------------------------
+// CDpTx2Pn::CancelBreakBytes
+// Clears pending break bytes. Client may have cancelled
+// it's break request.
+// ---------------------------------------------------------
+//
+void CDpTx2Pn::CancelBreakBytes()
+    {
+    OstTrace0( TRACE_NORMAL, CDPTX2PN_CANCELBREAKBYTES, "CDpTx2Pn::CancelBreakBytes" );
+    LOG(" CDpTx2Pn::CancelBreakBytes");
+    DEBUG( "CDpTx2Pn::CancelBreakBytes()" )
+
+    iBreakBytes = 0;
+    iBreakPending = EFalse;
+    }
+
+// ---------------------------------------------------------
+// CDpTx2Pn::SetOutputBufferEmptyNotification
+// Setup flag that we are requested to notify or not the
+// client, when output buffer (TX buffer) empties.
+// ---------------------------------------------------------
+//
+void CDpTx2Pn::SetOutputBufferEmptyNotification(
+    const TBool aUsedOrNot )
+    {
+    OstTrace0( TRACE_NORMAL, CDPTX2PN_SETOUTPUTBUFFEREMPTYNOTIFICATION, "CDpTx2Pn::SetOutputBufferEmptyNotification" );
+    LOG(" CDpTx2Pn::SetOutputBufferEmptyNotification");
+    DEBUG( "CDpTx2Pn::SetOutputBufferEmptyNotification")
+
+    iOutBufIsEmptyNotify = aUsedOrNot;
+    }
+
+// ---------------------------------------------------------
+// CDpTx2Pn::PipeSendWithParityAdd
+// This method writes data to Isc Api. In 7-bit data case
+// parity bits are added here using parity handler class.
+// ---------------------------------------------------------
+//
+TInt CDpTx2Pn::PipeSendWithParityAdd(
+    TPtr8& aTx )
+    {
+    OstTrace0( TRACE_NORMAL, CDPTX2PN_PIPESENDWITHPARITYADD, "CDpTx2Pn::PipeSendWithParityAdd" );
+    OstTrace1( TRACE_NORMAL, DUP1_CDPTX2PN_PIPESENDWITHPARITYADD, "CDpTx2Pn:: Port: %u", iDataPort.PortUnit() );
+
+    LOGM1("CDpTx2Pn::PipeSendWithParityAdd - Port %d", iDataPort.PortUnit() );
+
+    TUint8 pipeHandle( 0 );
+    TInt result( iDataPort.ActivePipeHandle( pipeHandle ) );
+
+    if ( KErrNone == result )
+        {
+        if ( EData7 == iDataConfig.DataBits() )
+            {
+            // DteParityBitWhen7Mode parameter tells whether parity bit should
+            // be carried or not in data mesages in a pipe when DTE interface
+            // is in  7-bit mode.
+            if ( iDataConfig.DteParityBitWhen7Mode() == PEP_COMM_DATA_WITH_PARITY )
+                {
+                // use parity bits
+                iParityHandler.AddParityBits( aTx, iDataConfig.Parity() );
+                }
+            //no else
+            }
+        //no else
+
+        result = iDataPort.ISAHandle().DataSend( aTx );
+
+#if defined(_DEBUG)
+        if ( KErrNone != result )
+            {
+            LOG1("Error Pipe send %d", result );
+            OstTrace1( TRACE_NORMAL, DUP2_CDPTX2PN_PIPESENDWITHPARITYADD, "CDpTx2Pn:: Error Pipe send %d", result );
+            }
+        //no else
+#endif
+        }
+    //no else
+
+    return result;
+    }
+
+// ---------------------------------------------------------
+// CDpTx2Pn::HandleReturnValue
+// Handles the reserve methods return value.
+// ---------------------------------------------------------
+//
+TInt CDpTx2Pn::HandleReturnValue(
+    const TInt aReturnValue )
+    {
+    OstTrace0( TRACE_NORMAL, CDPTX2PN_HANDLERETURNVALUE, "CDpTx2Pn::HandleReturnValue" );
+    OstTrace1( TRACE_NORMAL, DUP1_CDPTX2PN_HANDLERETURNVALUE, "CDpTx2Pn:: Port: %u", iDataPort.PortUnit() );
+
+    LOGM1("CDpTx2Pn::HandleReturnValue - Port %d", iDataPort.PortUnit() );
+
+    TInt result( KErrNone );
+
+    switch ( aReturnValue )
+        {
+        case KErrNone:
+            {
+            // write iTx
+            if ( 0 < iTx.Length() )
+                {
+                result = PipeSendWithParityAdd( iTx );
+                }
+            //no else
+
+#ifdef _DEBUG
+            LOG1("-- WRITE -- %x", &iDataPort);
+            OstTrace1( TRACE_NORMAL, DUP2_CDPTX2PN_HANDLERETURNVALUE, "CDpTx2Pn:: -- WRITE -- %x", &iDataPort );
+
+            if ( 0 < iTx.Length() )
+                {
+                if ( KErrOverflow != result )
+                    {
+                    iTotalSent = iTotalSent + iTx.Length();
+                    }
+                OstTraceExt2( TRACE_NORMAL, DUP3_CDPTX2PN_HANDLERETURNVALUE, "CDpTx2Pn:: Tx len = %d, Total Bytes sent = %d", iTx.Length(), iTotalSent );
+                OstTraceExt1( TRACE_NORMAL, DUP12_CDPTX2PN_HANDLERETURNVALUE, "CDpTx2Pn:: TX = %s", iTx );
+
+                LOG2("    Tx len = %d, Total Bytes sent = %d",
+                    iTx.Length(), iTotalSent );
+                LOGHEX( iTx, ETrue );
+                }
+            //no else
+#endif
+
+            if ( KErrNone == result )
+                {
+                TInt len( 0 );
+
+                // Write iTx OK => Write iTxTail
+                if ( 0 < iTxTail.Length() )
+                    {
+                    result = PipeSendWithParityAdd( iTxTail );
+                    }
+                //no else
+
+#ifdef _DEBUG
+                if ( 0 < iTxTail.Length() )
+                    {
+                    if ( KErrOverflow != result )
+                        {
+                        iTotalSent = iTotalSent + iTxTail.Length();
+                        }
+                    OstTraceExt2( TRACE_NORMAL, DUP5_CDPTX2PN_HANDLERETURNVALUE, "CDpTx2Pn:: Tx Tail len = %d, Total Bytes sent = %d", iTxTail.Length(), iTotalSent );
+                    OstTraceExt1( TRACE_NORMAL, DUP13_CDPTX2PN_HANDLERETURNVALUE, "CDpTx2Pn:: TX = %s", iTxTail );
+
+                    LOG2("    Tx Tail len = %d, Total Bytes sent = %d",
+                        iTxTail.Length(), iTotalSent );
+                    LOGHEX( iTxTail, ETrue );
+                    }
+                //no else
+#endif
+
+                if ( KErrNone == result )
+                    {
+                    // Write iTx OK & Write iTxTail OK
+                    // => release iTx and iTxTail
+                    LOG(" CDpTx2Pn::HandleReturnValue, Tx element release (iTx + iTxTail)");
+                    OstTrace0( TRACE_NORMAL, DUP7_CDPTX2PN_HANDLERETURNVALUE, "CDpTx2Pn:: Tx element release (iTx + iTxTail)" );
+                    len = iTx.Length() + iTxTail.Length();
+                    }
+                else
+                    {
+                    // Write iTx OK & Write iTxTail FAIL
+                    // => release only iTx
+                    OstTrace0( TRACE_NORMAL, DUP8_CDPTX2PN_HANDLERETURNVALUE, "CDpTx2Pn:: Tail sending failed" );
+                    OstTrace0( TRACE_NORMAL, DUP9_CDPTX2PN_HANDLERETURNVALUE, "CDpTx2Pn:: Tx element release (iTx)" );
+
+                    LOG(" CDpTx2Pn::HandleReturnValue, Tail sending failed");
+                    LOG(" CDpTx2Pn::HandleReturnValue, Tx element release (iTx)");
+                    len = iTx.Length();
+                    }
+
+                // release read element
+                result = iBufferTx.ReadElement().Release( len );
+
+                if ( KErrNone == result )
+                    {
+                    // reset descriptors
+                    iTx.SetLength( 0 );
+                    iTxTail.SetLength( 0 );
+
+                    if ( iBreakPending )
+                        {
+                        iBreakBytes -= len;
+
+                        if ( iBreakBytes == 0 )
+                            {
+                            iBreakPending = EFalse;
+                            TInt ret = iBreak.SendBreak();
+                            iDataPort.BreakCompleted( ret );
+                            }
+                        //no else
+                        }
+                    //no else
+                    }
+                //no else
+                }
+            //no else
+
+            break;
+            }
+        case KErrNoMemory:
+            {
+            DEBUG( "CDpTx2Pn, waiting..." )
+            OstTrace0( TRACE_NORMAL, DUP10_CDPTX2PN_HANDLERETURNVALUE, "CDpTx2Pn:: waiting..." );
+
+            // do nothing, in RunL we are set active again
+            break;
+            }
+        default:
+            {
+            LOG(" CDpTx2Pn::HandleReturnValue, Element reservation failed");
+            OstTrace0( TRACE_NORMAL, DUP11_CDPTX2PN_HANDLERETURNVALUE, "CDpTx2Pn:: Element reservation failed" );
+
+            // Return the error code. Caller of the WritePn can handel this.
+            result = aReturnValue;
+            }
+        }
+
+    return result;
+    }
+
+//===========================================================
+
+// ---------------------------------------------------------
+// CDpTx2Pn::CDpTx2PnObserver::Init
+// This method initializes Tx2Pn observer.
+// ---------------------------------------------------------
+//
+void CDpTx2Pn::CDpTx2PnObserver::Init(
+    CDpTx2Pn* aDpTx2Pn )
+    {
+    iDpTx2Pn = aDpTx2Pn;
+    }
+
+// ---------------------------------------------------------
+// CDpTx2Pn::CDpTx2PnObserver::UpDate
+// This method updates Tx2Pn.
+// ---------------------------------------------------------
+//
+void CDpTx2Pn::CDpTx2PnObserver::UpDate(
+    CDpSubject* aChangedSubject )
+    {
+    LOG(" CDpTx2Pn::CDpTx2PnObserver::UpDate");
+
+    if ( iDpTx2Pn )
+        {
+        iDpTx2Pn->UpDate( aChangedSubject );
+        }
+    }
+
+// ================= OTHER EXPORTED FUNCTIONS ==============
+// none
+
+//  End of File