diff -r 000000000000 -r 29b1cd4cb562 bluetooth/btstack/common/blogger.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetooth/btstack/common/blogger.cpp Fri Jan 15 08:13:17 2010 +0200 @@ -0,0 +1,894 @@ +// Copyright (c) 2001-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: +// + + +#include "blogger.h" + +#ifndef BLOGGING__ +EXPORT_C TAny* CBlogger::GetFloggerInfo() + { + return 0; + } +#endif + +#ifdef BLOGGING__ +#include "rfcommmuxer.h" +#include "rfcommframe.h" + + +CBlogger::~CBlogger() + { + delete ifilename; + ifile.Close (); + ifileserv.Close (); + } + +CBlogger::CBlogger() : + iOutputWindowSize(KBlogOutputWindowDefault), + iVerbosityLevel(KBlogVerbosityAllLevels), + iLayersToLogMask(KBlogAllLayers), + iLoggingMask(KBlogTypeLogAllMask) + { + } + +CBlogger* CBlogger::NewL() + { + CBlogger* self = new (ELeave)CBlogger(); + self->ConstructL(); + return self; + } + +void CBlogger::ConstructL() + { + User::LeaveIfError(ifileserv.Connect()); + MakefilenameL(_L("Blog.txt")); + iFileExists = EFalse; + } + +TInt CBlogger::LoggingMask(TInt aLayer, TInt aVerbosity) const + { + if(aLayer&iLayersToLogMask) + { + if(aVerbosity<=iVerbosityLevel) + { + return iLoggingMask; + } + } + //else + return 0; + } + +CBloggette* CBlogger::GetLayerBloggette(TInt aLayer) + { + switch(aLayer) + { + case KBlogLayerLinkLayer : + { + return iLLBloggette; + } + case KBlogLayerL2CAP : + { + return iL2Bloggette; + } + case KBlogLayerRFComm : + { + return iRFBloggette; + } + default: + { + Panic(EBloggerLayerRequestedOutOfRange); + return NULL; //for compiler to shut up + } + }; + } + +void CBlogger::Register(CBloggette* aLayerBloggette) +/** + only one per layer please +*/ + { + TUint layer = aLayerBloggette->Layer(); + switch(layer) + { + case KBlogLayerLinkLayer: + { + __ASSERT_DEBUG(iLLBloggette==NULL,Panic(EBloggerLayerBloggetteAlreadyRegistered)); + iLLBloggette=aLayerBloggette; + break; + } + case KBlogLayerL2CAP : + { + __ASSERT_DEBUG(iL2Bloggette==NULL,Panic(EBloggerLayerBloggetteAlreadyRegistered)); + iL2Bloggette=aLayerBloggette; + break; + } + case KBlogLayerRFComm : + { + __ASSERT_DEBUG(iRFBloggette==NULL,Panic(EBloggerLayerBloggetteAlreadyRegistered)); + iRFBloggette=aLayerBloggette; + break; + } + default: + { + Panic(EBloggerLayerRegistrationOutOfRange); + } + }; + } + + +TInt CBlogger::UpdateLoggingSettings(TUint aOptionType,const TDesC8& aOption) + { +#define CHECK_OPT_IS_(type) {if (aOption.Size() != sizeof(type)) \ + return KErrArgument;} + switch(aOptionType) + { + case KBloggerSetLayers: + { + CHECK_OPT_IS_(TInt); + iLayersToLogMask= *(TUint*)aOption.Ptr(); + break; + } + case KBloggerSetVerbosity: + { + CHECK_OPT_IS_(TInt); + TInt verbosity=*(TUint*)aOption.Ptr(); + if((verbosityKBlogVerbosityAllLevels)) + { + return KErrArgument; + } + iVerbosityLevel= verbosity; + break; + } + case KBloggerSetLoggingMask: + { + CHECK_OPT_IS_(TInt); + iLoggingMask= *(TInt*)aOption.Ptr(); + break; + } + case KBloggerSetMedium: + { + CHECK_OPT_IS_(TInt); + TInt mediumType=*(TUint*)aOption.Ptr(); + if((mediumType!=KBlogOutputTypeIsFlogger)||(mediumType!=KBlogOutputTypeIsRDebug)) + {//otherwise we will panic when we try to output + return KErrArgument; + } + iMediumType= mediumType; + break; + } + case KBloggerSetTestCaseName: + { + TInt length=Min(KRDBMaxLit,aOption.Length()); + iTestCaseLit.Copy(((TDesC16*)aOption.Ptr())->Left(length)); + BlogTestCase(iTestCaseLit); + break; + } + case KBloggerSetOutputWindow: + { + CHECK_OPT_IS_(TInt); + TInt windowSize=*(TUint*)aOption.Ptr(); + if((windowSize<1)||(windowSize>KRDBMaxLit)) + { + return KErrArgument; + } + iOutputWindowSize=windowSize; + break; + } + case KBloggerSetTestCaseResult: + { + CHECK_OPT_IS_(TInt); + TInt tcResult=*(TUint*)aOption.Ptr(); + if(tcResult>KBlogTestCaseResultUpperNo) + { + return KErrArgument; + } + BlogTestCaseResult(tcResult); + break; + } + case KBloggerSetTesterMessage: + { + BlogTesterMessage(*(TDesC16*)aOption.Ptr()); + break; + } + case KBloggerSetAllOptions: + { + CHECK_OPT_IS_(TBlogSettings); // we care about the data pckgd not he pckg itself + TBlogSettingsPckg theSettings; + theSettings.Copy(aOption); + + TInt verbosity=(theSettings()).iVerbosity; + if((verbosityKBlogVerbosityAllLevels)) + { + return KErrArgument; + } + + TInt mediumType=(theSettings()).iMediumToLog; + if((mediumType!=KBlogOutputTypeIsFlogger)&&(mediumType!=KBlogOutputTypeIsRDebug)) + {//otherwise we will panic when we try to output + return KErrArgument; + } + + TInt windowSize=(theSettings()).iOutputWindowSize; + if((windowSize<1)||(windowSize>KRDBMaxLit)) + { + return KErrArgument; + } + + iLayersToLogMask =(theSettings()).iLayersToLog; + iVerbosityLevel =verbosity; + iLoggingMask =(theSettings()).iLoggingMask; + iMediumType =mediumType; + iOutputWindowSize =windowSize; + iTestCaseLit =(theSettings()).iTestCaseLit; + + if (iTestCaseLit!=KNullDesC) + BlogTestCase(iTestCaseLit); + + break; + } + default: + { + return KErrArgument; + } + }; + return KErrNone; + } + + +void CBlogger::Panic(TBloggerPanic aPanic) + { + User::Panic(_L("BLogger Panic"),aPanic); + } + +void CBlogger::Blog(const TDesC& aMessage,TInt aFrameWindow) +/** + Formats the message with a date and time preamble and blogs it. + But a limitation is that although it breaks the message in parts of + aFrameWindow size characters, it cannot accept amessage which is longer + than KBlogMessageMaxLitLength +*/ + { + __ASSERT_DEBUG((KBlogMessageMaxLitLength-KBlogDateTimeLitLength)>=aMessage.Length(),Panic(EBloggerMessageLengthTooLong)); + TBuf logMessage; + DoDateTimeFormat(logMessage); + logMessage.Append(aMessage); + DoBlog(logMessage,aFrameWindow); + } + +void CBlogger::Blog(const TDesC& aMessage) +/** + Formats the message with a date and time preamble and blogs it. + But a limitation is that it cannot accept a message which is longer + than KBlogMessageMaxLitLength. +*/ + { + Blog(aMessage,iOutputWindowSize); + } + + +void CBlogger::BlogTestCase(TDesC& aTestCaseName) + { + // output a preamble indicating new test case (or a repeat of the previous one:-) + // include time date and a Lit for the preamble + __ASSERT_DEBUG(KBlogTestCaseMaxLitLength>=KBlogDateTimeLitLength,Panic(EBloggerDescriptorLengthWasShorter)); + TBuf testCaseString; + DoDateTimeFormat(testCaseString); // no need for ret val check here + testCaseString.Append(KBlogTestCaseLit); + testCaseString.Append(aTestCaseName); + DoBlog(testCaseString,iOutputWindowSize); + } + +void CBlogger::BlogTesterMessage(TDesC& aTesterMessage) +/** + A Test App can output a string in the Blogger logs through this method. + To do this the test app should issue a SetOpt of type KBloggerSetTesterMessage + and pass a packaged TDesC16. +*/ + { + TBuf tstInfoString; + DoDateTimeFormat(tstInfoString); + tstInfoString.Append(KBlogTesterMessageInfoLit); + tstInfoString.Append(aTesterMessage); + DoBlog(tstInfoString,iOutputWindowSize); +// DoBlog(aTesterMessage,iOutputWindowSize); + } + +void CBlogger::BlogTestCaseResult(TInt aTestCaseResult) + { + if(!(iTestCaseLit.Length())) //in the case the TC Lit was not setup + { + return; + } + + TBuf tcMessage; + __ASSERT_DEBUG(KBlogTestCaseResultMaxLitLength>KBlogDateTimeLitLength,Panic(EBloggerDescriptorLengthWasShorter)); + DoDateTimeFormat(tcMessage); + + switch(aTestCaseResult) + { + case KBlogTestCaseResultPassed: + { + tcMessage.Append(KBlogTestCaseResultLitPass); + break; + } + case KBlogTestCaseResultFailed: + { + tcMessage.Append(KBlogTestCaseResultLitFailed); + break; + } + case KBlogTestCaseResultInconclusive: + { + tcMessage.Append(KBlogTestCaseResultLitInconclusive); + break; + } + case KBlogTestCaseResultSkipped: + { + tcMessage.Append(KBlogTestCaseResultLitSkipped); + break; + } + default: + { + // check your bounds checking in the handler + Panic(EBloggerTestCaseResultIsBogus); + } + }; + + tcMessage.Append(iTestCaseLit); + DoBlog(tcMessage,iOutputWindowSize); + } + +void CBlogger::DoBlog(const TDesC& aMessage,TInt aFrameWindow) + { + TInt msgLength=aMessage.Length(); + if(!msgLength) + {return;} + + TInt min=Min(KRDBMaxLit,aMessage.Length()); + TInt len=Min(min,aFrameWindow); + + TInt frames=msgLength/len; + TInt lastFrameSize=msgLength%len;// i.e the remainder + + TInt position=0; + for(TInt f=0;f timeLit; // abit more bytes than needed + TTime time; + time.HomeTime(); + TRAPD(errD,time.FormatL(aDesToPrepend,KBlogDateFormat)); + if(errD) + { + //since we OOMed + aDesToPrepend.Append(KBlogBlankDate); + } + TRAPD(errT,time.FormatL(timeLit,KBlogTimeFormat)); + if (errT) + { + timeLit.Copy(KBlogBlankTime); + } + + aDesToPrepend.Append(timeLit); + + // although OOM may have happened, but the point is to get the log out quickly + return KErrNone; + } + + +void CBlogger::HexDump(const TDesC& aDescription,const TDesC8& aHexFrame, TInt aFrameWindow) +/** + It will trim the sDescription to fit in the aFrameWindow size. + It also log the HexFrame in chunks of size=aFrameWindow. +*/ + { + //255 is the max RDebug::Print size + + DoBlog(aDescription,aFrameWindow); + + TInt bufferSize=aHexFrame.Length(); + if(!bufferSize) + {return;} + + TInt frames=bufferSize/(aFrameWindow/5); // 5 is the size of the formating lit + TInt lastFrameSize=(bufferSize*5)%aFrameWindow;// i.e the remainder + + TInt i=0; + TBuf outBuf; + + for ( TInt f=0;f buf8; + buf8.Copy(aMessage); + User::LeaveIfError(ifile.Write(buf8)); + User::LeaveIfError(ifile.Write(_L8("\r\n"))); + User::LeaveIfError(ifile.Flush()); + break; + } + default: + { + Panic(EBloggerResourceTypeIsBogus); + } + }; + + } + +void CBlogger::StoreFloggerInfo(TAny* aLogInfo) +/** + Store the pointer from the HCI's TLS that indicates to which file the floffer should log. + This is necessary in order to be able (at will) to accomodate both Flogger + and Blogger functionality in the stack. + + This method will only be used from the LinkMgr when Flogging is enabled. +*/ + { + iFloggerInfo=aLogInfo; + } + + +EXPORT_C TAny* CBlogger::GetFloggerInfo() + { + return iFloggerInfo; + } + +void CBlogger::DoBloggerTests() + { +#ifdef BLOGGING__SELF_TESTS__ + LLQBLOG(1,Log(_L(" >>>>>>>>>>>>>>>>>> This is %d <<<<<<<<<<<<<<<<"),1)); + LLQBLOG(1,Log(_L("123456789a123456789b123456789c123456789d123456789e123456789f123456789g123456789h123456789i"))); + LLQBLOG(1,Log(_L(" a string %S and a number %d"),&_L("Andy"), 1)); + LLQBLOG(1,HexDump(_L("A hex dump"),_L8(" read hex mate?"),10)); + LLQBLOG(1,HexDump(_L("A long hex dump"),_L8("123456789a123456789b123456789c123456789d123456789e123456789f123456789g"),80)); + + // Testing test case Lit setup + TBuf tcName(_L("My First Test Case ,NO1")); + TPckgBuf tcNamePckg(tcName); + UpdateLoggingSettings(KBloggerSetTestCaseName,tcNamePckg); + + // Testing Test Case Results + TPckgBuf tcResult(KBlogTestCaseResultPassed); + UpdateLoggingSettings(KBloggerSetTestCaseResult,tcResult); + + //Testing Test app messages + TBuf tstMsg(_L("This is message from the tester saying it is doing a test")); + TPckgBuf tstMsgPckg(tstMsg); + UpdateLoggingSettings(KBloggerSetTesterMessage,tstMsgPckg); +#endif + } + +// Blogettes + +CBloggette::~CBloggette() + { + } + +CBloggette::CBloggette(CBlogger* aProvider, TInt aLayer) : + iLayer(aLayer), + iBlogger(aProvider) + { + } + +void CBloggette::Log(TRefByValue aFormatingLit, ...) +/** + The maximum length of the allowed string is 255. +*/ + { + VA_LIST tmpArgList; + VA_START(tmpArgList,aFormatingLit); + TBuf blogBuf; + blogBuf.Zero(); + blogBuf.AppendFormatList(aFormatingLit, tmpArgList); //FIXME overflow handler possibly ? + iBlogger->Blog(blogBuf); + VA_END(tmpArgList); + } + + +void CBloggette::HexDump(TRefByValue aDescription,const TDesC8& aHexFrame, TInt aFrameWindow) + { + iBlogger->HexDump(aDescription,aHexFrame,aFrameWindow); + } + +TInt CBloggette::Layer() const + { + return iLayer; + } + + +// Link Layer Bloggette + +CLLBloggette* CLLBloggette::NewL(CBlogger* aProvider, TInt aLayer) + { + CLLBloggette* self = new (ELeave)CLLBloggette(aProvider,aLayer); + self->iBlogger->Register(self); + return self; + } + +CLLBloggette::CLLBloggette(CBlogger* aProvider, TInt aLayer) + : CBloggette(aProvider,aLayer) + { + } + +CLLBloggette::~CLLBloggette() + { + } + +TDesC CLLBloggette::NameDes() + { + return _L("LL Dummy Bloggette"); + } + +// L2CAP Bloggette + +CL2Bloggette* CL2Bloggette::NewL(CBlogger* aProvider, TInt aLayer) + { + CL2Bloggette* self = new (ELeave)CL2Bloggette(aProvider,aLayer); + self->iBlogger->Register(self); + return self; + } + +CL2Bloggette::CL2Bloggette(CBlogger* aProvider, TInt aLayer) + : CBloggette(aProvider,aLayer) + { + } + +CL2Bloggette::~CL2Bloggette() + { + } + +TDesC CL2Bloggette::NameDes() + { + return _L("L2CAP Dummy Bloggette"); + } + +// RFCOMM Bloggette + +CRFBloggette* CRFBloggette::NewL(CBlogger* aProvider, TInt aLayer) + { + CRFBloggette* self = new (ELeave)CRFBloggette(aProvider,aLayer); + self->iBlogger->Register(self); + return self; + } + +CRFBloggette::CRFBloggette(CBlogger* aProvider, TInt aLayer) + : CBloggette(aProvider,aLayer) + { + } + +CRFBloggette::~CRFBloggette() + { + } + +TDesC CRFBloggette::NameDes() + { + return _L("RFComm Dummy Bloggette"); + } + +void CRFBloggette::Timeout(/*CRfcommSAP* aSAP, CRfcommMuxer* aMux,*/ CRfcommFrame* aFrm ) + { + TUint8 ctrlfield = aFrm->Ctrl(); + + switch((ctrlfield&~KPollFinalBitmask)) + { + case KSABMCtrlField: + Log(KBlogTimeout); + Log(KBlogSABM); + break; + case KDISCCtrlField: + Log(KBlogTimeout); + Log(KBlogDISC); + break; + default: + break; + }; + } + +void CRFBloggette::LogMuxCommand(CRfcommSAP* aSAP, CRfcommMuxer* aMux, TUint8 aCommand) + { + TUint8 signals; + + switch(aCommand) + { + case KTestType: + Log(KBlogTestCommand); + break; + case KPNType: + Log(KBlogPN);// + break; + case KRPNType: + Log(KBlogRPN);// + break; + case KFConType: + //may need length byte value + Log(KBlogFcOn);// + break; + case KFCoffType: + Log(KBlogFcOff);// + break; + case KMSCType: + signals = aSAP->Signals();//V.24 signals in MSC + Log(KBlogMSC);// + break; + case KNSCType: + Log(KBlogNSC);// + break; + case KRLSType: + Log(KBlogRLS);// + }; + + } +void CRFBloggette::ExplainOutgoingFrame(CRfcommFrame* aFrm, CRfcommMuxer* aMux ) + { +#ifndef TCI + //Show what type of frame we have sent and the various parts of the frame which are important. + + TInt frametype = aFrm->Type(); //Is it a Ctrl Frame, Data Frame, CreditDataFrame or Mux Ctrl Frame ? + TUint8 ctrlfield = aFrm->Ctrl(); + TUint8 ctrl = ctrlfield&~KPollFinalBitmask; //tells whether SABM, DISC, UA, DM + TUint8 addressfield = aFrm->Address(); //Contains EA, CR, DLCI +// TUint8 dlci = aMux->DecodeDLCI(addressfield); //extracts dlci + TBool EA = addressfield & KEABitmask; //Is the EA bit set? + TBool CR = addressfield & KCRBitmask; //Is the CR bit set? + TBool poll = ctrlfield & KPollFinalBitmask; //Is the p/f bit set? + + switch(frametype) + { + case KCtrlFrameType: + { + //CRfcommCtrlFrame* ctrlfrm=static_cast(aFrm); + //TUint16 ctrlframelength = ctrlfrm->DataLength(); + Log(_L("Tx:")); + + if(ctrl==KSABMCtrlField) + { + Log(_L("Tx: SABM")); + } + if(ctrl==KUACtrlField) + { + Log(_L("Tx: UA")); + } + if(ctrl==KDMCtrlField) + { + Log(_L("Tx: DM")); + } + if(ctrl==KDISCCtrlField) + { + Log(_L("Tx: DISC")); + } + } + break; + case KDataFrameType: //CRfCommUIHFrame + { + CRfcommUIHFrame* uihfrm=static_cast(aFrm); + TUint16 uihframelength = uihfrm->DataLength(); + + if(poll) + Log(_L("Tx: UIH credit data frame")); + + if (uihframelength<=127) + { + Log(_L("Tx: UIH simple data frame")); + } + else + { + Log(_L("Tx: UIH simple data frame")); + } + } + break; + case KCreditDataFrameType: //CRfcommCreditDataFrame + { + CRfcommCreditDataFrame* creditfrm=static_cast(aFrm); + TUint8 credits = creditfrm->Credit(); + //BLOG Credits + TUint16 length = creditfrm->DataLength(); + + if (length<=127) + { + Log(KBlogShortCreditUIH, credits); + } + else + { + Log(KBlogLongCreditUIH, credits); + } + } + break; + case KMuxCtrlFrameType: //CRfcommMuxCtrlFrame containing muxer messages/commands + { + //#ifndef TCI + CRfcommMuxCtrlFrame* muxfrm=static_cast(aFrm); + TUint8 muxdlci = muxfrm->iDLCI; + CRfcommSAP* sap = aMux->FindSAP(muxdlci); //Find the SAP that is on this dlci for aMux + TUint8 command = muxfrm->CommandType(); + LogMuxCommand(sap, aMux, command); + //#endif + } + break; + default: //CRfcommDataFrame + break; + }; + Log(KBlogPFSet, poll); + Log(KBlogEASet, EA); + Log(KBlogCRSet, CR); + + Log(KBlogFrameType, frametype); +#endif + } + +void CRFBloggette::ExplainIncomingFrame(TUint8 aDlci, TUint8 aCtrl, TBool aPoll) + { + Log(_L("Rx: ")); + switch (aCtrl) + { + case KSABMCtrlField: + Log(_L("Rx: SABM")); + break; + case KUACtrlField: + Log(_L("Rx: UA")); + break; + case KDMCtrlField: + Log(KBlogDM); + break; + case KDISCCtrlField: + Log(KBlogDISC); + break; + case KUIHCtrlField: + { + if(aDlci== KMuxDLCI) + { + Log(KBlogUIHCtrlFrame); + } + else + { + Log(KBlogSimpleUIH); + } + } + break; + default: + //FLOG(_L("Error: RFCOMM: Unexpected frame ctrl field")); + break; + }; + Log(KBlogDLCI, aDlci); + Log(KBlogPFSet, aPoll); + } + +void CRFBloggette::IncomingCtrlMessage(TUint8 aCommand, TInt aLength) + { + switch(aCommand) + { + case KTestType: + Log(KBlogTestCommand); + break; + case KPNType: + Log(KBlogPN); + break; + case KRPNType: + Log(KBlogRPN); + break; + case KFConType: + { + Log(KBlogFcOn); + if(aLength!=0) + { + Log(KBlogNonZeroLength); + } + } + break; + case KFCoffType: + { + Log(KBlogFcOff); + if(aLength!=0) + { + Log(KBlogNonZeroLength); + } + } + break; + case KMSCType: + Log(KBlogMSC); + break; + case KNSCType: + Log(KBlogNSC); + break; + case KRLSType: + Log(KBlogRLS); + }; + } + +#endif