diff -r 000000000000 -r dfb7c4ff071f serialserver/serialportcsy/ECUART.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/serialserver/serialportcsy/ECUART.CPP Thu Dec 17 09:22:25 2009 +0200 @@ -0,0 +1,2466 @@ +// Copyright (c) 2002-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: +// Implements a complete CSY for physical serial ports +// +// + +/** + @file +*/ + +#include +#include +#include +#include +// new header file introduced in C32 V2, old ecuart had no header file +#include "ECUART.H" +#include + +// This header import is new for C32 V2 but is not configured since then we don't need to configure all +// the logging we've added to this file during V2. The ecuartlog header file when pre-processed for pre-V2 +// will resolve all the logging to nothing since all its log macros for pre-V2 are defined empty. +#include "ECUARTLOG.H" + +const TUint KCommLowUnit=0; //< lowest port unit number for this CSY (i.e. COMM::0) + +#if defined(__WINS__) +const TUint KCommHighUnit=1; //< highest port unit number for this CSY (i.e. COMM::1) +#else // _MARM_ +const TUint KCommHighUnit=0; //< highest port unit number for this CSY (i.e. COMM::0) +#endif + +const TUint KDefaultBufSize = 0x100; //< size of the Tx/Rx buffers used in CCommWriter and CCommReader + +_LIT(KSerialDescription, "Built in Serial ports"); //< CSY description returned by RCommServ::GetPortInfo +#define SERIAL_NAME _S("COMM") //< name of prefix for each com port + +const TInt KReaderPriority=100; //< priority for the CCommReader active object +const TInt KWriterPriority=50; //< priority for the CCommWriter active object +const TInt KBreakerPriority=0; //< priority for the CCommBreaker active object +const TInt KNotifyPriority=0; //< priority for CCommNotifyBase derived active objects + + +//Security policy for a port. +class TPortSecurityPolicy + { +public: + //Port number which this policy will apply. + TInt iPort; + //Security policy. + TStaticSecurityPolicy iPolicy; + }; + +_LIT_SECURITY_POLICY_PASS(KDefaultPortPassPolicy); +_LIT_SECURITY_POLICY_FAIL(KPortAlwaysFailPolicy); + +#define KPlaceholderPortNumber -1 //a place holder port number used to initiliase KExplicitPortSecurityPolicies when no other ports require a policy different than the default. + +//Define policy for ports which are different from default policy (KDefaultPortPolicy) here. +//Default policy is EAlwaysPass but to provide example ports 0-1 are explicitly set to EAlwaysPass as well. +//Port policies must only apply for port number 0-(KMaxUnits-1). +//Add to this array for other ports that need policing with capabilities. +const TUint KExplicitPortPoliciesCount = 0; //Count of the number of entries in KExplicitPortSecurityPolicies. Currently only a place holder entry exists so the count = 0. +const struct TPortSecurityPolicy KExplicitPortSecurityPolicies[]= + { + {KPlaceholderPortNumber, _INIT_SECURITY_POLICY_FAIL} //this is a place holder entry which should be replaced with proper port policy when required to police a port with different capabiltiies to default policy. +// {0, _INIT_SECURITY_POLICY_C1( ECapabilityCommDD)}, //Example showing explicitly setting a policy different than default for Port 0 +// {1, _INIT_SECURITY_POLICY_C2( ECapabilityReadUserData, ECapabilityWriteUserData)} //Example showing explicitly setting a policy different than default for Port 1 + }; + + +// #define _DEBUG_CONSOLE_ + +#if defined(_DEBUG_CONSOLE_) +#include +class RDebugConsole : public RConsole + { +public: + RDebugConsole(); +public: + void Printf(TRefByValue aFmt,...); + }; + +#define DEBUG_TRACE(m) m + +#else // (_DEBUG) + +// debug trace (disabled in Release builds) +#define DEBUG_TRACE(m) +// +#endif + +// +// CCommReader CCommWriter and CCommBreaker are active objects which wait on +// completion from the serial channel for various actions. +// +class CHWPort; + +/** + * base class for CCommReader and CCommWriter + * + */ +class CCommReadWriteBase : public CActive + { +public: + CCommReadWriteBase(TInt aPriority, CHWPort* aParent); + ~CCommReadWriteBase(); + TInt SetServerConfig(TCommServerConfig& aConfig); + void GetServerConfig(TCommServerConfig& aConfig) const; + void FreeMemory(); + // set the role of this port unit @param aRole new role + inline void SetRole(TCommRole aRole){iRole=aRole;}; +protected: + void SetBuffersL(); + // return ETrue if partial buffering used + TBool UsePartial() {return ((iBufFlags & KCommBufferPartial)==KCommBufferPartial);} +protected: + HBufC8* iBuffer; //< pointer to the Tx/Rx buffer + TPtr8* iBuf; //< pointer to a TPtr8 that points to the current buffer + TUint iBufFlags; //< contains buffer flags e.g for partial read/write + TInt iBufSize; //< size of the Tx/Rx buffer + TCommRole iRole; //< DTE or DCE role for this port unit + CHWPort* iParent; //< pointer to the CHWPort object + }; + + +#if defined (_DEBUG_DEVCOMM) && defined (_DEBUG_CONSOLE_) +class CCommDebugDumper : public CActive + { +public: + static CCommDebugDumper* NewL(RDebugConsole &aConsole); + virtual void RunL(); + virtual void DoCancel(); + CCommDebugDumper::~CCommDebugDumper(); + // set the role of this port unit @param aRole new role + inline void SetRole(TCommRole aRole){iRole=aRole;}; +private: + CCommDebugDumper(RDebugConsole &aConsole); +private: + TCommRole iRole; //< DTE or DCE role for this port unit + RDebugConsole *iConsole; + TConsoleKey iKeystroke; + }; +#endif + + +/** + * Active Comm port Reader + * + * This class is responsible for reading data from the physical + * comm port. + */ +class CCommReader : public CCommReadWriteBase + { +public: + static CCommReader* NewL(CHWPort* aParent); + ~CCommReader(); + // from CActive + virtual void DoCancel(); + virtual void RunL(); + // + void Read(const TAny* aClientBuffer, TInt aLength); + void ReadCancel(); +private: + CCommReader(CHWPort* aParent); + void InitL(); +private: + TUint iLength; //< number of bytes to read + TAny* iClientBuffer; //< pointer to Client's buffer + TUint iBufPos; //< position in Client's buffer to read into (write) + TUint iBufActive; //< TRUE if partial buffering active + TInt iBufOneOrMoreSize; //< buffer size of ReadOneOrMore method + }; + + +/** + * Active Comm port Writer + * + * This class is responsible for writing data to the physical + * comm port. + */ +class CCommWriter : public CCommReadWriteBase + { +public: + static CCommWriter* NewL(CHWPort* aParent); + ~CCommWriter(); + // from CActive + virtual void DoCancel(); + virtual void RunL(); + // + void Write(const TAny* aClientBuffer, TInt aLength); + void WriteCancel(); + inline void NotificationEnable(); + inline void NotificationDisable(); + inline TBool IsNotificationEnabled(); +private: + CCommWriter(CHWPort* aParent); + void InitL(); +private: + TUint iLength; //< number of bytes to write + TAny* iClientBuffer; //< pointer to Client's buffer + TUint iBufPos; //< position in Client's buffer to read from + TUint iBufActive; //< TRUE if partial buffering active + TBool iNotificationEnabled; //< true if notification is enabled + }; + + + +/** + * Active Comm port Breaker + * + * This class is responsible for handling breaks on the physical + * comm port. + */ +class CCommBreaker : public CActive + { +public: + static CCommBreaker * NewL(CHWPort* aParent); + ~CCommBreaker(); + // from CActive + virtual void DoCancel(); + virtual void RunL(); + // + void Break(TInt aTime); + // set the role of this port unit @param aRole new role + inline void SetRole(TCommRole aRole){iRole=aRole;}; +private: + CCommBreaker(CHWPort* aParent); +private: + TCommRole iRole; //< DTE or DCE role for this port unit + CHWPort* iParent; //< pointer to the CHWPort object + }; + + +/** + * Base class for Notifiers + * + */ +class CCommNotifyBase : public CActive + { +public: + // set the role of this port unit @param aRole new role + inline void SetRole(TCommRole aRole){iRole=aRole;}; +protected: + CCommNotifyBase(CHWPort* aParent); + ~CCommNotifyBase(); +protected: + TCommRole iRole; //< DTE or DCE role for this port unit + CHWPort* iParent; //< pointer to the CHWPort object + }; + + +/** + * This class is responsible for notifying the client when + * the signal control lines are changing, including breaks. + */ +class CCommSignalNotifier : public CCommNotifyBase + { +public: + CCommSignalNotifier(CHWPort* aParent); + ~CCommSignalNotifier(); + // from CActive + virtual void DoCancel(); + virtual void RunL(); + // + void Start(); + void NotifySignal(TUint aSignalMask); + void NotifySignalCancel(); + void NotifyBreak(); + void NotifyBreakCancel(); +private: + TUint iSignals; //< bitmask with the new signal after notification completed + TUint iSignalMask; //< bitmask with the signals to be notified + TInt iNotifyCount; //< increased when either NotifySignals or NotifyBreak is using this class + //< decreased when RunL is called. Ensures that RComm::NotifyBreak will not + //< interfere with operation of RComm::NotifySignalsChange + }; + + +/** + * this class is responsible for notifying the client when + * there are some incoming data available. + */ +class CCommAvailableDataNotifier : public CCommNotifyBase + { +public: + CCommAvailableDataNotifier(CHWPort* aParent); + ~CCommAvailableDataNotifier(); + // from CActive + virtual void DoCancel(); + virtual void RunL(); + // + void Start(); + }; + + +/** + * this class is responsible for notifying the client when + * the flow control is changing. + */ +class CCommFlowControlChangeNotifier : public CCommNotifyBase + { +public: + CCommFlowControlChangeNotifier(CHWPort* aParent); + ~CCommFlowControlChangeNotifier(); + // from CActive + virtual void DoCancel(); + virtual void RunL(); + // + void Start(); +private: + TFlowControl iFlowControl; //< current flow control settings + }; + + +/** + * this class is responsible for notifying the client when + * the configuration is changing. + */ +class CCommConfigChangeNotifier : public CCommNotifyBase + { +public: + CCommConfigChangeNotifier(CHWPort* aParent); + ~CCommConfigChangeNotifier(); + void Start(); + // from CActive + virtual void DoCancel(); + virtual void RunL(); +private: + TCommNotificationPckg iConfig; //< current configuration package + }; + + +/** + * CPort is the object which interfaces to the commserver + */ +class CHWPort : public CPort + { +public: + static CHWPort* NewL(TUint aUnit); +private: + CHWPort(); +public: + virtual void StartRead(const TAny* aClientBuffer,TInt aLength); + virtual void ReadCancel(); + virtual TInt QueryReceiveBuffer(TInt& aLength) const; + virtual void ResetBuffers(TUint aFlags); + virtual void StartWrite(const TAny* aClientBuffer,TInt aLength); + virtual void WriteCancel(); + virtual void Break(TInt aTime); + virtual void BreakCancel(); + virtual TInt GetConfig(TDes8& aDes) const; + virtual TInt SetConfig(const TDesC8& aDes); + virtual TInt SetServerConfig(const TDesC8& aDes); + virtual TInt GetServerConfig(TDes8& aDes); + virtual TInt GetCaps(TDes8& aDes); + virtual TInt GetSignals(TUint& aSignals); + virtual TInt SetSignalsToMark(TUint aSignals); + virtual TInt SetSignalsToSpace(TUint aSignals); + virtual TInt GetReceiveBufferLength(TInt& aLength) const; + virtual TInt SetReceiveBufferLength(TInt aSignals); + virtual void Destruct(); + virtual void FreeMemory(); + virtual void NotifySignalChange(TUint aSignalMask); + virtual void NotifySignalChangeCancel(); + virtual void NotifyConfigChange(); + virtual void NotifyConfigChangeCancel(); + virtual void NotifyFlowControlChange(); + virtual void NotifyFlowControlChangeCancel(); + virtual void NotifyBreak(); + virtual void NotifyBreakCancel(); + virtual void NotifyDataAvailable(); + virtual void NotifyDataAvailableCancel(); + virtual void NotifyOutputEmpty(); + virtual void NotifyOutputEmptyCancel(); + virtual TInt GetFlowControlStatus(TFlowControl& aFlowControl); + virtual TInt GetRole(TCommRole& aRole); + virtual TInt SetRole(TCommRole aRole); + + virtual ~CHWPort(); +#if defined (_DEBUG_DEVCOMM) + virtual void DoDumpDebugInfo(const RMessage2 &aMessage); +#endif + RBusDevComm& DTEPort(); + RBusDevCommDCE& DCEPort(); +private: + CCommReader* iReader; //< pointer to the Active Reader + CCommWriter* iWriter; //< pointer to the Active Writer + CCommBreaker* iBreaker; //< pointer to the Active Breaker + CCommSignalNotifier* iSignalNotifier; //< pointer to the Active Signal Notifier + CCommAvailableDataNotifier* iDataAvailableNotifier; //< pointer to the Active Data available notifier + CCommFlowControlChangeNotifier* iFlowControlChangeNotifier; //< pointer to the Active Flow Control notifier + CCommConfigChangeNotifier* iConfigChangeNotifier; //< pointer to the Active Config Change notifier + + RBusDevComm iPort; //< interface to the logical Comm port device (DTE role) + RBusDevCommDCE iPortDCE; //< interface to the logical Comm port device (DCE role) + TCommRole iRole; //< DTE or DCE role for this port unit + TUint iPortName; //< contains the port unit number (i.e. 0 for COMM::0) + TBool iEarlyWriteCompletion; //< ETrue if early write completion enabled +#if defined (_DEBUG_CONSOLE_) +#if defined (_DEBUG_DEVCOMM) + CCommDebugDumper *iDumper; +#endif +public: + RDebugConsole iConsole; +#endif + }; + + +/** + * "Entry point object" makes the objects which do the work + */ +class CHWPortFactory : public CSerial + { +public: + CHWPortFactory(); + virtual CPort* NewPortL(const TUint aUnit); + virtual void Info(TSerialInfo &aSerialInfo); + +public: //from CSerial + TSecurityPolicy PortPlatSecCapability(TUint aPort) const; + }; + + +/** + * this class handles the 'Read one or more' method + * for ports with role DTE + */ +class RMaxComm : public RBusDevComm + { +public: + static void ReadOneOrMore(RBusDevComm& aComm, TRequestStatus& aStatus, TDes8& aDes, TInt aLen); + }; + + +void RMaxComm::ReadOneOrMore(RBusDevComm& aComm, TRequestStatus& aStatus, TDes8& aDes, TInt aLen) +/** + * reads one or more bytes from the physical DTE com port + * + * @param aComm handle to the logical com port device + * @param aStatus handle for asyncronous communications + * @param aDes buffer to be read into + * @param aLen max number of bytes to read + */ + { + LOGECUART2(_L8("RMaxComm::ReadOneOrMore(), (max. bytes to read) aLen = %d"), aLen); + RMaxComm& r = (RMaxComm&)aComm; + aLen = -aLen; // Note: negative length here means ReadOneOrMore + // see RComm::ReadOneOrMore in CC_CLI.CPP + r.DoRequest(ERequestRead, aStatus, &aDes, &aLen); + } + + +/** + * this class handles the 'Read one or more' method + * for ports with role DCE + */ +class RMaxCommDCE : public RBusDevCommDCE + { +public: + static void ReadOneOrMore(RBusDevCommDCE& aComm, TRequestStatus& aStatus, TDes8& aDes, TInt aLen); + }; + + +void RMaxCommDCE::ReadOneOrMore(RBusDevCommDCE& aComm, TRequestStatus& aStatus, TDes8& aDes, TInt aLen) +/** + * reads one or more bytes from the physical DCE com port + * + * @param aComm handle to the logical com port device + * @param aStatus handle for asyncronous communications + * @param aDes buffer to be read into + * @param aLen max number of bytes to read + */ + { + LOGECUART2(_L8("RMaxCommDCE::ReadOneOrMore(), (max. bytes to read) aLen = %d"), aLen); + RMaxCommDCE& r = (RMaxCommDCE&)aComm; + aLen = -aLen; // Note: negative length here means ReadOneOrMore + // see RComm::ReadOneOrMore in CC_CLI.CPP + r.DoRequest(ERequestRead, aStatus, &aDes, &aLen); + } + + + + +void Fault(TCommFault aFault) +/** + * Panic the comm module (us) + * + * @param aFault Panic code + */ + { + LOGECUART3(_L8("Fault(), (TCommFault) aFault = %d (%S)"), aFault, &TECUARTLOG::CommFaultStr(aFault)); + _LIT(KCsyPanicCategory, "CHWComm" ); + User::Panic(KCsyPanicCategory, aFault); + } + + +// +// implementation of CCommReadWriteBase +// + + +CCommReadWriteBase::CCommReadWriteBase(TInt aPriority, CHWPort* aParent) +/** + * C'tor + * + * @param aPriority priority of the Active Object + * @param aParent pointer to the owner, the CHWPort object + */ + :CActive(aPriority) + ,iBufSize(KDefaultBufSize) + ,iRole(ECommRoleDTE) + ,iParent(aParent) + { + LOGECUART1(_L8("CCommReadWriteBase::CCommReadWriteBase()")); + } + + +CCommReadWriteBase::~CCommReadWriteBase() +/** + * D'tor + */ + { + LOGECUART1(_L8("CCommReadWriteBase::~CCommReadWriteBase()")); + delete iBuffer; + delete iBuf; + } + + +TInt CCommReadWriteBase::SetServerConfig(TCommServerConfig& aConfig) +/** + * Set the port to use partial reads/writes or the bungee buffer + * + * @param aConfig new Comm server configurations + * @return TInt error code. KErrNone for sucess + */ + { + LOGECUART1(_L8("CCommReadWriteBase::SetServerConfig()")); + TCommServerConfigV01& c = aConfig(); + TInt res = KErrNone; + if (c.iBufFlags & KCommBufferPartial) + { + TInt bufSave = iBufSize; + iBufSize = c.iBufSize; + TRAP(res, SetBuffersL();) + if (res==KErrNone) + iBufFlags = c.iBufFlags; + else + iBufSize = bufSave; + } + return res; + } + + +void CCommReadWriteBase::GetServerConfig(TCommServerConfig& aConfig) const +/** + * read the comm server buffer config from the reader + * + * @param aConfig reference to Comm server configurations to be changed + */ + { + LOGECUART1(_L8("CCommReadWriteBase::GetServerConfig()")); + aConfig().iBufFlags = iBufFlags; + aConfig().iBufSize = iBufSize; + } + + +void CCommReadWriteBase::FreeMemory() +/** + * Reduce allocation levels by order of the comm server + */ + { + LOGECUART1(_L8("CCommReadWriteBase::FreeMemory()")); + TRAP_IGNORE(SetBuffersL()); + } + + +void CCommReadWriteBase::SetBuffersL() +/** + * Attempt to free up some memory + * + * @leave This function may leave in case of OOM + */ + { + LOGECUART1(_L8("CCommReadWriteBase::SetBuffersL()")); + if (!IsActive()) + { + TInt allocLen = Align4(iBufSize); + delete iBuffer; + delete iBuf; + iBuf = NULL; // set to NULL, in case new leaves + iBuffer = NULL; + iBuffer = HBufC8::NewMaxL(allocLen); + iBuf = new (ELeave) TPtr8((TText8*)iBuffer->Des().Ptr(), allocLen, allocLen); + } + } + + +// +// implementation of CCommReader +// + + +CCommReader* CCommReader::NewL(CHWPort* aParent) +/** + * static function, create and init a comm reader active object + * + * @param aParent pointer to the CHWPort object + * @return a newly created CCommReader object + */ + { + LOGECUART1(_L8("CCommReader::NewL()")); + CCommReader* c = new (ELeave) CCommReader(aParent); + CleanupStack::PushL(c); + c->InitL(); + CleanupStack::Pop(); + CActiveScheduler::Add(c); + return c; + } + + +CCommReader::~CCommReader() +/** + * D'tor + */ + { + LOGECUART1(_L8("CCommReader::~CCommReader()")); + Cancel(); + } + + +void CCommReader::DoCancel() +/** + * Cancel an outstanding request + */ + { + LOGECUART1(_L8("CCommReader::DoCancel()")); + __ASSERT_ALWAYS(IsActive(), Fault(ECancelNotOutstanding)); + if (iRole==ECommRoleDTE) + iParent->DTEPort().ReadCancel(); + else + iParent->DCEPort().ReadCancel(); + } + + +void CCommReader::RunL() +/** + * Read request has completed + */ + { + LOGECUART2(_L8("CCommReader::RunL(), iStatus = %d"), iStatus.Int()); + DEBUG_TRACE((iParent->iConsole.Printf(_L("CCommReader::RunL\n\r")))); + + TInt len = iLength; + + DEBUG_TRACE((iParent->iConsole.Printf(_L("Write %x bytes to 0x%x+%x\n\r"),iBuf->Size(),iPendingRead.Ptr0(),iBufPos))); + iParent->IPCWrite(iClientBuffer,*iBuf, iBufPos); + + if (iBufActive) + { + iBufPos+=iBufSize; + TInt left; + + if (iBufOneOrMoreSize) + { + // + // We are in ReadOneOrMore HELL + // + left=iBufOneOrMoreSize-iBufPos; + if (leftSetLength(0); + + LOGECUART2(_L8("Read %d bytes from serial"), len); + DEBUG_TRACE((iParent->iConsole.Printf(_L("read %x bytes from serial\n\r"),len))); + if (iRole==ECommRoleDTE) + iParent->DTEPort().Read(iStatus,*iBuf,len); + else + iParent->DCEPort().Read(iStatus,*iBuf,len);; + SetActive(); + return; + } + LOGECUART1(_L8("Read Completed")); + DEBUG_TRACE((iParent->iConsole.Write(_L("readCompleted \n\r")))); + + iParent->ReadCompleted(iStatus.Int()); + } + + + +void CCommReader::Read(const TAny* aClientBuffer, TInt aLength) +/** + * resize the buffer and queue a read + * + * @param aClientBuffer pointer to the Client's buffer + * @param aLength number of bytes to read + */ + { + LOGECUART2(_L8("CCommReader::Read(), aLength (number of Bytes to read) = %d"), aLength); + iClientBuffer=(TAny*)aClientBuffer; + iLength=aLength; + TInt& len=aLength; + if (len==0) + { + iParent->ReadCompleted(KErrNone); + return; + } + + TBool doOneOrMore=EFalse; + if (len<0) + { + doOneOrMore=ETrue; + len=-len; + } + + + if ((UsePartial() && len>iBufSize) || (UsePartial()==EFalse && len>iBuf->MaxLength())) + { + if (UsePartial()==EFalse) + { + TInt allocLen=Align4(len); + + TRAPD(res, iBuffer=iBuffer->ReAllocL(allocLen)); + if(res != KErrNone) + { + delete iBuffer; + iBuffer=NULL; + LOGECUART1(_L8("Read Completed")); + DEBUG_TRACE((iParent->iConsole.Write(_L("readCompleted \n\r")))); + iParent->ReadCompleted(res); + return; + } + + delete iBuf; + iBuf=NULL; + iBuf=new TPtr8((TText8*)iBuffer->Des().Ptr(), allocLen, allocLen); + if (iBuf == NULL) + { + iParent->ReadCompleted(KErrNoMemory); + return; + } + } + else + { + iBufActive=ETrue; + iBufPos=0; + len=iBufSize; + } + } + + + iBuf->SetLength(0); + if (iBufActive) + { + if (doOneOrMore) + { + if (iRole==ECommRoleDTE) + { + RBusDevComm port = iParent->DTEPort(); + iBufOneOrMoreSize = port.QueryReceiveBuffer(); + if (iBufOneOrMoreSize < iBuffer->Length()) + { + RMaxComm::ReadOneOrMore(port, iStatus, *iBuf, len); + iBufActive = EFalse; // Not needed + } + else + { + // Just do normal reads on it + LOGECUART2(_L8("Read %d bytes from serial"), len); + DEBUG_TRACE((iParent->iConsole.Printf(_L("read %x bytes from serial\n\r"),len))); + port.Read(iStatus,*iBuf,len); + } + } + else + { + RBusDevCommDCE port = iParent->DCEPort(); + iBufOneOrMoreSize=port.QueryReceiveBuffer(); + if (iBufOneOrMoreSizeLength()) + { + RMaxCommDCE::ReadOneOrMore(port,iStatus,*iBuf,len); + iBufActive=EFalse; // Not needed + } + else + { + // Just do normal reads on it + LOGECUART2(_L8("Read %d bytes from serial"), len); + DEBUG_TRACE((iParent->iConsole.Printf(_L("read %x bytes from serial\n\r"),len))); + port.Read(iStatus,*iBuf,len); + } + } + } + else + { + LOGECUART2(_L8("Read %d bytes from serial"), len); + DEBUG_TRACE((iParent->iConsole.Printf(_L("read %x bytes from serial\n\r"),len))); + if (iRole==ECommRoleDTE) + iParent->DTEPort().Read(iStatus,*iBuf,len); + else + iParent->DCEPort().Read(iStatus,*iBuf,len); + } + } + else + { + if (iRole==ECommRoleDTE) + { + RBusDevComm port = iParent->DTEPort(); + if (doOneOrMore) + RMaxComm::ReadOneOrMore(port,iStatus,*iBuf,len); + else + { + LOGECUART2(_L8("Read %d bytes from serial"), len); + DEBUG_TRACE((iParent->iConsole.Printf(_L("read %x bytes from serial\n\r"),len))); + port.Read(iStatus,*iBuf,len); + } + } + else + { + RBusDevCommDCE port = iParent->DCEPort(); + if (doOneOrMore) + RMaxCommDCE::ReadOneOrMore(port,iStatus,*iBuf,len); + else + { + LOGECUART2(_L8("Read %d bytes from serial"), len); + DEBUG_TRACE((iParent->iConsole.Printf(_L("read %x bytes from serial\n\r"),len))); + port.Read(iStatus,*iBuf,len); + } + } + } + + SetActive(); + } + + +void CCommReader::ReadCancel() +/** + * Cancel a read + */ + { + LOGECUART1(_L8("CCommReader::ReadCancel()")); + if(IsActive()) + { + Cancel(); + if(iBuf->Length()) // Copy any data to client + iParent->IPCWrite(iClientBuffer, *iBuf, iBufPos); // todo check return value ? + } + } + + +CCommReader::CCommReader(CHWPort* aParent) +/** + * C'tor - pass priority up to CActive + */ + :CCommReadWriteBase(KReaderPriority, aParent) + { + } + + +void CCommReader::InitL() +/** + * Allocate buffers + */ + { + SetBuffersL(); + } + + +// +// implementation of CCommWriter +// + + +CCommWriter* CCommWriter::NewL(CHWPort* aParent) +/** + * static function, create and init a comm writer active object + * + * @param aParent pointer to the CHWPort object + * @return a newly created CCommWriter object + */ + { + LOGECUART1(_L8("CCommWriter::NewL()")); + CCommWriter* c = new (ELeave) CCommWriter(aParent); + CleanupStack::PushL(c); + c->InitL(); + CleanupStack::Pop(); + CActiveScheduler::Add(c); + return c; + } + + +CCommWriter::~CCommWriter() +/** + * D'tor + */ + { + LOGECUART1(_L8("CCommWriter::~CCommWriter()")); + Cancel(); + } + + +void CCommWriter::DoCancel() +/** + * Cancel a pending write + */ + { + LOGECUART1(_L8("CCommWriter::DoCancel()")); + __ASSERT_ALWAYS(IsActive(), Fault(ECancelNotOutstanding)); + if (iRole==ECommRoleDTE) + iParent->DTEPort().WriteCancel(); + else + iParent->DCEPort().WriteCancel(); + } + + +void CCommWriter::RunL() +/** + * a write has completed + */ + { + LOGECUART2(_L8("CCommWriter::RunL(), iStatus = %d"), iStatus.Int()); + DEBUG_TRACE((iParent->iConsole.Write(_L("CCommWriter::RunL\n\r")))); + if (iBufActive) + { + // + // Did the last chunk get through OK ? + // + if (iStatus.Int() != KErrNone) + { + iBufActive=EFalse; + iBufPos=0; + iParent->WriteCompleted(iStatus.Int()); + return; + } + + TInt len=iLength; + TInt left=len-iBufPos; + // + // Read the next chunk into our buffer + // + DEBUG_TRACE((iParent->iConsole.Printf(_L("Read %x bytes from 0x%x+%x\n\r"),iBuf->Size(),iPendingWrite.Ptr0(),iBufPos))); + TInt res; + if((res=iParent->IPCRead(iClientBuffer,*iBuf, iBufPos))!=KErrNone) + { + iParent->WriteCompleted(res); + return; + } + // + // Still need buffering ? + // + if (leftSetLength(len); + LOGECUART2(_L8("Write %x bytes to serial"), len); + DEBUG_TRACE((iParent->iConsole.Printf(_L("Write %x bytes to serial\n\r"),len))); + if (iRole==ECommRoleDTE) + iParent->DTEPort().Write(iStatus,*iBuf,len); + else + iParent->DCEPort().Write(iStatus,*iBuf,len); + SetActive(); + return; + } + LOGECUART1(_L8("Write Completed")); + DEBUG_TRACE((iParent->iConsole.Write(_L("writeCompleted \n\r")))); + + if (iNotificationEnabled) + { + iParent->NotifyOutputEmptyCompleted(iStatus.Int()); + iNotificationEnabled=EFalse; + } + iParent->WriteCompleted(iStatus.Int()); + } + + +void CCommWriter::Write(const TAny* aClientBuffer, TInt aLength) +/** + * resize the buffer and queue a write + * + * @param aClientBuffer pointer to the Client's buffer + * @param aLength number of bytes to write + */ + { + LOGECUART2(_L8("CCommWriter::Write(), aLength = %d"), aLength); + iClientBuffer = (TAny*)aClientBuffer; + iLength = aLength; + + TInt& len = aLength; + if (len==0) + { + if (iRole==ECommRoleDTE) + iParent->DTEPort().Write(iStatus, TPtrC8(NULL,0)); + else + iParent->DCEPort().Write(iStatus, TPtrC8(NULL,0)); + } + else + { + if ((UsePartial() && len>iBufSize) || (UsePartial()==EFalse && len>iBuf->MaxLength())) + { + if (UsePartial()==EFalse) + { + TInt allocLen=Align4(len); + + TRAPD(res, iBuffer=iBuffer->ReAllocL(allocLen)); + if(res!=KErrNone) + { + delete iBuffer; + iBuffer=NULL; + iParent->WriteCompleted(res); + return; + } + + delete iBuf; + iBuf=NULL; + iBuf = new TPtr8((TText8*)iBuffer->Des().Ptr(), allocLen, allocLen); + if (iBuf == NULL) + { + iParent->WriteCompleted(KErrNoMemory); + return; + } + } + else + { + iBufActive=ETrue; + len=iBufSize; + iBufPos=len; + } + } + + iBuf->SetLength(len); + LOGECUART4(_L8("Read %d bytes from 0x%x+%x"), iBuf->Size(), aClientBuffer, iBufPos); + DEBUG_TRACE((iParent->iConsole.Printf(_L("Read %x bytes from 0x%x+%x\n\r"),iBuf->Size(),aClientBuffer,iBufPos))); + TInt res; + if((res=iParent->IPCRead(aClientBuffer,*iBuf))!=KErrNone) + { + iParent->WriteCompleted(res); + return; + } + LOGECUART2(_L8("Write %x bytes to serial"), len); + DEBUG_TRACE((iParent->iConsole.Printf(_L("Write %x bytes to serial\n\r"),len))); + + if (iRole==ECommRoleDTE) + iParent->DTEPort().Write(iStatus, *iBuf, len); + else + iParent->DCEPort().Write(iStatus, *iBuf, len); + } + + SetActive(); + } + + +void CCommWriter::WriteCancel() +/** + * Cancel a write + */ + { + LOGECUART1(_L8("CCommWriter::WriteCancel()")); + Cancel(); + } + + +void CCommWriter::NotificationEnable() +/** + * enables notification when output buffer is empty. + * activated when a clients calls RComm::NotifyOutputEmpty + */ + { + LOGECUART1(_L8("CCommWriter::NotificationEnable()")); + iNotificationEnabled = ETrue; + } + + +void CCommWriter::NotificationDisable() +/** + * disables notification when output buffer is empty + * deactivated when a clients calls RComm::NotifyOutputEmptyCancel + */ + { + LOGECUART1(_L8("CCommWriter::NotificationDisable()")); + iNotificationEnabled = EFalse; + } + + +TBool CCommWriter::IsNotificationEnabled() +/** + * returns ETrue if notification on output buffer empty is enabled + */ + { + LOGECUART2(_L8("CCommWriter::IsNotificationEnabled(), iNotificationEnabled = %d"), iNotificationEnabled); + return iNotificationEnabled; + } + + +CCommWriter::CCommWriter(CHWPort* aParent) +/** + * C'Tor + */ + :CCommReadWriteBase(KWriterPriority, aParent) + { + } + + +void CCommWriter::InitL() +/** + * Allocate buffers + */ + { + SetBuffersL(); + } + + +// +// implementation of CCommBreaker +// + + +CCommBreaker* CCommBreaker::NewL(CHWPort* aParent) +/** + * static function, create a comm breaker object + * + * @param aParent pointer to the CHWPort object + * @return a newly created CCommBreaker object + */ + { + LOGECUART1(_L8("CCommBreaker::NewL()")); + CCommBreaker* c = new (ELeave) CCommBreaker(aParent); + CActiveScheduler::Add(c); + return c; + } + + +CCommBreaker::~CCommBreaker() +/** + * D'Tor + */ + { + LOGECUART1(_L8("CCommBreaker::~CCommBreaker()")); + Cancel(); + } + + +void CCommBreaker::DoCancel() +/** + * Cancel a pending break. + */ + { + LOGECUART1(_L8("CCommBreaker::DoCancel()")); + __ASSERT_ALWAYS(IsActive(), Fault(ECancelNotOutstanding)); + if (iRole==ECommRoleDTE) + iParent->DTEPort().BreakCancel(); + else + iParent->DCEPort().BreakCancel(); + } + + +void CCommBreaker::RunL() +/** + * a break has completed. forward the news to the parent + */ + { + TInt status = iStatus.Int(); + LOGECUART2(_L8("CCommBreaker::RunL(), iStatus = %d"), status); + iParent->BreakCompleted(status); + } + + +void CCommBreaker::Break(TInt aTime) +/** + * Queue a break operation + * + * @param aTime Length of break in micro seconds + */ + { + LOGECUART2(_L8("CCommBreaker::Break(), aTime (length of break in micro secs) = %d"), aTime); + if (aTime==0) + { + iParent->BreakCompleted(KErrNone); + } + if (iRole==ECommRoleDTE) + iParent->DTEPort().Break(iStatus, aTime); + else + iParent->DCEPort().Break(iStatus, aTime); + SetActive(); + } + + +CCommBreaker::CCommBreaker(CHWPort* aParent) +/** + * C'Tor + * + * @param aParent pointer to the CHWPort object + */ + :CActive(KBreakerPriority) + ,iRole(ECommRoleDTE) + ,iParent(aParent) + { + } + + +// +// implementation of CCommNotifyBase +// + + +CCommNotifyBase::CCommNotifyBase(CHWPort* aParent) +/** + * C'tor + * + * @param aParent pointer to the CHWPort object + */ + :CActive(KNotifyPriority) + ,iRole(ECommRoleDTE) + ,iParent(aParent) + { + CActiveScheduler::Add(this); + } + + +CCommNotifyBase::~CCommNotifyBase() +/** + * D'tor + */ + { + LOGECUART1(_L8("CCommNotifyBase::~CCommNotifyBase()")); + } + + +// +// implementation of CCommSignalNotifier +// + + +CCommSignalNotifier::CCommSignalNotifier(CHWPort* aParent) +/** + * C'tor + * + * @param aParent pointer to the CHWPort object + */ + :CCommNotifyBase(aParent) + { + LOGECUART1(_L8("CCommSignalNotifier::CCommSignalNotifier()")); + } + + +CCommSignalNotifier::~CCommSignalNotifier() +/** + * D'tor + */ + { + LOGECUART1(_L8("CCommSignalNotifier::~CCommSignalNotifier()")); + } + + +void CCommSignalNotifier::DoCancel() +/** + * Cancel a pending notification. + */ + { + LOGECUART1(_L8("CCommSignalNotifier::DoCancel()")); + __ASSERT_ALWAYS(IsActive(), Fault(ECancelNotOutstanding)); + if (iRole==ECommRoleDTE) + iParent->DTEPort().NotifySignalChangeCancel(); + else + iParent->DCEPort().NotifySignalChangeCancel(); + } + + +void CCommSignalNotifier::RunL() +/** + * a notification has completed + */ + { + LOGECUART2(_L8("CCommSignalNotifier::RunL(), iStatus = %d"), iStatus.Int()); + if (iStatus.Int()) + { + iParent->SignalChangeCompleted(iSignals,iStatus.Int()); + iParent->BreakNotifyCompleted(iStatus.Int()); + iSignalMask = 0; + iNotifyCount = 0; + return; + } + + if (iSignals & ((KSignalDTEOutputs|KSignalDTEInputs)*KSignalChanged)) // these don't include BREAK + { + iNotifyCount--; + iParent->SignalChangeCompleted(iSignals,iStatus.Int()); + iSignalMask &= (KSignalBreak); // mask out everything but the BREAK signal + } + if (iSignals & KBreakChanged) + { + iNotifyCount--; + iParent->BreakNotifyCompleted(iStatus.Int()); + iSignalMask&=(~KSignalBreak); + } + __ASSERT_ALWAYS(iNotifyCount>=0, Fault(ENegativeCount)); + if (iNotifyCount>0) + Start(); + } + +void CCommSignalNotifier::Start() +/** + * start the notification + */ + { + LOGECUART1(_L8("CCommSignalNotifier::Start()")); + if (IsActive()) + Cancel(); + if (iRole==ECommRoleDTE) + iParent->DTEPort().NotifySignalChange(iStatus, iSignals, iSignalMask); + else + iParent->DCEPort().NotifySignalChange(iStatus, iSignals, iSignalMask); + SetActive(); + } + + +void CCommSignalNotifier::NotifySignal(TUint aSignalMask) +/** + * notify client when signal changes + * + * @param aSignalMask bitmask with the signals to be notified on + */ + { + LOGECUART2(_L8("CCommSignalNotifier::NotifySignal(), aSignalMask = %d"), aSignalMask); + TUint reqSigs = aSignalMask & ~KSignalBreak; + if (!reqSigs) + {// User has only asked to be notified of break. + iParent->SignalChangeCompleted(iSignals, KErrArgument); + return; + } + iNotifyCount++; + iSignalMask |= reqSigs; + Start(); + } + + +void CCommSignalNotifier::NotifySignalCancel() +/** + * cancel an outstanding signal change notification + */ + { + LOGECUART1(_L8("CCommSignalNotifier::NotifySignalCancel()")); + Cancel(); + iSignalMask &= (KSignalBreak); // set mask to zero, excluding BREAK + if (--iNotifyCount>0) // NotifyBreak may still be outstanding + Start(); + } + + +void CCommSignalNotifier::NotifyBreak() +/** + * notify client if break occurs + */ + { + LOGECUART1(_L8("CCommSignalNotifier::NotifyBreak()")); + iNotifyCount++; + iSignalMask |= KSignalBreak; + Start(); + } + + +void CCommSignalNotifier::NotifyBreakCancel() +/** + * cancel an outstanding break notification + */ + { + LOGECUART1(_L8("CCommSignalNotifier::NotifyBreakCancel()")); + Cancel(); + iSignalMask &= (~KSignalBreak); // mask out the BREAK signal + if (--iNotifyCount>0) // NotifySignals may still be outstanding + Start(); + } + + +// +// implementation of CCommAvailableDataNotifier +// + + +CCommAvailableDataNotifier::CCommAvailableDataNotifier(CHWPort* aParent) +/** + * C'tor + * + * @param aParent pointer to the CHWPort object + */ + :CCommNotifyBase(aParent) + { + } + + +CCommAvailableDataNotifier::~CCommAvailableDataNotifier() +/** + * D'tor + */ + { + LOGECUART1(_L8("CCommAvailableDataNotifier::~CCommAvailableDataNotifier()")); + } + + +void CCommAvailableDataNotifier::DoCancel() +/** + * Cancel a pending data available notification. + */ + { + __ASSERT_ALWAYS(IsActive(), Fault(ECancelNotOutstanding)); + if (iRole==ECommRoleDTE) + iParent->DTEPort().NotifyReceiveDataAvailableCancel(); + else + iParent->DCEPort().NotifyReceiveDataAvailableCancel(); + } + + +void CCommAvailableDataNotifier::RunL() +/** + * the notification has completed, and data is available + */ + { + LOGECUART2(_L8("CCommAvailableDataNotifier::RunL(), iStatus = %d"), iStatus.Int()); + iParent->NotifyDataAvailableCompleted(iStatus.Int()); + } + + +void CCommAvailableDataNotifier::Start() +/** + * start notification on data available + */ + { + LOGECUART1(_L8("CCommAvailableDataNotifier::Start()")); + if (iRole==ECommRoleDTE) + iParent->DTEPort().NotifyReceiveDataAvailable(iStatus); + else + iParent->DCEPort().NotifyReceiveDataAvailable(iStatus); + SetActive(); + } + + +// +// implementation of CCommFlowControlChangeNotifier +// + + +CCommFlowControlChangeNotifier::CCommFlowControlChangeNotifier(CHWPort* aParent) +/** + * C'tor + * + * @param aParent pointer to the CHWPort object + */ + :CCommNotifyBase(aParent) + { + } + + +CCommFlowControlChangeNotifier::~CCommFlowControlChangeNotifier() +/** + * D'tor + */ + { + LOGECUART1(_L8("CCommFlowControlChangeNotifier::~CCommFlowControlChangeNotifier()")); + } + + +void CCommFlowControlChangeNotifier::DoCancel() +/** + * Cancel a pending flow control change notification. + */ + { + LOGECUART1(_L8("CCommFlowControlChangeNotifier::DoCancel()")); + __ASSERT_ALWAYS(iRole==ECommRoleDCE,Fault(EWrongRole)); + __ASSERT_ALWAYS(IsActive(),Fault(ECancelNotOutstanding)); + iParent->DCEPort().NotifyFlowControlChangeCancel(); + } + + +void CCommFlowControlChangeNotifier::RunL() +/** + * The device driver does not give the new value of flow control status when the notification + * completes so we go and ask for it. If this impedes performance, it may be worth taking the + * plunge and working out the value ourselves - it should just be the opposite (ON/OFF) each time + * it completes. + */ + { + LOGECUART2(_L8("CCommFlowControlChangeNotifier::RunL(), iStatus = %d"), iStatus.Int()); + __ASSERT_ALWAYS(iRole==ECommRoleDCE, Fault(EWrongRole)); + iParent->DCEPort().GetFlowControlStatus(iFlowControl); + iParent->FlowControlChangeCompleted(iFlowControl,iStatus.Int()); + } + + +void CCommFlowControlChangeNotifier::Start() +/** + * start notification on flow control change + * + * @note Only supported for DCE role + */ + { + LOGECUART1(_L8("CCommFlowControlChangeNotifier::Start()")); + if (iRole==ECommRoleDTE) + iParent->FlowControlChangeCompleted(iFlowControl, KErrNotSupported); + else + { + iParent->DCEPort().NotifyFlowControlChange(iStatus); + SetActive(); + } + } + + +// +// implementation of CCommConfigChangeNotifier +// + + +CCommConfigChangeNotifier::CCommConfigChangeNotifier(CHWPort* aParent) +/** + * C'tor + * + * @param aParent pointer to the CHWPort object + */ + :CCommNotifyBase(aParent) + { + LOGECUART1(_L8("CCommConfigChangeNotifier::CCommConfigChangeNotifier()")); + } + + +CCommConfigChangeNotifier::~CCommConfigChangeNotifier() +/** + * D'tor + */ + { + LOGECUART1(_L8("CCommConfigChangeNotifier::~CCommConfigChangeNotifier()")); + } + + +void CCommConfigChangeNotifier::Start() +/** + * start notification on config change + * + * @note Only supported for DCE role + */ + { + LOGECUART1(_L8("CCommConfigChangeNotifier::Start()")); + if (iRole==ECommRoleDTE) + iParent->ConfigChangeCompleted(iConfig, KErrNotSupported); + else + { + iParent->DCEPort().NotifyConfigChange(iStatus, iConfig); + SetActive(); + } + } + + +void CCommConfigChangeNotifier::DoCancel() +/** + * Cancel a pending config change notification. + */ + { + LOGECUART1(_L8("CCommConfigChangeNotifier::DoCancel()")); + __ASSERT_ALWAYS(iRole==ECommRoleDCE,Fault(EWrongRole)); + __ASSERT_ALWAYS(IsActive(),Fault(ECancelNotOutstanding)); + iParent->DCEPort().NotifyConfigChangeCancel(); + } + + +void CCommConfigChangeNotifier::RunL() +/** + * the config change notification has completed, + * forward the news to the client. + */ + { + LOGECUART2(_L8("CCommConfigChangeNotifier::RunL(), iStatus = %d"), iStatus.Int()); + iParent->ConfigChangeCompleted(iConfig, iStatus.Int()); + } + + +void CloseObject(TAny* aObject) +/** + * Close an object from the cleanup stack + * + * @param aObject pointer to the object to close + */ + { + LOGECUART1(_L8("CloseObject()")); + ((CObject*)aObject)->Close(); + } + + +// +// implementation of CHWPort +// + + +CHWPort* CHWPort::NewL(TUint aUnit) +/** + * Make a new CPort for the comm server + * + * @param aUnit unit number of comm port (i.e. 0 for COMM::0) + * @return a newly created CHWPort object + */ + { + LOGECUART2(_L8("CHWPort::NewL(), aUint = %d (unit number of comm port)"), aUnit); + CHWPort* p = new (ELeave) CHWPort; + TCleanupItem closePort(CloseObject, p); + + CleanupStack::PushL(closePort); + + p->iReader=CCommReader::NewL(p); + p->iWriter=CCommWriter::NewL(p); + p->iBreaker=CCommBreaker::NewL(p); + p->iSignalNotifier=new (ELeave) CCommSignalNotifier(p); + p->iDataAvailableNotifier=new (ELeave) CCommAvailableDataNotifier(p); + p->iFlowControlChangeNotifier=new (ELeave) CCommFlowControlChangeNotifier(p); + p->iConfigChangeNotifier=new (ELeave) CCommConfigChangeNotifier(p); + + TName name; + name.Format(_L("%d"), aUnit); + p->SetName(&name); // todo check return value? + + // the C32 server does not check for the port number beeing to big. + // this is up to the CSY. If the aUnit number passed to the Logical + // device driver is greater than KMaxUnits, the kernel will Panic. + // We want to avoid this by gracefully leaving with Not Supported instead. + if(aUnit >= (TUint)KMaxUnits) + User::Leave(KErrNotSupported); + + p->iPortName = aUnit; +#if defined (_DEBUG_CONSOLE_) + name.Format(_L("Comm::%d"),aUnit); + p->iConsole.SetTitle(name); +#if defined (_DEBUG_DEVCOMM) + p->iDumper=CCommDebugDumper::NewL(p->iConsole); +#endif +#endif + CleanupStack::Pop(); + return p; + } + + +CHWPort::CHWPort() +/** + * C'Tor + */ + { + } + + +void CHWPort::StartRead(const TAny* aClientBuffer, TInt aLength) +/** + * Queue a read + * + * @param aClientBuffer pointer to the Client's buffer + * @param aLength number of bytes to read + */ + { + LOGECUART2(_L8("CHWPort::StartRead(), aLength = %d"), aLength); + DEBUG_TRACE((iConsole.Write(_L("DoRead \n\r")))); + if(iDataAvailableNotifier->IsActive()) + { + ReadCompleted(KErrInUse); + return; + } + iReader->Read(aClientBuffer, aLength); + } + + +void CHWPort::ReadCancel() +/** + * Cancel a read + */ + { + LOGECUART1(_L8("CHWPort::ReadCancel()")); + iReader->ReadCancel(); + } + + +TInt CHWPort::QueryReceiveBuffer(TInt& aLength) const +/** + * Get the size of the receive buffer from the real serial port + * + * @param aLength reference to where the size will be written to + * @return KErrNone always + */ + { + LOGECUART1(_L8("CHWPort::QueryReceiveBuffer()")); + // casting away constness with (CHWPort *)this + if (iRole==ECommRoleDTE) + aLength=((CHWPort *)this)->iPort.QueryReceiveBuffer(); + else + aLength=((CHWPort *)this)->iPortDCE.QueryReceiveBuffer(); + return KErrNone; + } + + +void CHWPort::ResetBuffers(TUint) +/** + * reset Tx and Rx buffers + * + * @note both Tx and Rx buffers are reset here + */ + { + LOGECUART1(_L8("CHWPort::ResetBuffers()")); + if (iRole==ECommRoleDTE) + iPort.ResetBuffers(); + else + iPortDCE.ResetBuffers(); + } + + +void CHWPort::StartWrite(const TAny* aClientBuffer, TInt aLength) +/** + * Queue a write + * + * @param aClientBuffer pointer to the Client's buffer + * @param aLength number of bytes to write + */ + { + LOGECUART2(_L8("CHWPort::StartWrite(), aLength = %d"), aLength); + DEBUG_TRACE((iConsole.Write(_L("DoWrite \n\r")))); + iWriter->Write(aClientBuffer,aLength); + } + + +void CHWPort::WriteCancel() +/** + * Cancel a pending write + */ + { + LOGECUART1(_L8("CHWPort::WriteCancel()")); + iWriter->WriteCancel(); + } + + +void CHWPort::Break(TInt aTime) +/** + * Queue a break + * + * @param aTime Length of break in micro seconds + */ + { + LOGECUART2(_L8("CHWPort::Break(), aTime = %d"), aTime); + iBreaker->Break(aTime); + } + + +void CHWPort::BreakCancel() +/** + * Cancel a pending break + */ + { + LOGECUART1(_L8("CHWPort::BreakCancel()")); + iBreaker->Cancel(); + } + + +TInt CHWPort::GetConfig(TDes8& aDes) const +/** + * Pass a config request + * + * @param aDes config will be written to this descriptor + * @return KErrNone always + */ + { + LOGECUART1(_L8("CHWPort::GetConfig()")); + if (iRole==ECommRoleDTE) + ((CHWPort*)this)->iPort.Config(aDes); + else + ((CHWPort*)this)->iPortDCE.Config(aDes); + return KErrNone; + } + + +TInt CHWPort::SetConfig(const TDesC8& aDes) +/** + * Set up the Comm LDD/PDD + * + * @param aDes descriptor containing the new config + * @return TInt error code + */ + { + LOGECUART1(_L8("CHWPort::SetConfig()")); + if (aDes.Length()<(TInt)sizeof(TCommConfigV01)) + return KErrGeneral; + TCommConfigV01 config(*(TCommConfigV01*)aDes.Ptr()); + + if (config.iHandshake & KConfigWriteBufferedComplete) + { + if (iWriter->IsNotificationEnabled()) + return KErrAccessDenied; + iEarlyWriteCompletion = ETrue; + } + else + { + iEarlyWriteCompletion = EFalse; + } + if (iRole==ECommRoleDTE) + return iPort.SetConfig(aDes); + else + return iPortDCE.SetConfig(aDes); + } + + +TInt CHWPort::SetServerConfig(const TDesC8& aDes) +/** + * Set the port to use partial reads/writes or the bungee buffer + * + * @param aDes package with new server configurations + * @return TInt error code + */ + { + LOGECUART1(_L8("CHWPort::SetServerConfig()")); + if (aDes.Length()<(TInt)sizeof(TCommServerConfigV01)) + return KErrGeneral; + TCommServerConfig c(*(TCommServerConfigV01*)aDes.Ptr()); + TInt r=0; + if ((r=iReader->SetServerConfig(c))==KErrNone) + r=iWriter->SetServerConfig(c); + return r; + } + + +TInt CHWPort::GetServerConfig(TDes8& aDes) +/** + * Get the server configs + * + * @param aDes server configs will be written to this descriptor + * @return TInt error code + */ + { + LOGECUART1(_L8("CHWPort::GetServerConfig()")); + if (aDes.Length()<(TInt)sizeof(TCommServerConfigV01)) + return KErrGeneral; + TCommServerConfig c; + + iReader->GetServerConfig(c); + aDes=c; + + return KErrNone; + } + + +TInt CHWPort::GetCaps(TDes8& aDes) +/** + * Read capabilities from the driver + * + * @param aDes caps will be written to this descriptor + * @return KErrNone always + */ + { + LOGECUART1(_L8("CHWPort::GetCaps()")); + if (iRole==ECommRoleDTE) + iPort.Caps(aDes); + else + iPortDCE.Caps(aDes); + if (aDes.Length()==sizeof(TCommCapsV02)) + { + TCommCapsV02* commcaps = (TCommCapsV02*)(aDes.Ptr()); + commcaps->iNotificationCaps |= KNotifyOutputEmptySupported; + commcaps->iRoleCaps = KCapsRoleSwitchSupported; + } + return KErrNone; + } + + +TInt CHWPort::GetSignals(TUint& aSignals) +/** + * get the status of the signal pins + * + * @param aSignals signals will be written to this descriptor + * @return KErrNone always + */ + { + LOGECUART1(_L8("CHWPort::GetSignals()")); + if (iRole==ECommRoleDTE) + aSignals=iPort.Signals(); + else + aSignals=iPortDCE.Signals(); + return KErrNone; + } + + +TInt CHWPort::SetSignalsToMark(TUint aSignals) +/** + * set selected signals to high (logical 1) + * + * @param aSignals bitmask with the signals to be set + * @return KErrNone always + */ + { + LOGECUART2(_L8("CHWPort::SetSignalsToMark(), aSignals = %d"), aSignals); + if (iRole==ECommRoleDTE) + iPort.SetSignals(aSignals,0); + else + iPortDCE.SetSignals(aSignals,0); + return KErrNone; + } + + +TInt CHWPort::SetSignalsToSpace(TUint aSignals) +/** + * set selected signals to low (logical 0) + * + * @param aSignals bitmask with the signals to be cleared + * @return KErrNone always + */ + { + LOGECUART2(_L8("CHWPort::SetSignalsToSpace(), aSignals = %d"), aSignals); + if (iRole==ECommRoleDTE) + iPort.SetSignals(0,aSignals); + else + iPortDCE.SetSignals(0,aSignals); + return KErrNone; + } + + +TInt CHWPort::GetReceiveBufferLength(TInt& aLength) const +/** + * get size of Tx and Rx buffer + * + * @param aLength reference to where the length will be written to + * @return KErrNone always + */ + { + LOGECUART1(_L8("CHWPort::GetReceiveBufferLength()")); + // casting away constness with (CHWPort *)this + if (iRole==ECommRoleDTE) + aLength=((CHWPort *)this)->iPort.ReceiveBufferLength(); + else + aLength=((CHWPort *)this)->iPortDCE.ReceiveBufferLength(); + return KErrNone; + } + + +TInt CHWPort::SetReceiveBufferLength(TInt aLength) +/** + * set the size of Tx and Rx buffer + * + * @param aLength new length of Tx and Rx buffer + * @return TInt error code + */ + { + LOGECUART2(_L8("CHWPort::SetReceiveBufferLength(), aLength = %d"), aLength); + if (iRole==ECommRoleDTE) + return iPort.SetReceiveBufferLength(aLength); + else + return iPortDCE.SetReceiveBufferLength(aLength); + } + + +void CHWPort::Destruct() +/** + * Destruct - we must (eventually) call delete this + */ + { + LOGECUART1(_L8("CHWPort::Destruct()")); + delete this; + } + + +void CHWPort::FreeMemory() +/** + * Attempt to reduce out memory foot print. + */ + { + LOGECUART1(_L8("CHWPort::FreeMemory()")); + iReader->FreeMemory(); + iWriter->FreeMemory(); + } + + +void CHWPort::NotifySignalChange(TUint aSignalMask) +/** + * notify client when the signals change + * + * @param aSignalMask bitmask with signal to be notified on + */ + { + LOGECUART2(_L8("CHWPort::NotifySignalChange(), aSignalMask = %d"), aSignalMask); + iSignalNotifier->NotifySignal(aSignalMask); + } + + +void CHWPort::NotifySignalChangeCancel() +/** + * cancel an outstanding signal change notification + */ + { + LOGECUART1(_L8("CHWPort::NotifySignalChangeCancel()")); + iSignalNotifier->NotifySignalCancel(); + } + + +void CHWPort::NotifyConfigChange() +/** + * notify client when the configation changes + */ + { + LOGECUART1(_L8("CHWPort::NotifyConfigChange()")); + iConfigChangeNotifier->Start(); + } + + +void CHWPort::NotifyConfigChangeCancel() +/** + * cancel an outstanding config change notification + */ + { + LOGECUART1(_L8("CHWPort::NotifyConfigChangeCancel()")); + iConfigChangeNotifier->Cancel(); + } + + +void CHWPort::NotifyFlowControlChange() +/** + * notify client when the flow control changes + */ + { + LOGECUART1(_L8("CHWPort::NotifyFlowControlChange()")); + iFlowControlChangeNotifier->Start(); + } + + +void CHWPort::NotifyFlowControlChangeCancel() +/** + * cancel an outstanding flow control change notification + */ + { + LOGECUART1(_L8("CHWPort::NotifyFlowControlChangeCancel()")); + iFlowControlChangeNotifier->Cancel(); + } + + +void CHWPort::NotifyBreak() +/** + * notify client when a break occurs + */ + { + LOGECUART1(_L8("CHWPort::NotifyBreak()")); + iSignalNotifier->NotifyBreak(); + } + + +void CHWPort::NotifyBreakCancel() +/** + * cancel an outstanding break notification + */ + { + LOGECUART1(_L8("CHWPort::NotifyBreakCancel()")); + iSignalNotifier->NotifyBreakCancel(); + } + + +void CHWPort::NotifyDataAvailable() +/** + * notify client when data is available + */ + { + LOGECUART1(_L8("CHWPort::NotifyDataAvailable()")); + if(iReader->IsActive()) + { + NotifyDataAvailableCompleted(KErrInUse); + return; + } + iDataAvailableNotifier->Start(); + } + + +void CHWPort::NotifyDataAvailableCancel() +/** + * cancel an outstanding data availalbe notification + */ + { + LOGECUART1(_L8("CHWPort::NotifyDataAvailableCancel()")); + iDataAvailableNotifier->Cancel(); + } + + +void CHWPort::NotifyOutputEmpty() +/** + * notify client when output buffer is empty + */ + { + LOGECUART1(_L8("CHWPort::NotifyOutputEmpty()")); + if (iEarlyWriteCompletion) + NotifyOutputEmptyCompleted(KErrAccessDenied); + else + iWriter->NotificationEnable(); + } + + +void CHWPort::NotifyOutputEmptyCancel() +/** + * cancel an outstanding output empty notification + */ + { + LOGECUART1(_L8("CHWPort::NotifyOutputEmptyCancel()")); + iWriter->NotificationDisable(); + } + + +TInt CHWPort::GetFlowControlStatus(TFlowControl& aFlowControl) +/** + * get the flow control status + * + * @param aFlowControl flow control status will be written to this descriptor + * @return TInt error code + * + * @note only supported for DCE role + */ + { + if (iRole==ECommRoleDTE) + return KErrNotSupported; + else + iPortDCE.GetFlowControlStatus(aFlowControl); + return KErrNone; + } + + +TInt CHWPort::GetRole(TCommRole& aRole) +/** + * get the role of this port unit + * + * @param aRole reference to where the role will be written to + * @return KErrNone always + */ + { + aRole = iRole; + return KErrNone; + } + + +TInt CHWPort::SetRole(TCommRole aRole) +/** + * set the role of this port unit + * + * @param aRole the new role + * @return TInt error code + */ + { + iRole=aRole; + TInt ret=KErrNone; + if (aRole==ECommRoleDTE) + ret = iPort.Open(iPortName); + else + ret = iPortDCE.Open(iPortName); + if (ret!=KErrNone) + { + LOGECUART3(_L8("CHWPort::SetRole - failed with %d when attempting to open hardware port unit: %d"),ret,iPortName); + return ret; + } + iReader->SetRole(aRole); + iWriter->SetRole(aRole); + iBreaker->SetRole(aRole); + iSignalNotifier->SetRole(aRole); + iDataAvailableNotifier->SetRole(aRole); + iFlowControlChangeNotifier->SetRole(aRole); + iConfigChangeNotifier->SetRole(aRole); + +#if defined (_DEBUG_DEVCOMM) && defined (_DEBUG_CONSOLE_) + iDumper->SetRole(aRole); +#endif + return KErrNone; + } + + +CHWPort::~CHWPort() +/** + * D'tor + */ + { + LOGECUART1(_L8("CHWPort::~CHWPort()")); + delete iReader; + delete iWriter; + delete iBreaker; + delete iSignalNotifier; + delete iDataAvailableNotifier; + delete iFlowControlChangeNotifier; + delete iConfigChangeNotifier; + + iPort.Close(); + iPortDCE.Close(); + +#if defined (_DEBUG_CONSOLE_) +#if defined (_DEBUG_DEVCOMM) + delete iDumper; +#endif + iConsole.Close(); +#endif + } + + +#ifdef _DEBUG_DEVCOMM +void CHWPort::DoDumpDebugInfo(const RMessage2 &aMessage) + { + TCommDebugInfoPckg d; + if (iRole==ECommRoleDTE) + iPort.DebugInfo(d); + else + iPortDCE.DebugInfo(d); + TRAPD(ret, aMessage.WriteL(0,aMessage,d) ); + aMessage.Complete(ret); + } +#endif + + +RBusDevComm& CHWPort::DTEPort() +/** + * return the handle to the logical DTE port + */ + { + return iPort; + } + + +RBusDevCommDCE& CHWPort::DCEPort() +/** + * return the handle to the logical DCE port + */ + { + return iPortDCE; + } + + +// +// todo implement this - for further improvements +// +#if 0 +RBusWhatever& CHWPort::Port() +/** + * return a handle to our port + */ + { + if (iRole==ECommRoleDTE) + return iPort; + else + return iPortDCE; + } +#endif + + +// +// implementation of CHWPortFactory +// + + +CHWPortFactory::CHWPortFactory() +/** + * C'tor + */ + { + TName name(SERIAL_NAME); + SetName(&name); // todo check return value? + iVersion = TVersion(KEC32MajorVersionNumber, KEC32MinorVersionNumber, KEC32BuildVersionNumber); + } + + +CPort* CHWPortFactory::NewPortL(const TUint aUnit) +/** + * Create a new port for the supplied unit number + * + * @param aUnit port unit number (i.e. 0 for COMM::0) + */ + { + LOGECUART2(_L8("CHWPortFactory::NewPortL(), aUnit = %d"), aUnit); +// __ASSERT_ALWAYS(aUnit>=KCommLowUnit,User::Leave(KErrNotSupported)); +// __ASSERT_ALWAYS(aUnit<=KCommHighUnit,User::Leave(KErrNotSupported)); + return (CPort *)CHWPort::NewL(aUnit); + } + + +void CHWPortFactory::Info(TSerialInfo& aSerialInfo) +/** + * get info about this CSY, fill in the supplied structure. + * + * @param aSerialInfo where info will be written to + */ + { + aSerialInfo.iDescription = KSerialDescription; + aSerialInfo.iName = SERIAL_NAME; + aSerialInfo.iLowUnit = KCommLowUnit; + aSerialInfo.iHighUnit = KCommHighUnit; + } + +/** +Returns capabilities for requested port +*/ +TSecurityPolicy CHWPortFactory::PortPlatSecCapability(TUint aPort) const + { + LOGECUART2(_L8("CHWPortFactory::PortPlatSecCapability(), aPort = %d"), aPort); + TSecurityPolicy csySecurityPolicy(KDefaultPortPassPolicy); + + if(aPort >= (TUint)KMaxUnits) //if greater than KMaxUnits it is an invalid port so fail. + { + csySecurityPolicy = KPortAlwaysFailPolicy; + } + else //see if it is defined in explicit policy list. + { + for(int i = 0;i < KExplicitPortPoliciesCount; i++) + { + // coverity [dead_error_line] : KExplicitPortPoliciesCount is currently 0, but this could change. + if(aPort == KExplicitPortSecurityPolicies[i].iPort) + { + csySecurityPolicy = KExplicitPortSecurityPolicies[i].iPolicy; + break; + } + } + } + return csySecurityPolicy; + } + +extern "C" + { + IMPORT_C CSerial* LibEntry(void); // Force export + }; + + +EXPORT_C CSerial* LibEntry() +/** + * Lib main entry point + */ + { + LOGECUART1(_L8("LibEntry()")); + return new CHWPortFactory; + } + + +#if defined(_DEBUG_CONSOLE_) + +RDebugConsole::RDebugConsole() + { + Create(); + Set(_L(""),TSize(64,15)); + + } + +void RDebugConsole::Printf(TRefByValue aFmt,...) +// +// Print to a console screen. +// + { + + VA_LIST list; + VA_START(list,aFmt); + TBuf<0x100> aBuf; + aBuf.AppendFormatList(aFmt,list); + Write(aBuf); + } +#endif + +#if defined (_DEBUG_DEVCOMM) && defined (_DEBUG_CONSOLE_) +CCommDebugDumper* CCommDebugDumper::NewL(RDebugConsole &aConsole) + { + CCommDebugDumper* p=new CCommDebugDumper(aConsole); + return p; + } + +CCommDebugDumper::CCommDebugDumper(RDebugConsole &aConsole) + :CActive(EPriorityStandard) + { + iRole=ECommRoleDTE; + iConsole=&aConsole; + CActiveScheduler::Add(this); + SetActive(); + iConsole->Read(iKeystroke,iStatus); + }; + +CCommDebugDumper::~CCommDebugDumper() + { + Cancel(); + } + +void CCommDebugDumper::RunL() + { + TInt key=iKeystroke.Code(); + switch(key) + { + case 'd': + case 'D': + { + TCommDebugInfoPckg d; + if (iRole==ECommRoleDTE) + iParent->DTEPort().DebugInfo(d); + else + iParent->DCEPort().DebugInfo(d); + TCommDebugInfo& debug=d(); + iConsole->Printf(_L("rxbusy : 0x%04x, rxHeld : 0x%04x, \n\r"),debug.iRxBusy,debug.iRxHeld); + iConsole->Printf(_L("txbusy : 0x%04x, txHeld : 0x%04x, \n\r"),debug.iTxBusy,debug.iTxHeld); + iConsole->Printf(_L("drainRx : 0x%04x, fillTx : 0x%04x\n\r"),debug.iDrainingRxBuf,debug.iFillingTxBuf); + iConsole->Printf(_L("Txonchar: 0x%04x, TxOffchar: 0x%04x\n\r"),debug.iTxXon,debug.iTxXoff); + iConsole->Printf(_L("RxonChar: 0x%04x, RxOffchar: 0x%04x\n\r"),debug.iRxXon,debug.iRxXoff); + iConsole->Printf(_L("NumTX : 0x%04x, NumRx : 0x%04x\n\r"),debug.iTxChars,debug.iRxChars); + iConsole->Printf(_L("TxLen : 0x%04x, RxLen : 0x%04x\n\r"),debug.iTxLength,debug.iRxLength); + iConsole->Printf(_L("TxOffset: 0x%04x, RxOffset : 0x%04x\n\r"),debug.iTxOffset,debug.iRxOffset); + iConsole->Printf(_L("TxInts : 0x%04x, RxInts : 0x%04x\n\r"),debug.iTxIntCount,debug.iRxIntCount); + } + break; + case 's': + case 'S': + { + TUint signals=0; + if (iRole==ECommRoleDTE) + signals=iParent->DTEPort().Signals(); + else + signals=iParent->DCEPort().Signals(); + iConsole->Printf(_L("Signals: ")); + if (signals&KSignalCTS) + iConsole->Printf(_L("CTS ")); + if (signals&KSignalDSR) + iConsole->Printf(_L("DSR ")); + if (signals&KSignalDCD) + iConsole->Printf(_L("DCD ")); + if (signals&KSignalRTS) + iConsole->Printf(_L("RTS ")); + if (signals&KSignalDTR) + iConsole->Printf(_L("DTR ")); + iConsole->Printf(_L("\n\r")); + } + break; + default: + break; + } + + SetActive(); + iConsole->Read(iKeystroke,iStatus); + }; + +void CCommDebugDumper::DoCancel() + { + iConsole->ReadCancel(); + } + +#endif + +// EOF - ECUART.CPP