/*
* 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: Haptics test (adaptation) plugin implementation.
*
*/
#include <s32mem.h>
#include <hwrmhapticscommands.h>
#include "hwrmhapticsstubplugin.h"
// ---------------------------------------------------------------------------
// Static instantiation method.
// ---------------------------------------------------------------------------
//
CHWRMHapticsStubPlugin* CHWRMHapticsStubPlugin::NewL(
MHWRMHapticsPluginCallback* aCallback )
{
CHWRMHapticsStubPlugin* self =
new ( ELeave ) CHWRMHapticsStubPlugin( aCallback );
CleanupStack::PushL( self );
self->ConstructL();
CleanupStack::Pop( self );
return self;
}
// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//
CHWRMHapticsStubPlugin::~CHWRMHapticsStubPlugin()
{
iResponders.ResetAndDestroy();
if ( iIdle )
{
iIdle->Cancel();
delete iIdle;
}
}
// ---------------------------------------------------------------------------
// Implementation of ProcessCommandL. Creates an idle responder and appends it
// to the array of idle responders. (Later then, when the responder gets
// runtime, it will initiate the response generation).
// ---------------------------------------------------------------------------
//
void CHWRMHapticsStubPlugin::ProcessCommandL( TInt aCommandId,
TUint8 aTransId,
TDesC8& aData )
{
if ( aCommandId != HWRMHapticsCommand::EHapticsCmdId ||
aData.Size() < 2 ) // minimum length check
{
User::Leave( KErrBadDescriptor );
}
TUint8* dataPtr = const_cast<TUint8*>( aData.Ptr() );
if ( !dataPtr )
{
User::Leave( KErrBadDescriptor );
}
CHWRMHapticsStubPluginIdleResponder* responder =
CHWRMHapticsStubPluginIdleResponder::NewL( this, aTransId, dataPtr );
CleanupStack::PushL( responder );
iResponders.AppendL( responder );
CleanupStack::Pop ( responder );
}
// ---------------------------------------------------------------------------
// Implementation of CancelCommandL. Just removes the corresponding idle
// responder.
// ---------------------------------------------------------------------------
//
void CHWRMHapticsStubPlugin::CancelCommandL( TUint8 aTransId,
TInt /* aCommandId */ )
{
RemoveResponder( aTransId );
}
// ---------------------------------------------------------------------------
// Method that does the actual response generation towards the issuer of
// command i.e., the HapticsPluginManager
// ---------------------------------------------------------------------------
//
void CHWRMHapticsStubPlugin::GenerateResponseL( TUint8 aTransId,
TUint8* aData )
{
// Hardcoded responses generated based on the command code (first 2 bytes
// of the aData data packet, but since at the moment the 2nd byte is
// always 0x00, we just use the 1st one)
TUint8 command = aData[0];
TBuf8<KHWRMHapticsRespMaxSize> binRespData;
binRespData.SetLength( KHWRMHapticsRespMaxSize );
TInt i( 0 );
// For each command the response data's first two bytes are copy of
// the received command code (first 2 bytes of aData).
binRespData[i++] = aData[0]; // command code bits 0..7
binRespData[i++] = aData[1]; // command code bits 8..15
switch ( command )
{
case 0x00: // API version query
{
// Response to API version query contains:
// 1 byte major version number
// 1 byte minor version number
// 2 bytes for build version
binRespData[i++] = 0x02; // major version
binRespData[i++] = 0x00; // minor version
binRespData[i++] = 0x53; // build version bits 0..7
binRespData[i++] = 0x04; // build version bits 8..15
break;
}
case 0x01: // Initialize
case 0x02: // Terminate
case 0x06: // Modify basis effect
case 0x07: // Stop effect
case 0x08: // Stop all effects
case 0x0B: // Reset debug buffer
case 0x0C: // Stop designed bridge
case 0x13: // Close device
case 0x14: // Start designed bridge
case 0x16: // Play streaming sample
case 0x18: // Destroy streaming effect
case 0x19: // Pause playing effect
case 0x1A: // Resume playing effect
case 0x1E: // Modify magsweep effect
case 0x1F: // Modify periodic effect
{
// For these commands the response only contains status byte
// (set to 0x00 ("Success") in this stub).
binRespData[i++] = 0x00; // status
break;
}
case 0x03: // Play basis effect
case 0x04: // Play IVT effect (with IVT data)
case 0x05: // Play IVT effect (without IVT data)
case 0x17: // Create streaming effect
case 0x1C: // Play magsweep effect
case 0x1D: // Play periodic effect
{
// The response consists of status byte (0x00) and 4-byte long
// effectHandle (here hardcoded as 0x01000000)
binRespData[i++] = 0x00; // status
binRespData[i++] = 0x01; // effectHandle bits 0..7
binRespData[i++] = 0x00; // effectHandle bits 8..15
binRespData[i++] = 0x00; // effectHandle bits 16..23
binRespData[i++] = 0x00; // effectHandle bits 24..31
break;
}
case 0x09: // Get device capabilities
{
// The response consists of status byte (0x00), 4-byte long
// capability type (copied from the received command (bytes
// 7..10)), 1-byte capability value type (copied from the
// received command (byte 2), 1-byte size byte and "size" bytes
// long value
binRespData[i++] = 0x00; // status
binRespData[i++] = aData[7]; // capability type bits 0..7
binRespData[i++] = aData[8]; // capability type bits 8..15
binRespData[i++] = aData[9]; // capability type bits 16..23
binRespData[i++] = aData[10]; // capability type bits 24..31
binRespData[i++] = aData[2]; // capability value type
// The size and value depend on what exactly is being queried
// Note: Currently only the lowest (0..7) bytes of capability
// type have meaning, thus the switch case below is
// simplified..
// Note: Since all values, except device name, are actually 32-bit
// integers, their size is always 4.
TUint8 capabilityType = aData[7];
switch ( capabilityType )
{
case 0: // device category
{
binRespData[i++] = 0x04; // size
binRespData[i++] = 0x02;
binRespData[i++] = 0x00;
binRespData[i++] = 0x00;
binRespData[i++] = 0x00; // value - virtual device
break;
}
case 1: // max nested repeats
case 2: // num of actuators
case 4: // num of effect slots
case 6: // min period
{
binRespData[i++] = 0x04; // size
binRespData[i++] = 0x01;
binRespData[i++] = 0x00;
binRespData[i++] = 0x00;
binRespData[i++] = 0x00; // value - 0x1
break;
}
case 3: // actuator type
{
binRespData[i++] = 0x04; // size
binRespData[i++] = 0x00;
binRespData[i++] = 0x00;
binRespData[i++] = 0x00;
binRespData[i++] = 0x00; // value - ERM actuator
break;
}
case 5: // supported styles
{
binRespData[i++] = 0x04; // size
binRespData[i++] = 0x07;
binRespData[i++] = 0x00;
binRespData[i++] = 0x00;
binRespData[i++] = 0x00; // value - all styles
break;
}
case 7: // max period
case 8: // max effect duration
case 11: // max envelope time
case 13: // max IVT file size (tethered)
case 14: // max IVT file size
{
binRespData[i++] = 0x04; // size
binRespData[i++] = 0xFF;
binRespData[i++] = 0xFF;
binRespData[i++] = 0x00; //
binRespData[i++] = 0x00; // value => 0xFFFF.
break;
}
case 9: // supported effects
{
binRespData[i++] = 0x04; // size
binRespData[i++] = 0x07;
binRespData[i++] = 0x00;
binRespData[i++] = 0x00;
binRespData[i++] = 0x00; // value - mag|per|timeline
break;
}
case 10: // device name
{
binRespData[i++] = 0x04; // size
binRespData[i++] = 0x52; // value - byte 1, ascii "S"
binRespData[i++] = 0x53; // value - byte 2, ascii "T"
binRespData[i++] = 0x54; // value - byte 3, ascii "U"
binRespData[i++] = 0x42; // value - byte 4, ascoo "B"
break;
}
case 12: // API version number
{
binRespData[i++] = 0x04; // size
binRespData[i++] = 0x02;
binRespData[i++] = 0x00;
binRespData[i++] = 0x00;
binRespData[i++] = 0x00; // value - API version
// Note: same as major version in
// specific API version query
// 0x2
break;
}
default:
{
// Here status byte changed to -6 (0xFA)
// ("incompatible capability type")
binRespData[2] = 0xFA; // status (re-assigned)
binRespData[i++] = 0x00; // value size set to zero
break;
}
} // inner switch ends
break;
}
case 0x0A: // Get debug buffer
{
// The response consists of status byte (0x00) and 2 bytes
// indicating the buffer size followed by the buffer itself.
// Here buffer size zero is used => thus this only consists of
// 3 bytes
// FFS: This may have to be changed if the zero-length is not ok.
binRespData[i++] = 0x00; // status
binRespData[i++] = 0x00; // buffer size bits 0..7
binRespData[i++] = 0x00; // buffer size bits 8..15
break;
}
case 0x0D: // Get device state
{
// The response consists of status byte (0x00) and 4 bytes that
// indicate the device state (the bytes used here mean
// "device attached to the system")
binRespData[i++] = 0x00; // status
binRespData[i++] = 0x01; // device state bits 0..7
binRespData[i++] = 0x00; // device state bits 8..15
binRespData[i++] = 0x00; // device state bits 16..23
binRespData[i++] = 0x00; // device state bits 24..31
break;
}
case 0x0E: // Set kernel param
{
// The response consists of status byte (0x00) and 2 bytes that
// are the kernel param Id's copied from the received command
// (bytes 6 and 7)
binRespData[i++] = 0x00; // status
binRespData[i++] = aData[6]; // kernel param Id bits 0..7
binRespData[i++] = aData[7]; // kernel param Id bits 8..15
break;
}
case 0x0F: // Get kernel param
{
// The response consists of status byte (0x00), 2 bytes that are
// the kernel param Id's copied from the received command
// (bytes 6&7) and two bytes for (here dummy 0x00) values
binRespData[i++] = 0x00; // status
binRespData[i++] = aData[6]; // kernel param Id bits 0..7
binRespData[i++] = aData[7]; // kernel param Id bits 8..15
binRespData[i++] = 0x00; // kernel param value bits 0..7
binRespData[i++] = 0x00; // kernel param value bits 8..15
break;
}
case 0x10: // Set device property
{
// The response consists of status byte (0x00), 4 bytes indicating
// the property type (copied from the received command's bytes
// 6..9) and 1 byte indicating the property value type (copied
// from the received command's byte 10).
binRespData[i++] = 0x00; // status
binRespData[i++] = aData[6]; // property type bits 0..7
binRespData[i++] = aData[7]; // property type bits 8..15
binRespData[i++] = aData[8]; // property type bits 16..23
binRespData[i++] = aData[9]; // property type bits 24..31
binRespData[i++] = aData[10]; // property value type
break;
}
case 0x11: // Get device property
{
// The response consists of 1-byte status (0x00), 4-byte long
// property type (copied from the received command bytes 7..10),
// 1-byte property value type (copied from the received command
// byte 2), 1-byte size byte and "size" bytes long value part
binRespData[i++] = 0x00; // status
binRespData[i++] = aData[7]; // property type bits 0..7
binRespData[i++] = aData[8]; // property type bits 8..15
binRespData[i++] = aData[9]; // property type bits 16..23
binRespData[i++] = aData[10]; // property type bits 24..31
binRespData[i++] = aData[2]; // property value type
// The size and value depend on what exactly is being queried
// Note: Currently only the lowest (0..7) bytes of capability type
// have meaning, thus the switch case below is simplified
TUint8 propertyType = aData[7];
switch ( propertyType )
{
case 0:
// license key.. not feasible as GET device property type
{
// re-assign the status
binRespData[2] = 0xF9; // status - incompatible property
// type
binRespData[i++] = 0x00; // value size == 0 (=> no value)
break;
}
case 1: // priority
{
binRespData[i++] = 0x04; // size (32-bit integer takes 4
// bytes)
binRespData[i++] = 0x00;
binRespData[i++] = 0x00;
binRespData[i++] = 0x00;
binRespData[i++] = 0x00; // value - 0x0 is lowest priority
break;
}
case 2: // disable effects
{
binRespData[i++] = 0x04; // size
binRespData[i++] = 0x00;
binRespData[i++] = 0x00;
binRespData[i++] = 0x00;
binRespData[i++] = 0x00; // value - 0x0 means not disabled
break;
}
case 3: // strength
case 4: // master strength
{
binRespData[i++] = 0x04; // size
binRespData[i++] = 0xFF;
binRespData[i++] = 0xFF;
binRespData[i++] = 0x00;
binRespData[i++] = 0x00; // => value 0xFFFF
break;
}
default:
{
// Pehaps it's best to change the status byte to -7 (0xF9)
// ("incompatible property type")
binRespData[2] = 0xF9; // status (re-assigned)
binRespData[i++] = 0x00; // value size, set to zero
break;
}
} // inner switch ends
break;
}
case 0x12: // Open device
{
// The response consists of status byte (0x00) and 4-byte long
// deviceHandle (here hardcoded as 0x01000000)
binRespData[i++] = 0x00; // status
binRespData[i++] = 0x01; // deviceHandle bits 0..7
binRespData[i++] = 0x00; // deviceHandle bits 8..15
binRespData[i++] = 0x00; // deviceHandle bits 16..23
binRespData[i++] = 0x00; // deviceHandle bits 24..31
break;
}
case 0x15: // Device count
{
// The response only contains the device count (here value == 1)
binRespData[i++] = 0x01;
break;
}
case 0x1B: // Get effect state
{
// The response consists of status byte (0x00) and one byte effect
// state (0x00 used here meaning "Not playing")
binRespData[i++] = 0x00; // status
binRespData[i++] = 0x00; // effect state
break;
}
case 0x20: // Load IVT data
{
// The response consists of status byte (0x00) and 4-byte long
// fileHandle (here hardcoded as 0x01000000)
binRespData[i++] = 0x00; // status
binRespData[i++] = 0x01; // fileHandle bits 0..7
binRespData[i++] = 0x00; // fileHandle bits 8..15
binRespData[i++] = 0x00; // fileHandle bits 16..23
binRespData[i++] = 0x00; // fileHandle bits 24..31
break;
}
case 0x30: // Get license key
{
binRespData[i++] = 0x00; // status
binRespData[i++] = 0x20; // size
for( TInt n=0; n<0x20; )
{
binRespData[i++] = 0x53; // S
n++;
binRespData[i++] = 0x54; // T
n++;
binRespData[i++] = 0x55; // U
n++;
binRespData[i++] = 0x42; // B
n++;
}
break;
}
case 0xFF: // Protocol version query
{
// Response to Protocol version query contains:
// 1 byte minor version number
// 1 byte major version number
binRespData[i++] = 0x00; // minor version
binRespData[i++] = 0x03; // major version
break;
}
default:
{
// Unknown command..
break;
}
} // switch ends
// set the lenght of the raw response data
binRespData.SetLength( i );
// create Haptics response data. This is done by externalizing
// (with RDesWriteStream whose sink is the Haptics response data)
TInt32 respDataErr( KErrNone );
CHWRMHapticsRespData* respData =
CHWRMHapticsRespData::NewLC( respDataErr, binRespData );
HWRMHapticsCommand::RHWRMHapticsRespData resp;
resp.CreateL( KHWRMHapticsRespMaxSize );
CleanupClosePushL( resp );
RDesWriteStream streamWriter( resp );
CleanupClosePushL( streamWriter );
streamWriter << *respData;
// This commits to stream's sink (i.e., to 'resp')
CleanupStack::PopAndDestroy( &streamWriter );
// Call the ProcessResponseL of the HapticsPluginManager
// object that created this stub plugin instance.
iResponseCallback->ProcessResponseL
( HWRMHapticsCommand::EHapticsCmdId, aTransId, resp );
CleanupStack::PopAndDestroy( &resp );
CleanupStack::PopAndDestroy( respData );
// Order garbage collection of "spent" responder(s), if not already
// waiting for scheduling
if ( !iIdle->IsActive() )
{
iIdle->Start( TCallBack ( CollectGarbageIdle, this ) );
}
}
// ---------------------------------------------------------------------------
// Static method called as CIdle TCallBack in order to remove obsolete
// responder from the array of responder pointers
// ---------------------------------------------------------------------------
//
TInt CHWRMHapticsStubPlugin::CollectGarbageIdle( TAny* aObjectPtr )
{
CHWRMHapticsStubPlugin* self =
reinterpret_cast<CHWRMHapticsStubPlugin*>( aObjectPtr );
if ( self )
{
self->CollectGarbage();
}
return KErrNone;
}
// ---------------------------------------------------------------------------
// Removes all responders that have finished their work from iResponders array
// ---------------------------------------------------------------------------
//
void CHWRMHapticsStubPlugin::CollectGarbage()
{
for( TInt i( 0 ); i < iResponders.Count(); )
{
if ( iResponders[i]->Active() )
{
++i; // skip this, it's still active..
}
else
{
delete iResponders[i];
iResponders.Remove( i );
// note: array index i is not incremented as in the next round
// it already is the position of next item..
// obviously the iResponders.Count() will be then one less
// than in this round.
}
}
}
// ---------------------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------------------
//
CHWRMHapticsStubPlugin::CHWRMHapticsStubPlugin(
MHWRMHapticsPluginCallback* aCallback )
{
// set callback to baseclass' member variable
iResponseCallback = aCallback;
}
// ---------------------------------------------------------------------------
// Two-phase construction ConstructL
// ---------------------------------------------------------------------------
//
void CHWRMHapticsStubPlugin::ConstructL()
{
iIdle = CIdle::NewL( CActive::EPriorityIdle );
// inform haptics of the plugin state
iResponseCallback->PluginEnabled( EHWRMLogicalActuatorAny, ETrue );
iResponseCallback->PluginEnabled( EHWRMLogicalActuatorDevice, ETrue );
}
// ---------------------------------------------------------------------------
// Removes a specific responder (based on transId) from iResponders array
// ---------------------------------------------------------------------------
//
void CHWRMHapticsStubPlugin::RemoveResponder( TUint8 aTransId )
{
TInt count( iResponders.Count() );
for( TInt i( 0 ); i < count; ++i )
{
if ( iResponders[i]->TransId() == aTransId )
{
delete iResponders[i];
iResponders.Remove( i );
break;
}
}
}
// end of file