/*
* Copyright (c) 2003-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:
* This is a simple program which demonstrates how to start USB services when
* the cable is plugged in, and stop them when it's unplugged. A couple of
* caveats:
* 1. This mechanism will only work on certain hardware platforms (eg. Lubbock).
* 2. The USB Manager will be loaded for the lifetime of this program.
*
*/
#include <e32base.h>
#include <e32math.h>
#include <e32cons.h>
#include <badesca.h>
#include <c32comm.h>
#include <usbman.h>
// The name of the logical device driver to load.
_LIT(KUsbLddName, "EUSBC");
// An argument which, when passed to this program, means "don't run another
// instance of yourself in the background".
_LIT(KForkFlag, "f");
class CUsbCableDetector : public CActive
/**
* This class provides a USB cable detection service. It monitors the state of
* the USB cable and starts and stops USB services appropriately.
*/
{
public:
enum TReqState
{
EIdle = 0,
ENotifyDeviceStateChange,
EStart,
EStop
};
static CUsbCableDetector* NewL();
static CUsbCableDetector* NewLC();
virtual ~CUsbCableDetector();
void CheckAndMonitorCableL();
void MonitorCable();
void RunL();
protected:
CUsbCableDetector();
void ConstructL();
void DoCancel();
TInt RunError(TInt aError);
private:
RUsb iUsbMan;
TUsbDeviceState iDeviceState;
TReqState iReqState;
};
CUsbCableDetector::CUsbCableDetector()
: CActive(EPriorityStandard)
/**
* Constructor. Performs standard active object setup.
*/
{
CActiveScheduler::Add(this);
}
CUsbCableDetector* CUsbCableDetector::NewLC()
/**
* Factory function which leaves the new object on the cleanup stack.
*
* @return a new CUsbCableDetector which is still on the cleanup stack
*/
{
CUsbCableDetector* self = new (ELeave) CUsbCableDetector;
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
CUsbCableDetector* CUsbCableDetector::NewL()
/**
* Factory function.
*
* @return a new CUsbCableDetector
*/
{
CUsbCableDetector* self = CUsbCableDetector::NewLC();
CleanupStack::Pop(self);
return self;
}
void CUsbCableDetector::ConstructL()
/**
* Connects to the USB Manager and gets the current device state.
*/
{
User::LeaveIfError(iUsbMan.Connect());
User::LeaveIfError(iUsbMan.GetDeviceState(iDeviceState));
}
CUsbCableDetector::~CUsbCableDetector()
/**
* Destructor. Cleans up all resources.
*/
{
Cancel();
iUsbMan.Close();
}
void CUsbCableDetector::CheckAndMonitorCableL()
/**
* Checks that the current USB service state is consistent with the state of
* the cable. If the cable is unplugged and USB services are started, we want
* to stop them. If the cable is plugged in and USB services are stopped, we
* want to stop them. In any other situation, we just want to go on monitoring.
*/
{
TUsbServiceState serviceState;
User::LeaveIfError(iUsbMan.GetServiceState(serviceState));
// RDebug::Print(_L("Service state: %d. Device state: %d"), serviceState, iDeviceState);
if ((serviceState != EUsbServiceIdle) &&
(iDeviceState == EUsbDeviceStateUndefined))
{
iReqState = EStop;
iUsbMan.Stop(iStatus);
SetActive();
}
else if ((serviceState != EUsbServiceStarted) &&
(iDeviceState != EUsbDeviceStateUndefined))
{
iReqState = EStart;
iUsbMan.Start(iStatus);
SetActive();
}
else
{
MonitorCable();
}
}
void CUsbCableDetector::MonitorCable()
/**
* Requests a notification from the USB Manager when the device state changes.
*/
{
iReqState = ENotifyDeviceStateChange;
iUsbMan.DeviceStateNotification(KMaxTInt, iDeviceState, iStatus);
SetActive();
}
void CUsbCableDetector::RunL()
/**
* An asynchronous request has completed. The way we handle this depends on our
* current state.
*/
{
User::LeaveIfError(iStatus.Int());
switch (iReqState)
{
case ENotifyDeviceStateChange:
CheckAndMonitorCableL();
break;
case EStart:
case EStop:
MonitorCable();
break;
default:
break;
}
}
void CUsbCableDetector::DoCancel()
/**
* Cancels the current asynchronous request.
*/
{
switch (iReqState)
{
case ENotifyDeviceStateChange:
iUsbMan.DeviceStateNotificationCancel();
break;
case EStart:
iUsbMan.StartCancel();
break;
case EStop:
iUsbMan.StopCancel();
break;
default:
break;
}
}
TInt CUsbCableDetector::RunError(TInt /*aError*/)
/**
* Error handler. Stops the active scheduler, which will cause this program to
* terminate.
*
* @param aError Unused
* @return Always KErrNone to avoid a panic
*/
{
CActiveScheduler::Stop();
return KErrNone;
}
void UsbCableDetectL()
/**
* Starts USB cable detection. This function will never return unless an error
* occurs.
*/
{
TInt ret;
// Load the USB logical device driver.
ret = User::LoadLogicalDevice(KUsbLddName);
if ((ret != KErrNone) && (ret != KErrAlreadyExists))
User::Leave(ret);
// Start the C32 process (in which the USB Manager currently lives).
ret = StartC32();
if ((ret != KErrNone) && (ret != KErrAlreadyExists))
User::Leave(ret);
// Create an active scheduler for the cable detector object.
CActiveScheduler* scheduler = new (ELeave) CActiveScheduler;
CleanupStack::PushL(scheduler);
CActiveScheduler::Install(scheduler);
// Prepare to start monitoring cable state.
CUsbCableDetector* cableDetector = CUsbCableDetector::NewLC();
cableDetector->CheckAndMonitorCableL();
// Action!
CActiveScheduler::Start();
// Clean everything up. We'll only get here if an error occurred.
CleanupStack::PopAndDestroy(2); // scheduler, cableDetector
}
void mainL()
/**
* Main function. If run without any arguments, creates another instance of
* this process with an argument which signifies that it should start cable
* detection. This allows the program to be fired off from the command-line.
*/
{
RProcess thisProcess;
// Create a buffer big enough for the command-line arguments.
HBufC* commandLine = HBufC::NewLC(User::CommandLineLength());
TPtr commandLinePtr = commandLine->Des();
// Get the command-line arguments.
User::CommandLine(commandLinePtr);
if (commandLinePtr == KForkFlag)
{
UsbCableDetectL();
}
else
{
thisProcess.Create(thisProcess.FileName(), KForkFlag);
thisProcess.Resume();
}
CleanupStack::PopAndDestroy(commandLine);
}
GLDEF_C TInt E32Main()
/**
* Symbian OS entry point. Creates a cleanup stack and runs the rest of the
* program.
*
* @return Always 0
*/
{
__UHEAP_MARK;
CTrapCleanup* cleanupStack=CTrapCleanup::New();
TRAP_IGNORE(mainL());
delete cleanupStack;
__UHEAP_MARKEND;
return 0;
}