The Sensor API provides clients with the access to the data provided by various sensors of a device.
API category | public |
API type | c++ |
API libraries | SensrvClient.lib |
Location | /sf/os/deviceio/deviceio_pub/sensor_channel_api
|
Buildfiles | /sf/os/deviceio/deviceio_pub/sensor_channel_api/group/bld.inf
|
The Sensor API consist of the following two parts:
The Sensor API is a library API providing methods to listen for 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 measures the acceleration of the device. As shown in the following diagram, three-dimensional Cartesian coordinate system is used to illustrate direction of the acceleration. The x- and y- axes define 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 the positive direction and negative if movement is toward the negative direction. For example, when a phone is moving along x-axis to the direction of -x, the acceleration is negative.
As shown in the following diagram, there are six basic orientations for a phone. 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.
Sensor channel data listening related use cases
Sensor channel properties related use cases:
Sensor channel conditions related use cases:
Classes | Files |
---|---|
|
/epoc32/include/sensrvchannel.h
CSensrvChannelCondition
/epoc32/include/sensrvchannelcondition.h
CSensrvChannelConditionSet
/epoc32/include/sensrvchannelconditionset.h
CSensrvChannelFinder
/epoc32/include/sensrvchannelfinder.h
MSensrvChannelConditionListener
/epoc32/include/sensrvchannelconditionlistener.h
MSensrvChannelListener
/epoc32/include/sensrvchannellistener.h
MSensrvDataListener
/epoc32/include/sensrvdatalistener.h
MSensrvPropertyListener
/epoc32/include/sensrvpropertylistener.h
TSensrvChannelInfo
/epoc32/include/sensrvchannelinfo.h
TSensrvProperty
/epoc32/include/sensrvproperty.h
/epoc32/include/sensrvtypes.h
The channel finder CSensrvChannelFinder
provides interfaces
to search and find sensor channels that the system provides. Clients can
listen if new channels are installed to the system through the MSensrvChannelListener
callback
interface.
The Sensor channel CSensrvChannel
provides methods to open
and control a sensor channel. The class provides operations to:
data is also provided. New data availability is informed through the MSensrvDataListener
callback
interface.
MSensrvChannelConditionListener
callback interface. Conditions are encapsulated to the CSensrvChannelConditionSet
and CSensrvChannelCondition
classes.
MSensrvPropertyListener
callback interface.
Clients create 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.
To use a sensor channel, a 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 number 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. The 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. A channel data type is the type of an object which a sensor channel provides. Double tapping channel data type declaration is shown as follows.
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; };
The channel data type ID, for example TSensrvTappingData::KDataTypeId
,
is a unique ID for each data type to be able to separate data types from each
other. The data type ID is used in TSensrvChannelInfo
to define
data type used in a channel.
The channel data type index, for example TSensrvTappingData::iDirection
,
is used to point to an attribute inside a data type. Attributes of the TSensrvTappingData
class
are iTimeStamp
and iDirection
. The channel data
type index is used in:
TSensrvProperty
) if a property scope is a channel item.
CSensrvChannelCondition
) to identify which attribute is used as a condition.
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. Accelerometer specific properties
are declared in the sensrvaccelerometersensor.h file. For each property,
a property ID constant and a short description are provided. The property type
specifies the type of the value the property contains. It can be TInt
, TReal
or TBuf
.
The property scope can be defined for:
A mandatory section specifies if the property is required for all channels. The capability section specifies the required capabilities to change value of the property. The 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 defined
are channel data item specific. The item index defines the data item
which the property is related to. If the property is a sensor or channel property,
the item index is KSensrvItemIndexNone
.
iPropertyId = KSensrvPropIdChannelAccuracy iItemIndex = KSensrvItemIndexNone iArrayIndex = ESensrvSingleProperty iRealValue = 10.0 iReadOnly = ETrue iRealValueMax = n/a iRealValueMin = n/a iPropertyType = ESensrvRealProperty iSecurityInfo = n/a
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 into 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 in the NewL()
constructor. After successful construction,
the channel can be opened using the OpenChannelL()
method.
For an opened channel, the client can set and retrieve channel properties, add channel
conditions and listen for sensor data. When the channel is not needed anymore,
it must be closed using 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 );
The channel must be opened before starting to listen for 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 through 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 the heap in the client's thread and its size is the channel data
item size multiplied by the maximum number of data items. There are two receiving
buffers for one client. For example, if the channel data item size
is 20 bytes and the maximum count is 10, the memory consumption is 400 bytes (20bytes*10*2=400 bytes). On the other hand, small desired data count increases the
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 the Sensor API. The following example shows how to handle double
tapping data received notifications. First the channel type of the received
data is checked, and then data object is got 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 is
used when data listening is started. The aDataLost
parameter
tells the number of the lost data objects, for exmaple, 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.
The channel finder CSensrvChannelFinder
provides functionality
to listen for channel changes, such as when new channels are installed to the system or old channels are
removed. Listening is started and stopped with the SetChannelListenerL()
method.
When a channel change occurs, a ChannelChangeDetected()
notification
is delivered through the channel listener callback interface MSensrvChannelListener
.
There is one restriction on the ChannelChangeDetected()
notification:
If a 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 the sensor driver to be reloaded.
The channel must be opened before its properties can be accessed. 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 the channel item property. This means that the item index
must point to valid a channel item index, for example, 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 ); }
The channel must be opened before its properties can be accessed. 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 the 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 }
A property that 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 using the GetArrayIndex()
method.
For array properties, the array index is not the ESensrvSingleProperty
.
An example of array property is illustrated in the KSensrvPropIdDataRate
property
declared in the sensorgeneralproperties.h file.
The following example shows how to get the current data rate of the channel. The data rate is declared as an array property. First, read the KSensrvPropIdDataRate
property
using the GetPropertyL()
method. If the property is
an array property, the result of the GetPropertyL()
call is
a property with the ESensrvArrayPropertyInfo
array index, 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, whose 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 ); }
The value of the channel data item can represent the actual value of the measured
quantity. The channel data item can also represent the 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 the scaled format. For scaled data items,
the KSensrvPropIdScaledRange
property defines the range of the
data item value, and the KSensrvPropIdMeasureRange
property
defines the 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
has considered 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. }
The 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. For example, the accelerometer channel provides the following properties:
KSensrvPropIdChannelDataFormat
with the ESensrvFormatScaled
value.
KSensrvPropIdScaledRange
with the maximum value of 127
KSensrvPropIdMeasureRange
with the maximum value of 2 g
KSensrvPropIdChannelUnit
with the ESensrvUnitGravityConstant
value
In the above example, the accelerometer channel data item value 64 means 1,01g
absolute value (64 / 127 * 2g = 1.01g). The value of the channel data item can
also be scaled and the scaling factor is published in the KSensrvPropIdChannelScale
property.
The channel must be opened before listening for 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 change listening is started and stopped with the SetPropertyListenerL()
method.
When property changes occurs, a PropertyChanged()
notification
is delivered through the property listener callback interface MSensrvPropertyListener
.
The channel must be opened before listening for channel data with conditions.
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 throught the data listener callback interface MSensrvChannelConditionListener
.
The 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 notifications 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 must 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; // The 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 ); // The 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 the condition to condition set iConditionSet->AddChannelConditionL( condition ); //Don't delete the condition because the ownership is transferred to the condition set CleanupStack::Pop( condition ); // Add the 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 the 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 the package descriptor, and the channel data value
which meets the condition is copied to a new package buffer. If the client wants
to use the same condition set after notification, the client must 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 meets the condition //Use the same condition set again if( iDoubleTappingConditionChannel ) { // Add the condition set for the double tapping channel. // Condition listening is not stopped therefore // only the new condition set needs to be added. iDoubleTappingConditionChannel->AddConditionL( *iConditionSet ); } } else { //Size of the aValue is unexpected } } else { //The condition is not met for double tapping channel } }
The leave mechanism and return values are used to indicate errors. Use practices such as stack cleanup
and the TRAP
harness to handle errors. Listener callback interfaces ( MSensrvDataListener
, MSensrvPropertyListener
, MSensrvChannelConditionListener
and MSensrvChannelListener
) offer a callback method to inform errors during listening.
The Sensor Channel API memory consumption cdepends on the channel's data rate and/or size of the data in the receiving buffer. High data rate with a small data receiving buffer causes increased interprocess communications. On the other hand, a big data receiving buffer reserves more memory.
Definition | Description |
Channel | Abstraction of a sensor. Data from one physical sensor may be mapped to several channels. |
Channel condition | A value-operator pair targeting a single value inside a data item, indicated by an index. A condition is met when the channel data value comparison with the condition value using condition operator is true. The conditions are gathered in condition sets. There are two condition types: single limit conditions and range conditions. Range conditions are actually made up from two separate conditions representing lower and upper limits of the range. |
Channel item property | A single property inside channel data item. |
Channel property | A single channel property. |
Data Item | A discrete data package that contains sensor data or an event parsed from sensor data and possibly some related values, such as timestamp. Each channel provides single type of data items only. |
Property | Properties are configuration values of sensors and channels. Changing a property affects all clients listening to affected channel(s). |
Sensor | Physical sensor. Single sensor can provide multiple channels, such as raw data channel and event channels, or multiple sensor readings can be incorporated into a single channel. |
Sensor property | These properties affect all channels which draw data from one physical sensor. |