API description
Sensor API consist of two parts: sensor channel API and sensor
definitions API. Sensor channel API defines the basic functionality
of and utilities of sensor API. Sensor definitions API defines the
features of different sensors. Sensor API is a library API providing
methods to listen data provided by sensor channels. Sensor channels
may also support condition listening to get notified when some limit
is met for a channel. Sensor channels are configured with properties
such as data rate.
Sensor channel measuring the acceleration of the device, three
dimensional Cartesian coordinate system is used to illustrate direction
of the acceleration, see the figure below. The x- and y- axes defines
a plane where z-axis direction is perpendicular to the xy plane. When
a phone is moving along an axis, the acceleration is positive if movement
is towards positive direction and negative if movement is on negative
direction. E.g. when a phone is moving along x-axis to the direction
of -x, the acceleration is negative.
The orientation of a phone is illustrated with six basic orientations,
see the figure below. In display up and display down orientation the
gravitation is along the y-axis. In phone left side up and phone right
side up orientation the gravitation is along the x-axis. In display
upwards and display downwards orientation the gravitation is along
the z-axis.
Use cases
Sensor channel data listening related use cases:
Sensor channel properties related use cases:
Sensor channel conditions related use cases:
API class structure
Channel finder
CSensrvChannelFinder
provides interfaces
to search and find sensor channels that the system provides. The client
can listen if new channels are installed to the system via the
MSensrvChannelListener
callback interface.
Sensor channel
CSensrvChannel
provides methods
to open and control a sensor channel. The class provides operations
to:
-
Start and stop channel data listening. Operation for getting
the new data is also provided. New data availability is informed via
the
MSensrvDataListener
callback interface.
-
Start and stop channel condition listening. The condition reached
is informed via the
MSensrvChannelConditionListener
callback interface. Conditions are encapsulated to the classes
CSensrvChannelConditionSet
and
CSensrvChannelCondition
.
-
Set and get channel properties. Property changes can be listened
via the
MSensrvPropertyListener
callback interface.
The client creates an instance of C classes using the standard
NewL
two phase construction. If a callback interface is
required the client must implement the appropriate M class and provide
its pointer when required.
Related APIs
-
CSensrvChannel
-
CSensrvChannelCondition
-
CSensrvChannelConditionSet
-
CSensrvChannelFinder
-
MSensrvChannelConditionListener
-
MSensrvChannelListener
-
MSensrvDataListener
-
MSensrvPropertyListener
-
NewL
Using Sensor API
To use a sensor channel, the client must find a channel and open
it. The
CSensrvChannelFinder
class provides functionality
to find channels. The
CSensrvChannel
class provides
functionality to open and control channels.
The supported sensor channels are declared in the sensor definitions
API. The amount of implemented channels may vary between products.
For each channel a channel type ID constant and a short description
is provided. Double tapping channel declaration is shown below as
an example. There are two types of channels: raw data channels and
event channels. Raw data channels provide data continuously and event
channels provide data when an appropriate event occurs. Data type
describes what type of data the channel provides.
/**
* - Name: Double tapping event channel type
* - Type: Event
* - Datatype: TSensrvTappingData
* - Description: Double tapping events
*/
const TSensrvChannelTypeId KSensrvChannelTypeIdAccelerometerDoubleTappingData = 0x10205081;
Channel data types are declared in each sensors header file. Channel
data type is the type of an object which a sensor channel provides.
Double tapping channel data type declaration is shown below.
class TSensrvTappingData
{
public:
/**
* Channel data type Id number
*/
static const TSensrvChannelDataTypeId KDataTypeId = 0x1020507F;
/**
* Channel data type enumerations
*/
enum TSensrvAccelerometerAxisDataIndexes
{
iTimeStamp = 0,
iDirection
};
};
public:
/**
* - Item name: Sampling time.
* - Item Index: 0
* - Conditions: None
* - Description: Timestamp for a sample.
*/
TTime iTimeStamp;
/**
* - Item name: Tapping direction bitmask
* - Item Index: 1
* - Conditions: Binary
* - Description: Direction bitmask of the tapping event.
* See constant definitions above.
*/
TUint32 iDirection;
};
Channel data type ID (e.g.
TSensrvTappingData::KDataTypeId
) is a unique ID for each data type to be able to separate data types
from each other. Data type ID is used in
TSensrvChannelInfo
to define data type used in a channel.
Channel data type index (e.g.
TSensrvTappingData::iDirection
) is used to point to an attribute inside a data type. Attributes
of the
TSensrvTappingData
class are
iTimeStamp
and
iDirection
. Channel data type index is used
in:
Channel properties are declared in the
sensrvgeneralproperties.h
and sensor specific files. General properties for all channel types
are declared in the
sensrvgeneralproperties.h
file and accelerometer
specific properties are declared in the
sensrvaccelerometersensor.h
file. For each property, a property ID constant and a short description
are provided. Property type specifies the type of the value the property
contains, it can be
TInt
,
TReal
or
TBuf
. Property scope can be defined for:
A mandatory section specifies if the property is required for all
channels. Capability section specifies the required capabilities to
change value of the property. Accuracy property is shown below as
an example.
/**
* - Name: Accuracy of the channel data
* - Type: TReal
* - Scope: Channel item property
* - Mandatory: No
* - Capability: None
* - Description: Returns the accuracy of this channel of the sensor as a
* percentage of reading (=data value).
*/
const TSensrvPropertyId KSensrvPropIdChannelAccuracy = 0x000000008;
Example content of the Accuracy property is shown below. Properties
which are defined as channel data item specific, item index defines
the data item which the property is related to. If the property is
sensor or channel property, item index is
KSensrvItemIndexNone
. Array index is explained in chapter
Array properties
.
iPropertyId = KSensrvPropIdChannelAccuracy
iItemIndex = KSensrvItemIndexNone
iArrayIndex = ESensrvSingleProperty
iRealValue = 10.0
iReadOnly = ETrue
iRealValueMax = n/a
iRealValueMin = n/a
iPropertyType = ESensrvRealProperty
iSecurityInfo = n/a
Finding, opening and closing a channel
The following example shows how to find, open and close a double
tapping channel. An instance of
CSensrvChannelFinder
is created to be able to find channels. The found channels are stored
to the
RSensrvChannelInfoList
type of object. All
double tapping channels provided by the device are queried by setting
the channel type as
KSensrvChannelTypeIdAccelerometerDoubleTappingData
to the
TSensrvChannelInfo
object which is used
as search criteria. After calling the
FindChannelsL()
method
channelInfoList
contains all the found double
tapping channels. If there are several found channels the client can
select the correct one by examining the content of channel information
objects inside
channelInfoList
.
To construct the
CSensrvChannel
object properly,
a channel information object from
channelInfoList
must be used as a parameter for the
NewL()
constructor.
After successful construction the channel can be opened with the
OpenChannelL()
method. For open channel the client can set
and get channel properties, add channel conditions and listen for
sensor data. When the channel is not needed anymore it must be closed
with the
CloseChannel()
method.
//Construct a channel finder.
CSensrvChannelFinder* channelFinder;
channelFinder = CSensrvChannelFinder::NewL();
CleanupStack::PushL( channelFinder );
//List of found channels.
RSensrvChannelInfoList channelInfoList;
CleanupClosePushL( channelInfoList );
//Create and fill channel search criteria.
//In this example double tapping channel is searched.
TSensrvChannelInfo channelInfo;
channelInfo.iChannelType = KSensrvChannelTypeIdAccelerometerDoubleTappingData;
//Find the double tapping channel
channelFinder->FindChannelsL( channelInfoList, channelInfo );
if( channelInfoList.Count() != 1 )
{
//The device doesn't support double tapping channel or
//there are several double tapping channels.
}
else
{
//double tapping channel found
}
//Open the double tapping channel.
//When the channel object is created the channel info object
//must be an object returned by CSensrvChannelFinder::FindChannelsL().
CSensrvChannel* sensorChannel;
sensorChannel = CSensrvChannel::NewL( channelInfoList[ 0 ] );
CleanupStack::PushL( sensorChannel );
sensorChannel->OpenChannelL();
//
//Double tapping channel is now open.
//
//Close the double tapping channel.
sensorChannel->CloseChannel();
CleanupStack::PopAndDestroy( sensorChannel );
CleanupStack::PopAndDestroy( &channelInfoList ); //Close() is being called on "channelInfoList"
CleanupStack::PopAndDestroy( channelFinder );
Related APIs
-
CSensrvChannel
-
CSensrvChannelFinder
-
CloseChannel()
-
FindChannelsL()
-
KSensrvChannelTypeIdAccelerometerDoubleTappingData
-
NewL()
-
OpenChannelL()
-
RSensrvChannelInfoList
-
TSensrvChannelInfo
-
channelInfoList
Listening channel data
The channel must be opened before starting to listen to channel
data. The following example shows how to start listening to a double
tapping channel and receive data from it. Channel data is received
into the receiving buffer and it can be read using the
GetData()
method. When new data is available in the receiving buffer, a
DataReceived()
notification is delivered via the data listener
callback interface
MSensrvDataListener
.
In case of double tapping channel, the desired count and maximum
count parameters are set to one to get a
DataReceived()
notification per one double tapping. The buffering period is set
to zero to get the
DataReceived()
notification only
when double tapping is done. Channel data can be read from the receiving
buffer using the
GetData()
method. The receiving
buffer is allocated from heap in the client's thread and its size
is the channel data item size multiplied by maximum number of data
items. There are two receiving buffers for one client, for example
in case of the channel data item size is 20 bytes and the maximum
count is 10 results to 400 bytes memory consumption (20bytes*10*2=400
bytes). On the other hand, small desired data count increases interprocess
communication. The client needs to provide a pointer to the data listener
for the channel to be able to receive
DataReceived()
notifications.
iSensorChannel->StartDataListeningL( this, //this object is data listener for this channel
1, //aDesiredCount is one, i.e. each double tapping is notified separately
1, //aMaximumCount is one, i.e. object count in receiving data buffer is one
0 );//buffering period is not used
To implement data listener the client needs to inherit from the
MSensrvDataListener
interface class and implement declared
pure virtual methods. When a new data is available in the sensor channel
and data listening is started, the
DataReceived()
method is called by Sensor API. The following example shows how
to handle double tapping data received notification. First the channel
type of the received data is checked and then data object is get with
the
GetData()
method. The
aCount
parameter tells the number of data objects in the channels receiving
buffer and it can be zero if the buffering period was used when data
listening was started. The
aDataLost
parameter tells
the number of the lost data objects e.g. in heavy load situations.
void CTestClass::DataReceived( CSensrvChannel& aChannel,
TInt aCount,
TInt aDataLost )
{
if ( aChannel.GetChannelInfo().iChannelType == KSensrvChannelTypeIdAccelerometerDoubleTappingData )
{
TSensrvTappingData tappingData;
TPckg<TSensrvTappingData> tappingPackage( tappingData );
aChannel.GetData( tappingPackage );
}
}
When data listening is not needed anymore it must be stopped with
the
StopDataListening()
method.
Related APIs
-
DataReceived()
-
GetData()
-
MSensrvDataListener
-
StopDataListening()
-
aCount
-
aDataLost
Listening channel changes
The channel finder
CSensrvChannelFinder
provides
functionality to listen if new channels are installed to the system
or old channels are removed. Listening is started and stopped with
the
SetChannelListenerL()
method. When channel change
occurs, a
ChannelChangeDetected()
notification is
delivered via the channel listener callback interface
MSensrvChannelListener
. There is one restriction on the
ChannelChangeDetected()
notification: If sensor changes the existing channel registration
there must be an open channel to that sensor to prevent sensor driver
unloading. In practise, this means that at least one channel from
this sensor must have a client to keep the channel open and sensor
driver loaded. If the sensor driver is unloaded while new channels
become available it cannot notify new channels until some existing
channel opening causes sensor driver to be reloaded.
Related APIs
-
CSensrvChannelFinder
-
ChannelChangeDetected()
-
MSensrvChannelListener
-
SetChannelListenerL()
Getting channel properties
The channel must be opened before accessing its properties. The
channel properties are capsulated to the
TSensrvProperty
class and can be queried with the
GetPropertyL()
method. The following example shows how to check accuracy of the
channel.
GetPropertyL()
leaves if the channel does
not support the Accuracy property. Leave also occurs if the Accuracy
property is defined as channel item property, i.e. item index must
point to valid channel item index e.g.
TSensrvAccelerometerAxisData::iAxisX
.
TSensrvProperty property;
TReal propertyValue( 0 );
iSensorChannel->GetPropertyL( KSensrvPropIdChannelAccuracy,
KSensrvItemIndexNone,
property );
// KSensrvPropIdDataType is specified as TReal of type in sensrvgeneralproperties.h.
// Type of the property can also be checked at runtime with PropertyType() method.
if( property.PropertyType() == ESensrvRealProperty )
{
property.GetValue( propertyValue );
}
Related APIs
-
GetPropertyL()
-
TSensrvAccelerometerAxisData::iAxisX
-
TSensrvProperty
Setting channel properties
The channel must be opened before accessing its properties. Channel
properties can be changed with the
SetProperty()
method.
In the following example the x-axis of accelerometer channel is deactivated.
The axis active property
KSensrvPropIdAxisActive
with
item index is first got with the
GetPropertyL()
method.
If the axis is active it is deactivated by setting a new value to
the previously got property. Updated property is set with the
SetProperty()
method.
TSensrvProperty property;
TInt err( KErrNone );
TInt axisActive( 0 );
iSensorChannel->GetPropertyL( KSensrvPropIdAxisActive,
TSensrvAccelerometerAxisData::Index::iAxisX,
property );
property.GetValue( axisActive );
if( 1 == axisActive )
{
property.SetValue( 0 );//Other value than one means that sensor axis is deactivated.
err = iSensorChannel->SetProperty( property );
if( KErrNone == err )
{
//Accelerometer x-axis was succesfully deactivated
}
}
else
{
//Accelerometer x-axis is allready deactive
}
Related APIs
-
GetPropertyL()
-
KSensrvPropIdAxisActive
-
SetProperty()
Array properties
A property which defines multiple discrete values inside one property
ID is called an array property. Array properties can be identified
with array index which can be queried from property with the
GetArrayIndex()
method. For array properties the array index
is something else than
ESensrvSingleProperty
. An
example of array property is illustrated in the
KSensrvPropIdDataRate
property documentation in the
sensorgeneralproperties.h
file.
The following example shows how to get current data rate of the
channel which data rate is declared as an array property. First, the
KSensrvPropIdDataRate
property is read with the
GetPropertyL()
method. If the property is an array property
the result of the
GetPropertyL()
call is a property
with array index
ESensrvArrayPropertyInfo
, otherwise
the array information index is
ESensrvSingleProperty
. In case of an array property, the value of the current data rate
is in the
KSensrvPropIdDataRate
property which array
index is same as the array property's value.
TSensrvProperty property;
TInt err( KErrNone );
TInt datarate( 0 );
iSensorChannel->GetPropertyL( KSensrvPropIdDataRate,
KSensrvItemIndexNone,
property );
if( ESensrvArrayPropertyInfo == property.GetArrayIndex() )
{
//Current data rate in use is in KSensrvPropIdDataRate property
//which array index is declared in array propertys value.
TInt arrayIndex( 0 );
property.GetValue( arrayIndex );
iSensorChannel->GetPropertyL( KSensrvPropIdDataRate,
KSensrvItemIndexNone,
arrayIndex,
property );
property.GetValue( datarate );
}
else
{
//KSensrvPropIdDataRate is a single property and current data rate can be read diretly from it.
property.GetValue( datarate );
}
Related APIs
-
ESensrvArrayPropertyInfo
-
ESensrvSingleProperty
-
GetArrayIndex()
-
GetPropertyL()
-
KSensrvPropIdDataRate
Scaling channel data
Value of channel data item can represent the actual value of the
measured quantity, or the channel data item can represent relative
value which is scaled to between maximum and minimum value of the
measured quantity. The
KSensrvPropIdChannelDataFormat
property defines if channel data items are in scaled format. For
scaled data items the
KSensrvPropIdScaledRange
property
defines range for the data item value and the
KSensrvPropIdMeasureRange
property defines range for the measured quantity.
The following example reads the maximum value of measure range
for data items
(KSensrvPropIdScaledRange)
and the
maximum value of the measured quantity
(KSensrvPropIdMeasureRange)
. The example takes into account that the
KSensrvPropIdMeasureRange
property can be defined as an array property.
TSensrvProperty property;
TInt channelDataFormat( ESensrvFormatAbsolute );
TInt channelDataScaledRange( 1 );
TReal channelDataMeasureRangeMaxValue( 1 );
//Read channel data format
iSensorChannel->GetPropertyL( KSensrvPropIdChannelDataFormat, KSensrvItemIndexNone, property );
property.GetValue( channelDataFormat );
if( ESensrvFormatScaled == channelDataFormat )
{
//Read data item scaled range
iSensorChannel->GetPropertyL( KSensrvPropIdScaledRange, KSensrvItemIndexNone, property );
property.GetMaxValue( channelDataScaledRange );
//Read data item measure range
iSensorChannel->GetPropertyL( KSensrvPropIdMeasureRange, KSensrvItemIndexNone, property );
if( ESensrvArrayPropertyInfo == property.GetArrayIndex() )
{
TInt arrayIndex( 0 );
property.GetValue( arrayIndex );//Value points to array index currently in use
iSensorChannel->GetPropertyL( KSensrvPropIdMeasureRange,
KSensrvItemIndexNone,
arrayIndex,
property );
}
else
{
//Single property
}
property.GetMaxValue( channelDataMeasureRangeMaxValue );
}
else
{
//No scaling needed.
//Value of the data item represents actual value of the measured quantity.
}
Scaled channel data item value can be converted to absolute value
by dividing the channel data item value with the maximum value of
scaled range of the channel and multiplying it with the maximum value
of the measured quantity. E.g. accelerometer channel provides the
following properties:
-
KSensrvPropIdChannelDataFormat
with value
ESensrvFormatScaled
-
KSensrvPropIdScaledRange
with maximum value
of 127
-
KSensrvPropIdMeasureRange
with maximum value
of 2 g
-
KSensrvPropIdChannelUnit
with value
ESensrvUnitGravityConstant
In the above example accelerometer channel data item value 64 means
1,01g absolute value (64 / 127 * 2g = 1.01g). Value of the channel
data item can also be scaled and the scaling factor is published in
the
KSensrvPropIdChannelScale
property.
Related APIs
-
(KSensrvPropIdMeasureRange)
-
(KSensrvPropIdScaledRange)
-
ESensrvFormatScaled
-
ESensrvUnitGravityConstant
-
KSensrvPropIdChannelDataFormat
-
KSensrvPropIdChannelScale
-
KSensrvPropIdChannelUnit
-
KSensrvPropIdMeasureRange
-
KSensrvPropIdScaledRange
Listening channel property changes
The channel must be opened before listening to channel property
changes. The client can use the property listener to get notifications
about changed properties. If the client itself changes a property
value, no notification is received. Property changes listening is
started and stopped with the
SetPropertyListenerL()
method. When property change occurs, a
PropertyChanged()
notification is delivered via the property listener callback interface
MSensrvPropertyListener
.
Related APIs
-
MSensrvPropertyListener
-
PropertyChanged()
-
SetPropertyListenerL()
Listening channel data with condition
The channel must be opened before listening to channel data with
condition. The following example shows how to start listening to double
taps coming from the x-axis direction. When the condition is met,
a
ConditionMet()
notification is delivered via the
data listener callback interface
MSensrvChannelConditionListener
.
Direction from tapping data (
TSensrvTappingData
) is used as a condition in this example. The direction value is
set to the x-axis plus and minus to get notification from double tap
in both x-axis directions. A condition set is created for a container
for one or more conditions. A condition is created to hold a channel
condition item, see detailed comments from the example below. The
condition is added to the condition set and the condition set is added
to the channel. The client has ownership to this condition set and
it has to ensure that the condition set object is valid until the
condition set is removed from the channel or the channel is destroyed.
After the condition set is added to the channel the condition listening
is started with the
StartConditionListeningL()
method.
The client needs to provide a pointer to the condition listener for
the channel to be able to receive the
ConditionMet()
notification.
CSensrvChannelCondition* condition = NULL;
// Condition for double tapping channel is set so that
// double tap to X-axis triggers condition met notification
TSensrvTappingData doubleTappingCondition;
TPckgC<TSensrvTappingData> doubleTappingConditionPckg( doubleTappingCondition );
doubleTappingCondition.iTimeStamp = 0;
doubleTappingCondition.iDirection = KSensrvAccelerometerDirectionXplus | KSensrvAccelerometerDirectionXminus;
// In this example logical operator to be used in the condition set
// does not have any effect because only one condition is added
// to the condition set
iConditionSet = CSensrvChannelConditionSet::NewL( ESensrvOrConditionSet );
// Binary condition (ESensrvBinaryCondition) is used because double tapping
// channel provides bitmask values.
// Binary and (ESensrvOperatorBinaryAnd) operator is used because operator
// checks if a bitmask data value got from double tapping channel has set at least
// one of the bits set in the condition value.
// In other words double tapping direction can be positive or negative.
// Item index (3rd parameter) defines which attribute in data item is used for condition evaluation.
// TSensrvTappingData::Index::iDirection means that iDirection is used
// for condition from TSensrvTappingData class.
// Last parameter (doubleTappingConditionPckg) contains value for
// condition evaluation encapsulated in the package descriptor.
condition = CSensrvChannelCondition::NewLC( ESensrvBinaryCondition,
ESensrvOperatorBinaryAnd,
TSensrvTappingData::Index::iDirection,
doubleTappingConditionPckg );
//Add condition to condition set
iConditionSet->AddChannelConditionL( condition );
//Don't delete condition since ownership is transferred to condition set
CleanupStack::Pop( condition );
// Add condition set for the double tapping channel
iDoubleTappingConditionChannel->AddConditionL( *iConditionSet );
// Start condition listening
// aObjectCount is one, i.e. each double tapping condition is notified separately
// buffering period is not used, i.e. it is set to zero
iDoubleTappingConditionChannel->StartConditionListeningL( iDataListener2,
1,
0 );
To implement condition listener the client needs to inherit from
the
MSensrvChannelConditionListener
interface class
and implement declared pure virtual methods. When a channel condition
set is met and condition listening is started, the
ConditionMet()
method is called by Sensor Channel API. The following example shows
how to handle condition met notification for double tapping channel.
First the channel type of the received data and correct data buffer
size is checked. The received data object is encapsulated in package
descriptor thus channel data value which met the condition is copied
to a new package buffer. If the client wants to use the same condition
set after notification, the client has to add the condition set again
to the channel object.
void CTestClass::ConditionMet( CSensrvChannel& aChannel,
CSensrvChannelConditionSet& aChannelConditionSet,
TDesC8& aValue )
{
if( aChannel.GetChannelInfo().iChannelType == KSensrvChannelTypeIdAccelerometerDoubleTappingData )
{
if ( sizeof(TSensrvTappingData) == aValue.Size() )
{
TPckgBuf<TSensrvTappingData> dataBuf;
dataBuf.Copy( aValue );
//dataBuf() contains channel data value which met the condition
//Use the same condition set again
if( iDoubleTappingConditionChannel )
{
// Add condition set for the double tapping channel.
// Condition listening is not stopped thus
// only new condition set is needed to be added.
iDoubleTappingConditionChannel->AddConditionL( *iConditionSet );
}
}
else
{
//Size of the aValue was unexpected
}
}
else
{
//Condition was not met for double tapping channel
}
}
Related APIs
-
ConditionMet()
-
MSensrvChannelConditionListener
-
StartConditionListeningL()
-
TSensrvTappingData
Error handling
The leave mechanism and return values are used to indicate errors.
Normal Symbian error handling practises should be used, including
e.g. using cleanup stack and the
TRAP
harness. Listener
callback interfaces (
MSensrvDataListener
,
MSensrvPropertyListener
,
MSensrvChannelConditionListener
and
MSensrvChannelListener
) offer a callback method
for informing error during listening.
Related APIs
-
MSensrvChannelConditionListener
-
MSensrvChannelListener
-
MSensrvDataListener
-
MSensrvPropertyListener
-
TRAP
Memory overhead
The Sensor Channel API memory overhead depends on the channel's
data rate and/or size of the data in the receiving buffer. High data
rate with small data receiving buffer causes increased interprocess
communication. On the other hand, big data receiving buffer reserves
more memory. See example from Section
Listening channel data
.
Related APIs
-
CSensrvChannel
-
CSensrvChannelCondition
-
CSensrvChannelFinder
-
KSensrvItemIndexNone
-
TBuf
-
TInt
-
TReal
-
TSensrvChannelInfo
-
TSensrvProperty
-
TSensrvTappingData
-
TSensrvTappingData::KDataTypeId
-
TSensrvTappingData::iDirection
-
iDirection
-
iTimeStamp