--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bthci/hci2implementations/hctls/bcsp/src/hctlbcspcontrollermanager.cpp Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,425 @@
+// Copyright (c) 2007-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 "hctlbcspcontrollermanager.h"
+
+#include "debug.h"
+#include "hctlbcsp.h"
+#include "bcsputils.h"
+
+#include <bluetooth/hci/controllerstateobserver.h>
+#include <bluetooth/hci/hctluartpowermanager.h>
+
+// BlueCore Commands - Must be 18 bytes in length, payload is treated in 16bit units.
+// |Command |Length |SeqNum |BC Cmd | Payload |
+// | SetReq |9 units| N/a | Reset | Pad |
+_LIT8(KBcCmdColdResetCommand, "\x02\x00\x09\x00\x00\x00\x01\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00");
+// | SetReq |9 units| N/a | Halt | Pad |
+_LIT8(KBcCmdColdHaltCommand, "\x02\x00\x09\x00\x00\x00\x03\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00");
+
+
+CHCTLBcspControllerManager* CHCTLBcspControllerManager::NewL(CHCTLBcsp& aHCTLBcsp, RBusDevComm& aPort,
+ CHCTLUartBase::TPowerControlDetectionMode aPwrCtrlMode)
+ {
+ LOG_STATIC_FUNC
+
+ CHCTLBcspControllerManager* self = new(ELeave) CHCTLBcspControllerManager(aHCTLBcsp, aPort, aPwrCtrlMode);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CHCTLBcspControllerManager::~CHCTLBcspControllerManager()
+ {
+ LOG_FUNC
+
+ delete iPowerDownCallback;
+ delete iReadyToResetControllerCallback;
+ delete iUartPowerManager;
+ }
+
+CHCTLBcspControllerManager::CHCTLBcspControllerManager(CHCTLBcsp& aHCTLBcsp, RBusDevComm& aPort,
+ CHCTLUartBase::TPowerControlDetectionMode aPwrCtrlMode)
+ : iPort(aPort),
+ iHCTLBcsp(aHCTLBcsp),
+ iControllerManagerState(EIdle),
+ iLastPowerRequest(EBTOn),
+ iCurrentPowerState(EBTOn),
+ iCurrentTask(ENoTask),
+ iPwrCtrlMode(aPwrCtrlMode)
+ {
+ LOG_FUNC
+ }
+
+void CHCTLBcspControllerManager::ConstructL()
+ {
+ LOG_FUNC
+
+ iColdResetCommand = KBcCmdColdResetCommand();
+ iColdHaltCommand = KBcCmdColdHaltCommand();
+
+ TCallBack cbHandlePowerDown(HandlePowerDown, this);
+ iPowerDownCallback = new(ELeave) CAsyncCallBack(cbHandlePowerDown, CActive::EPriorityStandard);
+
+ TCallBack cbHandleReadyToResetController(HandleReadyToResetController, this);
+ iReadyToResetControllerCallback = new(ELeave) CAsyncCallBack(cbHandleReadyToResetController, CActive::EPriorityStandard);
+
+ // if the ini file is configured to use CTS line to control the
+ // device's power on/off control than we instantiate iUartPowerManager.
+ // otherwise it remains NULL (as implicitly set by CBase base class).
+ // So, in the destructor, we can delete it directly.
+ if (iPwrCtrlMode == CHCTLUartBase::EPwrCtrlCTSTimedLow)
+ {
+ iUartPowerManager = CHCTLUartPowerManager::NewL(*this, iPort);
+ iUartPowerManager->Start();
+ }
+ }
+
+
+void CHCTLBcspControllerManager::Start()
+/*
+For future use - called when HCTL is started
+*/
+ {
+ LOG_FUNC
+ }
+
+void CHCTLBcspControllerManager::MhupoPowerChange(TInt aError)
+ {
+ LOG_FUNC
+
+ if (aError == KErrNone)
+ {
+ // if there is a task underway then the observer will be notified elsewhere
+ if (iCurrentTask == ENoTask)
+ {
+ // unsolicited power change
+ iCurrentPowerState = (iCurrentPowerState == EBTOn) ? EBTOff : EBTOn;
+ LOG1(_L8("Unsolicited power change detected, current power state: %d"), iCurrentPowerState);
+
+ if(iObserver)
+ {
+ iObserver->McsoProcessPowerChange(KErrNone, MControllerStateObserver::EBTFatalChange, iCurrentPowerState);
+ }
+ }
+ }
+ else
+ {
+ // If we get an error from the uart power manager then just log
+ // error but do not attempt to restart.
+ LOG1(_L8("Error detecting power change: %d"), aError);
+ }
+ }
+
+TInt CHCTLBcspControllerManager::MhpiGetPower(TBTPowerState& aState)
+ {
+ if(iCurrentTask != ENoTask)
+ //Information will not be reliable
+ {
+ return KErrInUse;
+ }
+
+ aState = iCurrentPowerState;
+ return KErrNone;
+ }
+
+TInt CHCTLBcspControllerManager::MhpiSetPower(TBTPowerState aState)
+/*
+To be called from outside the class only, for example in response to user request
+*/
+ {
+ TInt rerr = KErrNone;
+
+ switch(iCurrentTask)
+ {
+ case EPowerUp:
+ case EPowerDown:
+ //If SetPower is called whilst performing a power request error the BT client.
+ //There should only be one!
+ rerr = KErrInUse;
+ break;
+
+ case EControllerReset:
+ //Just postpone power request. A power down will be handled when
+ //the next link establshment comes in.
+ iLastPowerRequest = aState;
+ rerr = KErrInUse;
+ break;
+
+ case ENoTask:
+ iLastPowerRequest = aState;
+ if(iCurrentPowerState == iLastPowerRequest)
+ {
+ //Nothing to do - need to return an error to complete synchronously
+ //(Do not tell stack.)
+ rerr = KErrAlreadyExists;
+ }
+ else
+ {
+ rerr = DoSetPower(aState);
+ }
+ break;
+
+ default:
+ PANIC(KBcspPanicCat, EInvalidCurrentTask);
+ };
+
+ return rerr;
+ }
+
+TInt CHCTLBcspControllerManager::DoSetPower(TBTPowerState aState)
+ {
+ switch(aState)
+ {
+ case EBTOff:
+ {
+ iHCTLBcsp.WriteBcCmd(iColdHaltCommand); //this should not produce a response
+ iPowerDownCallback->CallBack(); //allows asynch callback to BTClient.
+ iCurrentTask = EPowerDown;
+ iControllerManagerState = EWaiting;
+ iHCTLBcsp.Choke();
+ }
+ break;
+
+ case EBTOn:
+ {
+ iHCTLBcsp.UnChoke();
+ iHCTLBcsp.ResetMuzzled(); // Reset the muzzled parameter of the BT host
+ iHCTLBcsp.WriteBcCmd(iColdResetCommand);
+ iCurrentTask = EPowerUp;
+ iControllerManagerState = EResetHardware;
+ }
+ break;
+
+ default:
+ PANIC(KBcspPanicCat, EUnexpectedPowerState);
+ break;
+ };
+
+ return KErrNone;
+ }
+
+void CHCTLBcspControllerManager::HardReset()
+ {
+ // Only perform reset if the power is on and the controller is
+ // not performing another action.
+ if(iLastPowerRequest == EBTOn && iCurrentTask == ENoTask)
+ {
+ /*
+ This implementation assumes a dedicated controller reset will be used.
+ However we provide an example of how a power cycle reset might be implemented.
+ */
+ iReadyToResetControllerCallback->CallBack();//call back will call reset on controller
+ iCurrentTask = EControllerReset;
+ iControllerManagerState = EWaiting;
+ }
+ }
+
+/*
+ Called when BCSP state reaches 'garrulous'.
+ Controller Manager may not want BCSP to inform the outside world,
+ for example, if it wishes to do a controller reset, and
+ so wishes to manage the controller itself and keep the outside world at bay.
+*/
+TBool CHCTLBcspControllerManager::BcspLinkEstablished()
+ {
+ if(iLastPowerRequest == EBTOff)
+ /*
+ Should only get here if a power off request occurred whilst
+ awaiting this link establishment - in which case abandon
+ whatever we were doing and switch power off.
+ */
+ {
+ DoSetPower(EBTOff);
+ return EFalse;
+ }
+
+ TBool doTellStack = ETrue;
+
+ switch(iCurrentTask)
+ {
+ case ENoTask:
+ break; //not to do with us
+ case EPowerUp:
+ {
+ doTellStack = DoBcspLinkEstablishedForPowerUp();
+ }
+ break;
+ case EControllerReset:
+ {
+ doTellStack = DoBcspLinkEstablishedForControllerReset();
+ }
+ break;
+ case EPowerDown:
+ default:
+ {
+ __ASSERT_DEBUG(EFalse, PANIC(KBcspPanicCat, EInvalidCurrentTask));
+ }
+ }
+
+ return doTellStack;
+ }
+
+/**
+ Called when the controller starts trying to establish a BCSP link whilst we
+ think a link is established. This state is intentional if the controller manager
+ has called a 'ColdReset' command.
+*/
+TBool CHCTLBcspControllerManager::ExpectedControllerReset()
+ {
+ return (iControllerManagerState == EResetHardware);
+ }
+
+TBool CHCTLBcspControllerManager::PowerOffRequested()
+ {
+ return (iLastPowerRequest == EBTOff);
+ }
+
+void CHCTLBcspControllerManager::ProcessBcCmdEvent(const TDesC8& /*aEvent*/)
+ {
+ //unlikely to happen - but just drop if it does
+ //maybe useful later if more BCCMDs (BlueCore VSCs) are used.
+ }
+
+TBool CHCTLBcspControllerManager::DoBcspLinkEstablishedForPowerUp()
+ {
+ __ASSERT_DEBUG(iControllerManagerState == EResetHardware, PANIC(KBcspPanicCat, EUnexpectedControllerMgrState));
+ if(iControllerManagerState == EResetHardware)
+ {
+ if(iObserver)
+ {
+ iObserver->McsoProcessPowerChange(KErrNone, MControllerStateObserver::EBTFatalChange, EBTOn);
+ }
+ iCurrentPowerState = EBTOn;
+ iCurrentTask = ENoTask;
+ iControllerManagerState = EIdle; //controller reset finished
+ }
+ return ETrue;
+ }
+
+TBool CHCTLBcspControllerManager::DoBcspLinkEstablishedForControllerReset()
+ {
+ TBool doTellStack = ETrue;
+
+ switch(iControllerManagerState)
+ {
+ case EResetBCSP:
+ {
+ iHCTLBcsp.WriteBcCmd(iColdResetCommand); //should result in callback to CHCTLBcsp::HandlePeerReset
+ iControllerManagerState = EResetHardware;
+ doTellStack = EFalse;
+ }
+ break;
+ case EResetHardware:
+ {
+ if(iObserver)
+ {
+ iObserver->McsoProcessHardResetPhaseChange(KErrNone, MControllerStateObserver::EBTFatalChange, EBTResetComplete);
+ }
+ iCurrentTask = ENoTask;
+ iControllerManagerState = EIdle; //controller reset finished
+ }
+ break;
+ case EIdle:
+ break;
+
+ default:
+ {
+ PANIC(KBcspPanicCat, EUnexpectedControllerMgrState);
+ }
+ }
+
+ return doTellStack;
+ }
+
+/*static*/TInt CHCTLBcspControllerManager::HandlePowerDown(TAny* aThis)
+ {
+ LOG_STATIC_FUNC
+
+ reinterpret_cast<CHCTLBcspControllerManager*>(aThis)->DoHandlePowerDown();
+ return KErrNone;
+ }
+
+void CHCTLBcspControllerManager::DoHandlePowerDown()
+ {
+ LOG_FUNC
+
+ if(iObserver)
+ {
+ iObserver->McsoProcessPowerChange(KErrNone, MControllerStateObserver::EBTFatalChange, EBTOff);
+ }
+ iCurrentPowerState = EBTOff;
+ iCurrentTask = ENoTask;
+ iControllerManagerState = EIdle;
+ }
+
+/*static*/TInt CHCTLBcspControllerManager::HandleReadyToResetController(TAny* aThis)
+ {
+ LOG_STATIC_FUNC
+
+ reinterpret_cast<CHCTLBcspControllerManager*>(aThis)->DoHandleReadyToResetController();
+ return KErrNone;
+ }
+
+void CHCTLBcspControllerManager::DoHandleReadyToResetController()
+ {
+ LOG_FUNC
+
+ // asynchronous call to tell stack hard reset has started
+ LOG(_L8("HCTLUART: ***Hard Reset Started***"));
+ if(iObserver)
+ {
+ iObserver->McsoProcessHardResetPhaseChange(KErrNone, MControllerStateObserver::EBTFatalChange, EBTResetStarted);
+ }
+ iHCTLBcsp.Reset(); //causes BCSP to re-establish BCSP link (causing call back to CHCLTBcsp::Unchoke())
+ iControllerManagerState = EResetBCSP;
+ }
+
+void CHCTLBcspControllerManager::McroControllerResetComplete()
+ {
+ LOG_FUNC
+
+ if(iObserver)
+ {
+ iObserver->McsoProcessHardResetPhaseChange(KErrNone, MControllerStateObserver::EBTFatalChange, EBTResetComplete);
+ }
+ iCurrentTask = ENoTask;
+ iControllerManagerState = EIdle;
+ }
+
+void CHCTLBcspControllerManager::McpooPowerOnComplete()
+ {
+ if(iObserver)
+ {
+ iObserver->McsoProcessPowerChange(KErrNone, MControllerStateObserver::EBTFatalChange, EBTOn);
+ }
+ iCurrentTask = ENoTask;
+ iControllerManagerState = EIdle;
+ }
+
+/**
+ Setter for the observer
+ @param aObserver A event observer the power man can use to notify power changes
+ */
+void CHCTLBcspControllerManager::SetObserver(MControllerStateObserver& aObserver)
+ {
+ iObserver = &aObserver;
+ }