diff -r 000000000000 -r 4e1aa6a622a0 hwrmhaptics/hapticspluginmanager/src/hwrmhapticsservice.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hwrmhaptics/hapticspluginmanager/src/hwrmhapticsservice.cpp Tue Feb 02 00:53:00 2010 +0200 @@ -0,0 +1,723 @@ +/* +* Copyright (c) 2008 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: Haptic service implementation. +* +*/ + + +#include // RDesReadStream +#include +#include +#include +#include // adaptation interface +#include + +#include "hwrmhapticsclientserver.h" // panic codes, service ID +#include "hwrmhapticsserver.h" // default case in ExecuteMessageL +#include "hwrmhapticsservice.h" +#include "hwrmhapticspluginmanager.h" +#include "hwrmhapticsreservationhandler.h" +#include "hwrmhapticscommondata.h" +#include "hwrmhapticstrace.h" +#include "hwrmhapticspluginrequestdata.h" + +_LIT( KPanicCategory, "HWRMHapticsSService" ); + +// --------------------------------------------------------------------------- +// Two-phased constructor. +// --------------------------------------------------------------------------- +// +EXPORT_C CHWRMHapticsService* CHWRMHapticsService::NewL( + CHWRMHapticsPluginManager* aPluginHandler, + CHWRMHapticsReservationHandler* aReservationHandler, + CHWRMHapticsCommonData& aHapticsCommonData, + const RMessage2& aMessage ) + { + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::NewL()" ) ) ); + + CHWRMHapticsService* self = + new ( ELeave ) CHWRMHapticsService( aHapticsCommonData, aMessage ); + + CleanupStack::PushL( self ); + self->ConstructL( aPluginHandler, aReservationHandler ); + CleanupStack::Pop( self ); + + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::NewL - return 0x%x" ), self ) ); + + return self; + } + +// --------------------------------------------------------------------------- +// Destructor. +// --------------------------------------------------------------------------- +// +CHWRMHapticsService::~CHWRMHapticsService() + { + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::~CHWRMHapticsService()" ) ) ); + + // Cleanup haptics just in case regular cleanup failed + CleanupHaptics(); + + if ( iPacketizer ) + { + delete iPacketizer; + iPacketizer = NULL; + } + + // Complete any pending requests + while ( iTransactionList->FirstItem() ) + { + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::~CHWRMHapticsService() - Deleting request %d" ), iTransactionList->FirstItem()->TransactionId() ) ); + CHWRMHapticsPluginRequestData* data = + static_cast( + iTransactionList->RemoveFirstItem() ); + + if ( data->RequestMessage().Handle() ) + { + // Check that this request is not first one of a split request + if ( !data->CommandSplit() || + !CheckForMessage(data->RequestMessage().Handle()) ) + { + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::~CHWRMHapticsService() - Canceling pending message" ) ) ); + data->RequestMessage().Complete( KErrCancel ); + } + else + { + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::~CHWRMHapticsService() - Split request, not canceling message yet" ) ) ); + } + } + + TRAPD ( err, iPluginManager->CancelCommandL( data->TransactionId() ) ); + + if ( err != KErrNone ) + { + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::~CHWRMHapticsService() - Cancelling Command (transid: %d) failed: %d" ), data->TransactionId(), err ) ); + } + + delete data; + } + + // Destroy transaction list + delete iTransactionList; + + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::~CHWRMHapticsService() - return" ) ) ); + } + +// --------------------------------------------------------------------------- +// Handles Haptics requests. +// --------------------------------------------------------------------------- +// +EXPORT_C TBool CHWRMHapticsService::ExecuteMessageL( + const RMessage2& aMessage ) + { + COMPONENT_TRACE( ( _L( "e_HWRMHAPTICS_SERVICE_EXECUTEMESSAGEL 1" ) ) ); + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ExecuteMessageL(0x%x)" ), aMessage.Function() ) ); + __ASSERT_ALWAYS( iPluginManager, + User::Panic( KPanicCategory, EPanicBadHandle ) ); + __ASSERT_ALWAYS( iReservationHandler, + User::Panic( KPanicCategory, EPanicBadHandle ) ); + + if ( aMessage.IsNull() ) + { + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ExecuteMessageL - NULL message!" ) ) ); + User::Leave( KErrBadHandle ); + } + + TBool completeMessage( EFalse ); + + switch( aMessage.Function() ) + { + case RMessage2::EDisConnect: + { + // send command to close actuator, if actuator has + // been opened (i.e. packetizer exists) + if ( iPacketizer ) + { + SendMsgToPluginManagerL( aMessage ); + } + + CleanupHaptics(); + break; + } + case EHWRMHaptics: + case EHWRMHapticsBridgeCommand: // flow through + { + // send haptics message + SendMsgToPluginManagerL( aMessage ); + break; + } + case EHWRMHapticsPlayEffect: + { + // check if suspended + if ( iSuspended ) + { + // no effect playing, just complete the message + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ExecuteMessageL - Haptics suspended; Play not executed." ) ) ); + aMessage.Complete( KErrNone ); + } + else if ( iReservationHandler->IsReserved( this ) && + iReservationHandler->ReservedPriorityHigher( iSid ) ) + { + // haptics has not been reserved for some other client with + // higher (or equal) priority, notify caller with an error code + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ExecuteMessageL - Haptics Reserved!" ) ) ); + User::Leave( KErrInUse ); + } + else + { + // send play effect -command forwards to plugin manager + SendMsgToPluginManagerL( aMessage ); + } + + break; + } + case EHWRMHapticsOpenActuator: + { + // get actuator type + THWRMLogicalActuators actuator = + static_cast( aMessage.Int2() ); + + // open the plugin to send the message to appropriate actuator; + TBool created = iPluginManager->OpenPluginToActuatorL( actuator ); + + // reset packetizer instance + if ( iPacketizer ) + { + delete iPacketizer; + iPacketizer = NULL; + } + + iPacketizer = CHWRMHapticsPacketizer::NewL( actuator ); + + // if plugin was not created, it already exists. Inform client + // about the last status of the plugin. + if ( !created ) + { + iHapticsCommonData.NotifyActuatorEvent( actuator, iSession ); + } + + // send the open device message; + SendMsgToPluginManagerL( aMessage ); + + break; + } + case EHWRMHapticsCleanup: + { + CleanupHaptics(); + + // complete as there is no ProcessResponse for this + aMessage.Complete( KErrNone ); + break; + } + case EHWRMHapticsReserve: + { + COMPONENT_TRACE( ( _L("CHWRMHapticsService::ExecuteMessageL - EHWRMReserveHaptics") ) ); + + ReserveHapticsL( aMessage ); + + // Since using dummy messages for freeze state restores, need complete always. + completeMessage = ETrue; + + break; + } + case EHWRMHapticsRelease: + { + COMPONENT_TRACE( ( _L("CHWRMHapticsService::ExecuteMessageL - EHWRMReleaseHaptics") ) ); + + ReleaseHaptics(); + + // Since using dummy messages for default state restores, need complete always. + completeMessage = ETrue; + + break; + } + case EHWRMHapticsSuppActuators: + { + // get the supported logical actuator types from + // the plugin manager + TUint32 types = iPluginManager->GetSupportedActuatorInfo(); + + // write the supported types to aMessage + TPckg actuatorInfoRetPckg( types ); + TInt err = aMessage.Write( 0, actuatorInfoRetPckg, 0 ); + + // complete the message + aMessage.Complete( err ); + break; + } + + case EHWRMHapticsSetLicenseProp: + { + // The license key is set automatically if it is given as empty + // string and if LicenseAutoSettingAllowed check succeeds. + // The actual license key setting occures in lower layer, + // here it is enough to create new command message. + + // check license key length + if ( aMessage.Int1() == 0 ) + { + // check if automatic license key setting is allowed + // for the calling client + if ( iPluginManager->LicenseAutoSettingAllowed( aMessage ) && + iPacketizer ) + { + // create buffer for new request data + HWRMHapticsCommand::RHWRMHapticsReqData reqData; + + // client is allowed to get automatic license key setting, + // create new command package + TInt err = iPacketizer->EncSetPlatformLicenseKeyReq( + iPacketizer->DeviceHandle(), + reqData ); + + // write new request data to request message, if creating + // it succeeded + if ( err == KErrNone ) + { + aMessage.Write( 0, reqData, 0 ); + } + + reqData.Close(); + } + } + + // send message to plugin manager + SendMsgToPluginManagerL( aMessage ); + break; + } + case EHWRMHapticsStatusNotification: + { + // store the message. It will be completed only + // when the haptics/actuator status for this client changes + // (thus the command should always be asynchronous on the + // client side) + iHapticsCommonData.AddStatusObserver( aMessage ); + + break; + } + case EHWRMHapticsGetStatus: + { + // get the current status value for this client + MHWRMHapticsObserver::THWRMHapticsStatus status = + iHapticsCommonData.CurrentStatus( aMessage.Session() ); + + // write the status to message + TPckg statusPckg( status ); + TInt err = aMessage.Write( 0, statusPckg, 0 ); + + // complete message + aMessage.Complete( err ); + + break; + } + default: + { + // Cannot identify the message, panic the client + aMessage.Panic( KPanicCategory, EPanicIllegalFunction ); + break; + } + + }//switch + + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ExecuteMessageL - return 0x%x" ), completeMessage ) ); + COMPONENT_TRACE( ( _L( "e_HWRMHAPTICS_SERVICE_EXECUTEMESSAGEL 0" ) ) ); + + return completeMessage; + } + +// --------------------------------------------------------------------------- +// Handles Haptics requests responses. +// --------------------------------------------------------------------------- +// +void CHWRMHapticsService::ProcessResponseL( TInt aCommandId, + TUint8 aTransId, + const TDesC8& aData ) + { + COMPONENT_TRACE( ( _L( "e_HWRMHAPTICS_SERVICE_PROCESSRESPONSEL 1" ) ) ); + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ProcessResponseL(0x%x, 0x%x, )" ), aCommandId, aTransId ) ); + + if( aCommandId == HWRMHapticsCommand::EHapticsCmdId ) + { + TInt contextErr = CompleteRequestL( aTransId, aData ); + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ProcessResponseL - CompleteRequestL ret = %d" ), contextErr ) ); + + // Leave if there is error in context + User::LeaveIfError( contextErr ); + } + + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ProcessResponseL - return" ) ) ); + COMPONENT_TRACE( ( _L( "e_HWRMHAPTICS_SERVICE_PROCESSRESPONSEL 0" ) ) ); + } + +// --------------------------------------------------------------------------- +// Suspends haptics. +// --------------------------------------------------------------------------- +// +void CHWRMHapticsService::SuspendResource() + { + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::SuspendSubResource()" ) ) ); + + iSuspended = ETrue; + + // notify client that haptics for it has been suspended + iHapticsCommonData.NotifyStatus( + MHWRMHapticsObserver::EHWRMHapticsStatusSuspended, iSession ); + + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::SuspendSubResource - return" ) ) ); + } + +// --------------------------------------------------------------------------- +// Resumes haptics. +// --------------------------------------------------------------------------- +// +void CHWRMHapticsService::ResumeResource() + { + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ResumeSubResource()" ) ) ); + + iSuspended = EFalse; + + // notify client that haptics for it is now available + iHapticsCommonData.NotifyStatus( + MHWRMHapticsObserver::EHWRMHapticsStatusAvailable, iSession ); + + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ResumeSubResource - return" ) ) ); + } + +// --------------------------------------------------------------------------- +// Cancels outstanding request by completing the RMessage2 and removing data +// from transaction list. +// --------------------------------------------------------------------------- +// +void CHWRMHapticsService::CancelRequest( TUint8 aTransId ) + { + CHWRMHapticsPluginRequestData* data = + static_cast( + iTransactionList->FindTransaction( aTransId, ETrue ) ); + + if ( data && data->RequestMessage().Handle() ) + { + data->RequestMessage().Complete( KErrTimedOut ); + } + } + +// --------------------------------------------------------------------------- +// Constructor. +// --------------------------------------------------------------------------- +// +CHWRMHapticsService::CHWRMHapticsService( + CHWRMHapticsCommonData& aHapticsCommonData, + const RMessage2& aMessage ) + : iHapticsCommonData( aHapticsCommonData ), iSid( aMessage.SecureId() ), + iSession( aMessage.Session() ) + { + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CHWRMHapticsService()" ) ) ); + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CHWRMHapticsService - return" ) ) ); + } + +// --------------------------------------------------------------------------- +// Symbian 2nd phase constructor. +// --------------------------------------------------------------------------- +// +void CHWRMHapticsService::ConstructL( + CHWRMHapticsPluginManager* aPluginManager, + CHWRMHapticsReservationHandler* aReservationHandler ) + { + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ConstructL(0x%x)" ), aPluginManager ) ); + + if ( !aPluginManager ) + { + User::Leave( KErrBadHandle ); + } + + iPluginManager = aPluginManager; + iReservationHandler = aReservationHandler; + + iTransactionList = new( ELeave ) CHWRMHapticsPluginTransactionList(); + + // set this session to the common data for storing the client + // specific status information + iHapticsCommonData.AddSessionL( iSession ); + + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ConstructL - return " ) ) ); + } + +// --------------------------------------------------------------------------- +// Completes request. Subclass calls this from ProcessResponseL +// --------------------------------------------------------------------------- +// +TInt CHWRMHapticsService::CompleteRequestL( TUint8 aTransId, + const TDesC8& aData ) + { + // return value + TInt contextErr( KErrNone ); + + // find transaction data + CHWRMHapticsPluginRequestData* data = + static_cast( + iTransactionList->FindTransaction( aTransId, ETrue ) ); + + CleanupStack::PushL( data ); + + if ( data && data->RequestMessage().Handle() ) + { + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CompleteRequestL - iRequestMessage.Handle() ok." ) ) ); + + // data storage for the protocol version and error code + CHWRMHapticsRespData* respData = + CHWRMHapticsRespData::NewLC( KErrNone, KNullDesC8 ); + + // internalize data using stream reader + RDesReadStream reader( aData ); + CleanupClosePushL( reader ); + reader >> *respData; + CleanupStack::PopAndDestroy( &reader ); + + // status filled in message decoding + TInt vibeStatus = KErrNone; + + // decode data, if no error + if ( respData->ErrorCode() == KErrNone ) + { + if ( data->RequestMessage().Function() == EHWRMHapticsBridgeCommand ) + { + // bridge command handling + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CompleteRequest - inside EHWRMHapticsBridgeCommand case:" ) ) ); + DATADUMP_TRACE( _L("CHWRMHapticsService::CompleteRequest - (EHWRMHapticsBridgeCommand case) - data dump "), respData->Data() ); + + // write error code and response data + TPckg vibeDummyCodePckg( KErrNone ); + data->RequestMessage().Write( 1, vibeDummyCodePckg, 0 ); + data->RequestMessage().Write( 2, respData->Data(), 0 ); + } + else + { + // decode the message and send it to the callback service + CDesC8ArraySeg* decodeArray = NULL; + TRAPD( err, decodeArray = iPacketizer->DecodeMessageL( + respData->Data(), vibeStatus ) ); + + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CompleteRequestL - Return msg decoding, err = %d" ), err ) ); + + for ( TInt i = 0; err == KErrNone && + i < decodeArray->MdcaCount(); ++i ) + { + // write data back to client + err = data->RequestMessage().Write( + KHapticsMessageResponseArgsOffset + i, + decodeArray->MdcaPoint( i ), 0 ); + } + + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CompleteRequestL - Data writing err = %d" ), err ) ); + } + } + + CleanupStack::PopAndDestroy( respData ); + + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CompleteRequestL - calling iRequestMessage.Complete()") ) ) ; + data->RequestMessage().Complete( vibeStatus ); + } + else + { + // transaction data not found + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CompleteRequest - No transaction data found!" ) ) ); + contextErr = KErrBadHandle; + } + + // cleanup data + CleanupStack::PopAndDestroy( data ); + + return contextErr; + } + +// --------------------------------------------------------------------------- +// Checks transaction list if specified message is in any transaction. +// --------------------------------------------------------------------------- +// +TBool CHWRMHapticsService::CheckForMessage( TInt aHandle ) + { + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CheckForMessage - Checking for message: 0x%x" ), aHandle ) ); + + CHWRMHapticsPluginRequestData* data = + static_cast( + iTransactionList->FirstItem() ); + + TBool retval( EFalse ); + + while ( !retval && data ) + { + if ( data->RequestMessage().Handle() == aHandle ) + { + retval = ETrue; + } + + data = static_cast( data->NextItem() ); + } + + return retval; + } + +// --------------------------------------------------------------------------- +// Cleans up haptics. +// --------------------------------------------------------------------------- +// +void CHWRMHapticsService::CleanupHaptics() + { + if ( !iCleanupDone ) + { + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CleanupHaptics()" ) ) ); + + // release haptics in case this client has made the reservation + ReleaseHaptics(); + + iSuspended = EFalse; + + // remove priority of the client from reservation handler + iReservationHandler->RemovePriority( iSid ); + + // remove this session from the common data + iHapticsCommonData.RemoveSession( iSession ); + + iCleanupDone = ETrue; + + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CleanupHaptics - return" ) ) ); + } + } + +// --------------------------------------------------------------------------- +// Handles Haptics requests. +// --------------------------------------------------------------------------- +// +void CHWRMHapticsService::SendMsgToPluginManagerL( const RMessage2& aMessage ) + { + // Create new data (TransId is updated later, commandId is not important) + CHWRMHapticsPluginRequestData* data( NULL ); + if ( aMessage.Function() == RMessage2::EDisConnect ) + { + data = new ( ELeave ) + CHWRMHapticsPluginRequestData( RMessage2(), 0, 0, EFalse ); + } + else + { + data = new ( ELeave ) + CHWRMHapticsPluginRequestData( aMessage, 0, 0, EFalse ); + } + + CleanupStack::PushL( data ); + + if ( aMessage.Function() == RMessage2::EDisConnect ) + { + // form from Disconnect message actuator closing request + RBuf8 closeBuf; + CleanupClosePushL( closeBuf ); + + User::LeaveIfError( iPacketizer->EncCloseDeviceReq( + iPacketizer->DeviceHandle(), closeBuf ) ); + + HBufC8* reqData = closeBuf.AllocL(); + + CleanupStack::PopAndDestroy( &closeBuf ); + + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::SendMsgToPluginManagerL - Disconnect actuator") ) ); + + // created buffer is deleted in the request data object + data->SetRequestData( reqData ); + + // command to plugin manager + TUint8 transId = iPluginManager->ProcessCommandL( + HWRMHapticsCommand::EHapticsCmdId, + *reqData, this ); + data->SetTransactionId( transId ); + } + else + { + // read message data into a heap buffer + HBufC8* reqData = HBufC8::NewL( aMessage.GetDesLength( 0 ) ); + TPtr8 dataPtr = reqData->Des(); + TInt err = aMessage.Read( 0, dataPtr, 0 ); + + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::SendMsgToPluginManagerL - aMessageRead err = %d"), err ) ); + + // created buffer is deleted in the request data object + data->SetRequestData( reqData ); + + // command to plugin manager + TUint8 transId = iPluginManager->ProcessCommandL( + HWRMHapticsCommand::EHapticsCmdId, + *reqData, this); + data->SetTransactionId( transId ); + } + + // data still needed, do not destroy, just pop + CleanupStack::Pop( data ); + + // Add data to list + iTransactionList->AddTransaction( data ); + } + +// --------------------------------------------------------------------------- +// Reserves haptics. +// --------------------------------------------------------------------------- +// +void CHWRMHapticsService::ReserveHapticsL( const RMessage2& aMessage ) + { + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ReserveHapticsL()" ) ) ); + + // Reserve the haptics + TBool noCoeEnv = aMessage.Int0(); + TBool suspended = iReservationHandler->ReserveL( iSid, noCoeEnv, this ); + + // if reservation became the affective reservation, inform all other + // clients that haptics is reserved + if ( !suspended ) + { + iHapticsCommonData.BroadcastStatus( + MHWRMHapticsObserver::EHWRMHapticsStatusReserved, iSession ); + } + + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ReserveHapticsL() return" ) ) ); + } + +// --------------------------------------------------------------------------- +// Releases haptics. +// --------------------------------------------------------------------------- +// +void CHWRMHapticsService::ReleaseHaptics() + { + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ReleaseHaptics()" ) ) ); + + // get info is haptics currently reserved for this client + TBool activeReservation = iReservationHandler->ActiveReservation( this ); + + // release reservation (removes, if this has a reservation) + TBool reserved = iReservationHandler->Release( this ); + + // if haptics is still reserved for another client, notify client + if ( reserved ) + { + iHapticsCommonData.NotifyStatus( + MHWRMHapticsObserver::EHWRMHapticsStatusReserved, iSession ); + } + else if ( activeReservation ) + { + // haptics was reserved for this client, but there are no more + // reservations --> inform all clients, which have been blocked + iHapticsCommonData.BroadcastStatus( + MHWRMHapticsObserver::EHWRMHapticsStatusAvailable, iSession ); + } + + COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ReleaseHaptics() return" ) ) ); + } + + +// End of File