cbsref/csyrefplugins/csy27010/src/ChannelMgrBase.cpp
branchRCL_3
changeset 65 630d2f34d719
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cbsref/csyrefplugins/csy27010/src/ChannelMgrBase.cpp	Tue Aug 31 16:23:08 2010 +0300
@@ -0,0 +1,818 @@
+//
+// * Copyright 2004 Neusoft America Inc.
+// * All rights reserved.
+// * This component and the accompanying materials are made available
+// * under the terms of the Eclipse Public License v1.0
+// * which accompanies this distribution, and is available
+// * at the URL "http://www.eclipse.org/legal/epl-v10.html".
+// *
+// * Contributors:
+// * Keith Collins (Neusoft America Inc.)  original software development and additional code and modifications.
+// * Thomas Gahagen (Neusoft America Inc.)  additional code and modifications.
+// * Zhen Yuan (Neusoft America Inc.)  additional code and modifications.
+// *
+// * Description:  The CChannelMgrBase class defines a single 3GPP 27.010 based logical channel
+// *               called DLC. This base class is inherited by derived control and data channel
+// *               classes which add specific channel type behavior.
+//
+
+// ChannelMgrBase.cpp
+
+/** @file ChannelMgrBase.cpp
+ *
+ */
+
+#include "ChannelMgrBase.h"
+#include "CsyMsgBufBpFrame.h"
+#include "PortC32Interface.h"
+#include "Mux0710Protocol.h"
+#include "CsyDebugLogger.h"
+#include "CommFrameWriterAo.h"
+
+CChannelMgrBase::CChannelMgrBase(const TUint8 aDlcNum,
+								 CPortFactory& aPortFactory,
+								 CMux0710Protocol& aMux0710Protocol)
+: iV24Signals(0x0D),
+  iDlcNum(aDlcNum),
+#ifndef __CSY_PROTOTYPE__
+  iChannelState(ECsyChannelStateDisconnected),
+#else
+  iChannelState(ECsyChannelStateConnected),
+#endif
+  iPortFactory(aPortFactory),
+  iPortC32Interface(NULL),
+#ifndef __CSY_PROTOTYPE__
+  iMux0710Protocol(aMux0710Protocol),
+#else
+  iMux0710Protocol(aMux0710Protocol),
+  iChannelReady(ETrue),
+  iInitFinished(ETrue),
+#endif
+  iModemAllowedToSendFrames(EFlowControlOff)
+/**
+ * Constructor.
+ * @param aDlcNum - DLC number for the channel
+ * @param aPortFactory - Reference to port factory
+ * @param aMux0710Protocol - Reference to the Mux 27.010 object
+ */
+ 	{
+	}
+
+CChannelMgrBase::~CChannelMgrBase()
+/**
+ * Destructor. Delete all resources and memory allocated by this object.
+ */
+	{
+	_LOG_L4C1("CChannelMgrBase::~CChannelMgrBase");
+
+	delete iChannelObserverAo;
+	delete iTimeouter;
+	}
+
+void CChannelMgrBase::ConstructL()
+/**
+ * Create any instances and allocate any memory used by this object.
+ */
+ 	{
+	_LOG_L4C1("CChannelMgrBase::ConstructL");
+
+	iChannelObserverAo = CChannelObserverAo::NewL();
+	CActiveScheduler::Add(iChannelObserverAo); 
+
+	iTimeouter = CActiveTimeouter::NewL(*this);
+	iTimeoutVal = KOneSecond;
+	iTxCountLimit = 10;
+	}
+
+TDes8& CChannelMgrBase::RefToMsgBuffer()
+/**
+ * This method returns a pointer to the message buffer to use
+ * to format a message to send to the baseband.
+ *
+ * @return pointer
+ */
+	{
+	// only one buffer is available for messages to the baseband
+	return iDataToSendToModem;
+	}
+
+void CChannelMgrBase::ProcessRecvFrame(CCsyMsgBufBpFrame* aBpFrame)
+/**
+ * This method is called to process a frame that was received
+ *
+ * @param aBpFrame - Pointer to the frame buffer
+ */
+	{
+	if (aBpFrame->GetFrameType() != KCsy0710CTLUIH)
+		ProcessNonUihRecvFrame(aBpFrame);
+	else
+		ProcessRecvUihFrame(aBpFrame);
+	}
+
+TInt CChannelMgrBase::PlaceOnOutboundQueue()
+/**
+ * This method is called to process the "to baseband Message Q" event
+ * for the channel. This event indicates that there is a message
+ * that needs to be sent to the baseband.
+ */
+	{
+	_LOG_L4C2(">>CChannelMgrBase::PlaceOnOutboundQueue [iDlcNum=%d]",iDlcNum);
+
+	TInt ret = KErrNone;
+
+	if (iCsyAllowedToSendFrames == EFlowControlOn)
+		{
+		_LOG_L4C1("Csy -> modem flow control = ON");
+		iDelayedWriteToModem = ETrue;
+
+		// We cannot fragment and place it on the write queue yet since
+		// flow control in the direction of Csy to modem is set to ON.
+		
+		_LOG_L4C1("<<CChannelMgrBase::PlaceOnOutboundQueue - write delayed");
+		return KErrNone;	
+		}
+
+	if (iChannelState != ECsyChannelStateConnected)
+		{
+		// this should not happen (should be caught by flow control above)
+		// MAF __ASSERT_DEBUG(EFalse,PANIC(KPanicIllegalState));
+		_LOG_L4C1("<<CChannelMgrBase::PlaceOnOutboundQueue - write ignored");
+		return KErrNone;	
+		}
+
+	ret = iMux0710Protocol.Create0710DataFrames(iDataToSendToModem, iDlcNum);
+
+	_LOG_L4C2("<<CChannelMgrBase::PlaceOnOutboundQueue [ret=%d]",ret);
+	return ret;
+	}
+
+void CChannelMgrBase::WriteCancel()
+/**
+ * The client has requested the write by this DLC be cancelled.
+ */
+	{
+	_LOG_L4C1(">>CChannelMgrBase::WriteCancel");
+
+	if (iDelayedWriteToModem)
+		{
+		_LOG_L4C1("Delayed write has been cancelled");
+		iDelayedWriteToModem = EFalse;
+		}
+
+	_LOG_L4C1("Remove any frames on write queue");
+
+	// remove any frames (if any exist) from the writer Ao and
+	// place them on the free queue
+	
+	CCommFrameWriterAo* writer = iPortFactory.GetCommWriterAo();
+
+	writer->RemoveAnyDlcFramesOnWriteList(iDlcNum, EFalse);
+	writer->RemoveAnyDlcFramesFromWaitList(iDlcNum, EFalse);
+
+	_LOG_L4C1("<<CChannelMgrBase::WriteCancel");
+	}
+
+TInt CChannelMgrBase::Connect()
+/**
+ * Request to connect the channel. If the channel state is not "Connected"
+ * then issue a SABM frame and change the channel state to "Connecting".
+ *
+ * @return KErrNone or KErrGeneral
+ */
+    {
+    _LOG_L4C3(">>CChannelMgrBase::Connect [iDlcNum=%d,iChannelState=%d]",
+		iDlcNum,iChannelState);
+
+	TInt ret = KErrNone;
+	if (iChannelState != ECsyChannelStateConnected)
+		{
+		_LOG_L4C1("Dlc is not currently connected");
+		ret = iMux0710Protocol.Create0710ControlFrame(CMux0710Protocol::ESABM, iDlcNum);
+		if (ret == KErrNone)
+			{
+			iChannelState = ECsyChannelStateConnecting;
+			iInitFinished = EFalse;
+			iTimeouter->Stop();
+			iTimeouter->Start(iTimeoutVal);
+			iTxCount = iTxCountLimit;
+			}
+		else
+			{
+			_LOG_L1C1("** Cannot send SABM **");
+			}
+		}
+	else
+		{
+		_LOG_L2C1("** Ignored Connect **");
+		ret = KErrGeneral;
+		}
+
+    _LOG_L4C2("<<CChannelMgrBase::Connect [ret=%d]",ret);
+	return ret;
+	}
+
+TInt CChannelMgrBase::ParameterNegotiate()
+/**
+ * Request to parameter negotiation for the channel. If the channel state is not 
+ * "Connected" then issue a UIH frame and with the parameter negotiation.
+ *
+ * @return KErrNone or KErrGeneral
+ */
+    {
+    _LOG_L4C3(">>CChannelMgrBase::ParameterNegotiate [iDlcNum=%d,iChannelState=%d]",
+		iDlcNum,iChannelState);
+
+	TInt ret = KErrNone;
+	if (iChannelState != ECsyChannelStateConnected) 
+		{
+		_LOG_L4C1("Dlc is not currently connected");
+		if (iMux0710Protocol.Create0710ControlFrame(CMux0710Protocol::EUIH, iDlcNum) == KErrNone)
+			{
+			iChannelState = ECsyChannelStateParameterNegotiating;
+			iTimeouter->Stop();
+			iTimeouter->Start(iTimeoutVal);
+			iTxCount = iTxCountLimit;
+			}
+		else
+			{
+			_LOG_L1C1("** Cannot send EUIH Param Neg. **");
+			ret = KErrGeneral;
+			}
+		}
+	else
+		{
+		_LOG_L2C1("** Ignored ParameterNegotiate **");
+		}
+
+    _LOG_L4C2("<<CChannelMgrBase::ParameterNegotiate [ret=%d]",ret);
+	return ret;
+	}
+
+TInt CChannelMgrBase::Disconnect()
+/**
+ * Request to disconnect the channel. If the channel is not "Disconnected"
+ * then issue a DISC frame and change the channel state to "Disconnecting".
+ *
+ * @return KErrNone or error code
+ */
+    {
+    _LOG_L4C3(">>CChannelMgrBase::Disconnect [iDlcNum=%d,iChannelState=%d]",
+		iDlcNum,iChannelState);
+		
+	TInt ret = KErrNone;
+	if (iChannelState == ECsyChannelStateConnected)
+		{
+		_LOG_L4C1("Dlc is currently connected");
+		if (iMux0710Protocol.Create0710ControlFrame(CMux0710Protocol::EDISC, iDlcNum) == KErrNone)
+			{
+			iChannelState = ECsyChannelStateDisconnecting;
+			_LOG_L1C2("** Setting Channel Ready to False for DLC %d **",iDlcNum);
+			iChannelReady = EFalse;
+			iTimeouter->Stop();
+			
+			// Allow time for the channel to disconnect...
+			User::After(1);
+			}
+		else
+			{
+			_LOG_L1C1("** Cannot send EDISC **");
+			ret = KErrGeneral;
+			}
+		}
+	else if (iChannelState == ECsyChannelStateTransmitError)
+		{
+		_LOG_L2C1("** Disconnect request for channel with transmit error **");
+		ret = KErrNone;
+		}
+	else
+		{
+		_LOG_L2C1("** Ignored disconnect **");
+		ret = KErrGeneral;
+		}
+
+    _LOG_L4C2("<<CChannelMgrBase::Disconnect [ret=%d]",ret);
+	return ret;
+	}
+
+void CChannelMgrBase::ProcessNonUihRecvFrame(CCsyMsgBufBpFrame* aBpFrame)
+/**
+ * This method is called to process a Non-UIH frame which the channel
+ * has received from the baseband for the channel.
+ *
+ * @param aBpFrame - Pointer to the received Non-UIH frame
+ */
+	{
+	_LOG_L4C2(">>CChannelMgrBase::ProcessNonUihRecvFrame [iDlcNum=%d]", iDlcNum);
+
+	TUint8 frameType = aBpFrame->GetFrameType();
+	iMux0710Protocol.AddFrameFreeQ(aBpFrame);
+
+	switch (frameType)
+		{
+	case KCsy0710CTLSABM:
+		_LOG_L4C1("SABM");
+		// MAF we should respond to this
+		break;
+
+	case KCsy0710CTLUA:
+		{
+		_LOG_L4C1("UA");
+		iTimeouter->Stop();
+
+		if (iChannelState == ECsyChannelStateConnecting)
+			{
+			_LOG_L4C1("SABM received by remote end - send MSC command");
+			if (SendMscCommand(iV24Signals) == KErrNone)
+				iChannelState = ECsyChannelStateMSCsent;
+			}
+		else if (iChannelState == ECsyChannelStateDisconnecting)
+			{
+			_LOG_L4C2("Channel disconnected %d", iDlcNum);
+			iChannelState = ECsyChannelStateDisconnected;
+
+			if (iPortFactory.DecrementNumOfOpenPorts())
+				{
+				NotifyChannelReady();
+				}
+			}
+		}
+		break;
+
+	case KCsy0710CTLDM:    // 0x0F
+		_LOG_L4C1("DM");
+		break;
+
+	case KCsy0710CTLDISC:  // 0x43
+		_LOG_L4C1("DISC");
+		// MAF we should respond to this
+		break;
+
+	case KCsy0710CTLUIH:
+	case KCsy0710CTLUI:
+		// MAF __ASSERT_DEBUG(EFalse,PANIC(KPanicIllegalState)); here
+		break;
+	
+	default:
+		_LOG_L1C2("** Unknown FrameType = 0x%02x **", frameType);
+		break;
+		}
+
+	_LOG_L4C1("<<CChannelMgrBase::ProcessNonUihRecvFrame");
+	}
+
+TInt CChannelMgrBase::SendMscCommand(TUint8 aV24Signals)
+/**
+ * Sends an MSC command
+ *
+ * @param aV24Signals
+ * @return error if failed to send
+ */
+	{
+	_LOG_L4C2(">>CChannelMgrBase::SendMscCommand [aV24Signals=0x%02x]",
+		aV24Signals);
+
+	if (iMscReplyExpected)
+		{
+		_LOG_L4C1("<<CChannelMgrBase::SendMscCommand - already doing MSC");
+		return KErrNotReady;
+		}
+
+	// Keep the signals in case of resend
+	iV24Signals = aV24Signals;
+	TInt ret = iMux0710Protocol.Create0710ControlFrame(
+		CMux0710Protocol::EUIH, iDlcNum, CMux0710Protocol::EMSC, iV24Signals);
+	
+	if (ret != KErrNone)
+		{
+		_LOG_L1C1("** Could not send MSC command **");
+		}
+	else
+		{
+		iTimeouter->Stop();
+		iTimeouter->Start(iTimeoutVal);
+		iTxCount = iTxCountLimit;
+		iMscReplyExpected = ETrue;
+		}
+
+	_LOG_L4C2("<<CChannelMgrBase::SendMscCommand [ret=%d]",ret);
+	return ret;
+	}
+
+void CChannelMgrBase::MscReceived(TUint8 aV24Signals)
+/**
+ * Processes a received MSC command
+ *
+ * @param aV24Signals
+ */
+	{
+	_LOG_L4C2(">>CChannelMgrBase::MscReceived [aV24Signals=0x%x]",
+		aV24Signals);
+
+	if (!iMscReplyExpected)
+		{
+		_LOG_L2C1("*** Not expecting MscReceived? ***");
+		return;
+		}
+
+	iMscReplyExpected = EFalse;
+	iTimeouter->Stop();
+
+	if (iChannelState == ECsyChannelStateMSCsent)
+		{
+		_LOG_L4C1("MSC cmd part of start up sequence");
+		iChannelState = ECsyChannelStateWaitingForChannelReady;
+
+		//different type of channel may need different init process.
+		if (iPortC32Interface)
+			{
+#ifdef _27010ADVANCEOPTION
+			if (iPortC32Interface->GetClientType() == CPortFactory::EC32ClientIpNif)
+				{
+				_LOG_L4C1(" IpNif Channel Initialized");
+				// Don't need to wait for AT command interpreter ready since not AT
+				iChannelState = ECsyChannelStateConnected;
+				NotifyChannelReady();
+				ModemAndCsyToClientFlowCtrl(EFlowControlOff);
+				}
+#endif
+			}
+		else
+			{
+			// Command channel
+			iChannelState = ECsyChannelStateConnected;
+			NotifyChannelReady();
+			}
+		}
+
+	if ((iDlcNum)&&(iV24Signals != aV24Signals))
+		{
+		_LOG_L4C3("Data Dlc - Response different to sent [%x != %x]",
+			iV24Signals, aV24Signals);
+
+		ReceivedV24Signals(aV24Signals);
+		}
+
+	_LOG_L4C1("<<CChannelMgrBase::MscReceived");
+	}
+
+void CChannelMgrBase::ModemAndCsyToClientFlowCtrl(const TFlowControl aFlowControl)
+/**
+ * Set the channel's flow control to the specified value.
+ * Update the associate port object's flow control if the port object 
+ * exists.
+ *
+ * @param aFlowControl - New flow control state
+ */
+ 	{
+	_LOG_L4C3(">>CChannelMgrBase::ModemAndCsyToClientFlowCtrl [aFlowControl=%d,iDlcNum=%d]", 
+		aFlowControl,iDlcNum);
+
+	iCsyAllowedToSendFrames = aFlowControl;
+	if ((aFlowControl == EFlowControlOff)&&(iDelayedWriteToModem))
+		{
+		_LOG_L4C1("Flow control now OFF - delayed frame to send");
+
+		TInt ret = iMux0710Protocol.Create0710DataFrames(iDataToSendToModem, iDlcNum);
+		if (ret)
+			{
+			_LOG_L1C2("** Fragmentation failed [ret=%d] **",ret);
+			}
+		else
+			{
+			_LOG_L4C1("Delayed write placed on write queue");
+			iDelayedWriteToModem = EFalse;
+			}
+		}
+
+	CPortC32InterfaceBase* port = GetC32Port();
+	if (port)
+		port->ModemAndCsyToClientFlowCtrl(aFlowControl);
+	else
+		{
+		_LOG_L2C1("** GetC32Port() returned NULL **");
+		}
+
+	_LOG_L4C1("<<CChannelMgrBase::ModemAndCsyToClientFlowCtrl");
+	}
+
+void CChannelMgrBase::ReceivedV24Signals(const TUint8 aV24Signals)
+/**
+ * Set the channel's signals to the specified value.
+ * Update the associate port object's flow control if the port object 
+ * exists.
+ *
+ * @param aSignals - new signal state
+ */
+ 	{
+	_LOG_L4C3(">>CChannelMgrBase::ReceivedV24Signals [aV24Signals=0x%x,iDlcNum=%d]", 
+		aV24Signals,iDlcNum);
+
+	CPortC32InterfaceBase* port = GetC32Port();
+	if (port)
+		{
+		// Flow control
+		TFlowControl flowControl = EFlowControlOff;
+
+		// FC (bit 2)
+		if (aV24Signals & 0x02)
+			{
+			_LOG_L4C2("FC=1 - modem dlc %d unable to accept frames",iDlcNum);
+			flowControl = EFlowControlOn;
+			_LOG_L4C1("flowControl On  (i.e stop flow)");
+
+			// move frames for this dlc from write list to wait list
+			iPortFactory.GetCommWriterAo()->RemoveAnyDlcFramesOnWriteList(iDlcNum);
+			}
+		else
+			{
+			// move any frames for this dlc from wait to write list
+			iPortFactory.GetCommWriterAo()->RemoveAnyDlcFramesFromWaitList(iDlcNum);
+			}
+
+		ModemAndCsyToClientFlowCtrl(flowControl);
+
+		port->ReceivedV24Signals(aV24Signals);
+		}
+	else
+		{
+		_LOG_L2C1("** GetC32Port() returned NULL **");
+		}
+
+	_LOG_L4C1("<<CChannelMgrBase::ReceivedV24Signals");
+	}
+
+void CChannelMgrBase::WaitForChannelReady()
+/**
+ * This method starts an active object and waits for the channel ready
+ * call back signal.
+ */
+	{
+	_LOG_L4C1(">>CChannelMgrBase::WaitForChannelReady");
+
+	if (iMux0710Protocol.MaxRetriesReached())
+		{
+		_LOG_L4C1("Mux Max Retries reached - so skip Channel Ready");
+		}
+	else
+		{
+		// kick off an active object and wait for channel ready call back
+		if (iChannelReady)
+			{
+			_LOG_L4C2("iChannelReady=%d",iChannelReady);
+			}
+		else if (!iChannelObserverAo->IsActive())
+			{
+			// start the active object. CSY will wait here until channel is ready
+			// nest active scheduler is used here as we did not want to block whole thread (reading/writing)
+
+			iChannelObserverAo->StartWait();
+
+			// start a nested scheduling; blocks until CActiveScheduler::Stop() 
+			// is called in DoCancel()
+
+			// MAF look at use CActiveSchedulerWait instead of this
+
+			// One basic assumption here is that CSY will process port open request one by one
+			// (although there may be mutiple port open requests from clients, c32 will call PortFactory::NewPortL
+			// one by one.) This assumption should be valid as it is only one thread for c32
+			// if this assumption does not hold, headache follows.
+			_LOG_L4C1("Start wait for channel ready");
+
+			CActiveScheduler::Start();
+			_LOG_L4C1("End wait for channel ready");
+			}
+		else
+			{
+			_LOG_L4C1("We are here only when others are already waiting");
+			}
+		}
+	_LOG_L4C1("<<CChannelMgrBase::WaitForChannelReady");
+	}
+
+void CChannelMgrBase::TimedOut()
+/**
+ * This method will be called when we have a timeout During receive a reply.
+ * It will retransmit if needed.
+ */
+	{
+	_LOG_L4C1(">>CChannelMgrBase::TimedOut");
+
+	iTxCount--;
+	if (iTxCount > 0)  // retransmit
+		{
+		_LOG_L4C2("iTxCount=%d",iTxCount);
+
+		TInt ret = KErrNone;
+		if (iMscReplyExpected)
+			{
+			iMscReplyExpected = EFalse;
+			ret = SendMscCommand(iV24Signals);
+			}
+		else
+			{
+			switch(iChannelState)
+				{
+			case ECsyChannelStateParameterNegotiating:
+				ret = iMux0710Protocol.Create0710ControlFrame(
+					CMux0710Protocol::EUIH, iDlcNum, CMux0710Protocol::EParamNeg);
+				break;
+			case ECsyChannelStateConnecting:
+				ret = iMux0710Protocol.Create0710ControlFrame(
+					CMux0710Protocol::ESABM, iDlcNum);
+				break;
+			case ECsyChannelStateDisconnecting:
+				ret = iMux0710Protocol.Create0710ControlFrame(
+					CMux0710Protocol::EDISC, iDlcNum);
+				break;
+			default:
+				// should never reach here
+				_LOG_L1C1("** unexpected receiving timeout **");
+				}
+			}
+		if (ret)
+			{
+			// Error sending - we shall just wait until the timeout and try again
+			_LOG_L1C2("** Error sending on dlc 0 [ret=%d] **",ret);
+			}
+		iTimeouter->Stop();
+		iTimeouter->Start(iTimeoutVal);
+		}
+	else
+		{
+		_LOG_L1C1("** Retries expired **");
+		if (iMscReplyExpected)
+			{
+			_LOG_L1C1("** Retries expired for MSC command **");
+			iMscReplyExpected = EFalse;
+			}
+
+		// we have problem communication, may need to reset?
+		iChannelState = ECsyChannelStateTransmitError;
+		NotifyChannelReady();
+		}
+
+	_LOG_L4C1("<<CChannelMgrBase::TimedOut");
+	}
+
+void CChannelMgrBase::NotifyChannelReady()
+/**
+ * This method stops the waiting for a channel.
+ */
+	{
+	_LOG_L4C1("CChannelMgrBase::NotifyChannelReady");
+
+	iChannelReady = ETrue;
+	iInitFinished = ETrue;
+
+	// complete the active object if it is running
+	if (iChannelObserverAo->IsActive())
+		{
+		iChannelObserverAo->ChannelReady();
+		}
+	}
+
+TInt CChannelMgrBase::SetCsyToModemFlowControl(TFlowControl aFlowControl)
+/**
+ * 
+ */
+	{
+	_LOG_L4C3(">>CChannelMgrBase::SetCsyToModemFlowControl [aFlowControl=%d,iDlcNum=%d]",
+		aFlowControl,iDlcNum);
+
+	TInt ret = KErrNone;
+	if (aFlowControl != iModemAllowedToSendFrames)
+		{
+		TUint8 v24Signals = iV24Signals;
+		TBool sendCommand = EFalse;
+		if (aFlowControl == EFlowControlOn)
+			{
+			_LOG_L4C1("aFlowControl = ON");
+			if (v24Signals & 0x02)
+				{
+				_LOG_L4C1("** Flow control already set **");
+				}
+			else
+				{
+				v24Signals |= 0x02;
+				sendCommand = ETrue;
+				}
+			}
+		else
+			{
+			_LOG_L4C1("aFlowControl = OFF");
+			if (v24Signals & 0x02)
+				{
+				v24Signals ^= 0x02;
+				sendCommand = ETrue;
+				}
+			else
+				{
+				_LOG_L4C1("Flow control already off");
+				}
+			}
+		if (sendCommand)
+			{
+			ret = SendMscCommand(v24Signals);
+			if (ret)
+				{
+				_LOG_L4C1("SendMscCommand failed");
+				}
+			else
+				{
+				_LOG_L4C3("Csy to modem flow control changed %d -> %d",
+					iModemAllowedToSendFrames,aFlowControl);
+				iModemAllowedToSendFrames = aFlowControl;
+				}
+			}
+		}
+
+	_LOG_L4C2("<<CChannelMgrBase::SetCsyToModemFlowControl [ret=%d]",ret);
+	return ret;
+	}
+
+//
+// class CChannelObserverAo
+//
+
+CChannelObserverAo::CChannelObserverAo()
+: CActive(CActive::EPriorityStandard)
+/**
+ * Constructor.  Pass priority of active object to base class.
+ *
+ */
+	{}
+
+CChannelObserverAo* CChannelObserverAo::NewL()
+/**
+ * This method uses two phase construction and the cleanup stack
+ * to create an instance of class CChannelObserverAo.
+ *
+ * @return Pointer to the created instance
+ */
+	{
+	_LOG_L4C1("CChannelObserverAo::NewL");
+	return new (ELeave) CChannelObserverAo();
+	}
+
+CChannelObserverAo::~CChannelObserverAo()
+/**
+ * Destructor. Cancel any outstanding request.
+ */
+	{	
+	if (IsActive())
+		Cancel();
+	}
+
+void CChannelObserverAo::RunL()
+/**
+ * This method should not be called. Request of this 
+ * active object will only be canceled.
+ */
+	{
+	// MAF __ASSERT_DEBUG(EFalse,PANIC(KPanicIllegalState));
+	_LOG_L1C1("** CChannelObserverAo::RunL() - should not be called **");
+	}
+
+void CChannelObserverAo::DoCancel()
+/**
+ * Cancel an outstanding request. This will complete request
+ * with KErrCancel and stop waiting.
+ */
+	{
+	_LOG_L4C1("CChannelObserverAo::DoCancel");
+
+	iStatus = KErrCancel;
+	TRequestStatus* temp = &iStatus;
+	User::RequestComplete(temp, KErrCancel);
+
+	_LOG_L4C1("CChannelObserverAo stop scheduler");
+	CActiveScheduler::Stop();
+	}
+
+void CChannelObserverAo::StartWait()
+/**
+ * Set active and start waiting.
+ */
+	{
+	_LOG_L4C1("CChannelObserverAo::StartWait");
+	if (!IsActive())
+		{
+		iStatus = KRequestPending;
+		SetActive();
+		}
+	}
+
+void CChannelObserverAo::ChannelReady()
+/**
+ * Called when expected event occured to stop waiting. 
+ */
+	{
+	_LOG_L4C1("CChannelObserverAo::ChannelReady");
+
+	// complete current request
+	if (IsActive())
+		{
+		_LOG_L4C1("CChannelObserverAo Active");
+		Cancel();
+		}
+	}