Symbian tracing over USB
This code snippet provides support for USB tracing on Symbian using virtual serial communication over USB (bulk transfer). It is a "poor mans" solution - a proper implementation would be a new csy-module just for tracing over USB and driver for PC side. It may however be useful to some developers.
Article Metadata
NOTES:
- you can copy paste CUsbTraceEngine class and inline functions to your logging header or use this one.
- remember to add in mmp-file
MACRO __USB_TRACE
// debug
DEBUGLIBRARY c32.lib
the code from logger.h::::
#ifndef __USBLOG_H__
#define __USBLOG_H__
#include <e32std.h>
#ifdef _DEBUG
#define __TRACE_CONSOLE
#endif //_DEBUG
#ifdef __TRACE_CONSOLE
#include <f32file.h>
#define __TRACE( strz )\
{\
RDebug::Print(_L(strz));\
UsbWrite8Format(strz);\
}
#define __TRACE1( strz,p1 ) \
{\
RDebug::Print(_L(strz),p1);\
UsbWrite8Format(strz,p1);\
}
#define __TRACE2( strz,p1,p2 ) \
{\
RDebug::Print(_L(strz),p1,p2);\
UsbWrite8Format(strz,p1,p2);\
}
#define __TRACE3( strz,p1,p2,p3 ) \
{\
RDebug::Print(_L(strz),p1,p2,p3);\
UsbWrite8Format(strz,p1,p2,p3);\
}
#else
#define __TRACE( strz );
#define __TRACE1( fmt,p1 );
#define __TRACE2( fmt,p1,p2 );
#define __TRACE3( fmt,p1,p2,p3 );
#endif
#define FREERESOURCE Free()
#include <e32base.h>
#if defined(__USB_TRACE) && defined(_DEBUG)// && !defined(__WINS__)
#include <c32comm.h>
#include <e32svr.h>
#include <flogger.h>
const TInt KTimeStampLength = 12;
class CUSBTraceEngine;
// set singleton instance default null
static CUSBTraceEngine* iInstance = NULL;
class CUSBTraceEngine : public CActive
{
public: // new functions
/**
* NewL()
*/
static CUSBTraceEngine* NewL()
{
User::LeaveIfNull( CActiveScheduler::Current() );
CUSBTraceEngine* self = new (ELeave) CUSBTraceEngine;
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
/**
* ~CUSBTraceEngine()
*/
~CUSBTraceEngine()
{
Cancel();
iMessageBuffer.ResetAndDestroy();
iRComm.Close();
iRCommServer.Close();
}
protected: // From CActive
void RunL()
{
/**
* if there is messages waiting in buffer
* start sending from oldest
*/
if( iStatus == KErrNone && iMessageBuffer.Count() > 0 )
{
Send( iMessageBuffer[0] );
iMessageBuffer.Remove( 0 );
}
}
void DoCancel()
{
iRComm.WriteCancel();
}
public: // new functions, example API
/**
* Creates new time stamp
*/
const TDesC8& CreateTimeStamp()
{
_LIT8( KTimeFormat , "%02d:%02d:%02d " );
iTime.HomeTime();
iTimeStampBuf.Zero();
iTimeStampBuf.Format( KTimeFormat()
, iTime.DateTime().Hour()
, iTime.DateTime().Minute()
, iTime.DateTime().Second() );
return iTimeStampBuf;
}
/**
* Sends data over serialport
*
* @param HBufC8* aBuf
*/
void Send( HBufC8* aBuf )
{
if( !IsActive() )
{
iStatus = KRequestPending;
iRComm.Write( iStatus , *aBuf );
SetActive();
delete aBuf;
}
else
{
if( iMessageBuffer.Append( aBuf ) )
{
delete aBuf;
}
}
}
/**
* Connects to virtual serial port over USB
*/
void DoConnectL()
{
/**
* CSY module to be loaded
* for USB communication
*/
_LIT(CSYMOD, "ECACM");
/**
* port to be opened
* for serial communication over USB
*/
_LIT(KACMPort1, "ACM::1");
// RComm is a client to the RCommServ Comms server
// Start this service before any connections are made.
User::LeaveIfError( StartC32() );
// Connect to CommServer
User::LeaveIfError( iRCommServer.Connect() );
// Load CSY Module
User::LeaveIfError( iRCommServer.LoadCommModule( CSYMOD ) );
// Open the comm. port
// if USB - cable is not connected leave will occur
// ECommShared The port can be shared by other RComm clients who open in the same mode.
User::LeaveIfError( iRComm.Open( iRCommServer, KACMPort1() , ECommShared ));
}
/**
* returns connection status
*
* @param void
* @return TInt KErrNone if connect was successful
*/
TInt ConnectionStatus()
{
return iConnectionStatus;
}
private: // new functions
/**
* Default constructor
*/
CUSBTraceEngine()
: CActive(CActive::EPriorityStandard)
{
CActiveScheduler::Add(this);
}
/**
* All leaving code here
*/
void ConstructL()
{
TRAP( iConnectionStatus , DoConnectL() );
}
private: // data
RCommServ iRCommServer;
RComm iRComm; // The rcomm for communication.
//
// status to be set when connecting to USB serialport
//
TInt iConnectionStatus;
TBuf8<KTimeStampLength> iTimeStampBuf;
RPointerArray<HBufC8> iMessageBuffer;
TTime iTime;
};
/**
* inline function for ParseStrLens
*/
inline TInt ParseStrLens(VA_LIST& aArgs,const char* aFmt)
{
TPtrC8 tpr( (const TUint8*)aFmt );
TInt str_len = tpr.Length();
for( TInt i(0); i < tpr.Length(); ++i )
{
if( aFmt[i] == '%' )
{
if( aFmt[i+1] == 'S' )
{
const TDesC8* ptr = VA_ARG( aArgs , const TDesC8* );
str_len += ( ptr ) ? ptr->Length() : 0;
}
else
{
VA_ARG( aArgs , const TAny* );
}
}
}
return str_len;
}
/**
* inline function for __TRACEx macros
*/
inline void UsbWrite8Format( const char* aFmt , ... )
{
if( !iInstance )
{
TRAP_IGNORE( iInstance = CUSBTraceEngine::NewL() );
}
if( iInstance && !iInstance->ConnectionStatus() )
{
// pointer to list of arguments
VA_LIST args;
// tells the code where to start the list
VA_START(args,aFmt);
HBufC8* msg = HBufC8::New( ParseStrLens(args,aFmt)+30 );
if( msg )
{
_LIT8( KLineFeedl , "\r\n");
// cleans up the stack
VA_END(args);
// tells the code where to start the list
VA_START(args,aFmt);
TDes8IgnoreOverflow overFlowHandler;
msg->Des().AppendFormatList( TPtrC8( (const TUint8*)aFmt) , args , &overFlowHandler );
msg->Des().Insert( 0 , iInstance->CreateTimeStamp() );
msg->Des().Append( KLineFeedl() );
iInstance->Send( msg );
}
// cleans up the stack
VA_END(args);
}
else
{
// RDebug::Printf(fmt);
}
}
/**
* inline function for FREERESOURCE macro
* to free CUSBTraceEngine
*/
inline void Free()
{
if( iInstance )
{
delete iInstance;
iInstance = NULL;
}
}
#else
inline void UsbWrite8Format( const char* /*aFmt*/ , ... ){}
inline void Free(){}
#endif
#endif // end of file


(no comments yet)