/*
* 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 "dprx2dte.h" // moves data from rx buffer to client
#include "dpbreak.h" // break handling
#include "dpflowctrl.h" // flow control handling
#include "dpdataconfig.h" // configuration store
#include "dptermdetect.h" // terminator detection
#include "dplog.h" // dataport logging
#include "OstTraceDefinitions.h"
#ifdef OST_TRACE_COMPILER_IN_USE
#include "dprx2dteTraces.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 ===============================
// -----------------------------------------------------------------------------
// CDpRx2Dte::CDpRx2Dte
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CDpRx2Dte::CDpRx2Dte (
CDpDataPort& aDataPort ) :
CActive( KDpRx2DtePriority ),
iDataPort( aDataPort ),
iBufferRx( iDataPort.Rx() ),
iFlowCtrl( iDataPort.FlowCtrl() ),
iDataConfig( iDataPort.DataConfig() ),
iBreak( iDataPort.BreakHandler() ),
iTermDetect( iDataPort.TermDetect() ),
iRx( 0, 0 ),
iRxTail( 0, 0 ),
iRole( MDpDataClient::EDbDataClientReader )
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_CDPRX2DTE, "CDpRx2Dte::CDpRx2Dte" );
LOGM("CDpRx2Dte::CDpRx2Dte");
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CDpRx2Dte::ConstructL()
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_CONSTRUCTL, "CDpRx2Dte::ConstructL" );
LOGM("CDpRx2Dte::ConstructL");
// If registering fails => can't do nothing here => must leave
User::LeaveIfError( iBufferRx.RegisterDataClient( *this ) );
CActiveScheduler::Add( this );
if ( !IsActive() )
{
iStatus = KRequestPending;
iRequestActive = ETrue;
SetActive();
}
//no else
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CDpRx2Dte* CDpRx2Dte::NewL(
CDpDataPort& aDataPort )
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_NEWL, "CDpRx2Dte::NewL" );
LOGM("CDpRx2Dte::NewL");
CDpRx2Dte* self = new (ELeave) CDpRx2Dte( aDataPort );
CleanupStack::PushL( self );
self->ConstructL();
CleanupStack::Pop( self );
return self;
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::~CDpRx2Dte
// Destructor
// -----------------------------------------------------------------------------
//
CDpRx2Dte::~CDpRx2Dte()
{
OstTrace0( TRACE_NORMAL, DUP1_CDPRX2DTE_CDPRX2DTE, "CDpRx2Dte::~CDpRx2Dte" );
LOGM("CDpRx2Dte::~CDpRx2Dte");
iClientBuffer = 0;
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::RunL
// We are signalled from Pn2Rx or from ourselves (Rx2Dte).
// Always when we are signalled there is data available to be written
// into client space. This method also checks if RX flow control
// 'water mark low' is reached and informs flow control handler about that.
// -----------------------------------------------------------------------------
//
void CDpRx2Dte::RunL()
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_RUNL, "CDpRx2Dte::RunL" );
OstTrace1( TRACE_NORMAL, DUP1_CDPRX2DTE_RUNL, "CDpRx2Dte:: Port: %u", iDataPort.PortUnit() );
LOGM1("CDpRx2Dte::RunL - Port %d", iDataPort.PortUnit() );
if ( iStatus != KErrCancel )
{
#ifdef _DEBUG
TInt ret( KErrNone );
#endif
if ( 0 < iEchoData.Length() && iReadPending )
{
// Writes echo bytes to the client
#ifdef _DEBUG
ret =
#endif
WriteEchoToClient();
}
else if ( iReadPending )
{
#ifdef _DEBUG
ret =
#endif
WriteIntoClientSpace();
}
//no else
#ifdef _DEBUG
if ( ret != KErrNone )
{
LOG(" ERROR, CDpRx2Dte::RunL, Writing echo bytes to the client");
OstTrace0( TRACE_NORMAL, DUP2_CDPRX2DTE_RUNL, "ERROR, CDpRx2Dte::RunL, Writing echo bytes to the client" );
}
//no else
#endif
if ( !IsActive() )
{
iStatus = KRequestPending;
iRequestActive = ETrue;
SetActive();
}
//no else
if ( iReadPending &&
( 0 < iBufferRx.UsedBytes() || 0 < iEchoData.Length() ) )
{
iDataPort.SignalRx2Dte();
}
//no else
}
//no else
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::RunError
// Leave in RunL() is handled here. RunL() should not leave.
// -----------------------------------------------------------------------------
//
TInt CDpRx2Dte::RunError(
TInt aError )
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_RUNERROR, "CDpRx2Dte::RunError" );
OstTraceExt2( TRACE_NORMAL, DUP1_CDPRX2DTE_RUNERROR, "CDpRx2Dte:: Port: %u, error code: %d", iDataPort.PortUnit(), aError );
LOGM2("CDpRx2Dte::RunError - Port %d, error code: %d",
iDataPort.PortUnit(), aError );
return aError;
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::DoCancel
// This method cancels this active object
// -----------------------------------------------------------------------------
//
void CDpRx2Dte::DoCancel()
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_DOCANCEL, "CDpRx2Dte::DoCancel" );
LOGM("CDpRx2Dte::DoCancel");
if ( iRequestActive )
{
// do the required signaling
iRequestActive = EFalse;
TRequestStatus* status = &iStatus;
User::RequestComplete( status, KErrCancel );
}
//no else
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::SetDteRead
// This is forwarded client StartRead().
// -----------------------------------------------------------------------------
//
TInt CDpRx2Dte::SetDteRead(
const TAny* aDes,
TInt aLength )
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_SETDTEREAD, "CDpRx2Dte::SetDteRead" );
LOGM("CDpRx2Dte::SetDteRead");
TInt ret( KErrNone );
// no pending read
if ( !iReadPending )
{
iReadPending = ETrue;
// pointer into client buffer
iClientBuffer = const_cast<TAny*>( aDes );
iClientRequestedLength = aLength;
if ( 0 > aLength )
{
// ReadOneOrMore
// C32 gives client buffer size as negative value
// see ECUART implementation
iClientBufferLength = -aLength;
}
else
{
iClientBufferLength = aLength;
}
// if there is data ready signal ourselves
if ( 0 < iBufferRx.UsedBytes() || 0 < iEchoData.Length() )
{
iDataPort.SignalRx2Dte();
}
//no else
}
else
{
// read twice attempted
ret = KErrInUse;
}
return ret;
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::ResetDteRead
// This is forwarded client made ReadCancel().
// C32 makes ReadCompleted() to DTE --> don't make it here at all.
// This is because DTE may have made timed read and when timer runs
// out C32 wants to complete read by KErrTimedOut.
// -----------------------------------------------------------------------------
//
TInt CDpRx2Dte::ResetDteRead()
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_RESETDTEREAD, "CDpRx2Dte::ResetDteRead" );
OstTrace1( TRACE_NORMAL, DUP1_CDPRX2DTE_RESETDTEREAD, "CDpRx2Dte:: Port: %u", iDataPort.PortUnit() );
LOGM1("CDpRx2Dte::ResetDteRead - Port %d", iDataPort.PortUnit() );
// reset pointer pointing into client space & its length
iReadPending = EFalse;
iClientBuffer = 0;
iClientBufferLength = 0;
iClientRequestedLength = 0;
iIPCWriteOffset = 0;
return KErrNone;
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::Write
// Reserve read element and IPCWrite data to client space.
// -----------------------------------------------------------------------------
//
TInt CDpRx2Dte::Write()
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_WRITE, "CDpRx2Dte::Write" );
OstTrace1( TRACE_NORMAL, DUP1_CDPRX2DTE_WRITE, "CDpRx2Dte:: Port: %u", iDataPort.PortUnit() );
LOGM1("CDpRx2Dte::Write - Port %d", iDataPort.PortUnit() );
TInt len( 0 );
TInt maxLen( 0 );
TInt ret( KErrNone );
TCommRole role;
iDataPort.GetRole( role );
// verify read pending, else do nothing
if ( !iReadPending )
{
ret = KErrNotReady;
}
// check line fail
else if ( iDataConfig.IsLineFail( role ) )
{
iDataPort.ReadCompleted( KErrCommsLineFail );
ResetDteRead();
}
else
{
// Find maximum length. i.e. which one is smaller our
// maximum reservation size or client buffer to write
// We can't write data over client buffer size -> smaller must be chocen
maxLen = FindMaximumLength();
// Lenght is count of bytes before break, but maximum maxLen or
// lenght is as much as possible, but maximum maxLen
len = FindLength( maxLen );
LOG1(" CDpRx2Dte::Write, Rx element reservation - len: %d", len );
OstTrace1( TRACE_NORMAL, DUP8_CDPRX2DTE_WRITE, "CDpRx2Dte:: Rx element reservation - len: %d", len );
// try reserve read element, if return success descriptors are
// set into buffer data
ret = iBufferRx.ReadElement().Reserve( len, iRx, iRxTail, ETrue );
switch ( ret )
{
case KErrNone:
{
#ifdef _DEBUG
iTotalReceived = iTotalReceived + iRx.Length();
OstTrace1( TRACE_NORMAL, DUP2_CDPRX2DTE_WRITE, "CDpRx2Dte:: iBufferRx.UsedBytes = %d", iBufferRx.UsedBytes() );
OstTraceExt2( TRACE_NORMAL, DUP3_CDPRX2DTE_WRITE, "CDpRx2Dte:: len = %d, Total Received Bytes = %d", iRx.Length(), iTotalReceived );
OstTraceExt2( TRACE_NORMAL, DUP4_CDPRX2DTE_WRITE, "CDpRx2Dte:: Client buffer size = %d, DP Max. resv. size = %d", (iClientBufferLength - iIPCWriteOffset), iBufferRx.MaxReservationSize() );
OstTraceExt2( TRACE_NORMAL, DUP5_CDPRX2DTE_WRITE, "CDpRx2Dte:: Chosen maxLength = %d, Elem. reserved length = %d", maxLen, len );
OstTraceExt2( TRACE_NORMAL, DUP6_CDPRX2DTE_WRITE, "CDpRx2Dte:: iClientBufferLength = %d, iIPCWriteOffset = %d", iClientBufferLength, iIPCWriteOffset );
if( iRx.Length() > 0 )
{
OstTraceExt1( TRACE_NORMAL, DUP7_CDPRX2DTE_WRITE, "CDpRx2Dte:: RX = %s", iRx );
}
else
{
OstTrace0( TRACE_NORMAL, DUP12_CDPRX2DTE_WRITE, "CDpRx2Dte:: RX buffer empty" );
}
LOG1(" \tiBufferRx.UsedBytes() = %d", iBufferRx.UsedBytes() );
LOG2(" \tlen = %d, Total Received Bytes = %d",
iRx.Length(), iTotalReceived );
LOG2(" \tClient buffer size = %d, DP Max. resv. size = %d",
( iClientBufferLength - iIPCWriteOffset ),
iBufferRx.MaxReservationSize() );
LOG2(" \tChocen maxLength = %d, Elem. reserved length = %d",
maxLen, len );
LOG2(" \tiClientBufferLength = %d, iIPCWriteOffset = %d",
iClientBufferLength, iIPCWriteOffset );
LOGHEX( iRx, EFalse );
#endif
if ( iRxTail.Length() )
{
OstTrace1( TRACE_NORMAL, DUP9_CDPRX2DTE_WRITE, "CDpRx2Dte:: len tail = %d", iRxTail.Length() );
OstTraceExt1( TRACE_NORMAL, DUP10_CDPRX2DTE_WRITE, "CDpRx2Dte:: RXTail = %s", iRxTail );
LOG1(" \tlen tail = %d", iRxTail.Length() );
LOGHEX( iRxTail, EFalse );
}
//no else
// Write operation is handled here.
ret = MakeRx2DteWrite( len );
break;
}
case KErrNotReady:
{
// we are set active in RunL
// OBS: returning KErrNone
ret = KErrNone;
break;
}
default:
{
LOG1(" ERROR, CDpRx2Dte::Write Element reservation FAILED, error code: %d",
ret );
OstTrace1( TRACE_NORMAL, DUP11_CDPRX2DTE_WRITE, "ERROR, CDpRx2Dte::Write Element reservation FAILED, error code: %d", ret );
// returning error code. There's no need to leave because
// the error situation can be handeled.
}
}
}
// if there is still data in buffer we are signalled from
// 1. CDpRx2Dte::SetDteRead when client makes new read
// 2. from end of RunL when buffer has data and read is pending
return ret;
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::ReleaseNotify
// This method signals ourselves (Rx2Dte).
// -----------------------------------------------------------------------------
//
void CDpRx2Dte::ReleaseNotify()
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_RELEASENOTIFY, "CDpRx2Dte::ReleaseNotify" );
LOG("CDpRx2Dte::ReleaseNotify");
// signal ourselves
if ( iRequestActive )
{
iRequestActive = EFalse;
TRequestStatus* status = &iStatus;
User::RequestComplete( status, KErrNone );
}
//no else
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::FlushNotify
// 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.
// -----------------------------------------------------------------------------
//
void CDpRx2Dte::FlushNotify()
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_FLUSHNOTIFY, "CDpRx2Dte::FlushNotify" );
LOGM("CDpRx2Dte::FlushNotify()");
ReleaseNotify();
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::Role
// This method gets the role (reader/writer) of data client.
// -----------------------------------------------------------------------------
//
TUint8 CDpRx2Dte::Role()
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_ROLE, "CDpRx2Dte::Role" );
return iRole;
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::SetBreakBytes
// Set break bytes to be send before break. If no breakbytes
// we can complete break notify right here.
// -----------------------------------------------------------------------------
//
void CDpRx2Dte::SetBreakBytes(
const TInt aBreakBytes )
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_SETBREAKBYTES, "CDpRx2Dte::SetBreakBytes" );
LOGM("CDpRx2Dte::SetBreakBytes");
iBreakBytes = aBreakBytes;
if ( iBreakBytes > 0 )
{
// there is some data before break
iBreakPending = ETrue;
}
else
{
// data before break has sent
iDataPort.BreakNotifyCompleted( KErrNone );
iBreak.SetBreakNotify( EFalse );
iBreakPending = EFalse;
}
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::EchoTx
// We are requested to write TX data back to client buffer.
// - Append echo data to small buffer.
// - Signal ourselves to data be written into client space
// -----------------------------------------------------------------------------
//
void CDpRx2Dte::EchoTx(
const TPtr8& aEchoData )
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_ECHOTX, "CDpRx2Dte::EchoTx" );
LOGM("CDpRx2Dte::EchoTx");
if ( EchoBytesFreeSpace() >= aEchoData.Length() )
{
iEchoData.Append( aEchoData );
ReleaseNotify();
}
//no else
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::EchoBytes
// This method gets count of echo bytes.
// -----------------------------------------------------------------------------
TInt CDpRx2Dte::EchoBytes()
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_ECHOBYTES, "CDpRx2Dte::EchoBytes" );
LOGM("CDpRx2Dte::EchoBytes");
return iEchoData.Length();
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::EchoBytesFreeSpace
// This method gets echo buffer's free space.
// -----------------------------------------------------------------------------
//
TInt CDpRx2Dte::EchoBytesFreeSpace()
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_ECHOBYTESFREESPACE, "CDpRx2Dte::EchoBytesFreeSpace" );
LOGM("CDpRx2Dte::EchoBytesFreeSpace");
TInt space( iEchoData.MaxLength() - iEchoData.Length() );
if ( 0 > space )
{
space = 0;
}
//no else
return space;
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::ResetEchoBytes
// This method resets bytes from echo data.
// -----------------------------------------------------------------------------
//
void CDpRx2Dte::ResetEchoBytes()
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_RESETECHOBYTES, "CDpRx2Dte::ResetEchoBytes" );
LOGM("CDpRx2Dte::ResetEchoBytes");
iEchoData.Zero();
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::WriteEchoToClient
// Writes echo bytes back to client
// -----------------------------------------------------------------------------
//
TInt CDpRx2Dte::WriteEchoToClient()
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_WRITEECHOTOCLIENT, "CDpRx2Dte::WriteEchoToClient" );
OstTrace1( TRACE_NORMAL, DUP1_CDPRX2DTE_WRITEECHOTOCLIENT, "CDpRx2Dte:: Port: %u", iDataPort.PortUnit() );
LOGM1("CDpRx2Dte::WriteEchoToClient - Port %d", iDataPort.PortUnit() );
TInt ret( KErrNone );
TInt spaceLeft( iClientBufferLength - iIPCWriteOffset );
LOG1(" Rx2Dte::WriteEchoToClient, Client buffer length: %d",
iClientBufferLength );
OstTrace1( TRACE_NORMAL, DUP2_CDPRX2DTE_WRITEECHOTOCLIENT, "CDpRx2Dte:: Client buffer length: %d", iClientBufferLength );
if ( iEchoData.Length() > spaceLeft )
{
// Avoid client buffer overflow when writing echo data
// (e.g. at-commands)
ret = iDataPort.IPCWrite(
iClientBuffer, iEchoData.Left(spaceLeft), iIPCWriteOffset );
// Move rest data to left
iEchoData.Copy( iEchoData.Mid( spaceLeft ) );
iIPCWriteOffset = iIPCWriteOffset + spaceLeft;
}
else
{
ret = iDataPort.IPCWrite( iClientBuffer, iEchoData, iIPCWriteOffset );
iIPCWriteOffset = iIPCWriteOffset + iEchoData.Length();
iEchoData.Zero();
}
if ( KErrNone != ret )
{
// Try to recover from write fail
iEchoData.Zero();
// Reset read
iReadPending = EFalse;
iStatus = KRequestPending;
if ( !IsActive() )
{
iStatus = KRequestPending;
iRequestActive = ETrue;
SetActive();
}
//no else
// Complete the read
iDataPort.ReadCompleted( ret );
ResetDteRead();
}
else
{
// We have space
iDataPort.SignalDte2Tx();
if ( ( 0 > iClientRequestedLength ) ||
( iIPCWriteOffset >= iClientRequestedLength ) ||
( iIPCWriteOffset >= iClientBufferLength ) )
{
// Complete the read in these situations:
// 1. ReadOneOrMore (iClientRequestedLength is then negative)
// 2. client requested length is full
// 3. client buffer is full
iDataPort.ReadCompleted( ret );
ResetDteRead();
}
//no else
}
return ret;
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::WriteIntoClientSpace
// Writes bytes into the client space
// -----------------------------------------------------------------------------
//
TInt CDpRx2Dte::WriteIntoClientSpace()
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_WRITEINTOCLIENTSPACE, "CDpRx2Dte::WriteIntoClientSpace" );
LOGM1("CDpRx2Dte::WriteIntoClientSpace - Port %d", iDataPort.PortUnit() );
TInt ret( KErrNone );
// Write into client space
ret = Write();
if ( ret != KErrNone )
{
// Try to recover from write fail
iDataPort.ReadCompleted( ret );
ResetDteRead();
if ( !IsActive() )
{
iStatus = KRequestPending;
iRequestActive = ETrue;
SetActive();
}
//no else
}
else
{
// Is flowctrl on and rxBuffer "low watermark" reached
if ( iFlowCtrl.FlowCtrlDcs2Dp() == EFlowControlOn )
{
if ( iBufferRx.UsedBytes() <= iDataConfig.WaterMarkLowSize( iBufferRx ) )
{
// OK, now we have again space in buffer
LOG(" CDpRx2Dte::WriteIntoClientSpace, Rx Low WaterMarkReached.");
OstTrace0( TRACE_NORMAL, DUP1_CDPRX2DTE_WRITEINTOCLIENTSPACE, "CDpRx2Dte:: Rx Low WaterMark reached" );
iFlowCtrl.WaterMarkLowReached();
}
//no else
}
//no else
}
return ret;
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::FindMaximumLength
// Find maximum length i.e. which one is smaller: our maximum
// reservation size or client buffer where we write. We can't
// write data over client buffer size -> smaller must be chocen.
// -----------------------------------------------------------------------------
//
TInt CDpRx2Dte::FindMaximumLength()
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_FINDMAXIMUMLENGTH, "CDpRx2Dte::FindMaximumLength" );
LOGM("CDpRx2Dte::FindMaximumLength");
TInt len( 0 );
if ( ( iClientBufferLength - iIPCWriteOffset ) >
iBufferRx.UsedBytes() )
{
len = iBufferRx.UsedBytes();
}
else
{
len = iClientBufferLength - iIPCWriteOffset;
}
return len;
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::FindLength
// This method returns amount of break bytes, if break is pending.
// Amount of used bytes is returned, if break is not pending. If the
// amount exceeds given length, the length is returned.
// -----------------------------------------------------------------------------
//
TInt CDpRx2Dte::FindLength(
const TInt aMaxLen )
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_FINDLENGTH, "CDpRx2Dte::FindLength" );
LOGM("CDpRx2Dte::FindLength");
TInt len( 0 );
if ( iBreakPending )
{
// lenght is count of bytes before break, but maximum maxLen
if ( iBreakBytes <= aMaxLen )
{
len = iBreakBytes;
}
else
{
len = aMaxLen;
}
}
else
{
// lenght is as much as possible, but maximum maxLen
if ( iBufferRx.UsedBytes() <= aMaxLen )
{
len = iBufferRx.UsedBytes();
}
else
{
len = aMaxLen;
}
}
return len;
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::MakeRx2DteWrite
// Makes the actual write operation.
// -----------------------------------------------------------------------------
//
TInt CDpRx2Dte::MakeRx2DteWrite(
const TInt aLen )
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_MAKERX2DTEWRITE, "CDpRx2Dte::MakeRx2DteWrite" );
OstTraceExt2( TRACE_NORMAL, DUP1_CDPRX2DTE_MAKERX2DTEWRITE, "CDpRx2Dte::MakeRx2DteWrite %x, Port: %u", (TUint)&iDataPort, iDataPort.PortUnit() );
LOGM2("CDpRx2Dte::MakeRx2DteWrite %x, Port %d",
&iDataPort, iDataPort.PortUnit() );
TInt ret( KErrNone );
TInt ind( 0 );
TInt termCount( iDataConfig.TerminatorCount() );
// There is data in rx buffer
if ( iRx.Length() )
{
// Scan terminator from iRx
if ( 0 < termCount )
{
ind = iTermDetect.Scan( iRx );
// terminator found
if ( 0 <= ind )
{
iRx.SetLength( ind + 1 );
iRxTail.SetLength( 0 );
}
//no else
}
//no else
// IPC write into client space
ret = iDataPort.IPCWrite( iClientBuffer, iRx, iIPCWriteOffset );
iIPCWriteOffset = iIPCWriteOffset + iRx.Length();
if ( KErrNone != ret )
{
LOG(" CDpRx2Dte::MakeRx2DteWrite, Rx element release (IPCWrite failed)");
OstTrace0( TRACE_NORMAL, DUP2_CDPRX2DTE_MAKERX2DTEWRITE, "CDpRx2Dte:: Rx element release (IPCWrite failed)" );
// Release element, because IPCWrite failed
TInt err ( iBufferRx.ReadElement().Release( 0 ) );
if ( KErrNone != err )
{
ret = err;
}
//no else
}
//no else
}
//no else
// Tail has a length, make the write in two pieces
if ( KErrNone == ret && iRxTail.Length() )
{
ret = WriteTail( ind, termCount );
iIPCWriteOffset = iIPCWriteOffset + iRxTail.Length();
if ( KErrNone != ret )
{
LOG(" CDpRx2Dte::MakeRx2DteWrite, Rx element release (IPCWrite failed)");
OstTrace0( TRACE_NORMAL, DUP3_CDPRX2DTE_MAKERX2DTEWRITE, "CDpRx2Dte:: Rx element release (IPCWrite failed)" );
// Release element, because IPCWrite failed
TInt err ( iBufferRx.ReadElement().Release( iRx.Length() ) );
if ( KErrNone == err )
{
iReadPending = EFalse;
}
else
{
ret = err;
}
}
//no else
}
//no else
if ( KErrNone == ret )
{
if ( ( 0 > iClientRequestedLength ) ||
( 0 < termCount && 0 <= ind ) ||
( iIPCWriteOffset >= iClientRequestedLength ) ||
( iIPCWriteOffset >= iClientBufferLength ) )
{
// Complete the read in these situations:
// 1. ReadOneOrMore (iClientRequestedLength is then negative)
// 2. client uses terminated_read and terminator byte found
// 3. client requested length is full
// 4. client buffer is full
//
// (if terminator not found we don't complete read yet)
iDataPort.ReadCompleted( ret );
ResetDteRead();
}
//no else
// Release read element
OstTrace0( TRACE_NORMAL, DUP4_CDPRX2DTE_MAKERX2DTEWRITE, "CDpRx2Dte:: Rx element release" );
OstTrace1( TRACE_NORMAL, DUP5_CDPRX2DTE_MAKERX2DTEWRITE, "CDpRx2Dte:: Rx element release - iRx: %d", iRx.Length() );
OstTrace1( TRACE_NORMAL, DUP6_CDPRX2DTE_MAKERX2DTEWRITE, "CDpRx2Dte:: Rx element release - iRxTail: %d", iRxTail.Length() );
LOG(" CDpRx2Dte::MakeRx2DteWrite, Rx element release");
LOG1(" CDpRx2Dte::MakeRx2DteWrite, Rx element release - iRx: %d",
iRx.Length() );
LOG1(" CDpRx2Dte::MakeRx2DteWrite, Rx element release - iRxTail: %d",
iRxTail.Length() );
ret = iBufferRx.ReadElement().Release( iRx.Length() + iRxTail.Length() );
if ( KErrNone == ret )
{
// Reset descriptors
iRx.SetLength( 0 );
iRxTail.SetLength( 0 );
if ( iBreakPending )
{
iBreakBytes -= aLen;
if ( 0 == iBreakBytes )
{
iBreakPending = EFalse;
iDataPort.BreakNotifyCompleted( KErrNone );
iBreak.SetBreakNotify( EFalse );
}
//no else
}
//no else
}
}
//no else
return ret;
}
// -----------------------------------------------------------------------------
// CDpRx2Dte::WriteTail
// Writes the tail.
// -----------------------------------------------------------------------------
//
TInt CDpRx2Dte::WriteTail(
TInt& aInd,
const TInt aTermCount )
{
OstTrace0( TRACE_NORMAL, CDPRX2DTE_WRITETAIL, "CDpRx2Dte::WriteTail" );
OstTrace1( TRACE_NORMAL, DUP1_CDPRX2DTE_WRITETAIL, "CDpRx2Dte:: Port: %u", iDataPort.PortUnit() );
OstTrace0( TRACE_NORMAL, DUP2_CDPRX2DTE_WRITETAIL, "CDpRx2Dte:: -------------- Write Rx Tail --------------" );
LOGM1("CDpRx2Dte::WriteTail - Port %d", iDataPort.PortUnit() );
LOG("-------------- Write Rx Tail --------------");
// scan terminator from iRxTail
if ( 0 < aTermCount )
{
aInd = iTermDetect.Scan( iRxTail );
// terminator found
if ( 0 <= aInd )
{
iRxTail.SetLength( aInd + 1 );
}
//no else
}
//no else
// we have to make two writes to client buffer. Second write starts
// from where first one ends --> offset = iRx.Length().
return ( iDataPort.IPCWrite( iClientBuffer, iRxTail, iIPCWriteOffset ) );
}
// ========================== OTHER EXPORTED FUNCTIONS =========================
// none
// End of File