diff -r 000000000000 -r 29b1cd4cb562 bthci/hci2implementations/hctls/bcsp/src/hctlbcsp.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bthci/hci2implementations/hctls/bcsp/src/hctlbcsp.cpp Fri Jan 15 08:13:17 2010 +0200 @@ -0,0 +1,630 @@ +// Copyright (c) 2006-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: +// + +/** + @file + @internalComponent +*/ + +#include "hctlbcsp.h" + +#include "hctlbcspFrameQueue.h" +#include "bcsputils.h" +#include "hctlbcspframe.h" +#include "hctlbcspconsts.h" +#include "linkestablishment.h" +#include "hctlbcspreceiver.h" +#include "hctlbcspsequencer.h" +#include "hctlbcspcontrollermanager.h" +#include "debug.h" + +#include +#include +#include +#include +#include + +/** + Implementation of Class CHCTLBcsp +*/ + +CHCTLBcsp::CHCTLBcsp() + { + LOG_FUNC + } + +CHCTLBcsp::~CHCTLBcsp() + { + LOG_FUNC + + HCI_LOG_UNLOAD(this); + delete iLinkEstablishment; + delete iReceiver; + delete iSequencer; + delete iFrameQueue; + delete iReceivedFrame; + delete iControllerMan; + } + +CHCTLBcsp* CHCTLBcsp::NewL() + { + LOG_STATIC_FUNC + + CHCTLBcsp* self=new(ELeave) CHCTLBcsp; + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +void CHCTLBcsp::ConstructL() + { + LOG_FUNC + + HCI_LOG_LOADL(this, KHCILoggerDatalinkTypeH1); // Technically it's BCSP but we're going + // to log at a higher layer + BaseConstructL(KIniFileName); + iControllerMan = CHCTLBcspControllerManager::NewL(*this, Port(), PowerCtrlMode()); + } + +TAny* CHCTLBcsp::Interface(TUid aUid) + { + LOG_FUNC + + TAny* ret = NULL; + switch(aUid.iUid) + { + case KHCTLInterfaceUid: + ret = reinterpret_cast(static_cast(this)); + break; + case KHCTLPowerInterfaceUid: + ret = reinterpret_cast(static_cast(iControllerMan)); + break; + case KHCHardResetUid: + ret = reinterpret_cast(static_cast(this)); + break; + + default: + break; + }; + + return ret; + } + +void CHCTLBcsp::DoConfigL() +/** + + Method to set the TCommConfigV01 settings for UART based HCTLs + enforced implementation by pure virtual method in CHCTLUartBase to allow for the original uart transport (H4) and BCSP + specific settings + + @leave method will leave if Port().SetConfig() fails +*/ + { + LOG_FUNC + + Port().ResetBuffers(); + TCommConfig conf; + Port().Config(conf); + + TCommConfigV01& config = conf(); //Get reference to TCommConfig iConfig + + config.iDataBits = EData8; + config.iStopBits = EStop1; + config.iTerminatorCount = 1; + config.iTerminator[0] = 0xc0; + config.iParity = EParityEven; + config.iParityError = KConfigParityErrorFail; + config.iHandshake = 0; + config.iXonChar = 0; + config.iXoffChar = 0; + + LEAVEIFERRORL(Port().SetConfig(conf)); + } + + +//Implemenation of MHCTLInterface + +TInt CHCTLBcsp::MhiWriteAclData(const TDesC8& aData) + { + LOG_FUNC + + iFrameQueue->AddReliableFrame(aData, KBcspACLDataChnl); + HCI_LOG_FRAME(this, KHCILoggerHostToController | KHCILoggerACLDataFrame, aData); + return KErrNone; + } + +TInt CHCTLBcsp::MhiWriteSynchronousData(const TDesC8& aData) + { + LOG_FUNC + + iFrameQueue->AddUnreliableFrame(aData, KBcspSynchronousDataChnl, 0, EFalse); + HCI_LOG_FRAME(this, KHCILoggerHostToController | KHCILoggerSynchronousDataFrame, aData); + return KErrNone; + } + +TInt CHCTLBcsp::MhiWriteCommand(const TDesC8& aData) + { + LOG_FUNC + + TRAPD(err,DoWriteCommandL(aData)); + if(err!=KErrNone) + { + return KErrBcspWriteCommandDataFailed; + } + else + { + HCI_LOG_FRAME(this, KHCILoggerHostToController | KHCILoggerCommandOrEvent, aData); + return err; + } + } + +TInt CHCTLBcsp::WriteBcCmd(const TDesC8& aData) + { + LOG_FUNC + + TRAPD(err,DoWriteBcCmdL(aData)); + if(err!=KErrNone) + { + return KErrBcspWriteBcCmdDataFailed; + } + else + { + HCI_LOG_FRAME(this, KHCILoggerHostToController | KHCILoggerCommandOrEvent, aData); + return err; + } + } + +void CHCTLBcsp::MhiSetQdpPluginInterfaceFinder(MQdpPluginInterfaceFinder& aQdpPluginInterfaceFinder) + { + iQdpPluginInterfaceFinder = &aQdpPluginInterfaceFinder; + } + +void CHCTLBcsp::MhriStartHardReset() + { + iControllerMan->HardReset(); + } + +void CHCTLBcsp::MhiGetAclDataTransportOverhead(TUint& aHeaderSize, TUint& aTrailerSize) const + { + aHeaderSize = KHCTLAclDataHeaderSize; + aTrailerSize = KHCTLAclDataTrailerSize; + } + + +void CHCTLBcsp::MhiGetSynchronousDataTransportOverhead(TUint& aHeaderSize, TUint& aTrailerSize) const + { + aHeaderSize = KHCTLSynchronousDataHeaderSize; + aTrailerSize = KHCTLSynchronousDataTrailerSize; + } + +void CHCTLBcsp::MhiGetCommandTransportOverhead(TUint& aHeaderSize, TUint& aTrailerSize) const + { + aHeaderSize = KHCTLCommandHeaderSize; + aTrailerSize = KHCTLCommandTrailerSize; + } + +//MHCTLInterface END + + +void CHCTLBcsp::DoWriteCommandL(const TDesC8 &aData) +/** + + Method called from MhiWriteCommand + + @param aData + aData is the formatted Command payload from the linkmanager + +*/ + { + LOG_FUNC + +#ifdef __DEBUG_FLOG_STACK_TX_ + LOG(_L8("STACK TX")); + LOGHEXDESC(aData); +#endif + User::LeaveIfError(iFrameQueue->AddReliableFrame(aData, KBcspCommEvntChnl));//KBcspBcCmdChnl + } + +void CHCTLBcsp::DoWriteBcCmdL(const TDesC8 &aData) +/** + + Method called from WriteBcCmdData + + @param aData + aData is the formatted BCCMD payload from the controller manager + +*/ + { + LOG_FUNC + +#ifdef __DEBUG_FLOG_STACK_TX_ + LOG(_L8("STACK TX")); + LOGHEXDESC(aData); +#endif + User::LeaveIfError(iFrameQueue->AddReliableFrame(aData, KBcspBcCmdChnl)); + } + +/** +Process Received data in to the format expected by the interface to the bottom of the stack +*/ + +void CHCTLBcsp::ProcessACLData() +/** + Passes ACL data to the data observer. +*/ + { + LOG_FUNC + + __ASSERT_DEBUG(iReceivedFrame->IsValid(), PANIC(KBcspPanicCat, EBadBcspFrame)); + + HCI_LOG_FRAME(this, KHCILoggerControllerToHost | KHCILoggerACLDataFrame, iReceivedFrame->Payload()); + iDataObserver->MhdoProcessAclData(iReceivedFrame->Payload()); + } + +void CHCTLBcsp::ProcessEventData() +/** + Passes event data to the data observer. +*/ + { + LOG_FUNC + + __ASSERT_DEBUG(iReceivedFrame->IsValid(), PANIC(KBcspPanicCat, EBadBcspFrame)); + + HCI_LOG_FRAME(this, KHCILoggerControllerToHost | KHCILoggerCommandOrEvent, iReceivedFrame->Payload()); + iEventObserver->MheoProcessEvent(iReceivedFrame->Payload()); + } + +void CHCTLBcsp::ProcessBcCmdEventData() +/** + + Method which parses the received Command data payload from the controller + and formats the data to be passed to the controller manager +*/ + { + LOG_FUNC + + __ASSERT_DEBUG(iReceivedFrame->IsValid(), PANIC(KBcspPanicCat, EBadBcspFrame)); + + HCI_LOG_FRAME(this, KHCILoggerControllerToHost | KHCILoggerCommandOrEvent, iReceivedFrame->Payload()); + iControllerMan->ProcessBcCmdEvent(iReceivedFrame->Payload()); + } + +void CHCTLBcsp::ProcessSynchronousData() + { + LOG_FUNC + + __ASSERT_DEBUG(iReceivedFrame->IsValid(), PANIC(KBcspPanicCat, EBadBcspFrame)); + + HCI_LOG_FRAME(this, KHCILoggerControllerToHost | KHCILoggerSynchronousDataFrame, iReceivedFrame->Payload()); + iDataObserver->MhdoProcessSynchronousData(iReceivedFrame->Payload()); + } + +TInt CHCTLBcsp::PacketRouter() +/** + Method called by CHCTLBcspReceiver after packet integrity checks have been performed + This routes packets according to the ProtocolId associated with the payload type in a + given BCSP frame to the appropriate interface to the top of the HCI and thus to the + link manager +*/ + { + LOG_FUNC + + TInt err = KErrNone; + __ASSERT_DEBUG(iReceivedFrame->IsValid(), PANIC(KBcspPanicCat, EBadBcspFrame)); + + switch (iReceivedFrame->ProtocolId()) + { + case KBcspCommEvntChnl: + { + LOG(_L8("HCTLBCSP: Event Packet Received...")); + ProcessEventData(); + } + break; + + case KBcspBcCmdChnl: + { + LOG(_L8("HCTLBCSP: BC Command Packet Received...")); + ProcessBcCmdEventData(); + } + break; + + case KBcspACLDataChnl: + { + LOG(_L8("HCTLBCSP: ACL Data Packet Received...")); + ProcessACLData(); + } + break; + + case KBcspSynchronousDataChnl: + { + LOG(_L8("HCTLBCSP: Synchronous Data Packet Received...")); + ProcessSynchronousData(); + } + break; + + case KBcspLinkChnl: + { + LOG(_L8("HCTLBCSP: Link Est Packet Received...")); + __ASSERT_DEBUG(iLinkEstablishment!=NULL, PANIC(KBcspPanicCat, EBadLinkPointer)); + TRAP(err,iLinkEstablishment->ProcessLinkMsg(iReceivedFrame->Payload())); + } + break; + + default: + LOG(_L8("HCTLBCSP: ERROR: KErrBcspUnRecognizableHCIData...")); + break; + }; + + return err; + } + +void CHCTLBcsp::QueueReadForNextFrame() + { + LOG_FUNC + + iReceiver->QueueReadForNextFrame(); + } + +void CHCTLBcsp::CanSend(TBool aCanSend) +/** + For BCSP this is always taken to be all channels or no channels +*/ + { + LOG_FUNC + + iCanSend = aCanSend; + // We can only open the channel after unchoked and iChannelObserver has been set + if(!iChoked && iChannelObserver) + { + if(iCanSend) + { + iChannelObserver->MhcoChannelOpen(KHCITransportAllChannels); + } + else + { + iChannelObserver->MhcoChannelClosed(KHCITransportAllChannels); + } + } + } + +void CHCTLBcsp::TxAckMsg() +/** + Method to send a BCSP Ack message + This is only called when an the Ack timer fires i.e. a certain amount of time has + passed without there being an outgoing BCSP frame to convey acknowledgement of received + reliable frames +*/ + { + LOG_FUNC + + iFrameQueue->AddUnreliableFrame(KBcspAckChnl, iSequencer->TxAck(), EFalse); + } + +void CHCTLBcsp::TxLinkMsg(const TDesC8& aData) +/** + + This is a method that takes a BCSP Link Establishment message as its parameter + and adds the data along with a number of other bits of information to make a frame + on the Unreliable frame queue via the iFrameQueue::AddUnreliableFrame() method +*/ + { + LOG_FUNC + + iFrameQueue->AddUnreliableFrame(aData, KBcspLinkChnl, 0, ETrue); + } + +TInt CHCTLBcsp::HandleRx(const TDesC8 &aReceivedFrame) +/** + + This is a method called from the CHCTLBcspReceiver::ProcessDataL() + with the parameter + @param const TDesC8 &aReceivedFrame + @return err + This method attempts to slip decode the received frame + Then if that is successful the remainder of the BCSP frame integrity checks are performed + using the iReceivedFrame->IsValid() method + Assuming that this all works without errors control is then passed to the sequencer + via the iSequencer->HandleRx(iReceivedFrame) call + and then the iReceivedFrame->Reset() method is called +*/ + { + LOG_FUNC + + TInt rerr = iReceivedFrame->SlipDecodeFrame(aReceivedFrame); + if (rerr == KErrNone) + { + // We've succeeded in decoding the Slip Frame into a CRxHctlBcspFrame + __ASSERT_DEBUG(iReceivedFrame->IsValid(), PANIC(KBcspPanicCat, EBadBcspFrame)); + +#ifdef __DEBUG_RxDecodedFrame__ + FlogRx(); +#endif + + iSequencer->HandleRx(iReceivedFrame); + iReceivedFrame->Reset(); + } + + return rerr; + } + +TBool CHCTLBcsp::CheckIsAckPacket() const +/** + + This is a relatively simple method that examines the ProtocolId of the Received Frame + and attempts to match it to the the KBcspAckChnl constant and then returns a TBool depending + on whether or not these match +*/ + { + LOG_FUNC + + return (iReceivedFrame->ProtocolId() == KBcspAckChnl); + } + +#ifdef __DEBUG_RxDecodedFrame__ +void CHCTLBcsp::FlogRx() + { + LOG(_L8("RxFrame")); + LOG1(_L8("Protocol type reliable(1) unreliable (0) = %d\n"),iReceivedFrame->IsReliableProtcolType()); + LOG1(_L8("Ack value = %d\n"),iReceivedFrame->Ack()); + LOG1(_L8("Seq value = %d\n"),iReceivedFrame->Sequence()); + LOG1(_L8("Protocol ID (Command/Event(5)) (ACL) (Ack Packet) = %d\n"),iReceivedFrame->ProtocolId()); + LOG1(_L8("Payload Length = %d\n"),iReceivedFrame->PayloadLength()); + LOG1(_L8("Checksum value = %d\n"),iReceivedFrame->CheckSum()); + LOG1(_L8("Header bytes = %d\n"),iReceivedFrame->FlagsField()); + LOG(_L8("Payload...")); + LOGHEXDESC(iReceivedFrame->Payload()); + } +#endif + + + +/** + See comments on iChoked +*/ +void CHCTLBcsp::Choke() + { + LOG_FUNC + + iChoked = ETrue; + CanSend(iCanSend); + } + +/** + See comments on iChoked +*/ +void CHCTLBcsp::UnChoke() + { + LOG_FUNC + + iChoked = EFalse; + if(iControllerMan->BcspLinkEstablished()) + { + CanSend(iCanSend); + } + } + +TBool CHCTLBcsp::Muzzled() + { + return iMuzzled; + } + +void CHCTLBcsp::ResetMuzzled() + { + iMuzzled = EFalse; + } + +/** + + Handle a reset of the BCSP transport. + 1) Reset the BCSP layer + 2) Inform the stack of a HCI error + 3) Stack will reinitialise with a "reset" command etc +*/ +void CHCTLBcsp::HandlePeerReset() + { + LOG_FUNC + + // If a poweroff is requested, the next reset will lead to a reset of the SP link + // and will set the state to shy sending a sync frame every 250ms + // So, Muzzle the host to avoid sending this command + if(iControllerMan->PowerOffRequested()) + { + iMuzzled = ETrue; + } + + Reset(); //reset BCSP + + if(!iControllerMan->ExpectedControllerReset() && !iControllerMan->PowerOffRequested()) + { + // Inform stack of hardware error + TUint8 errReason = static_cast(EInvalidHCIParameter); + TBuf8<3> buf(3); + buf[0]= EHardwareErrorEvent; //error code + buf[1] = 1; //length + buf[2] = errReason; //parameter + iEventObserver->MheoProcessEvent(buf); + } + } + +/** + Reset the BCSP layer +*/ +void CHCTLBcsp::Reset() + { + LOG_FUNC + + Choke(); //Disconnected + //Reset the link establishment state machine + iLinkEstablishment->Reset(); + //Reset and clear transmit queues + iFrameQueue->Reset(); + //Reset the sequencer + iSequencer->Reset(); + } + +//Implementation of pure virtual functions in CHCTLUartBase + +void CHCTLBcsp::PortOpenedL() + { + LOG_FUNC + + __ASSERT_DEBUG(Port().Handle(), PANIC(KBcspPanicCat, EPortNotOpen)); + + DoConfigL(); + + + iChoked = ETrue; + + iFrameQueue = CHCTLBcspFrameQueue::NewL(*this); + + // Creation of the sequencer creates the sender Active Object. + // The sender Active Object must be added to the Active Scheduler before + // the receiver Active Object so that it gets preferential treatment. It + // is reported that otherwise the response from a command can come in + // before the sending client is told that the send has completed! + iSequencer = CHCTLBcspSequencer::NewL(*this, Port(), *iFrameQueue); + iReceiver=CHCTLBcspReceiver::NewL(*this, Port()); + + iFrameQueue->SetSequencer(*iSequencer); + + iLinkEstablishment= CLinkEstablishment::NewL(*this); + + iReceivedFrame = CRxHctlBcspFrame::NewL(); + } + +void CHCTLBcsp::MhiSetDataObserver(MHCTLDataObserver& aDataObserver) + { + iDataObserver = &aDataObserver; + } + +void CHCTLBcsp::MhiSetEventObserver(MHCTLEventObserver& aEventObserver) + { + iEventObserver = &aEventObserver; + } + +void CHCTLBcsp::MhiSetChannelObserver(MHCTLChannelObserver& aChannelObserver) + { + iChannelObserver = &aChannelObserver; + //give the stack an initial kick + CanSend(iCanSend); + } + +void CHCTLBcsp::MhiSetControllerStateObserver(MControllerStateObserver& aControllerStateObserver) + { + iControllerStateObserver = &aControllerStateObserver; + iControllerMan->SetObserver(aControllerStateObserver); + iControllerMan->Start(); + }